Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ exports[`EuiQuickSelectPanels customQuickSelectPanels should render custom panel
aria-describedby="generated-id generated-id"
aria-label="Time value"
class="euiFieldNumber euiFieldNumber--compressed"
step="any"
type="number"
value="15"
/>
Expand Down Expand Up @@ -345,11 +346,11 @@ exports[`EuiQuickSelectPanels customQuickSelectPanels should render custom panel
>
<input
aria-describedby="generated-id generated-id"
aria-invalid="false"
aria-label="Refresh interval value"
class="euiFieldNumber euiFieldNumber--fullWidth euiFieldNumber--compressed"
data-test-subj="superDatePickerRefreshIntervalInput"
disabled=""
step="any"
type="number"
value="0"
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ exports[`EuiFieldNumber props controlOnly is rendered 1`] = `
<eui-validatable-control>
<input
class="euiFieldNumber"
step="any"
type="number"
value=""
/>
Expand All @@ -44,6 +45,7 @@ exports[`EuiFieldNumber props fullWidth is rendered 1`] = `
<eui-validatable-control>
<input
class="euiFieldNumber euiFieldNumber--fullWidth"
step="any"
type="number"
value=""
/>
Expand All @@ -64,6 +66,7 @@ exports[`EuiFieldNumber props isInvalid is rendered from a prop 1`] = `
<input
aria-invalid="true"
class="euiFieldNumber euiFormControlLayout--1icons"
step="any"
type="number"
value=""
/>
Expand All @@ -80,6 +83,7 @@ exports[`EuiFieldNumber props isLoading is rendered 1`] = `
<eui-validatable-control>
<input
class="euiFieldNumber euiFormControlLayout--1icons euiFieldNumber-isLoading"
step="any"
type="number"
value=""
/>
Expand All @@ -98,6 +102,7 @@ exports[`EuiFieldNumber props readOnly is rendered 1`] = `
<input
class="euiFieldNumber"
readonly=""
step="any"
type="number"
value=""
/>
Expand All @@ -114,6 +119,7 @@ exports[`EuiFieldNumber props value no initial value 1`] = `
<eui-validatable-control>
<input
class="euiFieldNumber"
step="any"
type="number"
value=""
/>
Expand All @@ -130,6 +136,7 @@ exports[`EuiFieldNumber props value value is number 1`] = `
<eui-validatable-control>
<input
class="euiFieldNumber"
step="any"
type="number"
value="0"
/>
Expand Down
15 changes: 15 additions & 0 deletions src/components/form/field_number/field_number.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,20 @@ describe('EuiFieldNumber', () => {
cy.get('input').click().type('2');
checkIsInvalid();
});

it('shows invalid state on blur', () => {
cy.mount(<EuiFieldNumber max={1} value={2} />);
checkIsValid();
cy.get('input').click();
cy.get('body').click('bottomRight');
checkIsInvalid();
});

it('does not show invalid state on decimal values by default', () => {
cy.mount(<EuiFieldNumber />);
checkIsValid();
cy.get('input').click().type('1.5');
checkIsValid();
});
});
});
44 changes: 25 additions & 19 deletions src/components/form/field_number/field_number.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@ export type EuiFieldNumberProps = Omit<
max?: number;
/**
* Specifies the granularity that the value must adhere to.
* Accepts a `number` or the string `'any'` for no stepping to allow for any value.
* Defaults to `1`
* Accepts a `number`, e.g. `1` for integers, or `0.5` for decimal steps.
* Defaults to `"any"` for no stepping, which allows any decimal value(s).
* @default "any"
*/
step?: number | 'any';
inputRef?: Ref<HTMLInputElement>;
Expand Down Expand Up @@ -91,6 +92,7 @@ export const EuiFieldNumber: FunctionComponent<EuiFieldNumberProps> = (
name,
min,
max,
step = 'any',
value,
isInvalid,
fullWidth = defaultFullWidth,
Expand All @@ -101,7 +103,8 @@ export const EuiFieldNumber: FunctionComponent<EuiFieldNumberProps> = (
inputRef,
readOnly,
controlOnly,
onKeyUp: _onKeyUp,
onKeyUp,
onBlur,
...rest
} = props;

Expand All @@ -113,19 +116,11 @@ export const EuiFieldNumber: FunctionComponent<EuiFieldNumberProps> = (
true | undefined
>();

// Note that we can't use hook into `onChange` because browsers don't emit change events
// for invalid values - see https://github.com/facebook/react/issues/16554
const onKeyUp = useCallback(
(e: React.KeyboardEvent<HTMLInputElement>) => {
_onKeyUp?.(e);

const { validity } = e.target as HTMLInputElement;
// Prefer `undefined` over `false` so that the `aria-invalid` prop unsets completely
const isInvalid = !validity.valid || undefined;
setIsNativelyInvalid(isInvalid);
},
[_onKeyUp]
);
const checkNativeValidity = useCallback((inputEl: HTMLInputElement) => {
// Prefer `undefined` over `false` so that the `aria-invalid` prop unsets completely
const isInvalid = !inputEl.validity.valid || undefined;
setIsNativelyInvalid(isInvalid);
}, []);

const numIconsClass = controlOnly
? false
Expand All @@ -147,16 +142,27 @@ export const EuiFieldNumber: FunctionComponent<EuiFieldNumberProps> = (
<input
type="number"
id={id}
name={name}
min={min}
max={max}
name={name}
step={step}
value={value}
placeholder={placeholder}
readOnly={readOnly}
className={classes}
ref={inputRef}
onKeyUp={onKeyUp}
aria-invalid={isInvalid == null ? isNativelyInvalid : isInvalid}
aria-invalid={isInvalid || isNativelyInvalid}
onKeyUp={(e) => {
// Note that we can't use `onChange` because browsers don't emit change events
// for invalid text - see https://github.com/facebook/react/issues/16554
onKeyUp?.(e);
checkNativeValidity(e.currentTarget);
}}
onBlur={(e) => {
// Browsers can also set/determine validity (e.g. when `step` is undefined) on focus blur
onBlur?.(e);
checkNativeValidity(e.currentTarget);
}}
{...rest}
/>
</EuiValidatableControl>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ exports[`EuiRangeInput renders 1`] = `
class="euiFieldNumber euiRangeInput euiRangeInput--max emotion-euiRangeInput"
max="100"
min="0"
step="any"
style="inline-size: calc(12px + 1ch + 2em + 0px);"
type="number"
value="0"
Expand Down
3 changes: 3 additions & 0 deletions upcoming_changelogs/6760.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
**Breaking changes**

- `EuiFieldNumber` now defaults the `step` prop to `"any"`