feat(input-stepper): align value with step size (#2511)
* feat(input-stepper): add alignToStep property to align value with step size * Create silver-eyes-count.md * refactor: make alignTosTep property behavior as default behavior and remove property attribute * test(input-stepper): handle min value as Infinity and update tests for decrement/increment behavior --------- Co-authored-by: Manuel Servais <manuel.servais@ing.com>
This commit is contained in:
parent
f9f55193c3
commit
cf4a8fd1b0
4 changed files with 138 additions and 4 deletions
5
.changeset/silver-eyes-count.md
Normal file
5
.changeset/silver-eyes-count.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
"@lion/ui": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
feat(input-stepper): add alignToStep property to align value with step value
|
||||||
|
|
@ -111,3 +111,19 @@ export const formatting = () => {
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Aligning to step
|
||||||
|
|
||||||
|
The value is always aligned with the defined step size when using the increase or decrease buttons. The input value will be adjusted to the nearest valid step multiple. For example, with a step of `10` starting from `1`, if the user enters `55` and clicks the increase button, the value will align to `61` instead of `65` (1 > 11 > 21 > ... > 51 > 61).
|
||||||
|
|
||||||
|
```html preview-story
|
||||||
|
<lion-input-stepper
|
||||||
|
label="Amount of oranges"
|
||||||
|
min="1"
|
||||||
|
max="100"
|
||||||
|
step="10"
|
||||||
|
name="value"
|
||||||
|
alignToStep
|
||||||
|
value="55"
|
||||||
|
></lion-input-stepper>
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -265,8 +265,19 @@ export class LionInputStepper extends LocalizeMixin(LionInput) {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
__increment() {
|
__increment() {
|
||||||
const { step, min, max } = this.values;
|
const { step, max } = this.values;
|
||||||
const newValue = this.currentValue + step;
|
let { min } = this.values;
|
||||||
|
if (min === Infinity) {
|
||||||
|
min = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let newValue = this.currentValue + step;
|
||||||
|
|
||||||
|
if ((this.currentValue + min) % step !== 0) {
|
||||||
|
// If the value is not aligned to step, align it to the nearest step
|
||||||
|
newValue = Math.floor(this.currentValue / step) * step + step + (min % step);
|
||||||
|
}
|
||||||
|
|
||||||
if (newValue <= max || max === Infinity) {
|
if (newValue <= max || max === Infinity) {
|
||||||
this.modelValue = newValue < min && min !== Infinity ? `${min}` : `${newValue}`;
|
this.modelValue = newValue < min && min !== Infinity ? `${min}` : `${newValue}`;
|
||||||
this.__toggleSpinnerButtonsState();
|
this.__toggleSpinnerButtonsState();
|
||||||
|
|
@ -279,8 +290,16 @@ export class LionInputStepper extends LocalizeMixin(LionInput) {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
__decrement() {
|
__decrement() {
|
||||||
const { step, min, max } = this.values;
|
const { step, max, min } = this.values;
|
||||||
const newValue = this.currentValue - step;
|
const stepMin = min !== Infinity ? min : 0;
|
||||||
|
|
||||||
|
let newValue = this.currentValue - step;
|
||||||
|
|
||||||
|
if ((this.currentValue + stepMin) % step !== 0) {
|
||||||
|
// If the value is not aligned to step, align it to the nearest step
|
||||||
|
newValue = Math.floor(this.currentValue / step) * step + (stepMin % step);
|
||||||
|
}
|
||||||
|
|
||||||
if (newValue >= min || min === Infinity) {
|
if (newValue >= min || min === Infinity) {
|
||||||
this.modelValue = newValue > max && max !== Infinity ? `${max}` : `${newValue}`;
|
this.modelValue = newValue > max && max !== Infinity ? `${max}` : `${newValue}`;
|
||||||
this.__toggleSpinnerButtonsState();
|
this.__toggleSpinnerButtonsState();
|
||||||
|
|
|
||||||
|
|
@ -265,6 +265,100 @@ describe('<lion-input-stepper>', () => {
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
expect(incrementButton?.getAttribute('disabled')).to.equal('true');
|
expect(incrementButton?.getAttribute('disabled')).to.equal('true');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('It align to steps', () => {
|
||||||
|
it('aligns the value to the nearest step when incrementing', async () => {
|
||||||
|
let el = await fixture(
|
||||||
|
html`<lion-input-stepper step="10" min="0" max="100" value="55"></lion-input-stepper>`,
|
||||||
|
);
|
||||||
|
let incrementButton = el.querySelector('[slot=suffix]');
|
||||||
|
incrementButton?.dispatchEvent(new Event('click'));
|
||||||
|
await el.updateComplete;
|
||||||
|
expect(el.modelValue).to.equal(60, 'Fail + : (0 > 100 by 10; val 55)');
|
||||||
|
|
||||||
|
// min 1
|
||||||
|
el = await fixture(
|
||||||
|
html`<lion-input-stepper step="10" min="1" max="100" value="55"></lion-input-stepper>`,
|
||||||
|
);
|
||||||
|
incrementButton = el.querySelector('[slot=suffix]');
|
||||||
|
incrementButton?.dispatchEvent(new Event('click'));
|
||||||
|
await el.updateComplete;
|
||||||
|
expect(el.modelValue).to.equal(61, 'Fail + : (1 > 100 by 10; val 55)');
|
||||||
|
|
||||||
|
// min 34
|
||||||
|
el = await fixture(
|
||||||
|
html`<lion-input-stepper step="10" min="34" max="100" value="55"></lion-input-stepper>`,
|
||||||
|
);
|
||||||
|
incrementButton = el.querySelector('[slot=suffix]');
|
||||||
|
incrementButton?.dispatchEvent(new Event('click'));
|
||||||
|
await el.updateComplete;
|
||||||
|
expect(el.modelValue).to.equal(64, 'Fail + : (34 > 100 by 10; val 55)');
|
||||||
|
|
||||||
|
// min -23
|
||||||
|
el = await fixture(
|
||||||
|
html`<lion-input-stepper step="10" min="-23" max="100" value="55"></lion-input-stepper>`,
|
||||||
|
);
|
||||||
|
incrementButton = el.querySelector('[slot=suffix]');
|
||||||
|
incrementButton?.dispatchEvent(new Event('click'));
|
||||||
|
await el.updateComplete;
|
||||||
|
expect(el.modelValue).to.equal(57, 'Fail + : (-23 > 100 by 10; val 55)'); // -23 > -13 > -3 > 7 > ... > 57
|
||||||
|
|
||||||
|
// min -23
|
||||||
|
el = await fixture(
|
||||||
|
html`<lion-input-stepper step="10" min="-23" max="100" value="-9"></lion-input-stepper>`,
|
||||||
|
);
|
||||||
|
incrementButton = el.querySelector('[slot=suffix]');
|
||||||
|
incrementButton?.dispatchEvent(new Event('click'));
|
||||||
|
await el.updateComplete;
|
||||||
|
expect(el.modelValue).to.equal(-3, 'Fail + : (-23 > 100 by 10; val 55)'); // -23 > -13 > -3 > 7
|
||||||
|
});
|
||||||
|
|
||||||
|
it('aligns the value to the nearest step when decrementing', async () => {
|
||||||
|
let el = await fixture(
|
||||||
|
html`<lion-input-stepper step="10" min="0" max="100" value="55"></lion-input-stepper>`,
|
||||||
|
);
|
||||||
|
let decrementButton = el.querySelector('[slot=prefix]');
|
||||||
|
decrementButton?.dispatchEvent(new Event('click'));
|
||||||
|
await el.updateComplete;
|
||||||
|
expect(el.modelValue).to.equal(50, 'Fail - : (0 > 100 by 10; val 55)');
|
||||||
|
|
||||||
|
// min 1
|
||||||
|
el = await fixture(
|
||||||
|
html`<lion-input-stepper step="10" min="1" max="100" value="55"></lion-input-stepper>`,
|
||||||
|
);
|
||||||
|
decrementButton = el.querySelector('[slot=prefix]');
|
||||||
|
decrementButton?.dispatchEvent(new Event('click'));
|
||||||
|
await el.updateComplete;
|
||||||
|
expect(el.modelValue).to.equal(51, 'Fail - : (1 > 100 by 10; val 55)');
|
||||||
|
|
||||||
|
// min 34
|
||||||
|
el = await fixture(
|
||||||
|
html`<lion-input-stepper step="10" min="34" max="100" value="55"></lion-input-stepper>`,
|
||||||
|
);
|
||||||
|
decrementButton = el.querySelector('[slot=prefix]');
|
||||||
|
decrementButton?.dispatchEvent(new Event('click'));
|
||||||
|
await el.updateComplete;
|
||||||
|
expect(el.modelValue).to.equal(54, 'Fail - : (34 > 100 by 10; val 55)');
|
||||||
|
|
||||||
|
// min -23
|
||||||
|
el = await fixture(
|
||||||
|
html`<lion-input-stepper step="10" min="-23" max="100" value="55"></lion-input-stepper>`,
|
||||||
|
);
|
||||||
|
decrementButton = el.querySelector('[slot=prefix]');
|
||||||
|
decrementButton?.dispatchEvent(new Event('click'));
|
||||||
|
await el.updateComplete;
|
||||||
|
expect(el.modelValue).to.equal(47, 'Fail - : (-23 > 100 by 10; val 55)'); // -23 > -13 > -3 > 7 > ... > 47
|
||||||
|
|
||||||
|
// min -23
|
||||||
|
el = await fixture(
|
||||||
|
html`<lion-input-stepper step="10" min="-23" max="100" value="-9"></lion-input-stepper>`,
|
||||||
|
);
|
||||||
|
decrementButton = el.querySelector('[slot=prefix]');
|
||||||
|
decrementButton?.dispatchEvent(new Event('click'));
|
||||||
|
await el.updateComplete;
|
||||||
|
expect(el.modelValue).to.equal(-13, 'Fail - : (-23 > 100 by 10; val 55)'); // -23 > -13 > -3 > 7
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Accessibility', () => {
|
describe('Accessibility', () => {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue