@wordpress/components 25.10.0 → 25.11.1-next.f8d8eceb.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 (74) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/build/autocomplete/index.js +104 -52
  3. package/build/autocomplete/index.js.map +1 -1
  4. package/build/dropdown-menu-v2-ariakit/index.js +217 -0
  5. package/build/dropdown-menu-v2-ariakit/index.js.map +1 -0
  6. package/build/dropdown-menu-v2-ariakit/styles.js +157 -0
  7. package/build/dropdown-menu-v2-ariakit/styles.js.map +1 -0
  8. package/build/dropdown-menu-v2-ariakit/types.js +6 -0
  9. package/build/dropdown-menu-v2-ariakit/types.js.map +1 -0
  10. package/build/input-control/styles/input-control-styles.js +23 -23
  11. package/build/input-control/styles/input-control-styles.js.map +1 -1
  12. package/build/mobile/global-styles-context/utils.native.js +1 -1
  13. package/build/mobile/global-styles-context/utils.native.js.map +1 -1
  14. package/build/private-apis.js +9 -1
  15. package/build/private-apis.js.map +1 -1
  16. package/build/select-control/styles/select-control-styles.js +8 -8
  17. package/build/select-control/styles/select-control-styles.js.map +1 -1
  18. package/build/tabs/index.js +2 -2
  19. package/build/tabs/index.js.map +1 -1
  20. package/build/tooltip/index.js +2 -2
  21. package/build/tooltip/index.js.map +1 -1
  22. package/build-module/autocomplete/index.js +104 -52
  23. package/build-module/autocomplete/index.js.map +1 -1
  24. package/build-module/dropdown-menu-v2-ariakit/index.js +199 -0
  25. package/build-module/dropdown-menu-v2-ariakit/index.js.map +1 -0
  26. package/build-module/dropdown-menu-v2-ariakit/styles.js +136 -0
  27. package/build-module/dropdown-menu-v2-ariakit/styles.js.map +1 -0
  28. package/build-module/dropdown-menu-v2-ariakit/types.js +2 -0
  29. package/build-module/dropdown-menu-v2-ariakit/types.js.map +1 -0
  30. package/build-module/input-control/styles/input-control-styles.js +23 -23
  31. package/build-module/input-control/styles/input-control-styles.js.map +1 -1
  32. package/build-module/mobile/global-styles-context/utils.native.js +2 -2
  33. package/build-module/mobile/global-styles-context/utils.native.js.map +1 -1
  34. package/build-module/private-apis.js +9 -1
  35. package/build-module/private-apis.js.map +1 -1
  36. package/build-module/select-control/styles/select-control-styles.js +8 -8
  37. package/build-module/select-control/styles/select-control-styles.js.map +1 -1
  38. package/build-module/tabs/index.js +3 -3
  39. package/build-module/tabs/index.js.map +1 -1
  40. package/build-module/tooltip/index.js +2 -2
  41. package/build-module/tooltip/index.js.map +1 -1
  42. package/build-style/style-rtl.css +1 -1
  43. package/build-style/style.css +1 -1
  44. package/build-types/autocomplete/index.d.ts.map +1 -1
  45. package/build-types/dropdown-menu-v2-ariakit/index.d.ts +11 -0
  46. package/build-types/dropdown-menu-v2-ariakit/index.d.ts.map +1 -0
  47. package/build-types/dropdown-menu-v2-ariakit/stories/index.story.d.ts +16 -0
  48. package/build-types/dropdown-menu-v2-ariakit/stories/index.story.d.ts.map +1 -0
  49. package/build-types/dropdown-menu-v2-ariakit/styles.d.ts +88 -0
  50. package/build-types/dropdown-menu-v2-ariakit/styles.d.ts.map +1 -0
  51. package/build-types/dropdown-menu-v2-ariakit/test/index.d.ts +2 -0
  52. package/build-types/dropdown-menu-v2-ariakit/test/index.d.ts.map +1 -0
  53. package/build-types/dropdown-menu-v2-ariakit/types.d.ts +174 -0
  54. package/build-types/dropdown-menu-v2-ariakit/types.d.ts.map +1 -0
  55. package/build-types/private-apis.d.ts.map +1 -1
  56. package/build-types/tooltip/index.d.ts.map +1 -1
  57. package/package.json +21 -20
  58. package/src/autocomplete/index.tsx +136 -77
  59. package/src/dimension-control/test/__snapshots__/index.test.js.snap +8 -8
  60. package/src/dropdown-menu-v2-ariakit/README.md +324 -0
  61. package/src/dropdown-menu-v2-ariakit/index.tsx +318 -0
  62. package/src/dropdown-menu-v2-ariakit/stories/index.story.tsx +506 -0
  63. package/src/dropdown-menu-v2-ariakit/styles.ts +297 -0
  64. package/src/dropdown-menu-v2-ariakit/test/index.tsx +1139 -0
  65. package/src/dropdown-menu-v2-ariakit/types.ts +186 -0
  66. package/src/input-control/styles/input-control-styles.tsx +2 -2
  67. package/src/mobile/global-styles-context/utils.native.js +2 -2
  68. package/src/private-apis.ts +16 -0
  69. package/src/select-control/styles/select-control-styles.ts +2 -2
  70. package/src/tabs/index.tsx +3 -3
  71. package/src/tabs/test/index.tsx +12 -3
  72. package/src/toggle-group-control/test/__snapshots__/index.tsx.snap +8 -0
  73. package/src/tooltip/index.tsx +2 -3
  74. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,318 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ // eslint-disable-next-line no-restricted-imports
