diff --git a/.changeset/shiny-plants-sleep.md b/.changeset/shiny-plants-sleep.md
new file mode 100644
index 0000000000..a1d9133c6e
--- /dev/null
+++ b/.changeset/shiny-plants-sleep.md
@@ -0,0 +1,5 @@
+---
+'@lion/ui': patch
+---
+
+[input-stepper] add parseNumber and formatNumber to format the value based on locale
diff --git a/docs/components/input-stepper/use-cases.md b/docs/components/input-stepper/use-cases.md
index 93a33862f6..76d8e88dde 100644
--- a/docs/components/input-stepper/use-cases.md
+++ b/docs/components/input-stepper/use-cases.md
@@ -48,3 +48,24 @@ Use `min` and `max` attribute to specify a range.
value="200"
>
```
+
+### Formatting
+
+Just like with the `input-amount` you can add the `formatOptions` to format the numbers to your preferences, to a different locale or adjust the amount of fractions.
+
+```js preview-story
+export const formatting = () => {
+ const format = { locale: 'nl-NL' };
+ return html`
+
+ `;
+};
+```
diff --git a/packages/ui/components/input-stepper/src/LionInputStepper.js b/packages/ui/components/input-stepper/src/LionInputStepper.js
index 8895fb94e5..8dc50d8647 100644
--- a/packages/ui/components/input-stepper/src/LionInputStepper.js
+++ b/packages/ui/components/input-stepper/src/LionInputStepper.js
@@ -1,5 +1,5 @@
import { html, css, render } from 'lit';
-import { LocalizeMixin } from '@lion/ui/localize-no-side-effects.js';
+import { formatNumber, LocalizeMixin, parseNumber } from '@lion/ui/localize-no-side-effects.js';
import { LionInput } from '@lion/ui/input.js';
import { IsNumber, MinNumber, MaxNumber } from '@lion/ui/form-core.js';
import { localizeNamespaceLoader } from './localizeNamespaceLoader.js';
@@ -52,7 +52,7 @@ export class LionInputStepper extends LocalizeMixin(LionInput) {
* @returns {number}
*/
get currentValue() {
- return parseFloat(this.value) || 0;
+ return this.modelValue || 0;
}
get _inputNode() {
@@ -62,7 +62,8 @@ export class LionInputStepper extends LocalizeMixin(LionInput) {
constructor() {
super();
/** @param {string} modelValue */
- this.parser = modelValue => parseFloat(modelValue);
+ this.parser = parseNumber;
+ this.formatter = formatNumber;
this.min = Infinity;
this.max = Infinity;
this.step = 1;
@@ -229,7 +230,7 @@ export class LionInputStepper extends LocalizeMixin(LionInput) {
const { step, min, max } = this.values;
const newValue = this.currentValue + step;
if (newValue <= max || max === Infinity) {
- this.value = newValue < min && min !== Infinity ? `${min}` : `${newValue}`;
+ this.modelValue = newValue < min && min !== Infinity ? `${min}` : `${newValue}`;
this.__toggleSpinnerButtonsState();
this._proxyInputEvent();
}
@@ -243,7 +244,7 @@ export class LionInputStepper extends LocalizeMixin(LionInput) {
const { step, min, max } = this.values;
const newValue = this.currentValue - step;
if (newValue >= min || min === Infinity) {
- this.value = newValue > max && max !== Infinity ? `${max}` : `${newValue}`;
+ this.modelValue = newValue > max && max !== Infinity ? `${max}` : `${newValue}`;
this.__toggleSpinnerButtonsState();
this._proxyInputEvent();
}
diff --git a/packages/ui/components/input-stepper/test/lion-input-stepper-integrations.test.js b/packages/ui/components/input-stepper/test/lion-input-stepper-integrations.test.js
new file mode 100644
index 0000000000..b2d2674649
--- /dev/null
+++ b/packages/ui/components/input-stepper/test/lion-input-stepper-integrations.test.js
@@ -0,0 +1,20 @@
+import {
+ runInteractionStateMixinSuite,
+ runFormatMixinSuite,
+} from '@lion/ui/form-core-test-suites.js';
+
+import '@lion/ui/define/lion-input-stepper.js';
+
+const tagString = 'lion-input-stepper';
+
+describe(' integrations', () => {
+ runInteractionStateMixinSuite({
+ tagString,
+ allowedModelValueTypes: [Number],
+ });
+
+ runFormatMixinSuite({
+ tagString,
+ modelValueType: Number,
+ });
+});
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 26406b6e07..e33294f0b7 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
@@ -1,6 +1,7 @@
import { expect, fixture as _fixture, nextFrame } from '@open-wc/testing';
import { html } from 'lit/static-html.js';
import sinon from 'sinon';
+import { formatNumber } from '@lion/ui/localize-no-side-effects.js';
import '@lion/ui/define/lion-input-stepper.js';
/**
@@ -49,6 +50,50 @@ describe('', () => {
});
});
+ describe('Formatter', () => {
+ it('uses formatNumber for formatting', async () => {
+ const el = await fixture(defaultInputStepper);
+ expect(el.formatter).to.equal(formatNumber);
+ });
+
+ it('formatNumber uses locale provided in formatOptions', async () => {
+ let el = await fixture(html`
+
+ `);
+ expect(el.formattedValue).to.equal('1,234.56');
+ el = await fixture(html`
+
+ `);
+ expect(el.formattedValue).to.equal('1.234,56');
+ });
+
+ it('supports overriding decimalSeparator in formatOptions', async () => {
+ const el = await fixture(
+ html``,
+ );
+ expect(el.formattedValue).to.equal('12.34');
+ });
+
+ it('supports overriding groupSeparator in formatOptions', async () => {
+ const el = await fixture(
+ html``,
+ );
+ expect(el.formattedValue).to.equal('1,234.56');
+ });
+ });
+
describe('User interaction', () => {
it('should increment the value to 1 on [ArrowUp]', async () => {
const el = await fixture(defaultInputStepper);
@@ -71,7 +116,7 @@ describe('', () => {
expect(el.value).to.equal('');
el.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }));
await el.updateComplete;
- expect(el.value).to.equal('-1');
+ expect(el.value).to.equal('−1');
});
it('should increment the value to minValue on [ArrowDown] if value is below min', async () => {
@@ -95,7 +140,7 @@ describe('', () => {
expect(el.value).to.equal('');
const decrementButton = el.querySelector('[slot=prefix]');
decrementButton?.dispatchEvent(new Event('click'));
- expect(el.value).to.equal('-1');
+ expect(el.value).to.equal('−1');
});
it('fires one "user-input-changed" event on + button click', async () => {
@@ -143,7 +188,7 @@ describe('', () => {
decrementButton?.dispatchEvent(new Event('focus'));
decrementButton?.dispatchEvent(new Event('click'));
decrementButton?.dispatchEvent(new Event('blur'));
- expect(el.value).to.equal('-1');
+ expect(el.value).to.equal('−1');
expect(blurSpy.calledOnce).to.be.true;
expect(el.touched).to.be.true;