@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.
Files changed (133) hide show
  1. package/CHANGELOG.md +10 -1
  2. package/build/menu-item/index.js +1 -0
  3. package/build/menu-item/index.js.map +1 -1
  4. package/build/validated-form-controls/components/checkbox-control.js +5 -3
  5. package/build/validated-form-controls/components/checkbox-control.js.map +1 -1
  6. package/build/validated-form-controls/components/combobox-control.js +5 -3
  7. package/build/validated-form-controls/components/combobox-control.js.map +1 -1
  8. package/build/validated-form-controls/components/custom-select-control.js +5 -3
  9. package/build/validated-form-controls/components/custom-select-control.js.map +1 -1
  10. package/build/validated-form-controls/components/input-control.js +5 -3
  11. package/build/validated-form-controls/components/input-control.js.map +1 -1
  12. package/build/validated-form-controls/components/number-control.js +5 -3
  13. package/build/validated-form-controls/components/number-control.js.map +1 -1
  14. package/build/validated-form-controls/components/radio-control.js +5 -3
  15. package/build/validated-form-controls/components/radio-control.js.map +1 -1
  16. package/build/validated-form-controls/components/range-control.js +5 -3
  17. package/build/validated-form-controls/components/range-control.js.map +1 -1
  18. package/build/validated-form-controls/components/select-control.js +5 -3
  19. package/build/validated-form-controls/components/select-control.js.map +1 -1
  20. package/build/validated-form-controls/components/text-control.js +5 -3
  21. package/build/validated-form-controls/components/text-control.js.map +1 -1
  22. package/build/validated-form-controls/components/textarea-control.js +5 -3
  23. package/build/validated-form-controls/components/textarea-control.js.map +1 -1
  24. package/build/validated-form-controls/components/toggle-control.js +5 -3
  25. package/build/validated-form-controls/components/toggle-control.js.map +1 -1
  26. package/build/validated-form-controls/components/toggle-group-control.js +5 -3
  27. package/build/validated-form-controls/components/toggle-group-control.js.map +1 -1
  28. package/build/validated-form-controls/components/types.js.map +1 -1
  29. package/build/validated-form-controls/control-with-error.js +57 -22
  30. package/build/validated-form-controls/control-with-error.js.map +1 -1
  31. package/build/validated-form-controls/validity-indicator.js +45 -0
  32. package/build/validated-form-controls/validity-indicator.js.map +1 -0
  33. package/build-module/menu-item/index.js +1 -0
  34. package/build-module/menu-item/index.js.map +1 -1
  35. package/build-module/validated-form-controls/components/checkbox-control.js +5 -3
  36. package/build-module/validated-form-controls/components/checkbox-control.js.map +1 -1
  37. package/build-module/validated-form-controls/components/combobox-control.js +5 -3
  38. package/build-module/validated-form-controls/components/combobox-control.js.map +1 -1
  39. package/build-module/validated-form-controls/components/custom-select-control.js +5 -3
  40. package/build-module/validated-form-controls/components/custom-select-control.js.map +1 -1
  41. package/build-module/validated-form-controls/components/input-control.js +5 -3
  42. package/build-module/validated-form-controls/components/input-control.js.map +1 -1
  43. package/build-module/validated-form-controls/components/number-control.js +5 -3
  44. package/build-module/validated-form-controls/components/number-control.js.map +1 -1
  45. package/build-module/validated-form-controls/components/radio-control.js +5 -3
  46. package/build-module/validated-form-controls/components/radio-control.js.map +1 -1
  47. package/build-module/validated-form-controls/components/range-control.js +5 -3
  48. package/build-module/validated-form-controls/components/range-control.js.map +1 -1
  49. package/build-module/validated-form-controls/components/select-control.js +5 -3
  50. package/build-module/validated-form-controls/components/select-control.js.map +1 -1
  51. package/build-module/validated-form-controls/components/text-control.js +5 -3
  52. package/build-module/validated-form-controls/components/text-control.js.map +1 -1
  53. package/build-module/validated-form-controls/components/textarea-control.js +5 -3
  54. package/build-module/validated-form-controls/components/textarea-control.js.map +1 -1
  55. package/build-module/validated-form-controls/components/toggle-control.js +5 -3
  56. package/build-module/validated-form-controls/components/toggle-control.js.map +1 -1
  57. package/build-module/validated-form-controls/components/toggle-group-control.js +5 -3
  58. package/build-module/validated-form-controls/components/toggle-group-control.js.map +1 -1
  59. package/build-module/validated-form-controls/components/types.js.map +1 -1
  60. package/build-module/validated-form-controls/control-with-error.js +57 -21
  61. package/build-module/validated-form-controls/control-with-error.js.map +1 -1
  62. package/build-module/validated-form-controls/validity-indicator.js +37 -0
  63. package/build-module/validated-form-controls/validity-indicator.js.map +1 -0
  64. package/build-style/style-rtl.css +34 -22
  65. package/build-style/style.css +34 -22
  66. package/build-types/menu-item/index.d.ts.map +1 -1
  67. package/build-types/validated-form-controls/components/checkbox-control.d.ts.map +1 -1
  68. package/build-types/validated-form-controls/components/combobox-control.d.ts.map +1 -1
  69. package/build-types/validated-form-controls/components/custom-select-control.d.ts.map +1 -1
  70. package/build-types/validated-form-controls/components/input-control.d.ts.map +1 -1
  71. package/build-types/validated-form-controls/components/number-control.d.ts.map +1 -1
  72. package/build-types/validated-form-controls/components/radio-control.d.ts.map +1 -1
  73. package/build-types/validated-form-controls/components/range-control.d.ts.map +1 -1
  74. package/build-types/validated-form-controls/components/select-control.d.ts.map +1 -1
  75. package/build-types/validated-form-controls/components/stories/checkbox-control.story.d.ts.map +1 -1
  76. package/build-types/validated-form-controls/components/stories/combobox-control.story.d.ts.map +1 -1
  77. package/build-types/validated-form-controls/components/stories/custom-select-control.story.d.ts.map +1 -1
  78. package/build-types/validated-form-controls/components/stories/input-control.story.d.ts.map +1 -1
  79. package/build-types/validated-form-controls/components/stories/number-control.story.d.ts.map +1 -1
  80. package/build-types/validated-form-controls/components/stories/overview.story.d.ts +13 -0
  81. package/build-types/validated-form-controls/components/stories/overview.story.d.ts.map +1 -1
  82. package/build-types/validated-form-controls/components/stories/radio-control.story.d.ts.map +1 -1
  83. package/build-types/validated-form-controls/components/stories/range-control.story.d.ts.map +1 -1
  84. package/build-types/validated-form-controls/components/stories/select-control.story.d.ts.map +1 -1
  85. package/build-types/validated-form-controls/components/stories/text-control.story.d.ts.map +1 -1
  86. package/build-types/validated-form-controls/components/stories/textarea-control.story.d.ts.map +1 -1
  87. package/build-types/validated-form-controls/components/stories/toggle-control.story.d.ts.map +1 -1
  88. package/build-types/validated-form-controls/components/stories/toggle-group-control.story.d.ts.map +1 -1
  89. package/build-types/validated-form-controls/components/text-control.d.ts.map +1 -1
  90. package/build-types/validated-form-controls/components/textarea-control.d.ts.map +1 -1
  91. package/build-types/validated-form-controls/components/toggle-control.d.ts.map +1 -1
  92. package/build-types/validated-form-controls/components/toggle-group-control.d.ts.map +1 -1
  93. package/build-types/validated-form-controls/components/types.d.ts +21 -10
  94. package/build-types/validated-form-controls/components/types.d.ts.map +1 -1
  95. package/build-types/validated-form-controls/control-with-error.d.ts +4 -5
  96. package/build-types/validated-form-controls/control-with-error.d.ts.map +1 -1
  97. package/build-types/validated-form-controls/validity-indicator.d.ts +5 -0
  98. package/build-types/validated-form-controls/validity-indicator.d.ts.map +1 -0
  99. package/package.json +19 -19
  100. package/src/calendar/style.scss +22 -22
  101. package/src/menu-item/index.tsx +1 -0
  102. package/src/utils/theme-variables.scss +1 -0
  103. package/src/validated-form-controls/components/checkbox-control.tsx +5 -3
  104. package/src/validated-form-controls/components/combobox-control.tsx +5 -3
  105. package/src/validated-form-controls/components/custom-select-control.tsx +5 -3
  106. package/src/validated-form-controls/components/input-control.tsx +5 -3
  107. package/src/validated-form-controls/components/number-control.tsx +5 -3
  108. package/src/validated-form-controls/components/radio-control.tsx +5 -3
  109. package/src/validated-form-controls/components/range-control.tsx +5 -3
  110. package/src/validated-form-controls/components/select-control.tsx +5 -3
  111. package/src/validated-form-controls/components/stories/checkbox-control.story.tsx +17 -6
  112. package/src/validated-form-controls/components/stories/combobox-control.story.tsx +17 -6
  113. package/src/validated-form-controls/components/stories/custom-select-control.story.tsx +17 -6
  114. package/src/validated-form-controls/components/stories/input-control.story.tsx +51 -18
  115. package/src/validated-form-controls/components/stories/number-control.story.tsx +17 -6
  116. package/src/validated-form-controls/components/stories/overview.mdx +1 -1
  117. package/src/validated-form-controls/components/stories/overview.story.tsx +122 -14
  118. package/src/validated-form-controls/components/stories/radio-control.story.tsx +17 -6
  119. package/src/validated-form-controls/components/stories/range-control.story.tsx +17 -6
  120. package/src/validated-form-controls/components/stories/select-control.story.tsx +17 -6
  121. package/src/validated-form-controls/components/stories/text-control.story.tsx +17 -6
  122. package/src/validated-form-controls/components/stories/textarea-control.story.tsx +17 -6
  123. package/src/validated-form-controls/components/stories/toggle-control.story.tsx +17 -6
  124. package/src/validated-form-controls/components/stories/toggle-group-control.story.tsx +17 -6
  125. package/src/validated-form-controls/components/text-control.tsx +5 -3
  126. package/src/validated-form-controls/components/textarea-control.tsx +5 -3
  127. package/src/validated-form-controls/components/toggle-control.tsx +5 -3
  128. package/src/validated-form-controls/components/toggle-group-control.tsx +5 -3
  129. package/src/validated-form-controls/components/types.ts +21 -12
  130. package/src/validated-form-controls/control-with-error.tsx +77 -26
  131. package/src/validated-form-controls/style.scss +19 -5
  132. package/src/validated-form-controls/validity-indicator.tsx +48 -0
  133. package/tsconfig.tsbuildinfo +1 -1
