@wordpress/components 30.3.2-next.836ecdcae.0 → 30.3.2-next.a730c9c8c.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/private-apis.js +9 -1
- package/build/private-apis.js.map +1 -1
- package/build/validated-form-controls/components/form-token-field.js +64 -0
- package/build/validated-form-controls/components/form-token-field.js.map +1 -0
- package/build/validated-form-controls/components/index.js +11 -0
- package/build/validated-form-controls/components/index.js.map +1 -1
- package/build/validated-form-controls/components/toggle-group-control.js +2 -5
- package/build/validated-form-controls/components/toggle-group-control.js.map +1 -1
- package/build-module/private-apis.js +10 -2
- package/build-module/private-apis.js.map +1 -1
- package/build-module/validated-form-controls/components/form-token-field.js +57 -0
- package/build-module/validated-form-controls/components/form-token-field.js.map +1 -0
- package/build-module/validated-form-controls/components/index.js +1 -0
- package/build-module/validated-form-controls/components/index.js.map +1 -1
- package/build-module/validated-form-controls/components/toggle-group-control.js +2 -5
- package/build-module/validated-form-controls/components/toggle-group-control.js.map +1 -1
- package/build-style/style-rtl.css +4 -0
- package/build-style/style.css +4 -0
- package/build-types/private-apis.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/form-token-field.d.ts +4 -0
- package/build-types/validated-form-controls/components/form-token-field.d.ts.map +1 -0
- package/build-types/validated-form-controls/components/index.d.ts +1 -0
- package/build-types/validated-form-controls/components/index.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/stories/form-token-field.story.d.ts +15 -0
- package/build-types/validated-form-controls/components/stories/form-token-field.story.d.ts.map +1 -0
- package/build-types/validated-form-controls/components/toggle-group-control.d.ts.map +1 -1
- package/package.json +19 -19
- package/src/private-apis.ts +14 -0
- package/src/validated-form-controls/components/form-token-field.tsx +84 -0
- package/src/validated-form-controls/components/index.ts +1 -0
- package/src/validated-form-controls/components/stories/form-token-field.story.tsx +83 -0
- package/src/validated-form-controls/components/toggle-group-control.tsx +1 -3
- package/src/validated-form-controls/style.scss +6 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { forwardRef, useRef } from '@wordpress/element';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Internal dependencies
|
|
8
|
+
*/
|
|
9
|
+
import { ControlWithError } from '../control-with-error';
|
|
10
|
+
import type { ValidatedControlProps } from './types';
|
|
11
|
+
import { FormTokenField } from '../../form-token-field';
|
|
12
|
+
import type { FormTokenFieldProps } from '../../form-token-field/types';
|
|
13
|
+
|
|
14
|
+
type Value = FormTokenFieldProps[ 'value' ];
|
|
15
|
+
|
|
16
|
+
const UnforwardedValidatedFormTokenField = (
|
|
17
|
+
{
|
|
18
|
+
required,
|
|
19
|
+
onValidate,
|
|
20
|
+
customValidity,
|
|
21
|
+
onChange,
|
|
22
|
+
markWhenOptional,
|
|
23
|
+
...restProps
|
|
24
|
+
}: Omit<
|
|
25
|
+
React.ComponentProps< typeof FormTokenField >,
|
|
26
|
+
'__next40pxDefaultSize' | '__nextHasNoMarginBottom'
|
|
27
|
+
> &
|
|
28
|
+
ValidatedControlProps< FormTokenFieldProps[ 'value' ] >,
|
|
29
|
+
forwardedRef: React.ForwardedRef< HTMLDivElement >
|
|
30
|
+
) => {
|
|
31
|
+
const validityTargetRef = useRef< HTMLInputElement >( null );
|
|
32
|
+
const valueRef = useRef< Value >( restProps.value );
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<div
|
|
36
|
+
className="components-validated-control__wrapper-with-error-delegate"
|
|
37
|
+
ref={ forwardedRef }
|
|
38
|
+
>
|
|
39
|
+
<ControlWithError
|
|
40
|
+
required={ required }
|
|
41
|
+
markWhenOptional={ markWhenOptional }
|
|
42
|
+
onValidate={ () => {
|
|
43
|
+
return onValidate?.( valueRef.current );
|
|
44
|
+
} }
|
|
45
|
+
customValidity={ customValidity }
|
|
46
|
+
getValidityTarget={ () => validityTargetRef.current }
|
|
47
|
+
>
|
|
48
|
+
<FormTokenField
|
|
49
|
+
__next40pxDefaultSize
|
|
50
|
+
__nextHasNoMarginBottom
|
|
51
|
+
{ ...restProps }
|
|
52
|
+
onChange={ ( value, ...args ) => {
|
|
53
|
+
valueRef.current = value;
|
|
54
|
+
onChange?.( value, ...args );
|
|
55
|
+
} }
|
|
56
|
+
/>
|
|
57
|
+
</ControlWithError>
|
|
58
|
+
<input
|
|
59
|
+
className="components-validated-control__error-delegate"
|
|
60
|
+
type="text"
|
|
61
|
+
ref={ validityTargetRef }
|
|
62
|
+
required={ required }
|
|
63
|
+
value={
|
|
64
|
+
valueRef.current && valueRef.current.length > 0
|
|
65
|
+
? 'hasvalue'
|
|
66
|
+
: ''
|
|
67
|
+
}
|
|
68
|
+
tabIndex={ -1 }
|
|
69
|
+
onChange={ () => {} }
|
|
70
|
+
onFocus={ ( e ) => {
|
|
71
|
+
e.target.previousElementSibling
|
|
72
|
+
?.querySelector< HTMLInputElement >(
|
|
73
|
+
'input[type="text"]'
|
|
74
|
+
)
|
|
75
|
+
?.focus();
|
|
76
|
+
} }
|
|
77
|
+
/>
|
|
78
|
+
</div>
|
|
79
|
+
);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export const ValidatedFormTokenField = forwardRef(
|
|
83
|
+
UnforwardedValidatedFormTokenField
|
|
84
|
+
);
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { useState } from '@wordpress/element';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* External dependencies
|
|
8
|
+
*/
|
|
9
|
+
import type { StoryObj, Meta } from '@storybook/react';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Internal dependencies
|
|
13
|
+
*/
|
|
14
|
+
import { ValidatedFormTokenField } from '../form-token-field';
|
|
15
|
+
import { formDecorator } from './story-utils';
|
|
16
|
+
import type { TokenItem } from '../../../form-token-field/types';
|
|
17
|
+
|
|
18
|
+
const meta: Meta< typeof ValidatedFormTokenField > = {
|
|
19
|
+
title: 'Components/Selection & Input/Validated Form Controls/ValidatedFormTokenField',
|
|
20
|
+
id: 'components-validatedformtokenfield',
|
|
21
|
+
component: ValidatedFormTokenField,
|
|
22
|
+
tags: [ 'status-private' ],
|
|
23
|
+
decorators: formDecorator,
|
|
24
|
+
args: { onChange: () => {} },
|
|
25
|
+
argTypes: {
|
|
26
|
+
onChange: { control: false },
|
|
27
|
+
value: { control: false },
|
|
28
|
+
customValidity: { control: false },
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
export default meta;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* This demonstrates how array validation would work with the ValidatedFormTokenField component.
|
|
35
|
+
*/
|
|
36
|
+
export const Default: StoryObj< typeof ValidatedFormTokenField > = {
|
|
37
|
+
render: function Template( { onChange, ...args } ) {
|
|
38
|
+
const [ value, setValue ] = useState< ( string | TokenItem )[] >( [] );
|
|
39
|
+
const [ customValidity, setCustomValidity ] =
|
|
40
|
+
useState<
|
|
41
|
+
React.ComponentProps<
|
|
42
|
+
typeof ValidatedFormTokenField
|
|
43
|
+
>[ 'customValidity' ]
|
|
44
|
+
>( undefined );
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<ValidatedFormTokenField
|
|
48
|
+
{ ...args }
|
|
49
|
+
value={ value }
|
|
50
|
+
onChange={ ( newValue, ...rest ) => {
|
|
51
|
+
setValue( newValue );
|
|
52
|
+
onChange?.( newValue, ...rest );
|
|
53
|
+
} }
|
|
54
|
+
onValidate={ ( v ) => {
|
|
55
|
+
if (
|
|
56
|
+
v?.some( ( token ) => {
|
|
57
|
+
const tokenValue =
|
|
58
|
+
typeof token === 'string' ? token : token.value;
|
|
59
|
+
return tokenValue.toLowerCase() === 'error';
|
|
60
|
+
} )
|
|
61
|
+
) {
|
|
62
|
+
setCustomValidity( {
|
|
63
|
+
type: 'invalid',
|
|
64
|
+
message: 'The tag "error" is not allowed.',
|
|
65
|
+
} );
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
setCustomValidity( undefined );
|
|
70
|
+
} }
|
|
71
|
+
customValidity={ customValidity }
|
|
72
|
+
/>
|
|
73
|
+
);
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
Default.args = {
|
|
78
|
+
required: true,
|
|
79
|
+
label: 'Tags',
|
|
80
|
+
placeholder: 'Add tags...',
|
|
81
|
+
suggestions: [ 'Posts', 'Pages', 'Media', 'Error' ],
|
|
82
|
+
__experimentalExpandOnFocus: true,
|
|
83
|
+
};
|
|
@@ -48,8 +48,6 @@ const UnforwardedValidatedToggleGroupControl = (
|
|
|
48
48
|
__nextHasNoMarginBottom
|
|
49
49
|
__next40pxDefaultSize
|
|
50
50
|
ref={ forwardedRef }
|
|
51
|
-
// TODO: Upstream limitation - In uncontrolled mode, starting from an undefined value then
|
|
52
|
-
// setting a value has a visual bug.
|
|
53
51
|
onChange={ ( value ) => {
|
|
54
52
|
valueRef.current = value;
|
|
55
53
|
onChange?.( value );
|
|
@@ -62,7 +60,7 @@ const UnforwardedValidatedToggleGroupControl = (
|
|
|
62
60
|
type="radio"
|
|
63
61
|
ref={ validityTargetRef }
|
|
64
62
|
required={ required }
|
|
65
|
-
checked={ restProps.value !==
|
|
63
|
+
checked={ restProps.value !== undefined }
|
|
66
64
|
tabIndex={ -1 }
|
|
67
65
|
// A name attribute is needed for the `required` behavior to work.
|
|
68
66
|
name={ nameAttr }
|
|
@@ -34,6 +34,12 @@
|
|
|
34
34
|
&:has(input[type="radio"]:invalid) {
|
|
35
35
|
--wp-components-color-accent: #{$alert-red};
|
|
36
36
|
}
|
|
37
|
+
|
|
38
|
+
// For FormTokenField
|
|
39
|
+
&:has(input:user-invalid) .components-form-token-field__input-container:not(:has([aria-expanded="true"])) {
|
|
40
|
+
--wp-components-color-accent: #{$alert-red};
|
|
41
|
+
border-color: $alert-red;
|
|
42
|
+
}
|
|
37
43
|
}
|
|
38
44
|
|
|
39
45
|
.components-validated-control__error-delegate {
|