diff --git a/packages/core/package.json b/packages/core/package.json index 2f9e42746..002761ade 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,7 +1,7 @@ { "name": "@department-of-veterans-affairs/component-library", "description": "VA.gov component library. Includes React and web components.", - "version": "19.0.1", + "version": "19.1.0", "license": "MIT", "scripts": { "build": "webpack" diff --git a/packages/storybook/stories/va-number-input-uswds.stories.jsx b/packages/storybook/stories/va-number-input-uswds.stories.jsx index dbde74ec3..721d6420c 100644 --- a/packages/storybook/stories/va-number-input-uswds.stories.jsx +++ b/packages/storybook/stories/va-number-input-uswds.stories.jsx @@ -11,7 +11,15 @@ export default { docs: { page: () => , }, - } + }, + argTypes: { + inputmode: { + control: { + type: 'select', + options: ['decimal', 'numeric'], + }, + }, + }, }; const defaultArgs = { @@ -21,6 +29,7 @@ const defaultArgs = { 'required': false, 'error': undefined, 'value': 0, + 'inputmode': 'numeric', 'min': undefined, 'max': undefined, hint: null, @@ -35,6 +44,7 @@ const vaNumberInput = args => { required, error, value, + inputmode, min, max, hint, @@ -50,6 +60,7 @@ const vaNumberInput = args => { required={required} error={error} value={value} + inputmode={inputmode} max={max} min={min} hint={hint} diff --git a/packages/storybook/stories/va-number-input.stories.jsx b/packages/storybook/stories/va-number-input.stories.jsx index 8d5f7865a..47412b09e 100644 --- a/packages/storybook/stories/va-number-input.stories.jsx +++ b/packages/storybook/stories/va-number-input.stories.jsx @@ -11,7 +11,15 @@ export default { docs: { page: () => , }, - } + }, + argTypes: { + inputmode: { + control: { + type: 'select', + options: ['decimal', 'numeric'], + }, + }, + }, }; const defaultArgs = { @@ -21,6 +29,7 @@ const defaultArgs = { 'required': false, 'error': undefined, 'value': 0, + 'inputmode': 'numeric', 'min': undefined, 'max': undefined, hint: null, @@ -36,6 +45,7 @@ const vaNumberInput = args => { required, error, value, + inputmode, min, max, hint, @@ -51,6 +61,7 @@ const vaNumberInput = args => { required={required} error={error} value={value} + inputmode={inputmode} max={max} min={min} hint={hint} diff --git a/packages/web-components/src/components.d.ts b/packages/web-components/src/components.d.ts index 38ab8466b..bf877fc64 100644 --- a/packages/web-components/src/components.d.ts +++ b/packages/web-components/src/components.d.ts @@ -678,6 +678,10 @@ export namespace Components { * Optional hint text. */ "hint"?: string; + /** + * The inputmode attribute. + */ + "inputmode"?: 'decimal' | 'numeric'; /** * The label for the text input. */ @@ -2473,6 +2477,10 @@ declare namespace LocalJSX { * Optional hint text. */ "hint"?: string; + /** + * The inputmode attribute. + */ + "inputmode"?: 'decimal' | 'numeric'; /** * The label for the text input. */ diff --git a/packages/web-components/src/components/va-number-input/test/va-number-input.e2e.ts b/packages/web-components/src/components/va-number-input/test/va-number-input.e2e.ts index 273bfa31e..0e99b4f5b 100644 --- a/packages/web-components/src/components/va-number-input/test/va-number-input.e2e.ts +++ b/packages/web-components/src/components/va-number-input/test/va-number-input.e2e.ts @@ -141,6 +141,15 @@ describe('va-number-input', () => { expect(analyticsSpy).not.toHaveReceivedEvent(); }); + it('defaults to type of text', async () => { + const page = await newE2EPage(); + await page.setContent(''); + + // Level-setting expectations + const inputEl = await page.find('va-number-input >>> input'); + expect(inputEl.getAttribute('type')).toBe('text'); + }); + it('sets a range based on min and max attributes', async () => { const page = await newE2EPage(); await page.setContent(''); @@ -150,6 +159,16 @@ describe('va-number-input', () => { expect(inputEl.getAttribute('max')).toBe('4'); }); + it('allows manually setting the inputmode attribute', async () => { + const inputModes = ['decimal', 'numeric']; + for (const inputMode of inputModes) { + const page = await newE2EPage(); + await page.setContent(``); + const inputEl = await page.find('va-number-input >>> input'); + expect(inputEl.getAttribute('inputmode')).toBe(inputMode); + } + }); + it('renders a "$" if currency flag set to true', async () => { const page = await newE2EPage(); await page.setContent(''); @@ -314,6 +333,15 @@ describe('va-number-input', () => { expect(analyticsSpy).not.toHaveReceivedEvent(); }); + it('uswds defaults to type of text', async () => { + const page = await newE2EPage(); + await page.setContent(''); + + // Level-setting expectations + const inputEl = await page.find('va-number-input >>> input'); + expect(inputEl.getAttribute('type')).toBe('text'); + }); + it('uswds sets a range based on min and max attributes', async () => { const page = await newE2EPage(); await page.setContent(''); @@ -323,6 +351,16 @@ describe('va-number-input', () => { expect(inputEl.getAttribute('max')).toBe('4'); }); + it('uswds allows manually setting the inputmode attribute', async () => { + const inputModes = ['decimal', 'numeric']; + for (const inputMode of inputModes) { + const page = await newE2EPage(); + await page.setContent(``); + const inputEl = await page.find('va-number-input >>> input'); + expect(inputEl.getAttribute('inputmode')).toBe(inputMode); + } + }); + it('uswds adds aria-describedby input-message id', async () => { const page = await newE2EPage(); await page.setContent(''); diff --git a/packages/web-components/src/components/va-number-input/va-number-input.tsx b/packages/web-components/src/components/va-number-input/va-number-input.tsx index 72198efc8..08edbe3b9 100644 --- a/packages/web-components/src/components/va-number-input/va-number-input.tsx +++ b/packages/web-components/src/components/va-number-input/va-number-input.tsx @@ -46,6 +46,12 @@ export class VaNumberInput { */ @Prop() required?: boolean = false; + /** + * The inputmode attribute. + */ + @Prop() inputmode?: 'decimal' | 'numeric'; + + /** * Emit component-library-analytics events on the blur event. */ @@ -143,6 +149,7 @@ export class VaNumberInput { label, required, error, + inputmode, name, max, min, @@ -158,7 +165,8 @@ export class VaNumberInput { const ariaDescribedbyIds = `${messageAriaDescribedby ? 'input-message' : ''} ${error ? 'input-error-message' : ''}` .trim() || null; // Null so we don't add the attribute if we have an empty string - + const inputMode = inputmode ? inputmode : 'numeric'; + if (uswds) { const labelClasses = classnames({ 'usa-label': true, @@ -197,7 +205,7 @@ export class VaNumberInput { aria-invalid={error ? 'true' : 'false'} id="inputField" type="text" - inputmode="numeric" + inputmode={inputMode} pattern="[0-9]+(\.[0-9]{1,})?" name={name} max={max} @@ -243,7 +251,7 @@ export class VaNumberInput { aria-invalid={error ? 'true' : 'false'} id="inputField" type="text" - inputmode="numeric" + inputmode={inputMode} pattern="[0-9]+(\.[0-9]{1,})?" name={name} max={max}