@wordpress/components 30.1.0 → 30.2.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 +19 -3
- package/build/custom-gradient-picker/serializer.js +14 -0
- package/build/custom-gradient-picker/serializer.js.map +1 -1
- package/build/custom-gradient-picker/utils.js +12 -0
- package/build/custom-gradient-picker/utils.js.map +1 -1
- package/build/date-time/date/index.js +2 -4
- package/build/date-time/date/index.js.map +1 -1
- package/build/date-time/date/styles.js +41 -20
- package/build/date-time/date/styles.js.map +1 -1
- package/build/menu-item/index.js +1 -0
- package/build/menu-item/index.js.map +1 -1
- package/build/validated-form-controls/components/checkbox-control.js +5 -3
- package/build/validated-form-controls/components/checkbox-control.js.map +1 -1
- package/build/validated-form-controls/components/combobox-control.js +5 -3
- package/build/validated-form-controls/components/combobox-control.js.map +1 -1
- package/build/validated-form-controls/components/custom-select-control.js +5 -3
- package/build/validated-form-controls/components/custom-select-control.js.map +1 -1
- package/build/validated-form-controls/components/input-control.js +5 -3
- package/build/validated-form-controls/components/input-control.js.map +1 -1
- package/build/validated-form-controls/components/number-control.js +5 -3
- package/build/validated-form-controls/components/number-control.js.map +1 -1
- package/build/validated-form-controls/components/radio-control.js +5 -3
- package/build/validated-form-controls/components/radio-control.js.map +1 -1
- package/build/validated-form-controls/components/range-control.js +5 -3
- package/build/validated-form-controls/components/range-control.js.map +1 -1
- package/build/validated-form-controls/components/select-control.js +5 -3
- package/build/validated-form-controls/components/select-control.js.map +1 -1
- package/build/validated-form-controls/components/text-control.js +5 -3
- package/build/validated-form-controls/components/text-control.js.map +1 -1
- package/build/validated-form-controls/components/textarea-control.js +5 -3
- package/build/validated-form-controls/components/textarea-control.js.map +1 -1
- package/build/validated-form-controls/components/toggle-control.js +5 -3
- package/build/validated-form-controls/components/toggle-control.js.map +1 -1
- package/build/validated-form-controls/components/toggle-group-control.js +5 -3
- package/build/validated-form-controls/components/toggle-group-control.js.map +1 -1
- package/build/validated-form-controls/components/types.js.map +1 -1
- package/build/validated-form-controls/control-with-error.js +57 -22
- package/build/validated-form-controls/control-with-error.js.map +1 -1
- package/build/validated-form-controls/validity-indicator.js +45 -0
- package/build/validated-form-controls/validity-indicator.js.map +1 -0
- package/build-module/custom-gradient-picker/serializer.js +14 -0
- package/build-module/custom-gradient-picker/serializer.js.map +1 -1
- package/build-module/custom-gradient-picker/utils.js +12 -0
- package/build-module/custom-gradient-picker/utils.js.map +1 -1
- package/build-module/date-time/date/index.js +3 -4
- package/build-module/date-time/date/index.js.map +1 -1
- package/build-module/date-time/date/styles.js +39 -14
- package/build-module/date-time/date/styles.js.map +1 -1
- package/build-module/menu-item/index.js +1 -0
- package/build-module/menu-item/index.js.map +1 -1
- package/build-module/validated-form-controls/components/checkbox-control.js +5 -3
- package/build-module/validated-form-controls/components/checkbox-control.js.map +1 -1
- package/build-module/validated-form-controls/components/combobox-control.js +5 -3
- package/build-module/validated-form-controls/components/combobox-control.js.map +1 -1
- package/build-module/validated-form-controls/components/custom-select-control.js +5 -3
- package/build-module/validated-form-controls/components/custom-select-control.js.map +1 -1
- package/build-module/validated-form-controls/components/input-control.js +5 -3
- package/build-module/validated-form-controls/components/input-control.js.map +1 -1
- package/build-module/validated-form-controls/components/number-control.js +5 -3
- package/build-module/validated-form-controls/components/number-control.js.map +1 -1
- package/build-module/validated-form-controls/components/radio-control.js +5 -3
- package/build-module/validated-form-controls/components/radio-control.js.map +1 -1
- package/build-module/validated-form-controls/components/range-control.js +5 -3
- package/build-module/validated-form-controls/components/range-control.js.map +1 -1
- package/build-module/validated-form-controls/components/select-control.js +5 -3
- package/build-module/validated-form-controls/components/select-control.js.map +1 -1
- package/build-module/validated-form-controls/components/text-control.js +5 -3
- package/build-module/validated-form-controls/components/text-control.js.map +1 -1
- package/build-module/validated-form-controls/components/textarea-control.js +5 -3
- package/build-module/validated-form-controls/components/textarea-control.js.map +1 -1
- package/build-module/validated-form-controls/components/toggle-control.js +5 -3
- package/build-module/validated-form-controls/components/toggle-control.js.map +1 -1
- package/build-module/validated-form-controls/components/toggle-group-control.js +5 -3
- package/build-module/validated-form-controls/components/toggle-group-control.js.map +1 -1
- package/build-module/validated-form-controls/components/types.js.map +1 -1
- package/build-module/validated-form-controls/control-with-error.js +57 -21
- package/build-module/validated-form-controls/control-with-error.js.map +1 -1
- package/build-module/validated-form-controls/validity-indicator.js +37 -0
- package/build-module/validated-form-controls/validity-indicator.js.map +1 -0
- package/build-style/style-rtl.css +37 -25
- package/build-style/style.css +37 -25
- package/build-types/confirm-dialog/stories/index.story.d.ts.map +1 -1
- package/build-types/custom-gradient-picker/serializer.d.ts.map +1 -1
- package/build-types/custom-gradient-picker/utils.d.ts.map +1 -1
- package/build-types/date-time/date/index.d.ts.map +1 -1
- package/build-types/date-time/date/styles.d.ts +6 -0
- package/build-types/date-time/date/styles.d.ts.map +1 -1
- package/build-types/divider/stories/index.story.d.ts.map +1 -1
- package/build-types/elevation/stories/index.story.d.ts.map +1 -1
- package/build-types/form-token-field/stories/index.story.d.ts +10 -5
- package/build-types/form-token-field/stories/index.story.d.ts.map +1 -1
- package/build-types/gradient-picker/stories/index.story.d.ts +2 -1
- package/build-types/gradient-picker/stories/index.story.d.ts.map +1 -1
- package/build-types/grid/stories/index.story.d.ts.map +1 -1
- package/build-types/h-stack/stories/index.story.d.ts.map +1 -1
- package/build-types/heading/stories/index.story.d.ts.map +1 -1
- package/build-types/input-control/stories/index.story.d.ts.map +1 -1
- package/build-types/item-group/stories/index.story.d.ts.map +1 -1
- package/build-types/menu-item/index.d.ts.map +1 -1
- package/build-types/number-control/stories/index.story.d.ts.map +1 -1
- package/build-types/scrollable/stories/index.story.d.ts.map +1 -1
- package/build-types/spacer/stories/index.story.d.ts.map +1 -1
- package/build-types/surface/stories/index.story.d.ts.map +1 -1
- package/build-types/text/stories/index.story.d.ts.map +1 -1
- package/build-types/toggle-group-control/stories/index.story.d.ts.map +1 -1
- package/build-types/tools-panel/stories/index.story.d.ts.map +1 -1
- package/build-types/tree-grid/stories/index.story.d.ts.map +1 -1
- package/build-types/truncate/stories/index.story.d.ts.map +1 -1
- package/build-types/unit-control/stories/index.story.d.ts.map +1 -1
- package/build-types/v-stack/stories/index.story.d.ts.map +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.map +1 -1
- package/build-types/validated-form-controls/components/custom-select-control.d.ts.map +1 -1
- 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.map +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.map +1 -1
- 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/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 +13 -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.map +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.map +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 +21 -10
- 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/build-types/validated-form-controls/validity-indicator.d.ts +5 -0
- package/build-types/validated-form-controls/validity-indicator.d.ts.map +1 -0
- package/build-types/view/stories/index.story.d.ts.map +1 -1
- package/build-types/z-stack/stories/index.story.d.ts.map +1 -1
- package/package.json +21 -21
- package/src/button/style.scss +3 -3
- package/src/calendar/style.scss +22 -22
- package/src/confirm-dialog/stories/index.story.tsx +3 -2
- package/src/custom-gradient-picker/serializer.ts +14 -0
- package/src/custom-gradient-picker/test/serializer.ts +25 -0
- package/src/custom-gradient-picker/utils.ts +10 -0
- package/src/date-time/date/index.tsx +4 -3
- package/src/date-time/date/styles.ts +13 -20
- package/src/divider/stories/index.story.tsx +2 -1
- package/src/elevation/stories/index.story.tsx +2 -1
- package/src/form-token-field/stories/index.story.tsx +15 -7
- package/src/gradient-picker/stories/index.story.tsx +48 -0
- package/src/grid/stories/index.story.tsx +2 -1
- package/src/h-stack/stories/e2e/index.story.tsx +1 -1
- package/src/h-stack/stories/index.story.tsx +3 -2
- package/src/heading/stories/index.story.tsx +3 -2
- package/src/input-control/stories/index.story.tsx +3 -2
- package/src/item-group/stories/index.story.tsx +2 -1
- package/src/menu/stories/index.story.tsx +1 -1
- package/src/menu-item/index.tsx +1 -0
- package/src/number-control/stories/index.story.tsx +3 -2
- package/src/scrollable/stories/index.story.tsx +2 -1
- package/src/spacer/stories/index.story.tsx +2 -1
- package/src/surface/stories/index.story.tsx +2 -1
- package/src/text/stories/index.story.tsx +3 -2
- package/src/toggle-group-control/stories/index.story.tsx +3 -2
- package/src/tools-panel/stories/index.story.tsx +2 -1
- package/src/tree-grid/stories/index.story.tsx +3 -2
- package/src/truncate/stories/index.story.tsx +3 -2
- package/src/unit-control/stories/index.story.tsx +3 -2
- package/src/utils/theme-variables.scss +1 -0
- package/src/v-stack/stories/e2e/index.story.tsx +1 -1
- package/src/v-stack/stories/index.story.tsx +3 -2
- package/src/validated-form-controls/components/checkbox-control.tsx +5 -3
- package/src/validated-form-controls/components/combobox-control.tsx +5 -3
- package/src/validated-form-controls/components/custom-select-control.tsx +5 -3
- package/src/validated-form-controls/components/input-control.tsx +5 -3
- package/src/validated-form-controls/components/number-control.tsx +5 -3
- package/src/validated-form-controls/components/radio-control.tsx +5 -3
- package/src/validated-form-controls/components/range-control.tsx +5 -3
- package/src/validated-form-controls/components/select-control.tsx +5 -3
- package/src/validated-form-controls/components/stories/checkbox-control.story.tsx +19 -7
- package/src/validated-form-controls/components/stories/combobox-control.story.tsx +19 -7
- package/src/validated-form-controls/components/stories/custom-select-control.story.tsx +19 -7
- package/src/validated-form-controls/components/stories/input-control.story.tsx +53 -19
- package/src/validated-form-controls/components/stories/number-control.story.tsx +19 -7
- package/src/validated-form-controls/components/stories/overview.mdx +2 -2
- package/src/validated-form-controls/components/stories/overview.story.tsx +124 -16
- package/src/validated-form-controls/components/stories/radio-control.story.tsx +19 -7
- package/src/validated-form-controls/components/stories/range-control.story.tsx +19 -7
- package/src/validated-form-controls/components/stories/select-control.story.tsx +19 -7
- package/src/validated-form-controls/components/stories/text-control.story.tsx +19 -7
- package/src/validated-form-controls/components/stories/textarea-control.story.tsx +19 -7
- package/src/validated-form-controls/components/stories/toggle-control.story.tsx +19 -7
- package/src/validated-form-controls/components/stories/toggle-group-control.story.tsx +19 -7
- package/src/validated-form-controls/components/text-control.tsx +5 -3
- package/src/validated-form-controls/components/textarea-control.tsx +5 -3
- package/src/validated-form-controls/components/toggle-control.tsx +5 -3
- package/src/validated-form-controls/components/toggle-group-control.tsx +5 -3
- package/src/validated-form-controls/components/types.ts +21 -12
- package/src/validated-form-controls/control-with-error.tsx +77 -26
- package/src/validated-form-controls/style.scss +19 -5
- package/src/validated-form-controls/validity-indicator.tsx +48 -0
- package/src/view/stories/index.story.tsx +2 -1
- package/src/z-stack/stories/index.story.tsx +2 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -15,7 +15,8 @@ import { ValidatedCheckboxControl } from '../checkbox-control';
|
|
|
15
15
|
import { formDecorator } from './story-utils';
|
|
16
16
|
|
|
17
17
|
const meta: Meta< typeof ValidatedCheckboxControl > = {
|
|
18
|
-
title: 'Components
|
|
18
|
+
title: 'Components/Selection & Input/Validated Form Controls/ValidatedCheckboxControl',
|
|
19
|
+
id: 'components-validatedcheckboxcontrol',
|
|
19
20
|
component: ValidatedCheckboxControl,
|
|
20
21
|
tags: [ 'status-private' ],
|
|
21
22
|
decorators: formDecorator,
|
|
@@ -31,6 +32,12 @@ export default meta;
|
|
|
31
32
|
export const Default: StoryObj< typeof ValidatedCheckboxControl > = {
|
|
32
33
|
render: function Template( { onChange, ...args } ) {
|
|
33
34
|
const [ checked, setChecked ] = useState( false );
|
|
35
|
+
const [ customValidity, setCustomValidity ] =
|
|
36
|
+
useState<
|
|
37
|
+
React.ComponentProps<
|
|
38
|
+
typeof ValidatedCheckboxControl
|
|
39
|
+
>[ 'customValidity' ]
|
|
40
|
+
>( undefined );
|
|
34
41
|
|
|
35
42
|
return (
|
|
36
43
|
<ValidatedCheckboxControl
|
|
@@ -40,6 +47,17 @@ export const Default: StoryObj< typeof ValidatedCheckboxControl > = {
|
|
|
40
47
|
setChecked( value );
|
|
41
48
|
onChange?.( value );
|
|
42
49
|
} }
|
|
50
|
+
onValidate={ ( value ) => {
|
|
51
|
+
if ( value ) {
|
|
52
|
+
setCustomValidity( {
|
|
53
|
+
type: 'invalid',
|
|
54
|
+
message: 'This checkbox may not be checked.',
|
|
55
|
+
} );
|
|
56
|
+
} else {
|
|
57
|
+
setCustomValidity( undefined );
|
|
58
|
+
}
|
|
59
|
+
} }
|
|
60
|
+
customValidity={ customValidity }
|
|
43
61
|
/>
|
|
44
62
|
);
|
|
45
63
|
},
|
|
@@ -48,10 +66,4 @@ Default.args = {
|
|
|
48
66
|
required: true,
|
|
49
67
|
label: 'Checkbox',
|
|
50
68
|
help: 'This checkbox may neither be checked nor unchecked.',
|
|
51
|
-
customValidator: ( value ) => {
|
|
52
|
-
if ( value ) {
|
|
53
|
-
return 'This checkbox may not be checked.';
|
|
54
|
-
}
|
|
55
|
-
return undefined;
|
|
56
|
-
},
|
|
57
69
|
};
|
|
@@ -15,7 +15,8 @@ import { ValidatedComboboxControl } from '../combobox-control';
|
|
|
15
15
|
import { formDecorator } from './story-utils';
|
|
16
16
|
|
|
17
17
|
const meta: Meta< typeof ValidatedComboboxControl > = {
|
|
18
|
-
title: 'Components
|
|
18
|
+
title: 'Components/Selection & Input/Validated Form Controls/ValidatedComboboxControl',
|
|
19
|
+
id: 'components-validatedcomboboxcontrol',
|
|
19
20
|
component: ValidatedComboboxControl,
|
|
20
21
|
tags: [ 'status-private' ],
|
|
21
22
|
decorators: formDecorator,
|
|
@@ -34,6 +35,12 @@ export const Default: StoryObj< typeof ValidatedComboboxControl > = {
|
|
|
34
35
|
typeof ValidatedComboboxControl
|
|
35
36
|
>[ 'value' ]
|
|
36
37
|
>();
|
|
38
|
+
const [ customValidity, setCustomValidity ] =
|
|
39
|
+
useState<
|
|
40
|
+
React.ComponentProps<
|
|
41
|
+
typeof ValidatedComboboxControl
|
|
42
|
+
>[ 'customValidity' ]
|
|
43
|
+
>( undefined );
|
|
37
44
|
|
|
38
45
|
return (
|
|
39
46
|
<ValidatedComboboxControl
|
|
@@ -43,6 +50,17 @@ export const Default: StoryObj< typeof ValidatedComboboxControl > = {
|
|
|
43
50
|
setValue( newValue );
|
|
44
51
|
onChange?.( newValue );
|
|
45
52
|
} }
|
|
53
|
+
onValidate={ ( v ) => {
|
|
54
|
+
if ( v === 'a' ) {
|
|
55
|
+
setCustomValidity( {
|
|
56
|
+
type: 'invalid',
|
|
57
|
+
message: 'Option A is not allowed.',
|
|
58
|
+
} );
|
|
59
|
+
} else {
|
|
60
|
+
setCustomValidity( undefined );
|
|
61
|
+
}
|
|
62
|
+
} }
|
|
63
|
+
customValidity={ customValidity }
|
|
46
64
|
/>
|
|
47
65
|
);
|
|
48
66
|
},
|
|
@@ -55,10 +73,4 @@ Default.args = {
|
|
|
55
73
|
{ value: 'a', label: 'Option A (not allowed)' },
|
|
56
74
|
{ value: 'b', label: 'Option B' },
|
|
57
75
|
],
|
|
58
|
-
customValidator: ( value ) => {
|
|
59
|
-
if ( value === 'a' ) {
|
|
60
|
-
return 'Option A is not allowed.';
|
|
61
|
-
}
|
|
62
|
-
return undefined;
|
|
63
|
-
},
|
|
64
76
|
};
|
|
@@ -15,7 +15,8 @@ import { ValidatedCustomSelectControl } from '../custom-select-control';
|
|
|
15
15
|
import { formDecorator } from './story-utils';
|
|
16
16
|
|
|
17
17
|
const meta: Meta< typeof ValidatedCustomSelectControl > = {
|
|
18
|
-
title: 'Components
|
|
18
|
+
title: 'Components/Selection & Input/Validated Form Controls/ValidatedCustomSelectControl',
|
|
19
|
+
id: 'components-validatedcustomselectcontrol',
|
|
19
20
|
component: ValidatedCustomSelectControl,
|
|
20
21
|
tags: [ 'status-private' ],
|
|
21
22
|
decorators: formDecorator,
|
|
@@ -34,6 +35,12 @@ export const Default: StoryObj< typeof ValidatedCustomSelectControl > = {
|
|
|
34
35
|
typeof ValidatedCustomSelectControl
|
|
35
36
|
>[ 'value' ]
|
|
36
37
|
>();
|
|
38
|
+
const [ customValidity, setCustomValidity ] =
|
|
39
|
+
useState<
|
|
40
|
+
React.ComponentProps<
|
|
41
|
+
typeof ValidatedCustomSelectControl
|
|
42
|
+
>[ 'customValidity' ]
|
|
43
|
+
>( undefined );
|
|
37
44
|
|
|
38
45
|
return (
|
|
39
46
|
<ValidatedCustomSelectControl
|
|
@@ -43,6 +50,17 @@ export const Default: StoryObj< typeof ValidatedCustomSelectControl > = {
|
|
|
43
50
|
setValue( newValue.selectedItem );
|
|
44
51
|
onChange?.( newValue );
|
|
45
52
|
} }
|
|
53
|
+
onValidate={ ( v ) => {
|
|
54
|
+
if ( v?.key === 'a' ) {
|
|
55
|
+
setCustomValidity( {
|
|
56
|
+
type: 'invalid',
|
|
57
|
+
message: 'Option A is not allowed.',
|
|
58
|
+
} );
|
|
59
|
+
} else {
|
|
60
|
+
setCustomValidity( undefined );
|
|
61
|
+
}
|
|
62
|
+
} }
|
|
63
|
+
customValidity={ customValidity }
|
|
46
64
|
/>
|
|
47
65
|
);
|
|
48
66
|
},
|
|
@@ -55,10 +73,4 @@ Default.args = {
|
|
|
55
73
|
{ key: 'a', name: 'Option A (not allowed)' },
|
|
56
74
|
{ key: 'b', name: 'Option B' },
|
|
57
75
|
],
|
|
58
|
-
customValidator: ( value ) => {
|
|
59
|
-
if ( value?.key === 'a' ) {
|
|
60
|
-
return 'Option A is not allowed.';
|
|
61
|
-
}
|
|
62
|
-
return undefined;
|
|
63
|
-
},
|
|
64
76
|
};
|
|
@@ -22,7 +22,8 @@ import InputControlSuffixWrapper from '../../../input-control/input-suffix-wrapp
|
|
|
22
22
|
import { Button } from '../../../button';
|
|
23
23
|
|
|
24
24
|
const meta: Meta< typeof ValidatedInputControl > = {
|
|
25
|
-
title: 'Components
|
|
25
|
+
title: 'Components/Selection & Input/Validated Form Controls/ValidatedInputControl',
|
|
26
|
+
id: 'components-validatedinputcontrol',
|
|
26
27
|
component: ValidatedInputControl,
|
|
27
28
|
tags: [ 'status-private' ],
|
|
28
29
|
decorators: formDecorator,
|
|
@@ -45,6 +46,12 @@ export const Default: StoryObj< typeof ValidatedInputControl > = {
|
|
|
45
46
|
useState<
|
|
46
47
|
React.ComponentProps< typeof ValidatedInputControl >[ 'value' ]
|
|
47
48
|
>( '' );
|
|
49
|
+
const [ customValidity, setCustomValidity ] =
|
|
50
|
+
useState<
|
|
51
|
+
React.ComponentProps<
|
|
52
|
+
typeof ValidatedInputControl
|
|
53
|
+
>[ 'customValidity' ]
|
|
54
|
+
>( undefined );
|
|
48
55
|
|
|
49
56
|
return (
|
|
50
57
|
<ValidatedInputControl
|
|
@@ -54,6 +61,17 @@ export const Default: StoryObj< typeof ValidatedInputControl > = {
|
|
|
54
61
|
setValue( newValue );
|
|
55
62
|
onChange?.( newValue, ...rest );
|
|
56
63
|
} }
|
|
64
|
+
onValidate={ ( v ) => {
|
|
65
|
+
if ( v?.toLowerCase() === 'error' ) {
|
|
66
|
+
setCustomValidity( {
|
|
67
|
+
type: 'invalid',
|
|
68
|
+
message: 'The word "error" is not allowed.',
|
|
69
|
+
} );
|
|
70
|
+
} else {
|
|
71
|
+
setCustomValidity( undefined );
|
|
72
|
+
}
|
|
73
|
+
} }
|
|
74
|
+
customValidity={ customValidity }
|
|
57
75
|
/>
|
|
58
76
|
);
|
|
59
77
|
},
|
|
@@ -62,12 +80,6 @@ Default.args = {
|
|
|
62
80
|
required: true,
|
|
63
81
|
label: 'Input',
|
|
64
82
|
help: 'The word "error" will trigger an error.',
|
|
65
|
-
customValidator: ( value ) => {
|
|
66
|
-
if ( value?.toLowerCase() === 'error' ) {
|
|
67
|
-
return 'The word "error" is not allowed.';
|
|
68
|
-
}
|
|
69
|
-
return undefined;
|
|
70
|
-
},
|
|
71
83
|
};
|
|
72
84
|
|
|
73
85
|
/**
|
|
@@ -82,6 +94,12 @@ export const Password: StoryObj< typeof ValidatedInputControl > = {
|
|
|
82
94
|
React.ComponentProps< typeof ValidatedInputControl >[ 'value' ]
|
|
83
95
|
>( '' );
|
|
84
96
|
const [ visible, setVisible ] = useState( false );
|
|
97
|
+
const [ customValidity, setCustomValidity ] =
|
|
98
|
+
useState<
|
|
99
|
+
React.ComponentProps<
|
|
100
|
+
typeof ValidatedInputControl
|
|
101
|
+
>[ 'customValidity' ]
|
|
102
|
+
>( undefined );
|
|
85
103
|
|
|
86
104
|
return (
|
|
87
105
|
<ValidatedInputControl
|
|
@@ -104,6 +122,34 @@ export const Password: StoryObj< typeof ValidatedInputControl > = {
|
|
|
104
122
|
setValue( newValue );
|
|
105
123
|
onChange?.( newValue, ...rest );
|
|
106
124
|
} }
|
|
125
|
+
onValidate={ ( v ) => {
|
|
126
|
+
if ( ! /\d/.test( v ?? '' ) ) {
|
|
127
|
+
setCustomValidity( {
|
|
128
|
+
type: 'invalid',
|
|
129
|
+
message:
|
|
130
|
+
'Password must include at least one number.',
|
|
131
|
+
} );
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
if ( ! /[A-Z]/.test( v ?? '' ) ) {
|
|
135
|
+
setCustomValidity( {
|
|
136
|
+
type: 'invalid',
|
|
137
|
+
message:
|
|
138
|
+
'Password must include at least one capital letter.',
|
|
139
|
+
} );
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if ( ! /[!@£$%^&*#]/.test( v ?? '' ) ) {
|
|
143
|
+
setCustomValidity( {
|
|
144
|
+
type: 'invalid',
|
|
145
|
+
message:
|
|
146
|
+
'Password must include at least one symbol.',
|
|
147
|
+
} );
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
setCustomValidity( undefined );
|
|
151
|
+
} }
|
|
152
|
+
customValidity={ customValidity }
|
|
107
153
|
/>
|
|
108
154
|
);
|
|
109
155
|
},
|
|
@@ -113,18 +159,6 @@ Password.args = {
|
|
|
113
159
|
label: 'Password',
|
|
114
160
|
help: 'Minimum 8 characters, include a number, capital letter, and symbol (!@£$%^&*#).',
|
|
115
161
|
minLength: 8,
|
|
116
|
-
customValidator: ( value ) => {
|
|
117
|
-
if ( ! /\d/.test( value ?? '' ) ) {
|
|
118
|
-
return 'Password must include at least one number.';
|
|
119
|
-
}
|
|
120
|
-
if ( ! /[A-Z]/.test( value ?? '' ) ) {
|
|
121
|
-
return 'Password must include at least one capital letter.';
|
|
122
|
-
}
|
|
123
|
-
if ( ! /[!@£$%^&*#]/.test( value ?? '' ) ) {
|
|
124
|
-
return 'Password must include at least one symbol.';
|
|
125
|
-
}
|
|
126
|
-
return undefined;
|
|
127
|
-
},
|
|
128
162
|
};
|
|
129
163
|
Password.argTypes = {
|
|
130
164
|
suffix: { control: false },
|
|
@@ -15,7 +15,8 @@ import { ValidatedNumberControl } from '../number-control';
|
|
|
15
15
|
import { formDecorator } from './story-utils';
|
|
16
16
|
|
|
17
17
|
const meta: Meta< typeof ValidatedNumberControl > = {
|
|
18
|
-
title: 'Components
|
|
18
|
+
title: 'Components/Selection & Input/Validated Form Controls/ValidatedNumberControl',
|
|
19
|
+
id: 'components-validatednumbercontrol',
|
|
19
20
|
component: ValidatedNumberControl,
|
|
20
21
|
tags: [ 'status-private' ],
|
|
21
22
|
decorators: formDecorator,
|
|
@@ -36,6 +37,12 @@ export const Default: StoryObj< typeof ValidatedNumberControl > = {
|
|
|
36
37
|
useState<
|
|
37
38
|
React.ComponentProps< typeof ValidatedNumberControl >[ 'value' ]
|
|
38
39
|
>();
|
|
40
|
+
const [ customValidity, setCustomValidity ] =
|
|
41
|
+
useState<
|
|
42
|
+
React.ComponentProps<
|
|
43
|
+
typeof ValidatedNumberControl
|
|
44
|
+
>[ 'customValidity' ]
|
|
45
|
+
>( undefined );
|
|
39
46
|
|
|
40
47
|
return (
|
|
41
48
|
<ValidatedNumberControl
|
|
@@ -45,6 +52,17 @@ export const Default: StoryObj< typeof ValidatedNumberControl > = {
|
|
|
45
52
|
setValue( newValue );
|
|
46
53
|
onChange?.( newValue, ...rest );
|
|
47
54
|
} }
|
|
55
|
+
onValidate={ ( v ) => {
|
|
56
|
+
if ( v && parseInt( v.toString(), 10 ) % 2 !== 0 ) {
|
|
57
|
+
setCustomValidity( {
|
|
58
|
+
type: 'invalid',
|
|
59
|
+
message: 'Choose an even number.',
|
|
60
|
+
} );
|
|
61
|
+
} else {
|
|
62
|
+
setCustomValidity( undefined );
|
|
63
|
+
}
|
|
64
|
+
} }
|
|
65
|
+
customValidity={ customValidity }
|
|
48
66
|
/>
|
|
49
67
|
);
|
|
50
68
|
},
|
|
@@ -53,10 +71,4 @@ Default.args = {
|
|
|
53
71
|
required: true,
|
|
54
72
|
label: 'Number',
|
|
55
73
|
help: 'Odd numbers are not allowed.',
|
|
56
|
-
customValidator: ( value ) => {
|
|
57
|
-
if ( value && parseInt( value.toString(), 10 ) % 2 !== 0 ) {
|
|
58
|
-
return 'Choose an even number.';
|
|
59
|
-
}
|
|
60
|
-
return undefined;
|
|
61
|
-
},
|
|
62
74
|
};
|
|
@@ -2,7 +2,7 @@ import { ArgTypes, Meta, Stories } from '@storybook/blocks';
|
|
|
2
2
|
import * as OverviewStories from './overview.story';
|
|
3
3
|
import { ValidatedInputControl } from '..';
|
|
4
4
|
|
|
5
|
-
<Meta of={ OverviewStories } title="Components
|
|
5
|
+
<Meta of={ OverviewStories } title="Components/Selection & Input/Validated Form Controls/Overview" />
|
|
6
6
|
|
|
7
7
|
# Validated Form Controls
|
|
8
8
|
|
|
@@ -16,7 +16,7 @@ We are still gathering feedback and iterating. Please get in touch with `@WordPr
|
|
|
16
16
|
|
|
17
17
|
Component APIs are the same as the underlying WordPress components, with the addition of some optional props:
|
|
18
18
|
|
|
19
|
-
<ArgTypes of={ ValidatedInputControl } include={ [ 'required', 'markWhenOptional', '
|
|
19
|
+
<ArgTypes of={ ValidatedInputControl } include={ [ 'required', 'markWhenOptional', 'onValidate', 'customValidity' ] } />
|
|
20
20
|
|
|
21
21
|
## Implementation
|
|
22
22
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* WordPress dependencies
|
|
3
3
|
*/
|
|
4
|
-
import { useState } from '@wordpress/element';
|
|
4
|
+
import { useRef, useCallback, useState } from '@wordpress/element';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* External dependencies
|
|
@@ -14,10 +14,11 @@ import type { Meta, StoryObj } from '@storybook/react';
|
|
|
14
14
|
import { ValidatedInputControl } from '..';
|
|
15
15
|
import { formDecorator } from './story-utils';
|
|
16
16
|
import type { ControlWithError } from '../../control-with-error';
|
|
17
|
+
import { debounce } from '@wordpress/compose';
|
|
17
18
|
|
|
18
19
|
const meta: Meta< typeof ControlWithError > = {
|
|
19
|
-
title: 'Components
|
|
20
|
-
|
|
20
|
+
title: 'Components/Selection & Input/Validated Form Controls/Overview',
|
|
21
|
+
id: 'components-validated-form-controls-overview',
|
|
21
22
|
decorators: formDecorator,
|
|
22
23
|
};
|
|
23
24
|
export default meta;
|
|
@@ -32,6 +33,18 @@ export const WithMultipleControls: Story = {
|
|
|
32
33
|
render: function Template() {
|
|
33
34
|
const [ text, setText ] = useState( '' );
|
|
34
35
|
const [ text2, setText2 ] = useState( '' );
|
|
36
|
+
const [ customValidity, setCustomValidity ] =
|
|
37
|
+
useState<
|
|
38
|
+
React.ComponentProps<
|
|
39
|
+
typeof ValidatedInputControl
|
|
40
|
+
>[ 'customValidity' ]
|
|
41
|
+
>( undefined );
|
|
42
|
+
const [ customValidity2, setCustomValidity2 ] =
|
|
43
|
+
useState<
|
|
44
|
+
React.ComponentProps<
|
|
45
|
+
typeof ValidatedInputControl
|
|
46
|
+
>[ 'customValidity' ]
|
|
47
|
+
>( undefined );
|
|
35
48
|
|
|
36
49
|
return (
|
|
37
50
|
<>
|
|
@@ -40,12 +53,17 @@ export const WithMultipleControls: Story = {
|
|
|
40
53
|
required
|
|
41
54
|
value={ text }
|
|
42
55
|
help="The word 'error' will trigger an error."
|
|
43
|
-
|
|
56
|
+
onValidate={ ( value ) => {
|
|
44
57
|
if ( value?.toLowerCase() === 'error' ) {
|
|
45
|
-
|
|
58
|
+
setCustomValidity( {
|
|
59
|
+
type: 'invalid',
|
|
60
|
+
message: 'The word "error" is not allowed.',
|
|
61
|
+
} );
|
|
62
|
+
} else {
|
|
63
|
+
setCustomValidity( undefined );
|
|
46
64
|
}
|
|
47
|
-
return undefined;
|
|
48
65
|
} }
|
|
66
|
+
customValidity={ customValidity }
|
|
49
67
|
onChange={ ( value ) => setText( value ?? '' ) }
|
|
50
68
|
/>
|
|
51
69
|
<ValidatedInputControl
|
|
@@ -53,13 +71,18 @@ export const WithMultipleControls: Story = {
|
|
|
53
71
|
required
|
|
54
72
|
value={ text2 }
|
|
55
73
|
help="The word 'error' will trigger an error."
|
|
56
|
-
|
|
74
|
+
onValidate={ ( value ) => {
|
|
57
75
|
if ( value?.toLowerCase() === 'error' ) {
|
|
58
|
-
|
|
76
|
+
setCustomValidity2( {
|
|
77
|
+
type: 'invalid',
|
|
78
|
+
message: 'The word "error" is not allowed.',
|
|
79
|
+
} );
|
|
80
|
+
} else {
|
|
81
|
+
setCustomValidity2( undefined );
|
|
59
82
|
}
|
|
60
|
-
return undefined;
|
|
61
83
|
} }
|
|
62
84
|
onChange={ ( value ) => setText2( value ?? '' ) }
|
|
85
|
+
customValidity={ customValidity2 }
|
|
63
86
|
/>
|
|
64
87
|
</>
|
|
65
88
|
);
|
|
@@ -73,7 +96,12 @@ export const WithMultipleControls: Story = {
|
|
|
73
96
|
export const WithHelpTextReplacement: Story = {
|
|
74
97
|
render: function Template() {
|
|
75
98
|
const [ text, setText ] = useState( '' );
|
|
76
|
-
const [
|
|
99
|
+
const [ customValidity, setCustomValidity ] =
|
|
100
|
+
useState<
|
|
101
|
+
React.ComponentProps<
|
|
102
|
+
typeof ValidatedInputControl
|
|
103
|
+
>[ 'customValidity' ]
|
|
104
|
+
>( undefined );
|
|
77
105
|
|
|
78
106
|
return (
|
|
79
107
|
<ValidatedInputControl
|
|
@@ -81,20 +109,100 @@ export const WithHelpTextReplacement: Story = {
|
|
|
81
109
|
required
|
|
82
110
|
value={ text }
|
|
83
111
|
help={
|
|
84
|
-
|
|
112
|
+
customValidity
|
|
85
113
|
? undefined
|
|
86
114
|
: 'The word "error" is not allowed.'
|
|
87
115
|
}
|
|
88
|
-
|
|
116
|
+
onValidate={ ( value ) => {
|
|
89
117
|
if ( value?.toLowerCase() === 'error' ) {
|
|
90
|
-
|
|
91
|
-
|
|
118
|
+
setCustomValidity( {
|
|
119
|
+
type: 'invalid',
|
|
120
|
+
message: 'The word "error" is not allowed.',
|
|
121
|
+
} );
|
|
122
|
+
} else {
|
|
123
|
+
setCustomValidity( undefined );
|
|
92
124
|
}
|
|
93
|
-
setHasCustomError( false );
|
|
94
|
-
return undefined;
|
|
95
125
|
} }
|
|
96
126
|
onChange={ ( value ) => setText( value ?? '' ) }
|
|
127
|
+
customValidity={ customValidity }
|
|
97
128
|
/>
|
|
98
129
|
);
|
|
99
130
|
},
|
|
100
131
|
};
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* To provide feedback from server-side validation, the `customValidity` prop can be used
|
|
135
|
+
* to show additional status indicators while waiting for the server response,
|
|
136
|
+
* and after the response is received.
|
|
137
|
+
*
|
|
138
|
+
* These indicators are intended for asynchronous validation calls that may take more than 1 second to complete.
|
|
139
|
+
* They may be unnecessary when responses are generally quick.
|
|
140
|
+
*/
|
|
141
|
+
export const AsyncValidation: StoryObj< typeof ValidatedInputControl > = {
|
|
142
|
+
render: function Template( { ...args } ) {
|
|
143
|
+
const [ text, setText ] = useState( '' );
|
|
144
|
+
const [ customValidity, setCustomValidity ] =
|
|
145
|
+
useState<
|
|
146
|
+
React.ComponentProps<
|
|
147
|
+
typeof ValidatedInputControl
|
|
148
|
+
>[ 'customValidity' ]
|
|
149
|
+
>( undefined );
|
|
150
|
+
|
|
151
|
+
const timeoutRef = useRef< ReturnType< typeof setTimeout > >();
|
|
152
|
+
const previousValidationValueRef = useRef< unknown >( '' );
|
|
153
|
+
|
|
154
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
155
|
+
const debouncedValidate = useCallback(
|
|
156
|
+
debounce( ( v ) => {
|
|
157
|
+
if ( v === previousValidationValueRef.current ) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
previousValidationValueRef.current = v;
|
|
162
|
+
|
|
163
|
+
setCustomValidity( {
|
|
164
|
+
type: 'validating',
|
|
165
|
+
message: 'Validating...',
|
|
166
|
+
} );
|
|
167
|
+
|
|
168
|
+
clearTimeout( timeoutRef.current );
|
|
169
|
+
timeoutRef.current = setTimeout(
|
|
170
|
+
() => {
|
|
171
|
+
if ( v?.toString().toLowerCase() === 'error' ) {
|
|
172
|
+
setCustomValidity( {
|
|
173
|
+
type: 'invalid',
|
|
174
|
+
message: 'The word "error" is not allowed.',
|
|
175
|
+
} );
|
|
176
|
+
} else {
|
|
177
|
+
setCustomValidity( {
|
|
178
|
+
type: 'valid',
|
|
179
|
+
message: 'Validated',
|
|
180
|
+
} );
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
// Mimics a random server response time.
|
|
184
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
185
|
+
Math.random() < 0.5 ? 1500 : 300
|
|
186
|
+
);
|
|
187
|
+
}, 500 ),
|
|
188
|
+
[]
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
return (
|
|
192
|
+
<ValidatedInputControl
|
|
193
|
+
{ ...args }
|
|
194
|
+
value={ text }
|
|
195
|
+
onChange={ ( newValue ) => {
|
|
196
|
+
setText( newValue ?? '' );
|
|
197
|
+
} }
|
|
198
|
+
onValidate={ debouncedValidate }
|
|
199
|
+
customValidity={ customValidity }
|
|
200
|
+
/>
|
|
201
|
+
);
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
AsyncValidation.args = {
|
|
205
|
+
label: 'Text',
|
|
206
|
+
help: 'The word "error" will trigger an error asynchronously.',
|
|
207
|
+
required: true,
|
|
208
|
+
};
|
|
@@ -15,7 +15,8 @@ import { ValidatedRadioControl } from '../radio-control';
|
|
|
15
15
|
import { formDecorator } from './story-utils';
|
|
16
16
|
|
|
17
17
|
const meta: Meta< typeof ValidatedRadioControl > = {
|
|
18
|
-
title: 'Components
|
|
18
|
+
title: 'Components/Selection & Input/Validated Form Controls/ValidatedRadioControl',
|
|
19
|
+
id: 'components-validatedradiocontrol',
|
|
19
20
|
component: ValidatedRadioControl,
|
|
20
21
|
tags: [ 'status-private' ],
|
|
21
22
|
decorators: formDecorator,
|
|
@@ -34,6 +35,12 @@ export const Default: StoryObj< typeof ValidatedRadioControl > = {
|
|
|
34
35
|
typeof ValidatedRadioControl
|
|
35
36
|
>[ 'selected' ]
|
|
36
37
|
>();
|
|
38
|
+
const [ customValidity, setCustomValidity ] =
|
|
39
|
+
useState<
|
|
40
|
+
React.ComponentProps<
|
|
41
|
+
typeof ValidatedRadioControl
|
|
42
|
+
>[ 'customValidity' ]
|
|
43
|
+
>( undefined );
|
|
37
44
|
|
|
38
45
|
return (
|
|
39
46
|
<ValidatedRadioControl
|
|
@@ -43,6 +50,17 @@ export const Default: StoryObj< typeof ValidatedRadioControl > = {
|
|
|
43
50
|
setSelected( value );
|
|
44
51
|
onChange?.( value );
|
|
45
52
|
} }
|
|
53
|
+
onValidate={ ( v ) => {
|
|
54
|
+
if ( v === 'b' ) {
|
|
55
|
+
setCustomValidity( {
|
|
56
|
+
type: 'invalid',
|
|
57
|
+
message: 'Option B is not allowed.',
|
|
58
|
+
} );
|
|
59
|
+
} else {
|
|
60
|
+
setCustomValidity( undefined );
|
|
61
|
+
}
|
|
62
|
+
} }
|
|
63
|
+
customValidity={ customValidity }
|
|
46
64
|
/>
|
|
47
65
|
);
|
|
48
66
|
},
|
|
@@ -55,10 +73,4 @@ Default.args = {
|
|
|
55
73
|
{ label: 'Option A', value: 'a' },
|
|
56
74
|
{ label: 'Option B (not allowed)', value: 'b' },
|
|
57
75
|
],
|
|
58
|
-
customValidator: ( value ) => {
|
|
59
|
-
if ( value === 'b' ) {
|
|
60
|
-
return 'Option B is not allowed.';
|
|
61
|
-
}
|
|
62
|
-
return undefined;
|
|
63
|
-
},
|
|
64
76
|
};
|
|
@@ -15,7 +15,8 @@ import { formDecorator } from './story-utils';
|
|
|
15
15
|
import { ValidatedRangeControl } from '../range-control';
|
|
16
16
|
|
|
17
17
|
const meta: Meta< typeof ValidatedRangeControl > = {
|
|
18
|
-
title: 'Components
|
|
18
|
+
title: 'Components/Selection & Input/Validated Form Controls/ValidatedRangeControl',
|
|
19
|
+
id: 'components-validatedrangecontrol',
|
|
19
20
|
component: ValidatedRangeControl,
|
|
20
21
|
tags: [ 'status-private' ],
|
|
21
22
|
decorators: formDecorator,
|
|
@@ -32,6 +33,12 @@ export const Default: StoryObj< typeof ValidatedRangeControl > = {
|
|
|
32
33
|
useState<
|
|
33
34
|
React.ComponentProps< typeof ValidatedRangeControl >[ 'value' ]
|
|
34
35
|
>();
|
|
36
|
+
const [ customValidity, setCustomValidity ] =
|
|
37
|
+
useState<
|
|
38
|
+
React.ComponentProps<
|
|
39
|
+
typeof ValidatedRangeControl
|
|
40
|
+
>[ 'customValidity' ]
|
|
41
|
+
>( undefined );
|
|
35
42
|
|
|
36
43
|
return (
|
|
37
44
|
<ValidatedRangeControl
|
|
@@ -41,6 +48,17 @@ export const Default: StoryObj< typeof ValidatedRangeControl > = {
|
|
|
41
48
|
setValue( newValue );
|
|
42
49
|
onChange?.( newValue );
|
|
43
50
|
} }
|
|
51
|
+
onValidate={ ( v ) => {
|
|
52
|
+
if ( v && v % 2 !== 0 ) {
|
|
53
|
+
setCustomValidity( {
|
|
54
|
+
type: 'invalid',
|
|
55
|
+
message: 'Choose an even number.',
|
|
56
|
+
} );
|
|
57
|
+
} else {
|
|
58
|
+
setCustomValidity( undefined );
|
|
59
|
+
}
|
|
60
|
+
} }
|
|
61
|
+
customValidity={ customValidity }
|
|
44
62
|
/>
|
|
45
63
|
);
|
|
46
64
|
},
|
|
@@ -51,10 +69,4 @@ Default.args = {
|
|
|
51
69
|
help: 'Odd numbers are not allowed.',
|
|
52
70
|
min: 0,
|
|
53
71
|
max: 20,
|
|
54
|
-
customValidator: ( value ) => {
|
|
55
|
-
if ( value && value % 2 !== 0 ) {
|
|
56
|
-
return 'Choose an even number.';
|
|
57
|
-
}
|
|
58
|
-
return undefined;
|
|
59
|
-
},
|
|
60
72
|
};
|