@@ -2,7 +2,6 @@
2
2
  * WordPress dependencies
3
3
  */
4
4
  import { __ } from '@wordpress/i18n';
5
- import { error } from '@wordpress/icons';
6
5
 
7
6
  /**
8
7
  * External dependencies
@@ -18,8 +17,8 @@ import {
18
17
  * Internal dependencies
19
18
  */
20
19
  import { withIgnoreIMEEvents } from '../utils/with-ignore-ime-events';
21
-
22
- import Icon from '../icon';
20
+ import type { ValidatedControlProps } from './components/types';
21
+ import { ValidityIndicator } from './validity-indicator';
23
22
 
24
23
  function appendRequiredIndicator(
25
24
  label: React.ReactNode,
@@ -61,7 +60,8 @@ function UnforwardedControlWithError< C extends React.ReactElement >(
61
60
  {
62
61
  required,
63
62
  markWhenOptional,
64
- customValidator,
63
+ onValidate,
64
+ customValidity,
65
65
  getValidityTarget,
66
66
  children,
67
67
  }: {
@@ -74,12 +74,10 @@ function UnforwardedControlWithError< C extends React.ReactElement >(
74
74
  */
75
75
  markWhenOptional?: boolean;
76
76
  /**
77
- * A function that returns a custom validity message when applicable.
78
- *
79
- * This message will be applied to the element returned by `getValidityTarget`.
80
- * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/setCustomValidity
77
+ * The callback to run when the input should be validated.
81
78
  */
82
- customValidator?: () => string | void;
79
+ onValidate?: () => void;
80
+ customValidity?: ValidatedControlProps< unknown >[ 'customValidity' ];
83
81
  /**
84
82
  * A function that returns the actual element on which the validity data should be applied.
85
83
  */
@@ -92,6 +90,13 @@ function UnforwardedControlWithError< C extends React.ReactElement >(
92
90
  forwardedRef: React.ForwardedRef< HTMLDivElement >
93
91
  ) {
94
92
  const [ errorMessage, setErrorMessage ] = useState< string | undefined >();
93
+ const [ statusMessage, setStatusMessage ] = useState<
94
+ | {
95
+ type: 'validating' | 'valid';
96
+ message?: string;
97
+ }
98
+ | undefined
99
+ >();
95
100
  const [ isTouched, setIsTouched ] = useState( false );
96
101
 
97
102
  // Ensure that error messages are visible after user attemps to submit a form
@@ -111,13 +116,58 @@ function UnforwardedControlWithError< C extends React.ReactElement >(
111
116
  };
112
117
  } );
113
118
 
114
- const validate = () => {
115
- const message = customValidator?.();
119
+ useEffect( () => {
120
+ if ( ! isTouched ) {
121
+ return;
122
+ }
123
+
116
124
  const validityTarget = getValidityTarget();
117
125
 
118
- validityTarget?.setCustomValidity( message ?? '' );
119
- setErrorMessage( validityTarget?.validationMessage );
120
- };
126
+ if ( ! customValidity?.type ) {
127
+ validityTarget?.setCustomValidity( '' );
128
+ setErrorMessage( validityTarget?.validationMessage );
129
+ setStatusMessage( undefined );
130
+ return;
131
+ }
132
+
133
+ switch ( customValidity.type ) {
134
+ case 'validating': {
135
+ // Wait before showing a validating state.
136
+ const timer = setTimeout( () => {
137
+ setStatusMessage( {
138
+ type: 'validating',
139
+ message: customValidity.message,
140
+ } );
141
+ }, 1000 );
142
+
143
+ return () => clearTimeout( timer );
144
+ }
145
+ case 'valid': {
146
+ validityTarget?.setCustomValidity( '' );
147
+ setErrorMessage( validityTarget?.validationMessage );
148
+
149
+ setStatusMessage( {
150
+ type: 'valid',
151
+ message: customValidity.message,
152
+ } );
153
+ return;
154
+ }
155
+ case 'invalid': {
156
+ validityTarget?.setCustomValidity(
157
+ customValidity.message ?? ''
158
+ );
159
+ setErrorMessage( validityTarget?.validationMessage );
160
+
161
+ setStatusMessage( undefined );
162
+ return undefined;
163
+ }
164
+ }
165
+ }, [
166
+ isTouched,
167
+ customValidity?.type,
168
+ customValidity?.message,
169
+ getValidityTarget,
170
+ ] );
121
171
 
122
172
  const onBlur = ( event: React.FocusEvent< HTMLDivElement > ) => {
123
173
  // Only consider "blurred from the component" if focus has fully left the wrapping div.
@@ -138,7 +188,7 @@ function UnforwardedControlWithError< C extends React.ReactElement >(
138
188
  return;
139
189
  }
140
190
 
141
- validate();
191
+ onValidate?.();
142
192
  }
143
193
  };
144
194
 
@@ -148,7 +198,7 @@ function UnforwardedControlWithError< C extends React.ReactElement >(
148
198
  // Only validate incrementally if the field has blurred at least once,
149
199
  // or currently has an error message.
150
200
  if ( isTouched || errorMessage ) {
151
- validate();
201
+ onValidate?.();
152
202
  }
153
203
  };
154
204
 
@@ -156,7 +206,7 @@ function UnforwardedControlWithError< C extends React.ReactElement >(
156
206
  // Ensures that custom validators are triggered when the user submits by pressing Enter,
157
207
  // without ever blurring the control.
158
208
  if ( event.key === 'Enter' ) {
159
- validate();
209
+ onValidate?.();
160
210
  }
161
211
  };
162
212
 
@@ -180,15 +230,16 @@ function UnforwardedControlWithError< C extends React.ReactElement >(
180
230
  } ) }
