fix(LionInputStepper): improve handling of decimal step values and al… (#2621)
Some checks failed
Release / Release (push) Has been cancelled

* fix(LionInputStepper): improve handling of decimal step values and alignment

* fix: add changeset LionInputStepper improvements
This commit is contained in:
MiB-1 2025-11-18 09:10:33 +01:00 committed by GitHub
parent cc4ca7fe9d
commit 579e42b339
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 68 additions and 8 deletions

View file

@ -0,0 +1,5 @@
---
'@lion/ui': patch
---
fix(LionInputStepper): improve handling of decimal step values and alignment closes #2615

View file

@ -267,12 +267,19 @@ export class LionInputStepper extends LocalizeMixin(LionInput) {
_increment() { _increment() {
const { step, min, max } = this.values; const { step, min, max } = this.values;
const stepMin = min !== Infinity ? min : 0; const stepMin = min !== Infinity ? min : 0;
const epsilon = 1e-10; // Tolerance for floating-point comparison
let newValue = this.currentValue + step; let newValue;
if ((this.currentValue + stepMin) % step !== 0) { const remainder = (this.currentValue - stepMin) % step;
// If the value is not aligned to step, align it to the nearest step const isAligned = Math.abs(remainder) < epsilon || Math.abs(remainder - step) < epsilon;
newValue = Math.floor(this.currentValue / step) * step + step + (stepMin % step);
if (!isAligned) {
// If the value is not aligned to step, align it to the next valid step
newValue = Math.ceil((this.currentValue - stepMin) / step) * step + stepMin;
} else {
// If the value is aligned, just add the step
newValue = this.currentValue + step;
} }
if (newValue <= max || max === Infinity) { if (newValue <= max || max === Infinity) {
@ -289,12 +296,19 @@ export class LionInputStepper extends LocalizeMixin(LionInput) {
_decrement() { _decrement() {
const { step, max, min } = this.values; const { step, max, min } = this.values;
const stepMin = min !== Infinity ? min : 0; const stepMin = min !== Infinity ? min : 0;
const epsilon = 1e-10; // Tolerance for floating-point comparison
let newValue = this.currentValue - step; let newValue;
if ((this.currentValue + stepMin) % step !== 0) { const remainder = (this.currentValue - stepMin) % step;
// If the value is not aligned to step, align it to the nearest step const isAligned = Math.abs(remainder) < epsilon || Math.abs(remainder - step) < epsilon;
newValue = Math.floor(this.currentValue / step) * step + (stepMin % step);
if (!isAligned) {
// If the value is not aligned to step, align it to the previous valid step
newValue = Math.floor((this.currentValue - stepMin) / step) * step + stepMin;
} else {
// If the value is aligned, just subtract the step
newValue = this.currentValue - step;
} }
if (newValue >= min || min === Infinity) { if (newValue >= min || min === Infinity) {

View file

@ -359,6 +359,47 @@ describe('<lion-input-stepper>', () => {
await el.updateComplete; await el.updateComplete;
expect(el.modelValue).to.equal(-13, 'Fail - : (-23 > 100 by 10; val 55)'); // -23 > -13 > -3 > 7 expect(el.modelValue).to.equal(-13, 'Fail - : (-23 > 100 by 10; val 55)'); // -23 > -13 > -3 > 7
}); });
it('handles decimal step values correctly', async () => {
// Test with decimal step 0.1
let el = await fixture(
html`<lion-input-stepper step="0.1" min="0" max="9" value="5.55"></lion-input-stepper>`,
);
// Test increment with decimal step
let incrementButton = el.querySelector('[slot=suffix]');
incrementButton?.dispatchEvent(new Event('click'));
await el.updateComplete;
expect(el.modelValue).to.equal(5.6, 'Fail + : (0 > 9 by 0.1; val 5.55)');
// Test decrement with decimal step
let decrementButton = el.querySelector('[slot=prefix]');
decrementButton?.dispatchEvent(new Event('click'));
await el.updateComplete;
expect(el.modelValue).to.equal(5.5, 'Fail - : (0 > 9 by 0.1; val 5.6)');
// Test with value that needs alignment
el = await fixture(
html`<lion-input-stepper step="0.1" min="0" max="9" value="3.27"></lion-input-stepper>`,
);
// Should align to next step when incrementing
incrementButton = el.querySelector('[slot=suffix]');
incrementButton?.dispatchEvent(new Event('click'));
await el.updateComplete;
expect(el.modelValue).to.equal(3.3, 'Fail + alignment: (0 > 9 by 0.1; val 3.27)');
// Reset and test decrement alignment
el = await fixture(
html`<lion-input-stepper step="0.1" min="0" max="9" value="3.27"></lion-input-stepper>`,
);
// Should align to previous step when decrementing
decrementButton = el.querySelector('[slot=prefix]');
decrementButton?.dispatchEvent(new Event('click'));
await el.updateComplete;
expect(el.modelValue).to.equal(3.2, 'Fail - alignment: (0 > 9 by 0.1; val 3.27)');
});
}); });
}); });