@wordpress/components 30.2.1-next.0f6f9d12c.0 → 30.2.1-next.f34ab90e9.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 +10 -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/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 +34 -22
- package/build-style/style.css +34 -22
- package/build-types/menu-item/index.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/package.json +19 -19
- package/src/calendar/style.scss +22 -22
- package/src/menu-item/index.tsx +1 -0
- package/src/utils/theme-variables.scss +1 -0
- 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 +17 -6
- package/src/validated-form-controls/components/stories/combobox-control.story.tsx +17 -6
- package/src/validated-form-controls/components/stories/custom-select-control.story.tsx +17 -6
- package/src/validated-form-controls/components/stories/input-control.story.tsx +51 -18
- package/src/validated-form-controls/components/stories/number-control.story.tsx +17 -6
- package/src/validated-form-controls/components/stories/overview.mdx +1 -1
- package/src/validated-form-controls/components/stories/overview.story.tsx +122 -14
- package/src/validated-form-controls/components/stories/radio-control.story.tsx +17 -6
- package/src/validated-form-controls/components/stories/range-control.story.tsx +17 -6
- package/src/validated-form-controls/components/stories/select-control.story.tsx +17 -6
- package/src/validated-form-controls/components/stories/text-control.story.tsx +17 -6
- package/src/validated-form-controls/components/stories/textarea-control.story.tsx +17 -6
- package/src/validated-form-controls/components/stories/toggle-control.story.tsx +17 -6
- package/src/validated-form-controls/components/stories/toggle-group-control.story.tsx +17 -6
- 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/tsconfig.tsbuildinfo +1 -1
|
@@ -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,6 +14,7 @@ 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
20
|
title: 'Components/Selection & Input/Validated Form Controls/Overview',
|
|
@@ -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
|
+
};
|
|
@@ -35,6 +35,12 @@ export const Default: StoryObj< typeof ValidatedRadioControl > = {
|
|
|
35
35
|
typeof ValidatedRadioControl
|
|
36
36
|
>[ 'selected' ]
|
|
37
37
|
>();
|
|
38
|
+
const [ customValidity, setCustomValidity ] =
|
|
39
|
+
useState<
|
|
40
|
+
React.ComponentProps<
|
|
41
|
+
typeof ValidatedRadioControl
|
|
42
|
+
>[ 'customValidity' ]
|
|
43
|
+
>( undefined );
|
|
38
44
|
|
|
39
45
|
return (
|
|
40
46
|
<ValidatedRadioControl
|
|
@@ -44,6 +50,17 @@ export const Default: StoryObj< typeof ValidatedRadioControl > = {
|
|
|
44
50
|
setSelected( value );
|
|
45
51
|
onChange?.( value );
|
|
46
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 }
|
|
47
64
|
/>
|
|
48
65
|
);
|
|
49
66
|
},
|
|
@@ -56,10 +73,4 @@ Default.args = {
|
|
|
56
73
|
{ label: 'Option A', value: 'a' },
|
|
57
74
|
{ label: 'Option B (not allowed)', value: 'b' },
|
|
58
75
|
],
|
|
59
|
-
customValidator: ( value ) => {
|
|
60
|
-
if ( value === 'b' ) {
|
|
61
|
-
return 'Option B is not allowed.';
|
|
62
|
-
}
|
|
63
|
-
return undefined;
|
|
64
|
-
},
|
|
65
76
|
};
|
|
@@ -33,6 +33,12 @@ export const Default: StoryObj< typeof ValidatedRangeControl > = {
|
|
|
33
33
|
useState<
|
|
34
34
|
React.ComponentProps< typeof ValidatedRangeControl >[ 'value' ]
|
|
35
35
|
>();
|
|
36
|
+
const [ customValidity, setCustomValidity ] =
|
|
37
|
+
useState<
|
|
38
|
+
React.ComponentProps<
|
|
39
|
+
typeof ValidatedRangeControl
|
|
40
|
+
>[ 'customValidity' ]
|
|
41
|
+
>( undefined );
|
|
36
42
|
|
|
37
43
|
return (
|
|
38
44
|
<ValidatedRangeControl
|
|
@@ -42,6 +48,17 @@ export const Default: StoryObj< typeof ValidatedRangeControl > = {
|
|
|
42
48
|
setValue( newValue );
|
|
43
49
|
onChange?.( newValue );
|
|
44
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 }
|
|
45
62
|
/>
|
|
46
63
|
);
|
|
47
64
|
},
|
|
@@ -52,10 +69,4 @@ Default.args = {
|
|
|
52
69
|
help: 'Odd numbers are not allowed.',
|
|
53
70
|
min: 0,
|
|
54
71
|
max: 20,
|
|
55
|
-
customValidator: ( value ) => {
|
|
56
|
-
if ( value && value % 2 !== 0 ) {
|
|
57
|
-
return 'Choose an even number.';
|
|
58
|
-
}
|
|
59
|
-
return undefined;
|
|
60
|
-
},
|
|
61
72
|
};
|
|
@@ -30,6 +30,12 @@ export default meta;
|
|
|
30
30
|
export const Default: StoryObj< typeof ValidatedSelectControl > = {
|
|
31
31
|
render: function Template( { onChange, ...args } ) {
|
|
32
32
|
const [ value, setValue ] = useState( '' );
|
|
33
|
+
const [ customValidity, setCustomValidity ] =
|
|
34
|
+
useState<
|
|
35
|
+
React.ComponentProps<
|
|
36
|
+
typeof ValidatedSelectControl
|
|
37
|
+
>[ 'customValidity' ]
|
|
38
|
+
>( undefined );
|
|
33
39
|
|
|
34
40
|
return (
|
|
35
41
|
<ValidatedSelectControl
|
|
@@ -39,6 +45,17 @@ export const Default: StoryObj< typeof ValidatedSelectControl > = {
|
|
|
39
45
|
setValue( newValue );
|
|
40
46
|
onChange?.( newValue );
|
|
41
47
|
} }
|
|
48
|
+
onValidate={ ( v ) => {
|
|
49
|
+
if ( v === '1' ) {
|
|
50
|
+
setCustomValidity( {
|
|
51
|
+
type: 'invalid',
|
|
52
|
+
message: 'Option 1 is not allowed.',
|
|
53
|
+
} );
|
|
54
|
+
} else {
|
|
55
|
+
setCustomValidity( undefined );
|
|
56
|
+
}
|
|
57
|
+
} }
|
|
58
|
+
customValidity={ customValidity }
|
|
42
59
|
/>
|
|
43
60
|
);
|
|
44
61
|
},
|
|
@@ -52,10 +69,4 @@ Default.args = {
|
|
|
52
69
|
{ value: '1', label: 'Option 1 (not allowed)' },
|
|
53
70
|
{ value: '2', label: 'Option 2' },
|
|
54
71
|
],
|
|
55
|
-
customValidator: ( value ) => {
|
|
56
|
-
if ( value === '1' ) {
|
|
57
|
-
return 'Option 1 is not allowed.';
|
|
58
|
-
}
|
|
59
|
-
return undefined;
|
|
60
|
-
},
|
|
61
72
|
};
|
|
@@ -30,6 +30,12 @@ export default meta;
|
|
|
30
30
|
export const Default: StoryObj< typeof ValidatedTextControl > = {
|
|
31
31
|
render: function Template( { onChange, ...args } ) {
|
|
32
32
|
const [ value, setValue ] = useState( '' );
|
|
33
|
+
const [ customValidity, setCustomValidity ] =
|
|
34
|
+
useState<
|
|
35
|
+
React.ComponentProps<
|
|
36
|
+
typeof ValidatedTextControl
|
|
37
|
+
>[ 'customValidity' ]
|
|
38
|
+
>( undefined );
|
|
33
39
|
|
|
34
40
|
return (
|
|
35
41
|
<ValidatedTextControl
|
|
@@ -39,6 +45,17 @@ export const Default: StoryObj< typeof ValidatedTextControl > = {
|
|
|
39
45
|
setValue( newValue );
|
|
40
46
|
onChange?.( newValue );
|
|
41
47
|
} }
|
|
48
|
+
onValidate={ ( v ) => {
|
|
49
|
+
if ( v?.toString().toLowerCase() === 'error' ) {
|
|
50
|
+
setCustomValidity( {
|
|
51
|
+
type: 'invalid',
|
|
52
|
+
message: 'The word "error" is not allowed.',
|
|
53
|
+
} );
|
|
54
|
+
} else {
|
|
55
|
+
setCustomValidity( undefined );
|
|
56
|
+
}
|
|
57
|
+
} }
|
|
58
|
+
customValidity={ customValidity }
|
|
42
59
|
/>
|
|
43
60
|
);
|
|
44
61
|
},
|
|
@@ -47,10 +64,4 @@ Default.args = {
|
|
|
47
64
|
required: true,
|
|
48
65
|
label: 'Text',
|
|
49
66
|
help: "The word 'error' will trigger an error.",
|
|
50
|
-
customValidator: ( value ) => {
|
|
51
|
-
if ( value?.toString().toLowerCase() === 'error' ) {
|
|
52
|
-
return 'The word "error" is not allowed.';
|
|
53
|
-
}
|
|
54
|
-
return undefined;
|
|
55
|
-
},
|
|
56
67
|
};
|
|
@@ -27,6 +27,12 @@ export default meta;
|
|
|
27
27
|
export const Default: StoryObj< typeof ValidatedTextareaControl > = {
|
|
28
28
|
render: function Template( { onChange, ...args } ) {
|
|
29
29
|
const [ value, setValue ] = useState( '' );
|
|
30
|
+
const [ customValidity, setCustomValidity ] =
|
|
31
|
+
useState<
|
|
32
|
+
React.ComponentProps<
|
|
33
|
+
typeof ValidatedTextareaControl
|
|
34
|
+
>[ 'customValidity' ]
|
|
35
|
+
>( undefined );
|
|
30
36
|
|
|
31
37
|
return (
|
|
32
38
|
<ValidatedTextareaControl
|
|
@@ -36,6 +42,17 @@ export const Default: StoryObj< typeof ValidatedTextareaControl > = {
|
|
|
36
42
|
onChange?.( newValue );
|
|
37
43
|
} }
|
|
38
44
|
value={ value }
|
|
45
|
+
onValidate={ ( v ) => {
|
|
46
|
+
if ( v?.toLowerCase() === 'error' ) {
|
|
47
|
+
setCustomValidity( {
|
|
48
|
+
type: 'invalid',
|
|
49
|
+
message: 'The word "error" is not allowed.',
|
|
50
|
+
} );
|
|
51
|
+
} else {
|
|
52
|
+
setCustomValidity( undefined );
|
|
53
|
+
}
|
|
54
|
+
} }
|
|
55
|
+
customValidity={ customValidity }
|
|
39
56
|
/>
|
|
40
57
|
);
|
|
41
58
|
},
|
|
@@ -44,10 +61,4 @@ Default.args = {
|
|
|
44
61
|
required: true,
|
|
45
62
|
label: 'Textarea',
|
|
46
63
|
help: 'The word "error" will trigger an error.',
|
|
47
|
-
customValidator: ( value ) => {
|
|
48
|
-
if ( value?.toLowerCase() === 'error' ) {
|
|
49
|
-
return 'The word "error" is not allowed.';
|
|
50
|
-
}
|
|
51
|
-
return undefined;
|
|
52
|
-
},
|
|
53
64
|
};
|
|
@@ -30,6 +30,12 @@ export default meta;
|
|
|
30
30
|
export const Default: StoryObj< typeof ValidatedToggleControl > = {
|
|
31
31
|
render: function Template( { onChange, ...args } ) {
|
|
32
32
|
const [ checked, setChecked ] = useState( false );
|
|
33
|
+
const [ customValidity, setCustomValidity ] =
|
|
34
|
+
useState<
|
|
35
|
+
React.ComponentProps<
|
|
36
|
+
typeof ValidatedToggleControl
|
|
37
|
+
>[ 'customValidity' ]
|
|
38
|
+
>( undefined );
|
|
33
39
|
|
|
34
40
|
return (
|
|
35
41
|
<ValidatedToggleControl
|
|
@@ -39,6 +45,17 @@ export const Default: StoryObj< typeof ValidatedToggleControl > = {
|
|
|
39
45
|
setChecked( value );
|
|
40
46
|
onChange?.( value );
|
|
41
47
|
} }
|
|
48
|
+
onValidate={ ( v ) => {
|
|
49
|
+
if ( v ) {
|
|
50
|
+
setCustomValidity( {
|
|
51
|
+
type: 'invalid',
|
|
52
|
+
message: 'This toggle may not be enabled.',
|
|
53
|
+
} );
|
|
54
|
+
} else {
|
|
55
|
+
setCustomValidity( undefined );
|
|
56
|
+
}
|
|
57
|
+
} }
|
|
58
|
+
customValidity={ customValidity }
|
|
42
59
|
/>
|
|
43
60
|
);
|
|
44
61
|
},
|
|
@@ -47,10 +64,4 @@ Default.args = {
|
|
|
47
64
|
required: true,
|
|
48
65
|
label: 'Toggle',
|
|
49
66
|
help: 'This toggle may neither be enabled nor disabled.',
|
|
50
|
-
customValidator: ( value ) => {
|
|
51
|
-
if ( value ) {
|
|
52
|
-
return 'This toggle may not be enabled.';
|
|
53
|
-
}
|
|
54
|
-
return undefined;
|
|
55
|
-
},
|
|
56
67
|
};
|
|
@@ -36,6 +36,12 @@ export const Default: StoryObj< typeof ValidatedToggleGroupControl > = {
|
|
|
36
36
|
typeof ValidatedToggleGroupControl
|
|
37
37
|
>[ 'value' ]
|
|
38
38
|
>( '1' );
|
|
39
|
+
const [ customValidity, setCustomValidity ] =
|
|
40
|
+
useState<
|
|
41
|
+
React.ComponentProps<
|
|
42
|
+
typeof ValidatedToggleGroupControl
|
|
43
|
+
>[ 'customValidity' ]
|
|
44
|
+
>( undefined );
|
|
39
45
|
|
|
40
46
|
return (
|
|
41
47
|
<ValidatedToggleGroupControl
|
|
@@ -45,6 +51,17 @@ export const Default: StoryObj< typeof ValidatedToggleGroupControl > = {
|
|
|
45
51
|
setValue( newValue );
|
|
46
52
|
onChange?.( newValue );
|
|
47
53
|
} }
|
|
54
|
+
onValidate={ ( v ) => {
|
|
55
|
+
if ( v === '2' ) {
|
|
56
|
+
setCustomValidity( {
|
|
57
|
+
type: 'invalid',
|
|
58
|
+
message: 'Option 2 is not allowed.',
|
|
59
|
+
} );
|
|
60
|
+
} else {
|
|
61
|
+
setCustomValidity( undefined );
|
|
62
|
+
}
|
|
63
|
+
} }
|
|
64
|
+
customValidity={ customValidity }
|
|
48
65
|
/>
|
|
49
66
|
);
|
|
50
67
|
},
|
|
@@ -58,10 +75,4 @@ Default.args = {
|
|
|
58
75
|
<ToggleGroupControlOption value="2" key="2" label="Option 2" />,
|
|
59
76
|
],
|
|
60
77
|
help: 'Selecting option 2 will trigger an error.',
|
|
61
|
-
customValidator: ( value ) => {
|
|
62
|
-
if ( value === '2' ) {
|
|
63
|
-
return 'Option 2 is not allowed.';
|
|
64
|
-
}
|
|
65
|
-
return undefined;
|
|
66
|
-
},
|
|
67
78
|
};
|
|
@@ -17,7 +17,8 @@ type Value = TextControlProps[ 'value' ];
|
|
|
17
17
|
const UnforwardedValidatedTextControl = (
|
|
18
18
|
{
|
|
19
19
|
required,
|
|
20
|
-
|
|
20
|
+
onValidate,
|
|
21
|
+
customValidity,
|
|
21
22
|
onChange,
|
|
22
23
|
markWhenOptional,
|
|
23
24
|
...restProps
|
|
@@ -36,9 +37,10 @@ const UnforwardedValidatedTextControl = (
|
|
|
36
37
|
<ControlWithError
|
|
37
38
|
required={ required }
|
|
38
39
|
markWhenOptional={ markWhenOptional }
|
|
39
|
-
|
|
40
|
-
return
|
|
40
|
+
onValidate={ () => {
|
|
41
|
+
return onValidate?.( valueRef.current );
|
|
41
42
|
} }
|
|
43
|
+
customValidity={ customValidity }
|
|
42
44
|
getValidityTarget={ () => validityTargetRef.current }
|
|
43
45
|
>
|
|
44
46
|
<TextControl
|
|
@@ -17,7 +17,8 @@ type Value = TextareaControlProps[ 'value' ];
|
|
|
17
17
|
const UnforwardedValidatedTextareaControl = (
|
|
18
18
|
{
|
|
19
19
|
required,
|
|
20
|
-
|
|
20
|
+
onValidate,
|
|
21
|
+
customValidity,
|
|
21
22
|
onChange,
|
|
22
23
|
markWhenOptional,
|
|
23
24
|
...restProps
|
|
@@ -36,9 +37,10 @@ const UnforwardedValidatedTextareaControl = (
|
|
|
36
37
|
<ControlWithError
|
|
37
38
|
required={ required }
|
|
38
39
|
markWhenOptional={ markWhenOptional }
|
|
39
|
-
|
|
40
|
-
return
|
|
40
|
+
onValidate={ () => {
|
|
41
|
+
return onValidate?.( valueRef.current );
|
|
41
42
|
} }
|
|
43
|
+
customValidity={ customValidity }
|
|
42
44
|
getValidityTarget={ () => validityTargetRef.current }
|
|
43
45
|
>
|
|
44
46
|
<TextareaControl
|
|
@@ -19,7 +19,8 @@ type Value = ToggleControlProps[ 'checked' ];
|
|
|
19
19
|
const UnforwardedValidatedToggleControl = (
|
|
20
20
|
{
|
|
21
21
|
required,
|
|
22
|
-
|
|
22
|
+
onValidate,
|
|
23
|
+
customValidity,
|
|
23
24
|
onChange,
|
|
24
25
|
markWhenOptional,
|
|
25
26
|
...restProps
|
|
@@ -46,9 +47,10 @@ const UnforwardedValidatedToggleControl = (
|
|
|
46
47
|
<ControlWithError
|
|
47
48
|
required={ required }
|
|
48
49
|
markWhenOptional={ markWhenOptional }
|
|
49
|
-
|
|
50
|
-
return
|
|
50
|
+
onValidate={ () => {
|
|
51
|
+
return onValidate?.( valueRef.current );
|
|
51
52
|
} }
|
|
53
|
+
customValidity={ customValidity }
|
|
52
54
|
getValidityTarget={ () => validityTargetRef.current }
|
|
53
55
|
>
|
|
54
56
|
<ToggleControl
|
|
@@ -16,7 +16,8 @@ type Value = ToggleGroupControlProps[ 'value' ];
|
|
|
16
16
|
const UnforwardedValidatedToggleGroupControl = (
|
|
17
17
|
{
|
|
18
18
|
required,
|
|
19
|
-
|
|
19
|
+
onValidate,
|
|
20
|
+
customValidity,
|
|
20
21
|
onChange,
|
|
21
22
|
markWhenOptional,
|
|
22
23
|
...restProps
|
|
@@ -37,9 +38,10 @@ const UnforwardedValidatedToggleGroupControl = (
|
|
|
37
38
|
<ControlWithError
|
|
38
39
|
required={ required }
|
|
39
40
|
markWhenOptional={ markWhenOptional }
|
|
40
|
-
|
|
41
|
-
return
|
|
41
|
+
onValidate={ () => {
|
|
42
|
+
return onValidate?.( valueRef.current );
|
|
42
43
|
} }
|
|
44
|
+
customValidity={ customValidity }
|
|
43
45
|
getValidityTarget={ () => validityTargetRef.current }
|
|
44
46
|
>
|
|
45
47
|
<ToggleGroupControl
|
|
@@ -10,19 +10,28 @@ export type ValidatedControlProps< V > = {
|
|
|
10
10
|
*/
|
|
11
11
|
markWhenOptional?: boolean;
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* This means the custom validator will be run _in addition_ to any other HTML attribute-based validation, and
|
|
16
|
-
* will be prioritized over any existing validity messages dictated by the HTML attributes.
|
|
17
|
-
* An empty string or `undefined` return value will clear any existing custom validity message.
|
|
13
|
+
* Optional callback to run when the input should be validated. Use this to set
|
|
14
|
+
* a `customValidity` as necessary.
|
|
18
15
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
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
|
+
/**
|
|
21
|
+
* Show a custom message based on the validation status.
|
|
21
22
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
23
|
+
* - When `type` is `invalid`, the message will be applied to the underlying element using the
|
|
24
|
+
* native [`setCustomValidity()` method](https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/setCustomValidity).
|
|
25
|
+
* This means the custom message will be prioritized over any existing validity messages
|
|
26
|
+
* triggered by HTML attribute-based validation.
|
|
27
|
+
* - When `type` is `validating` or `valid`, the custom validity message of the underlying element
|
|
28
|
+
* will be cleared. If there are no remaining validity messages triggered by HTML attribute-based validation,
|
|
29
|
+
* the message will be presented as a status indicator rather than an error. These indicators are intended
|
|
30
|
+
* for asynchronous validation calls that may take more than 1 second to complete.
|
|
31
|
+
* Otherwise, custom errors can simply be cleared by setting the `customValidity` prop to `undefined`.
|
|
24
32
|
*/
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
33
|
+
customValidity?: {
|
|
34
|
+
type: 'validating' | 'valid' | 'invalid';
|
|
35
|
+
message: string;
|
|
36
|
+
};
|
|
28
37
|
};
|