5
+ import * as Ariakit from '@ariakit/react';
6
+
7
+ /**
8
+ * WordPress dependencies
9
+ */
10
+ import {
11
+ forwardRef,
12
+ createContext,
13
+ useContext,
14
+ useMemo,
15
+ cloneElement,
16
+ isValidElement,
17
+ } from '@wordpress/element';
18
+ import { isRTL } from '@wordpress/i18n';
19
+ import { check, chevronRightSmall } from '@wordpress/icons';
20
+ import { SVG, Circle } from '@wordpress/primitives';
21
+
22
+ /**
23
+ * Internal dependencies
24
+ */
25
+ import { useContextSystem, contextConnect } from '../context';
26
+ import type { WordPressComponentProps } from '../context';
27
+ import Icon from '../icon';
28
+ import type {
29
+ DropdownMenuContext as DropdownMenuContextType,
30
+ DropdownMenuProps,
31
+ DropdownMenuGroupProps,
32
+ DropdownMenuGroupLabelProps,
33
+ DropdownMenuItemProps,
34
+ DropdownMenuCheckboxItemProps,
35
+ DropdownMenuRadioItemProps,
36
+ DropdownMenuSeparatorProps,
37
+ } from './types';
38
+ import * as Styled from './styles';
39
+
40
+ export const DropdownMenuContext = createContext<
41
+ DropdownMenuContextType | undefined
42
+ >( undefined );
43
+
44
+ export const DropdownMenuItem = forwardRef<
45
+ HTMLDivElement,
46
+ WordPressComponentProps< DropdownMenuItemProps, 'div', false >
47
+ >( function DropdownMenuItem(
48
+ { prefix, suffix, children, hideOnClick = true, ...props },
49
+ ref
50
+ ) {
51
+ const dropdownMenuContext = useContext( DropdownMenuContext );
52
+
53
+ return (
54
+ <Styled.DropdownMenuItem
55
+ ref={ ref }
56
+ { ...props }
57
+ hideOnClick={ hideOnClick }
58
+ store={ dropdownMenuContext?.store }
59
+ >
60
+ { prefix && (
61
+ <Styled.ItemPrefixWrapper>{ prefix }</Styled.ItemPrefixWrapper>
62
+ ) }
63
+ { children }
64
+ { suffix && (
65
+ <Styled.ItemSuffixWrapper>{ suffix }</Styled.ItemSuffixWrapper>
66
+ ) }
67
+ </Styled.DropdownMenuItem>
68
+ );
69
+ } );
70
+
71
+ export const DropdownMenuCheckboxItem = forwardRef<
72
+ HTMLDivElement,
73
+ WordPressComponentProps< DropdownMenuCheckboxItemProps, 'div', false >
74
+ >( function DropdownMenuCheckboxItem(
75
+ { suffix, children, hideOnClick = false, ...props },
76
+ ref
77
+ ) {
78
+ const dropdownMenuContext = useContext( DropdownMenuContext );
79
+
80
+ return (
81
+ <Styled.DropdownMenuCheckboxItem
82
+ ref={ ref }
83
+ { ...props }
84
+ hideOnClick={ hideOnClick }
85
+ store={ dropdownMenuContext?.store }
86
+ >
87
+ <Ariakit.MenuItemCheck
88
+ store={ dropdownMenuContext?.store }
89
+ render={ <Styled.ItemPrefixWrapper /> }
90
+ >
91
+ <Icon icon={ check } size={ 24 } />
92
+ </Ariakit.MenuItemCheck>
93
+
94
+ { children }
95
+ { suffix && (
96
+ <Styled.ItemSuffixWrapper>{ suffix }</Styled.ItemSuffixWrapper>
97
+ ) }
98
+ </Styled.DropdownMenuCheckboxItem>
99
+ );
100
+ } );
101
+
102
+ export const DropdownMenuRadioItem = forwardRef<
103
+ HTMLDivElement,
104
+ WordPressComponentProps< DropdownMenuRadioItemProps, 'div', false >
105
+ >( function DropdownMenuRadioItem(
106
+ { suffix, children, hideOnClick = false, ...props },
107
+ ref
108
+ ) {
109
+ const dropdownMenuContext = useContext( DropdownMenuContext );
110
+
111
+ return (
112
+ <Styled.DropdownMenuRadioItem
113
+ ref={ ref }
114
+ { ...props }
115
+ hideOnClick={ hideOnClick }
116
+ store={ dropdownMenuContext?.store }
117
+ >
118
+ <Ariakit.MenuItemCheck
119
+ store={ dropdownMenuContext?.store }
120
+ render={ <Styled.ItemPrefixWrapper /> }
121
+ >
122
+ <SVG viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
123
+ <Circle
124
+ cx={ 12 }
125
+ cy={ 12 }
126
+ r={ 3 }
127
+ fill="currentColor"
128
+ ></Circle>
129
+ </SVG>
130
+ </Ariakit.MenuItemCheck>
131
+ { children }
132
+ { suffix }
133
+ </Styled.DropdownMenuRadioItem>
134
+ );
135
+ } );
136
+
137
+ export const DropdownMenuGroup = forwardRef<
138
+ HTMLDivElement,
139
+ WordPressComponentProps< DropdownMenuGroupProps, 'div', false >
140
+ >( function DropdownMenuGroup( props, ref ) {
141
+ const dropdownMenuContext = useContext( DropdownMenuContext );
142
+ return (
143
+ <Styled.DropdownMenuGroup
144
+ ref={ ref }
145
+ { ...props }
146
+ store={ dropdownMenuContext?.store }
147
+ />
148
+ );
149
+ } );
150
+
151
+ export const DropdownMenuGroupLabel = forwardRef<
152
+ HTMLDivElement,
153
+ WordPressComponentProps< DropdownMenuGroupLabelProps, 'div', false >
154
+ >( function DropdownMenuGroupLabel( props, ref ) {
155
+ const dropdownMenuContext = useContext( DropdownMenuContext );
156
+ return (
157
+ <Styled.DropdownMenuGroupLabel
158
+ ref={ ref }
159
+ { ...props }
160
+ store={ dropdownMenuContext?.store }
161
+ />
162
+ );
163
+ } );
164
+
165
+ const UnconnectedDropdownMenu = (
166
+ props: WordPressComponentProps< DropdownMenuProps, 'div', false >,
167
+ ref: React.ForwardedRef< HTMLDivElement >
168
+ ) => {
169
+ const {
170
+ // Store props
171
+ open,
172
+ defaultOpen = false,
173
+ onOpenChange,
174
+ placement,
175
+
176
+ // Menu trigger props
177
+ trigger,
178
+
179
+ // Menu props
180
+ gutter,
181
+ children,
182
+ shift,
183
+ modal = true,
184
+ hideOnEscape = true,
185
+
186
+ // From internal components context
187
+ variant,
188
+
189
+ // Rest
190
+ ...otherProps
191
+ } = useContextSystem<
192
+ typeof props & Pick< DropdownMenuContextType, 'variant' >
193
+ >( props, 'DropdownMenu' );
194
+
195
+ const parentContext = useContext( DropdownMenuContext );
196
+
197
+ const computedDirection = isRTL() ? 'rtl' : 'ltr';
198
+
199
+ // If an explicit value for the `placement` prop is not passed,
200
+ // apply a default placement of `bottom-start` for the root dropdown,
201
+ // and of `right-start` for nested dropdowns.
202
+ let computedPlacement =
203
+ props.placement ??
204
+ ( parentContext?.store ? 'right-start' : 'bottom-start' );
205
+ // Swap left/right in case of RTL direction
206
+ if ( computedDirection === 'rtl' ) {
207
+ if ( /right/.test( computedPlacement ) ) {
208
+ computedPlacement = computedPlacement.replace(
209
+ 'right',
210
+ 'left'
211
+ ) as typeof computedPlacement;
212
+ } else if ( /left/.test( computedPlacement ) ) {
213
+ computedPlacement = computedPlacement.replace(
214
+ 'left',
215
+ 'right'
216
+ ) as typeof computedPlacement;
217
+ }
218
+ }
219
+
220
+ const dropdownMenuStore = Ariakit.useMenuStore( {
221
+ parent: parentContext?.store,
222
+ open,
223
+ defaultOpen,
224
+ placement: computedPlacement,
225
+ focusLoop: true,
226
+ setOpen( willBeOpen ) {
227
+ onOpenChange?.( willBeOpen );
228
+ },
229
+ rtl: computedDirection === 'rtl',
230
+ } );
231
+
232
+ const contextValue = useMemo(
233
+ () => ( { store: dropdownMenuStore, variant } ),
234
+ [ dropdownMenuStore, variant ]
235
+ );
236
+
237
+ // Extract the side from the applied placement — useful for animations.
238
+ const appliedPlacementSide = dropdownMenuStore
239
+ .useState( 'placement' )
240
+ .split( '-' )[ 0 ];
241
+
242
+ if (
243
+ dropdownMenuStore.parent &&
244
+ ! ( isValidElement( trigger ) && DropdownMenuItem === trigger.type )
245
+ ) {
246
+ // eslint-disable-next-line no-console
247
+ console.warn(
248
+ 'For nested DropdownMenus, the `trigger` should always be a `DropdownMenuItem`.'
249
+ );
250
+ }
251
+
252
+ return (
253
+ <>
254
+ { /* Menu trigger */ }
255
+ <Ariakit.MenuButton
256
+ ref={ ref }
257
+ store={ dropdownMenuStore }
258
+ render={
259
+ dropdownMenuStore.parent
260
+ ? cloneElement( trigger, {
261
+ // Add submenu arrow, unless a `suffix` is explicitly specified
262
+ suffix: trigger.props.suffix ?? (
263
+ <Styled.SubmenuChevronIcon
264
+ aria-hidden="true"
265
+ icon={ chevronRightSmall }
266
+ size={ 24 }
267
+ />
268
+ ),
269
+ } )
270
+ : trigger
271
+ }
272
+ />
273
+
274
+ { /* Menu popover */ }
275
+ <Styled.DropdownMenu
276
+ { ...otherProps }
277
+ modal={ modal }
278
+ store={ dropdownMenuStore }
279
+ gutter={ gutter ?? ( dropdownMenuStore.parent ? 16 : 8 ) }
280
+ shift={ shift ?? ( dropdownMenuStore.parent ? -8 : 0 ) }
281
+ hideOnHoverOutside={ false }
282
+ data-side={ appliedPlacementSide }
283
+ variant={ variant }
284
+ wrapperProps={ {
285
+ dir: computedDirection,
286
+ style: {
287
+ direction: computedDirection,
288
+ },
289
+ } }
290
+ hideOnEscape={ hideOnEscape }
291
+ unmountOnHide
292
+ >
293
+ <DropdownMenuContext.Provider value={ contextValue }>
294
+ { children }
295
+ </DropdownMenuContext.Provider>
296
+ </Styled.DropdownMenu>
297
+ </>
298
+ );
299
+ };
300
+ export const DropdownMenu = contextConnect(
301
+ UnconnectedDropdownMenu,
302
+ 'DropdownMenu'
303
+ );
304
+
305
+ export const DropdownMenuSeparator = forwardRef<
306
+ HTMLHRElement,
307
+ WordPressComponentProps< DropdownMenuSeparatorProps, 'hr', false >
308
+ >( function DropdownMenuSeparator( props, ref ) {
309
+ const dropdownMenuContext = useContext( DropdownMenuContext );
310
+ return (
311
+ <Styled.DropdownMenuSeparator
312
+ ref={ ref }
313
+ { ...props }
314
+ store={ dropdownMenuContext?.store }
315
+ variant={ dropdownMenuContext?.variant }
316
+ />
317
+ );
318
+ } );