@wordpress/components 30.9.0 → 31.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -4
- package/build/alignment-matrix-control/cell.js +131 -3
- package/build/alignment-matrix-control/cell.js.map +4 -4
- package/build/alignment-matrix-control/index.js +134 -6
- package/build/alignment-matrix-control/index.js.map +3 -3
- package/build/angle-picker-control/angle-circle.js +119 -15
- package/build/angle-picker-control/angle-circle.js.map +4 -4
- package/build/angle-picker-control/index.js +12 -7
- package/build/angle-picker-control/index.js.map +3 -3
- package/build/dropdown-menu/index.js +1 -1
- package/build/dropdown-menu/index.js.map +2 -2
- package/build/form-token-field/index.js +1 -13
- package/build/form-token-field/index.js.map +3 -3
- package/build/menu/styles.js +17 -17
- package/build/menu/styles.js.map +2 -2
- package/build/menu-item/index.js +1 -1
- package/build/menu-item/index.js.map +2 -2
- package/build/notice/index.js +1 -1
- package/build/notice/index.js.map +2 -2
- package/build/query-controls/index.js +0 -1
- package/build/query-controls/index.js.map +2 -2
- package/build/snackbar/index.js +1 -1
- package/build/snackbar/index.js.map +1 -1
- package/build/validated-form-controls/components/checkbox-control.js +0 -10
- package/build/validated-form-controls/components/checkbox-control.js.map +2 -2
- package/build/validated-form-controls/components/combobox-control.js +1 -11
- package/build/validated-form-controls/components/combobox-control.js.map +2 -2
- package/build/validated-form-controls/components/custom-select-control.js +0 -10
- package/build/validated-form-controls/components/custom-select-control.js.map +2 -2
- package/build/validated-form-controls/components/form-token-field.js +2 -13
- package/build/validated-form-controls/components/form-token-field.js.map +2 -2
- package/build/validated-form-controls/components/input-control.js +0 -10
- package/build/validated-form-controls/components/input-control.js.map +2 -2
- package/build/validated-form-controls/components/number-control.js +0 -10
- package/build/validated-form-controls/components/number-control.js.map +2 -2
- package/build/validated-form-controls/components/radio-control.js +0 -10
- package/build/validated-form-controls/components/radio-control.js.map +2 -2
- package/build/validated-form-controls/components/range-control.js +0 -10
- package/build/validated-form-controls/components/range-control.js.map +2 -2
- package/build/validated-form-controls/components/select-control.js +0 -10
- package/build/validated-form-controls/components/select-control.js.map +2 -2
- package/build/validated-form-controls/components/text-control.js +0 -10
- package/build/validated-form-controls/components/text-control.js.map +2 -2
- package/build/validated-form-controls/components/textarea-control.js +0 -10
- package/build/validated-form-controls/components/textarea-control.js.map +2 -2
- package/build/validated-form-controls/components/toggle-control.js +0 -10
- package/build/validated-form-controls/components/toggle-control.js.map +2 -2
- package/build/validated-form-controls/components/toggle-group-control.js +0 -10
- package/build/validated-form-controls/components/toggle-group-control.js.map +2 -2
- package/build/validated-form-controls/control-with-error.js +53 -58
- package/build/validated-form-controls/control-with-error.js.map +2 -2
- package/build-module/alignment-matrix-control/cell.js +131 -3
- package/build-module/alignment-matrix-control/cell.js.map +3 -3
- package/build-module/alignment-matrix-control/index.js +134 -6
- package/build-module/alignment-matrix-control/index.js.map +3 -3
- package/build-module/angle-picker-control/angle-circle.js +109 -15
- package/build-module/angle-picker-control/angle-circle.js.map +3 -3
- package/build-module/angle-picker-control/index.js +12 -7
- package/build-module/angle-picker-control/index.js.map +2 -2
- package/build-module/dropdown-menu/index.js +1 -1
- package/build-module/dropdown-menu/index.js.map +2 -2
- package/build-module/form-token-field/index.js +1 -13
- package/build-module/form-token-field/index.js.map +2 -2
- package/build-module/menu/styles.js +17 -17
- package/build-module/menu/styles.js.map +2 -2
- package/build-module/menu-item/index.js +1 -1
- package/build-module/menu-item/index.js.map +2 -2
- package/build-module/notice/index.js +1 -1
- package/build-module/notice/index.js.map +2 -2
- package/build-module/query-controls/index.js +0 -1
- package/build-module/query-controls/index.js.map +2 -2
- package/build-module/snackbar/index.js +1 -1
- package/build-module/snackbar/index.js.map +1 -1
- package/build-module/validated-form-controls/components/checkbox-control.js +0 -10
- package/build-module/validated-form-controls/components/checkbox-control.js.map +2 -2
- package/build-module/validated-form-controls/components/combobox-control.js +1 -11
- package/build-module/validated-form-controls/components/combobox-control.js.map +2 -2
- package/build-module/validated-form-controls/components/custom-select-control.js +0 -10
- package/build-module/validated-form-controls/components/custom-select-control.js.map +2 -2
- package/build-module/validated-form-controls/components/form-token-field.js +2 -13
- package/build-module/validated-form-controls/components/form-token-field.js.map +2 -2
- package/build-module/validated-form-controls/components/input-control.js +0 -10
- package/build-module/validated-form-controls/components/input-control.js.map +2 -2
- package/build-module/validated-form-controls/components/number-control.js +0 -10
- package/build-module/validated-form-controls/components/number-control.js.map +2 -2
- package/build-module/validated-form-controls/components/radio-control.js +0 -10
- package/build-module/validated-form-controls/components/radio-control.js.map +2 -2
- package/build-module/validated-form-controls/components/range-control.js +0 -10
- package/build-module/validated-form-controls/components/range-control.js.map +2 -2
- package/build-module/validated-form-controls/components/select-control.js +0 -10
- package/build-module/validated-form-controls/components/select-control.js.map +2 -2
- package/build-module/validated-form-controls/components/text-control.js +0 -10
- package/build-module/validated-form-controls/components/text-control.js.map +2 -2
- package/build-module/validated-form-controls/components/textarea-control.js +0 -10
- package/build-module/validated-form-controls/components/textarea-control.js.map +2 -2
- package/build-module/validated-form-controls/components/toggle-control.js +0 -10
- package/build-module/validated-form-controls/components/toggle-control.js.map +2 -2
- package/build-module/validated-form-controls/components/toggle-group-control.js +0 -10
- package/build-module/validated-form-controls/components/toggle-group-control.js.map +2 -2
- package/build-module/validated-form-controls/control-with-error.js +53 -58
- package/build-module/validated-form-controls/control-with-error.js.map +2 -2
- package/build-style/style-rtl.css +21 -33
- package/build-style/style.css +21 -33
- package/build-types/alignment-matrix-control/cell.d.ts.map +1 -1
- package/build-types/alignment-matrix-control/index.d.ts.map +1 -1
- package/build-types/angle-picker-control/angle-circle.d.ts +1 -1
- package/build-types/angle-picker-control/angle-circle.d.ts.map +1 -1
- package/build-types/angle-picker-control/index.d.ts.map +1 -1
- package/build-types/form-token-field/index.d.ts.map +1 -1
- package/build-types/form-token-field/stories/index.story.d.ts.map +1 -1
- package/build-types/form-token-field/types.d.ts +0 -6
- package/build-types/form-token-field/types.d.ts.map +1 -1
- package/build-types/notice/index.d.ts.map +1 -1
- package/build-types/notice/stories/index.story.d.ts.map +1 -1
- package/build-types/query-controls/index.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/checkbox-control.d.ts +1 -1
- package/build-types/validated-form-controls/components/checkbox-control.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/combobox-control.d.ts +2 -3
- package/build-types/validated-form-controls/components/combobox-control.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/custom-select-control.d.ts +1 -2
- package/build-types/validated-form-controls/components/custom-select-control.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/form-token-field.d.ts +1 -2
- package/build-types/validated-form-controls/components/form-token-field.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/input-control.d.ts +1 -2
- package/build-types/validated-form-controls/components/input-control.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/number-control.d.ts +1 -1
- package/build-types/validated-form-controls/components/number-control.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/radio-control.d.ts +1 -1
- package/build-types/validated-form-controls/components/radio-control.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/range-control.d.ts +1 -1
- package/build-types/validated-form-controls/components/range-control.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/select-control.d.ts +2 -3
- package/build-types/validated-form-controls/components/select-control.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/stories/checkbox-control.story.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/stories/combobox-control.story.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/stories/custom-select-control.story.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/stories/form-token-field.story.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/stories/input-control.story.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/stories/number-control.story.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/stories/overview.story.d.ts +7 -0
- package/build-types/validated-form-controls/components/stories/overview.story.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/stories/radio-control.story.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/stories/range-control.story.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/stories/select-control.story.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/stories/text-control.story.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/stories/textarea-control.story.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/stories/toggle-control.story.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/stories/toggle-group-control.story.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/text-control.d.ts +1 -1
- package/build-types/validated-form-controls/components/text-control.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/textarea-control.d.ts +1 -1
- package/build-types/validated-form-controls/components/textarea-control.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/toggle-control.d.ts +1 -1
- package/build-types/validated-form-controls/components/toggle-control.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/toggle-group-control.d.ts +1 -1
- package/build-types/validated-form-controls/components/toggle-group-control.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/types.d.ts +1 -9
- package/build-types/validated-form-controls/components/types.d.ts.map +1 -1
- package/build-types/validated-form-controls/control-with-error.d.ts +4 -5
- package/build-types/validated-form-controls/control-with-error.d.ts.map +1 -1
- package/package.json +20 -20
- package/src/alignment-matrix-control/cell.tsx +14 -3
- package/src/alignment-matrix-control/index.tsx +15 -6
- package/src/alignment-matrix-control/style.module.scss +84 -0
- package/src/angle-picker-control/angle-circle.tsx +27 -12
- package/src/angle-picker-control/index.tsx +8 -7
- package/src/angle-picker-control/style.module.scss +40 -0
- package/src/button/style.scss +1 -1
- package/src/dropdown-menu/index.tsx +1 -1
- package/src/dropdown-menu/style.scss +1 -1
- package/src/form-token-field/README.md +0 -2
- package/src/form-token-field/index.tsx +1 -13
- package/src/form-token-field/stories/index.story.tsx +0 -2
- package/src/form-token-field/test/index.tsx +0 -1
- package/src/form-token-field/types.ts +0 -6
- package/src/guide/style.scss +3 -3
- package/src/menu/styles.ts +2 -2
- package/src/menu-item/index.tsx +1 -1
- package/src/menu-item/test/__snapshots__/index.js.snap +4 -4
- package/src/modal/style.scss +5 -5
- package/src/notice/index.tsx +53 -46
- package/src/notice/stories/index.story.tsx +17 -1
- package/src/notice/style.scss +3 -20
- package/src/query-controls/index.tsx +0 -1
- package/src/snackbar/index.tsx +1 -1
- package/src/validated-form-controls/components/checkbox-control.tsx +1 -14
- package/src/validated-form-controls/components/combobox-control.tsx +1 -14
- package/src/validated-form-controls/components/custom-select-control.tsx +1 -19
- package/src/validated-form-controls/components/form-token-field.tsx +4 -21
- package/src/validated-form-controls/components/input-control.tsx +1 -14
- package/src/validated-form-controls/components/number-control.tsx +1 -16
- package/src/validated-form-controls/components/radio-control.tsx +2 -18
- package/src/validated-form-controls/components/range-control.tsx +1 -14
- package/src/validated-form-controls/components/select-control.tsx +1 -23
- package/src/validated-form-controls/components/stories/checkbox-control.story.tsx +11 -20
- package/src/validated-form-controls/components/stories/combobox-control.story.tsx +8 -17
- package/src/validated-form-controls/components/stories/custom-select-control.story.tsx +8 -17
- package/src/validated-form-controls/components/stories/form-token-field.story.tsx +14 -26
- package/src/validated-form-controls/components/stories/input-control.story.tsx +25 -50
- package/src/validated-form-controls/components/stories/number-control.story.tsx +10 -19
- package/src/validated-form-controls/components/stories/overview.mdx +3 -3
- package/src/validated-form-controls/components/stories/overview.story.tsx +94 -79
- package/src/validated-form-controls/components/stories/radio-control.story.tsx +11 -20
- package/src/validated-form-controls/components/stories/range-control.story.tsx +8 -17
- package/src/validated-form-controls/components/stories/select-control.story.tsx +9 -18
- package/src/validated-form-controls/components/stories/text-control.story.tsx +11 -17
- package/src/validated-form-controls/components/stories/textarea-control.story.tsx +12 -16
- package/src/validated-form-controls/components/stories/toggle-control.story.tsx +11 -20
- package/src/validated-form-controls/components/stories/toggle-group-control.story.tsx +8 -17
- package/src/validated-form-controls/components/text-control.tsx +1 -14
- package/src/validated-form-controls/components/textarea-control.tsx +1 -14
- package/src/validated-form-controls/components/toggle-control.tsx +1 -14
- package/src/validated-form-controls/components/toggle-group-control.tsx +1 -14
- package/src/validated-form-controls/components/types.ts +1 -9
- package/src/validated-form-controls/control-with-error.tsx +57 -84
- package/src/validated-form-controls/style.scss +7 -7
- package/src/validated-form-controls/test/control-with-error.tsx +66 -5
- package/tsconfig.json +1 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/build/alignment-matrix-control/styles.js +0 -105
- package/build/alignment-matrix-control/styles.js.map +0 -7
- package/build/angle-picker-control/styles/angle-picker-control-styles.js +0 -88
- package/build/angle-picker-control/styles/angle-picker-control-styles.js.map +0 -7
- package/build-module/alignment-matrix-control/styles.js +0 -67
- package/build-module/alignment-matrix-control/styles.js.map +0 -7
- package/build-module/angle-picker-control/styles/angle-picker-control-styles.js +0 -50
- package/build-module/angle-picker-control/styles/angle-picker-control-styles.js.map +0 -7
- package/build-types/alignment-matrix-control/styles.d.ts +0 -21
- package/build-types/alignment-matrix-control/styles.d.ts.map +0 -1
- package/build-types/angle-picker-control/styles/angle-picker-control-styles.d.ts +0 -18
- package/build-types/angle-picker-control/styles/angle-picker-control-styles.d.ts.map +0 -1
- package/src/alignment-matrix-control/styles.ts +0 -113
- package/src/angle-picker-control/styles/angle-picker-control-styles.tsx +0 -58
|
@@ -10,30 +10,24 @@ import { useMergeRefs } from '@wordpress/compose';
|
|
|
10
10
|
import { ControlWithError } from '../control-with-error';
|
|
11
11
|
import type { ValidatedControlProps } from './types';
|
|
12
12
|
import ToggleControl from '../../toggle-control';
|
|
13
|
-
import type { ToggleControlProps } from '../../toggle-control/types';
|
|
14
|
-
|
|
15
|
-
type Value = ToggleControlProps[ 'checked' ];
|
|
16
13
|
|
|
17
14
|
// TODO: Should we customize the default `missingValue` message? It says to "check this box".
|
|
18
15
|
|
|
19
16
|
const UnforwardedValidatedToggleControl = (
|
|
20
17
|
{
|
|
21
18
|
required,
|
|
22
|
-
onValidate,
|
|
23
19
|
customValidity,
|
|
24
|
-
onChange,
|
|
25
20
|
markWhenOptional,
|
|
26
21
|
...restProps
|
|
27
22
|
}: Omit<
|
|
28
23
|
React.ComponentProps< typeof ToggleControl >,
|
|
29
24
|
'__nextHasNoMarginBottom'
|
|
30
25
|
> &
|
|
31
|
-
ValidatedControlProps
|
|
26
|
+
ValidatedControlProps,
|
|
32
27
|
forwardedRef: React.ForwardedRef< HTMLInputElement >
|
|
33
28
|
) => {
|
|
34
29
|
const validityTargetRef = useRef< HTMLInputElement >( null );
|
|
35
30
|
const mergedRefs = useMergeRefs( [ forwardedRef, validityTargetRef ] );
|
|
36
|
-
const valueRef = useRef< Value >( restProps.checked );
|
|
37
31
|
|
|
38
32
|
// TODO: Upstream limitation - The `required` attribute is not passed down to the input,
|
|
39
33
|
// so we need to set it manually.
|
|
@@ -47,19 +41,12 @@ const UnforwardedValidatedToggleControl = (
|
|
|
47
41
|
<ControlWithError
|
|
48
42
|
required={ required }
|
|
49
43
|
markWhenOptional={ markWhenOptional }
|
|
50
|
-
onValidate={ () => {
|
|
51
|
-
return onValidate?.( valueRef.current );
|
|
52
|
-
} }
|
|
53
44
|
customValidity={ customValidity }
|
|
54
45
|
getValidityTarget={ () => validityTargetRef.current }
|
|
55
46
|
>
|
|
56
47
|
<ToggleControl
|
|
57
48
|
__nextHasNoMarginBottom
|
|
58
49
|
ref={ mergedRefs }
|
|
59
|
-
onChange={ ( value ) => {
|
|
60
|
-
valueRef.current = value;
|
|
61
|
-
onChange?.( value );
|
|
62
|
-
} }
|
|
63
50
|
{ ...restProps }
|
|
64
51
|
/>
|
|
65
52
|
</ControlWithError>
|
|
@@ -9,27 +9,21 @@ import { forwardRef, useId, useRef } from '@wordpress/element';
|
|
|
9
9
|
import { ControlWithError } from '../control-with-error';
|
|
10
10
|
import type { ValidatedControlProps } from './types';
|
|
11
11
|
import { ToggleGroupControl } from '../../toggle-group-control';
|
|
12
|
-
import type { ToggleGroupControlProps } from '../../toggle-group-control/types';
|
|
13
|
-
|
|
14
|
-
type Value = ToggleGroupControlProps[ 'value' ];
|
|
15
12
|
|
|
16
13
|
const UnforwardedValidatedToggleGroupControl = (
|
|
17
14
|
{
|
|
18
15
|
required,
|
|
19
|
-
onValidate,
|
|
20
16
|
customValidity,
|
|
21
|
-
onChange,
|
|
22
17
|
markWhenOptional,
|
|
23
18
|
...restProps
|
|
24
19
|
}: Omit<
|
|
25
20
|
React.ComponentProps< typeof ToggleGroupControl >,
|
|
26
21
|
'__next40pxDefaultSize' | '__nextHasNoMarginBottom'
|
|
27
22
|
> &
|
|
28
|
-
ValidatedControlProps
|
|
23
|
+
ValidatedControlProps,
|
|
29
24
|
forwardedRef: React.ForwardedRef< HTMLInputElement >
|
|
30
25
|
) => {
|
|
31
26
|
const validityTargetRef = useRef< HTMLInputElement >( null );
|
|
32
|
-
const valueRef = useRef< Value >( restProps.value );
|
|
33
27
|
|
|
34
28
|
const nameAttr = useId();
|
|
35
29
|
|
|
@@ -38,9 +32,6 @@ const UnforwardedValidatedToggleGroupControl = (
|
|
|
38
32
|
<ControlWithError
|
|
39
33
|
required={ required }
|
|
40
34
|
markWhenOptional={ markWhenOptional }
|
|
41
|
-
onValidate={ () => {
|
|
42
|
-
return onValidate?.( valueRef.current );
|
|
43
|
-
} }
|
|
44
35
|
customValidity={ customValidity }
|
|
45
36
|
getValidityTarget={ () => validityTargetRef.current }
|
|
46
37
|
>
|
|
@@ -48,10 +39,6 @@ const UnforwardedValidatedToggleGroupControl = (
|
|
|
48
39
|
__nextHasNoMarginBottom
|
|
49
40
|
__next40pxDefaultSize
|
|
50
41
|
ref={ forwardedRef }
|
|
51
|
-
onChange={ ( value ) => {
|
|
52
|
-
valueRef.current = value;
|
|
53
|
-
onChange?.( value );
|
|
54
|
-
} }
|
|
55
42
|
{ ...restProps }
|
|
56
43
|
/>
|
|
57
44
|
</ControlWithError>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type ValidatedControlProps
|
|
1
|
+
export type ValidatedControlProps = {
|
|
2
2
|
/**
|
|
3
3
|
* Whether the control is required.
|
|
4
4
|
* @default false
|
|
@@ -9,14 +9,6 @@ export type ValidatedControlProps< V > = {
|
|
|
9
9
|
* @default false
|
|
10
10
|
*/
|
|
11
11
|
markWhenOptional?: boolean;
|
|
12
|
-
/**
|
|
13
|
-
* Optional callback to run when the input should be validated. Use this to set
|
|
14
|
-
* a `customValidity` as necessary.
|
|
15
|
-
*
|
|
16
|
-
* Always prefer using standard HTML attributes like `required` and `min`/`max` over
|
|
17
|
-
* custom validators when possible, as they are simpler and have localized error messages built in.
|
|
18
|
-
*/
|
|
19
|
-
onValidate?: ( currentValue: V ) => void;
|
|
20
12
|
/**
|
|
21
13
|
* Show a custom message based on the validation status.
|
|
22
14
|
*
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* WordPress dependencies
|
|
3
3
|
*/
|
|
4
|
-
import { usePrevious } from '@wordpress/compose';
|
|
5
4
|
import { __ } from '@wordpress/i18n';
|
|
6
5
|
import {
|
|
7
6
|
cloneElement,
|
|
@@ -13,7 +12,6 @@ import {
|
|
|
13
12
|
/**
|
|
14
13
|
* Internal dependencies
|
|
15
14
|
*/
|
|
16
|
-
import { withIgnoreIMEEvents } from '../utils/with-ignore-ime-events';
|
|
17
15
|
import type { ValidatedControlProps } from './components/types';
|
|
18
16
|
import { ValidityIndicator } from './validity-indicator';
|
|
19
17
|
|
|
@@ -38,6 +36,7 @@ function appendRequiredIndicator(
|
|
|
38
36
|
}
|
|
39
37
|
return label;
|
|
40
38
|
}
|
|
39
|
+
const VALIDITY_VISIBLE_ATTRIBUTE = 'data-validity-visible';
|
|
41
40
|
|
|
42
41
|
/**
|
|
43
42
|
* HTML elements that support the Constraint Validation API.
|
|
@@ -57,7 +56,6 @@ function UnforwardedControlWithError< C extends React.ReactElement >(
|
|
|
57
56
|
{
|
|
58
57
|
required,
|
|
59
58
|
markWhenOptional,
|
|
60
|
-
onValidate,
|
|
61
59
|
customValidity,
|
|
62
60
|
getValidityTarget,
|
|
63
61
|
children,
|
|
@@ -70,11 +68,7 @@ function UnforwardedControlWithError< C extends React.ReactElement >(
|
|
|
70
68
|
* Label the control as "optional" when _not_ `required`, instead of the inverse.
|
|
71
69
|
*/
|
|
72
70
|
markWhenOptional?: boolean;
|
|
73
|
-
|
|
74
|
-
* The callback to run when the input should be validated.
|
|
75
|
-
*/
|
|
76
|
-
onValidate?: () => void;
|
|
77
|
-
customValidity?: ValidatedControlProps< unknown >[ 'customValidity' ];
|
|
71
|
+
customValidity?: ValidatedControlProps[ 'customValidity' ];
|
|
78
72
|
/**
|
|
79
73
|
* A function that returns the actual element on which the validity data should be applied.
|
|
80
74
|
*/
|
|
@@ -99,31 +93,24 @@ function UnforwardedControlWithError< C extends React.ReactElement >(
|
|
|
99
93
|
}
|
|
100
94
|
| undefined
|
|
101
95
|
>();
|
|
96
|
+
const [ showMessage, setShowMessage ] = useState( false );
|
|
102
97
|
const [ isTouched, setIsTouched ] = useState( false );
|
|
103
|
-
const previousCustomValidityType = usePrevious( customValidity?.type );
|
|
104
98
|
|
|
105
|
-
// Ensure that error messages are visible
|
|
106
|
-
//
|
|
99
|
+
// Ensure that error messages are visible when an `invalid` event is triggered,
|
|
100
|
+
// e.g. when a form is submitted or reportValidity() is called.
|
|
107
101
|
useEffect( () => {
|
|
108
102
|
const validityTarget = getValidityTarget();
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
validityTarget?.addEventListener( 'invalid', showValidationMessage );
|
|
113
|
-
|
|
114
|
-
return () => {
|
|
115
|
-
validityTarget?.removeEventListener(
|
|
116
|
-
'invalid',
|
|
117
|
-
showValidationMessage
|
|
118
|
-
);
|
|
103
|
+
const handler = () => {
|
|
104
|
+
setShowMessage( true );
|
|
105
|
+
validityTarget?.setAttribute( VALIDITY_VISIBLE_ATTRIBUTE, '' );
|
|
119
106
|
};
|
|
120
|
-
} );
|
|
121
107
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
108
|
+
validityTarget?.addEventListener( 'invalid', handler );
|
|
109
|
+
return () => validityTarget?.removeEventListener( 'invalid', handler );
|
|
110
|
+
}, [ getValidityTarget ] );
|
|
126
111
|
|
|
112
|
+
// Handle validity messages.
|
|
113
|
+
useEffect( () => {
|
|
127
114
|
const validityTarget = getValidityTarget();
|
|
128
115
|
|
|
129
116
|
if ( ! customValidity?.type ) {
|
|
@@ -135,26 +122,16 @@ function UnforwardedControlWithError< C extends React.ReactElement >(
|
|
|
135
122
|
|
|
136
123
|
switch ( customValidity.type ) {
|
|
137
124
|
case 'validating': {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
} );
|
|
147
|
-
}, 1000 );
|
|
148
|
-
|
|
149
|
-
return () => clearTimeout( timer );
|
|
125
|
+
validityTarget?.setCustomValidity( '' );
|
|
126
|
+
setErrorMessage( undefined );
|
|
127
|
+
|
|
128
|
+
setStatusMessage( {
|
|
129
|
+
type: 'validating',
|
|
130
|
+
message: customValidity.message,
|
|
131
|
+
} );
|
|
132
|
+
break;
|
|
150
133
|
}
|
|
151
134
|
case 'valid': {
|
|
152
|
-
// Ensures that we wait for any async responses before showing
|
|
153
|
-
// a synchronously valid state.
|
|
154
|
-
if ( previousCustomValidityType === 'valid' ) {
|
|
155
|
-
break;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
135
|
validityTarget?.setCustomValidity( '' );
|
|
159
136
|
setErrorMessage( validityTarget?.validationMessage );
|
|
160
137
|
|
|
@@ -174,14 +151,28 @@ function UnforwardedControlWithError< C extends React.ReactElement >(
|
|
|
174
151
|
break;
|
|
175
152
|
}
|
|
176
153
|
}
|
|
177
|
-
}, [
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
154
|
+
}, [ customValidity, getValidityTarget ] );
|
|
155
|
+
|
|
156
|
+
// Show messages if field has been touched (i.e. has blurred at least once),
|
|
157
|
+
// or validation has been triggered by the consumer/user.
|
|
158
|
+
useEffect( (): ReturnType< React.EffectCallback > => {
|
|
159
|
+
if ( ! isTouched || showMessage ) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
184
162
|
|
|
163
|
+
if ( customValidity?.type === 'validating' ) {
|
|
164
|
+
// Don't show validating indicators for quick calls that take less than 1 sec.
|
|
165
|
+
const timer = setTimeout( () => {
|
|
166
|
+
setShowMessage( true );
|
|
167
|
+
}, 1000 );
|
|
168
|
+
|
|
169
|
+
return () => clearTimeout( timer );
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
setShowMessage( true );
|
|
173
|
+
}, [ isTouched, customValidity?.type, showMessage ] );
|
|
174
|
+
|
|
175
|
+
// Mark blurred fields as touched.
|
|
185
176
|
const onBlur = ( event: React.FocusEvent< HTMLDivElement > ) => {
|
|
186
177
|
if ( isTouched ) {
|
|
187
178
|
return;
|
|
@@ -194,36 +185,32 @@ function UnforwardedControlWithError< C extends React.ReactElement >(
|
|
|
194
185
|
! event.currentTarget.contains( event.relatedTarget )
|
|
195
186
|
) {
|
|
196
187
|
setIsTouched( true );
|
|
197
|
-
|
|
188
|
+
getValidityTarget()?.setAttribute( VALIDITY_VISIBLE_ATTRIBUTE, '' );
|
|
198
189
|
}
|
|
199
190
|
};
|
|
200
191
|
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
if ( isTouched || errorMessage ) {
|
|
207
|
-
onValidate?.();
|
|
192
|
+
const message = () => {
|
|
193
|
+
if ( errorMessage ) {
|
|
194
|
+
return (
|
|
195
|
+
<ValidityIndicator type="invalid" message={ errorMessage } />
|
|
196
|
+
);
|
|
208
197
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
198
|
+
if ( statusMessage?.type ) {
|
|
199
|
+
return (
|
|
200
|
+
<ValidityIndicator
|
|
201
|
+
type={ statusMessage.type }
|
|
202
|
+
message={ statusMessage.message }
|
|
203
|
+
/>
|
|
204
|
+
);
|
|
216
205
|
}
|
|
206
|
+
return null;
|
|
217
207
|
};
|
|
218
208
|
|
|
219
209
|
return (
|
|
220
|
-
// Disable reason: Just listening to a bubbled event, not for interaction.
|
|
221
|
-
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
|
|
222
210
|
<div
|
|
223
211
|
className="components-validated-control"
|
|
224
212
|
ref={ forwardedRef }
|
|
225
213
|
onBlur={ onBlur }
|
|
226
|
-
onKeyDown={ withIgnoreIMEEvents( onKeyDown ) }
|
|
227
214
|
>
|
|
228
215
|
{ cloneElement( children, {
|
|
229
216
|
label: appendRequiredIndicator(
|
|
@@ -231,23 +218,9 @@ function UnforwardedControlWithError< C extends React.ReactElement >(
|
|
|
231
218
|
required,
|
|
232
219
|
markWhenOptional
|
|
233
220
|
),
|
|
234
|
-
onChange,
|
|
235
221
|
required,
|
|
236
222
|
} ) }
|
|
237
|
-
<div aria-live="polite">
|
|
238
|
-
{ errorMessage && (
|
|
239
|
-
<ValidityIndicator
|
|
240
|
-
type="invalid"
|
|
241
|
-
message={ errorMessage }
|
|
242
|
-
/>
|
|
243
|
-
) }
|
|
244
|
-
{ ! errorMessage && statusMessage && (
|
|
245
|
-
<ValidityIndicator
|
|
246
|
-
type={ statusMessage.type }
|
|
247
|
-
message={ statusMessage.message }
|
|
248
|
-
/>
|
|
249
|
-
) }
|
|
250
|
-
</div>
|
|
223
|
+
<div aria-live="polite">{ showMessage && message() }</div>
|
|
251
224
|
</div>
|
|
252
225
|
);
|
|
253
226
|
}
|
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
.components-validated-control {
|
|
6
6
|
// For components based on InputBase
|
|
7
|
-
&:has(:is(input, select):
|
|
7
|
+
&:has(:is(input, select):invalid[data-validity-visible])
|
|
8
8
|
.components-input-control__backdrop {
|
|
9
9
|
--wp-components-color-accent: #{$alert-red};
|
|
10
10
|
border-color: $alert-red;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
// For TextControl, TextareaControl
|
|
14
|
-
:is(textarea, input[type="text"]):
|
|
14
|
+
:is(textarea, input[type="text"]):invalid[data-validity-visible] {
|
|
15
15
|
--wp-admin-theme-color: #{$alert-red};
|
|
16
16
|
--wp-components-color-accent: #{$alert-red};
|
|
17
17
|
border-color: $alert-red;
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
|
|
20
20
|
// For ComboboxControl
|
|
21
21
|
.components-combobox-control__suggestions-container:has(
|
|
22
|
-
input:
|
|
22
|
+
input:invalid[data-validity-visible]
|
|
23
23
|
):not(:has([aria-expanded="true"])) {
|
|
24
|
-
|
|
24
|
+
--wp-components-color-accent: #{$alert-red};
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
|
|
@@ -29,18 +29,18 @@
|
|
|
29
29
|
position: relative;
|
|
30
30
|
|
|
31
31
|
// For CustomSelectControl
|
|
32
|
-
&:has(select:
|
|
32
|
+
&:has(select:invalid[data-validity-visible]) .components-input-control__backdrop {
|
|
33
33
|
--wp-components-color-accent: #{$alert-red};
|
|
34
34
|
border-color: $alert-red;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
// For ToggleGroupControl
|
|
38
|
-
&:has(input[type="radio"]:invalid) {
|
|
38
|
+
&:has(input[type="radio"]:invalid[data-validity-visible]) {
|
|
39
39
|
--wp-components-color-accent: #{$alert-red};
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
// For FormTokenField
|
|
43
|
-
&:has(input:
|
|
43
|
+
&:has(input:invalid[data-validity-visible]) .components-form-token-field__input-container:not(:has([aria-expanded="true"])) {
|
|
44
44
|
--wp-components-color-accent: #{$alert-red};
|
|
45
45
|
border-color: $alert-red;
|
|
46
46
|
}
|
|
@@ -38,7 +38,7 @@ describe( 'ControlWithError', () => {
|
|
|
38
38
|
>[ 'customValidity' ]
|
|
39
39
|
>( undefined );
|
|
40
40
|
|
|
41
|
-
const
|
|
41
|
+
const onChange = useCallback(
|
|
42
42
|
( value?: string ) => {
|
|
43
43
|
setCustomValidity( {
|
|
44
44
|
type: 'validating',
|
|
@@ -59,6 +59,8 @@ describe( 'ControlWithError', () => {
|
|
|
59
59
|
} );
|
|
60
60
|
}
|
|
61
61
|
}, serverDelayMs );
|
|
62
|
+
|
|
63
|
+
setText( value ?? '' );
|
|
62
64
|
},
|
|
63
65
|
[ serverDelayMs ]
|
|
64
66
|
);
|
|
@@ -67,10 +69,7 @@ describe( 'ControlWithError', () => {
|
|
|
67
69
|
<ValidatedInputControl
|
|
68
70
|
label="Text"
|
|
69
71
|
value={ text }
|
|
70
|
-
onChange={
|
|
71
|
-
setText( newValue ?? '' );
|
|
72
|
-
} }
|
|
73
|
-
onValidate={ onValidate }
|
|
72
|
+
onChange={ onChange }
|
|
74
73
|
customValidity={ customValidity }
|
|
75
74
|
{ ...restProps }
|
|
76
75
|
/>
|
|
@@ -221,4 +220,66 @@ describe( 'ControlWithError', () => {
|
|
|
221
220
|
} );
|
|
222
221
|
} );
|
|
223
222
|
} );
|
|
223
|
+
|
|
224
|
+
describe( 'Form submission', () => {
|
|
225
|
+
const CustomValidatedInputControl = ( {
|
|
226
|
+
...restProps
|
|
227
|
+
}: React.ComponentProps< typeof ValidatedInputControl > ) => {
|
|
228
|
+
const [ customValidity, setCustomValidity ] =
|
|
229
|
+
useState<
|
|
230
|
+
React.ComponentProps<
|
|
231
|
+
typeof ValidatedInputControl
|
|
232
|
+
>[ 'customValidity' ]
|
|
233
|
+
>( undefined );
|
|
234
|
+
return (
|
|
235
|
+
<ValidatedInputControl
|
|
236
|
+
onChange={ ( value ) =>
|
|
237
|
+
value === 'error'
|
|
238
|
+
? setCustomValidity( {
|
|
239
|
+
type: 'invalid',
|
|
240
|
+
message: 'The word "error" is not allowed.',
|
|
241
|
+
} )
|
|
242
|
+
: setCustomValidity( undefined )
|
|
243
|
+
}
|
|
244
|
+
customValidity={ customValidity }
|
|
245
|
+
{ ...restProps }
|
|
246
|
+
/>
|
|
247
|
+
);
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
it( 'should show custom validity messages regardless of "touched" state if parent form is submitted', async () => {
|
|
251
|
+
const user = userEvent.setup();
|
|
252
|
+
const onSubmit = jest.fn();
|
|
253
|
+
render(
|
|
254
|
+
<form onSubmit={ onSubmit }>
|
|
255
|
+
<CustomValidatedInputControl label="Text" />
|
|
256
|
+
<button type="submit">Submit</button>
|
|
257
|
+
</form>
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
const input = screen.getByRole< HTMLInputElement >( 'textbox', {
|
|
261
|
+
name: 'Text',
|
|
262
|
+
} );
|
|
263
|
+
|
|
264
|
+
// User has interacted, but not blurred
|
|
265
|
+
await user.type( input, 'error' );
|
|
266
|
+
await user.keyboard( '{enter}' );
|
|
267
|
+
|
|
268
|
+
// Input is marked as invalid at the HTML level
|
|
269
|
+
await waitFor( () => {
|
|
270
|
+
expect( input.checkValidity() ).toBe( false );
|
|
271
|
+
} );
|
|
272
|
+
expect( input.validationMessage ).toBe(
|
|
273
|
+
'The word "error" is not allowed.'
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
// Field is showing the error message
|
|
277
|
+
expect(
|
|
278
|
+
screen.getByText( 'The word "error" is not allowed.' )
|
|
279
|
+
).toBeVisible();
|
|
280
|
+
|
|
281
|
+
// Form is not submitted
|
|
282
|
+
expect( onSubmit ).not.toHaveBeenCalled();
|
|
283
|
+
} );
|
|
284
|
+
} );
|
|
224
285
|
} );
|