From 579e42b3391460725999ef3f96c215e270f8a962 Mon Sep 17 00:00:00 2001 From: MiB-1 <133959537+MiB-1@users.noreply.github.com> Date: Tue, 18 Nov 2025 09:10:33 +0100 Subject: [PATCH] =?UTF-8?q?fix(LionInputStepper):=20improve=20handling=20o?= =?UTF-8?q?f=20decimal=20step=20values=20and=20al=E2=80=A6=20(#2621)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(LionInputStepper): improve handling of decimal step values and alignment * fix: add changeset LionInputStepper improvements --- .changeset/four-rabbits-cover.md | 5 +++ .../input-stepper/src/LionInputStepper.js | 30 ++++++++++---- .../test/lion-input-stepper.test.js | 41 +++++++++++++++++++ 3 files changed, 68 insertions(+), 8 deletions(-) create mode 100644 .changeset/four-rabbits-cover.md diff --git a/.changeset/four-rabbits-cover.md b/.changeset/four-rabbits-cover.md new file mode 100644 index 000000000..a1a0bb20a --- /dev/null +++ b/.changeset/four-rabbits-cover.md @@ -0,0 +1,5 @@ +--- +'@lion/ui': patch +--- + +fix(LionInputStepper): improve handling of decimal step values and alignment closes #2615 diff --git a/packages/ui/components/input-stepper/src/LionInputStepper.js b/packages/ui/components/input-stepper/src/LionInputStepper.js index a04936a38..89f8c7531 100644 --- a/packages/ui/components/input-stepper/src/LionInputStepper.js +++ b/packages/ui/components/input-stepper/src/LionInputStepper.js @@ -267,12 +267,19 @@ export class LionInputStepper extends LocalizeMixin(LionInput) { _increment() { const { step, min, max } = this.values; 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) { - // If the value is not aligned to step, align it to the nearest step - newValue = Math.floor(this.currentValue / step) * step + step + (stepMin % step); + const remainder = (this.currentValue - stepMin) % step; + const isAligned = Math.abs(remainder) < epsilon || Math.abs(remainder - step) < epsilon; + + 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) { @@ -289,12 +296,19 @@ export class LionInputStepper extends LocalizeMixin(LionInput) { _decrement() { const { step, max, min } = this.values; 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) { - // If the value is not aligned to step, align it to the nearest step - newValue = Math.floor(this.currentValue / step) * step + (stepMin % step); + const remainder = (this.currentValue - stepMin) % step; + const isAligned = Math.abs(remainder) < epsilon || Math.abs(remainder - step) < epsilon; + + 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) { diff --git a/packages/ui/components/input-stepper/test/lion-input-stepper.test.js b/packages/ui/components/input-stepper/test/lion-input-stepper.test.js index 5479d8350..17ba2509d 100644 --- a/packages/ui/components/input-stepper/test/lion-input-stepper.test.js +++ b/packages/ui/components/input-stepper/test/lion-input-stepper.test.js @@ -359,6 +359,47 @@ describe('', () => { await el.updateComplete; 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``, + ); + + // 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``, + ); + + // 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``, + ); + + // 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)'); + }); }); });