@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.
Files changed (35) hide show
  1. package/CHANGELOG.md +10 -1
  2. package/build/private-apis.js +9 -1
  3. package/build/private-apis.js.map +1 -1
  4. package/build/validated-form-controls/components/form-token-field.js +64 -0
  5. package/build/validated-form-controls/components/form-token-field.js.map +1 -0
  6. package/build/validated-form-controls/components/index.js +11 -0
  7. package/build/validated-form-controls/components/index.js.map +1 -1
  8. package/build/validated-form-controls/components/toggle-group-control.js +2 -5
  9. package/build/validated-form-controls/components/toggle-group-control.js.map +1 -1
  10. package/build-module/private-apis.js +10 -2
  11. package/build-module/private-apis.js.map +1 -1
  12. package/build-module/validated-form-controls/components/form-token-field.js +57 -0
  13. package/build-module/validated-form-controls/components/form-token-field.js.map +1 -0
  14. package/build-module/validated-form-controls/components/index.js +1 -0
  15. package/build-module/validated-form-controls/components/index.js.map +1 -1
  16. package/build-module/validated-form-controls/components/toggle-group-control.js +2 -5
  17. package/build-module/validated-form-controls/components/toggle-group-control.js.map +1 -1
  18. package/build-style/style-rtl.css +4 -0
  19. package/build-style/style.css +4 -0
  20. package/build-types/private-apis.d.ts.map +1 -1
  21. package/build-types/validated-form-controls/components/form-token-field.d.ts +4 -0
  22. package/build-types/validated-form-controls/components/form-token-field.d.ts.map +1 -0
  23. package/build-types/validated-form-controls/components/index.d.ts +1 -0
  24. package/build-types/validated-form-controls/components/index.d.ts.map +1 -1
  25. package/build-types/validated-form-controls/components/stories/form-token-field.story.d.ts +15 -0
  26. package/build-types/validated-form-controls/components/stories/form-token-field.story.d.ts.map +1 -0
  27. package/build-types/validated-form-controls/components/toggle-group-control.d.ts.map +1 -1
  28. package/package.json +19 -19
  29. package/src/private-apis.ts +14 -0
  30. package/src/validated-form-controls/components/form-token-field.tsx +84 -0
  31. package/src/validated-form-controls/components/index.ts +1 -0
  32. package/src/validated-form-controls/components/stories/form-token-field.story.tsx +83 -0
  33. package/src/validated-form-controls/components/toggle-group-control.tsx +1 -3
  34. package/src/validated-form-controls/style.scss +6 -0
  35. 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
+ );
@@ -1,6 +1,7 @@
1
1
  export * from './checkbox-control';
2
2
  export * from './combobox-control';
3
3
  export * from './custom-select-control';
4
+ export * from './form-token-field';
4
5
  export * from './input-control';
5
6
  export * from './number-control';
6
7
  export * from './radio-control';
@@ -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 !== null }
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 {