181
231
  <div aria-live="polite">
182
232
  { errorMessage && (
183
- <p className="components-validated-control__error">
184
- <Icon
185
- className="components-validated-control__error-icon"
186
- icon={ error }
187
- size={ 16 }
188
- fill="currentColor"
189
- />
190
- { errorMessage }
191
- </p>
233
+ <ValidityIndicator
234
+ type="invalid"
235
+ message={ errorMessage }
236
+ />
237
+ ) }
238
+ { ! errorMessage && statusMessage && (
239
+ <ValidityIndicator
240
+ type={ statusMessage.type }
241
+ message={ statusMessage.message }
242
+ />
192
243
  ) }
193
244
  </div>
194
245
  </div>
@@ -45,7 +45,7 @@
45
45
  pointer-events: none;
46
46
  }
47
47
 
48
- .components-validated-control__error {
48
+ .components-validated-control__indicator {
49
49
  display: flex;
50
50
  align-items: flex-start;
51
51
  gap: 4px;
@@ -53,17 +53,31 @@
53
53
  font-family: $font-family-body;
54
54
  font-size: 0.75rem;
55
55
  line-height: 16px; // matches the icon size
56
- color: $alert-red;
56
+ color: $components-color-gray-700;
57
57
  animation:
58
- components-validated-control__error-jump 0.2s
58
+ components-validated-control__indicator-jump 0.2s
59
59
  cubic-bezier(0.68, -0.55, 0.27, 1.55);
60
+
61
+ &.is-invalid {
62
+ color: $alert-red;
63
+ }
64
+
65
+ &.is-valid {
66
+ color: color-mix(in srgb, $black 30%, $alert-green);
67
+ }
60
68
  }
61
69
 
62
- .components-validated-control__error-icon {
70
+ .components-validated-control__indicator-icon {
63
71
  flex-shrink: 0;
64
72
  }
65
73
 
66
- @keyframes components-validated-control__error-jump {
74
+ .components-validated-control__indicator-spinner {
75
+ margin: 2px;
76
+ width: $grid-unit-15;
77
+ height: $grid-unit-15;
78
+ }
79
+
80
+ @keyframes components-validated-control__indicator-jump {
67
81
  0% {
68
82
  transform: translateY(-4px);
69
83
  opacity: 0;
@@ -0,0 +1,48 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import clsx from 'clsx';
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import { error, published } from '@wordpress/icons';
10
+
11
+ /**
12
+ * Internal dependencies
13
+ */
14
+ import Icon from '../icon';
15
+ import Spinner from '../spinner';
16
+
17
+ export function ValidityIndicator( {
18
+ type,
19
+ message,
20
+ }: {
21
+ type: 'validating' | 'valid' | 'invalid';
22
+ message?: string;
23
+ } ) {
24
+ const ICON = {
25
+ valid: published,
26
+ invalid: error,
27
+ };
28
+ return (
29
+ <p
30
+ className={ clsx(
31
+ 'components-validated-control__indicator',
32
+ `is-${ type }`
33
+ ) }
34
+ >
35
+ { type === 'validating' ? (
36
+ <Spinner className="components-validated-control__indicator-spinner" />
37
+ ) : (
38
+ <Icon
39
+ className="components-validated-control__indicator-icon"
40
+ icon={ ICON[ type ] }
41
+ size={ 16 }
42
+ fill="currentColor"
43
+ />
44
+ ) }
45
+ { message }
46
+ </p>
47
+ );
48
+ }