fix(input-stepper): add parseNumber and formatNumber to format the va… (#2312)
* fix(input-stepper): add parseNumber and formatNumber to format the value based on locale * Update packages/ui/components/input-stepper/test/lion-input-stepper.test.js * Update packages/ui/components/input-stepper/test/lion-input-stepper.test.js
This commit is contained in:
parent
58796deb0e
commit
cdf0a9e8f0
5 changed files with 100 additions and 8 deletions
5
.changeset/shiny-plants-sleep.md
Normal file
5
.changeset/shiny-plants-sleep.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@lion/ui': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
[input-stepper] add parseNumber and formatNumber to format the value based on locale
|
||||||
|
|
@ -48,3 +48,24 @@ Use `min` and `max` attribute to specify a range.
|
||||||
value="200"
|
value="200"
|
||||||
></lion-input-stepper>
|
></lion-input-stepper>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 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`
|
||||||
|
<lion-input-stepper
|
||||||
|
label="Amount of oranges"
|
||||||
|
min="0"
|
||||||
|
max="5000"
|
||||||
|
step="100"
|
||||||
|
name="value"
|
||||||
|
.formatOptions="${format}"
|
||||||
|
.modelValue="${1200}"
|
||||||
|
></lion-input-stepper>
|
||||||
|
`;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { html, css, render } from 'lit';
|
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 { LionInput } from '@lion/ui/input.js';
|
||||||
import { IsNumber, MinNumber, MaxNumber } from '@lion/ui/form-core.js';
|
import { IsNumber, MinNumber, MaxNumber } from '@lion/ui/form-core.js';
|
||||||
import { localizeNamespaceLoader } from './localizeNamespaceLoader.js';
|
import { localizeNamespaceLoader } from './localizeNamespaceLoader.js';
|
||||||
|
|
@ -52,7 +52,7 @@ export class LionInputStepper extends LocalizeMixin(LionInput) {
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
get currentValue() {
|
get currentValue() {
|
||||||
return parseFloat(this.value) || 0;
|
return this.modelValue || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
get _inputNode() {
|
get _inputNode() {
|
||||||
|
|
@ -62,7 +62,8 @@ export class LionInputStepper extends LocalizeMixin(LionInput) {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
/** @param {string} modelValue */
|
/** @param {string} modelValue */
|
||||||
this.parser = modelValue => parseFloat(modelValue);
|
this.parser = parseNumber;
|
||||||
|
this.formatter = formatNumber;
|
||||||
this.min = Infinity;
|
this.min = Infinity;
|
||||||
this.max = Infinity;
|
this.max = Infinity;
|
||||||
this.step = 1;
|
this.step = 1;
|
||||||
|
|
@ -229,7 +230,7 @@ export class LionInputStepper extends LocalizeMixin(LionInput) {
|
||||||
const { step, min, max } = this.values;
|
const { step, min, max } = this.values;
|
||||||
const newValue = this.currentValue + step;
|
const newValue = this.currentValue + step;
|
||||||
if (newValue <= max || max === Infinity) {
|
if (newValue <= max || max === Infinity) {
|
||||||
this.value = newValue < min && min !== Infinity ? `${min}` : `${newValue}`;
|
this.modelValue = newValue < min && min !== Infinity ? `${min}` : `${newValue}`;
|
||||||
this.__toggleSpinnerButtonsState();
|
this.__toggleSpinnerButtonsState();
|
||||||
this._proxyInputEvent();
|
this._proxyInputEvent();
|
||||||
}
|
}
|
||||||
|
|
@ -243,7 +244,7 @@ export class LionInputStepper extends LocalizeMixin(LionInput) {
|
||||||
const { step, min, max } = this.values;
|
const { step, min, max } = this.values;
|
||||||
const newValue = this.currentValue - step;
|
const newValue = this.currentValue - step;
|
||||||
if (newValue >= min || min === Infinity) {
|
if (newValue >= min || min === Infinity) {
|
||||||
this.value = newValue > max && max !== Infinity ? `${max}` : `${newValue}`;
|
this.modelValue = newValue > max && max !== Infinity ? `${max}` : `${newValue}`;
|
||||||
this.__toggleSpinnerButtonsState();
|
this.__toggleSpinnerButtonsState();
|
||||||
this._proxyInputEvent();
|
this._proxyInputEvent();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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('<lion-input-stepper> integrations', () => {
|
||||||
|
runInteractionStateMixinSuite({
|
||||||
|
tagString,
|
||||||
|
allowedModelValueTypes: [Number],
|
||||||
|
});
|
||||||
|
|
||||||
|
runFormatMixinSuite({
|
||||||
|
tagString,
|
||||||
|
modelValueType: Number,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { expect, fixture as _fixture, nextFrame } from '@open-wc/testing';
|
import { expect, fixture as _fixture, nextFrame } from '@open-wc/testing';
|
||||||
import { html } from 'lit/static-html.js';
|
import { html } from 'lit/static-html.js';
|
||||||
import sinon from 'sinon';
|
import sinon from 'sinon';
|
||||||
|
import { formatNumber } from '@lion/ui/localize-no-side-effects.js';
|
||||||
import '@lion/ui/define/lion-input-stepper.js';
|
import '@lion/ui/define/lion-input-stepper.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -49,6 +50,50 @@ describe('<lion-input-stepper>', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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`
|
||||||
|
<lion-input-stepper
|
||||||
|
.formatOptions="${{ locale: 'en-GB' }}"
|
||||||
|
.modelValue="${1234.56}"
|
||||||
|
></lion-input-stepper>
|
||||||
|
`);
|
||||||
|
expect(el.formattedValue).to.equal('1,234.56');
|
||||||
|
el = await fixture(html`
|
||||||
|
<lion-input-stepper
|
||||||
|
.formatOptions="${{ locale: 'nl-NL' }}"
|
||||||
|
.modelValue="${1234.56}"
|
||||||
|
></lion-input-stepper>
|
||||||
|
`);
|
||||||
|
expect(el.formattedValue).to.equal('1.234,56');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('supports overriding decimalSeparator in formatOptions', async () => {
|
||||||
|
const el = await fixture(
|
||||||
|
html`<lion-input-stepper
|
||||||
|
.formatOptions="${{ locale: 'nl-NL', decimalSeparator: '.' }}"
|
||||||
|
.modelValue="${12.34}"
|
||||||
|
></lion-input-stepper>`,
|
||||||
|
);
|
||||||
|
expect(el.formattedValue).to.equal('12.34');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('supports overriding groupSeparator in formatOptions', async () => {
|
||||||
|
const el = await fixture(
|
||||||
|
html`<lion-input-stepper
|
||||||
|
.formatOptions="${{ locale: 'nl-NL', groupSeparator: ',', decimalSeparator: '.' }}"
|
||||||
|
.modelValue="${1234.56}"
|
||||||
|
></lion-input-stepper>`,
|
||||||
|
);
|
||||||
|
expect(el.formattedValue).to.equal('1,234.56');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('User interaction', () => {
|
describe('User interaction', () => {
|
||||||
it('should increment the value to 1 on [ArrowUp]', async () => {
|
it('should increment the value to 1 on [ArrowUp]', async () => {
|
||||||
const el = await fixture(defaultInputStepper);
|
const el = await fixture(defaultInputStepper);
|
||||||
|
|
@ -71,7 +116,7 @@ describe('<lion-input-stepper>', () => {
|
||||||
expect(el.value).to.equal('');
|
expect(el.value).to.equal('');
|
||||||
el.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }));
|
el.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }));
|
||||||
await el.updateComplete;
|
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 () => {
|
it('should increment the value to minValue on [ArrowDown] if value is below min', async () => {
|
||||||
|
|
@ -95,7 +140,7 @@ describe('<lion-input-stepper>', () => {
|
||||||
expect(el.value).to.equal('');
|
expect(el.value).to.equal('');
|
||||||
const decrementButton = el.querySelector('[slot=prefix]');
|
const decrementButton = el.querySelector('[slot=prefix]');
|
||||||
decrementButton?.dispatchEvent(new Event('click'));
|
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 () => {
|
it('fires one "user-input-changed" event on + button click', async () => {
|
||||||
|
|
@ -143,7 +188,7 @@ describe('<lion-input-stepper>', () => {
|
||||||
decrementButton?.dispatchEvent(new Event('focus'));
|
decrementButton?.dispatchEvent(new Event('focus'));
|
||||||
decrementButton?.dispatchEvent(new Event('click'));
|
decrementButton?.dispatchEvent(new Event('click'));
|
||||||
decrementButton?.dispatchEvent(new Event('blur'));
|
decrementButton?.dispatchEvent(new Event('blur'));
|
||||||
expect(el.value).to.equal('-1');
|
expect(el.value).to.equal('−1');
|
||||||
expect(blurSpy.calledOnce).to.be.true;
|
expect(blurSpy.calledOnce).to.be.true;
|
||||||
expect(el.touched).to.be.true;
|
expect(el.touched).to.be.true;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue