@wordpress/components 24.0.0 → 25.0.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 (166) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/CONTRIBUTING.md +10 -0
  3. package/build/color-picker/styles.js +8 -8
  4. package/build/color-picker/styles.js.map +1 -1
  5. package/build/date-time/date-time/index.js +3 -84
  6. package/build/date-time/date-time/index.js.map +1 -1
  7. package/build/date-time/date-time/styles.js +4 -19
  8. package/build/date-time/date-time/styles.js.map +1 -1
  9. package/build/dropdown-menu/index.js +87 -11
  10. package/build/dropdown-menu/index.js.map +1 -1
  11. package/build/dropdown-menu/types.js +6 -0
  12. package/build/dropdown-menu/types.js.map +1 -0
  13. package/build/dropdown-menu-v2/index.js +195 -0
  14. package/build/dropdown-menu-v2/index.js.map +1 -0
  15. package/build/dropdown-menu-v2/styles.js +176 -0
  16. package/build/dropdown-menu-v2/styles.js.map +1 -0
  17. package/build/dropdown-menu-v2/types.js +6 -0
  18. package/build/dropdown-menu-v2/types.js.map +1 -0
  19. package/build/index.native.js +0 -9
  20. package/build/index.native.js.map +1 -1
  21. package/build/input-control/styles/input-control-styles.js +30 -23
  22. package/build/input-control/styles/input-control-styles.js.map +1 -1
  23. package/build/mobile/bottom-sheet/cell.native.js +16 -8
  24. package/build/mobile/bottom-sheet/cell.native.js.map +1 -1
  25. package/build/mobile/bottom-sheet/range-cell.native.js +3 -2
  26. package/build/mobile/bottom-sheet/range-cell.native.js.map +1 -1
  27. package/build/mobile/bottom-sheet/stepper-cell/index.native.js +4 -2
  28. package/build/mobile/bottom-sheet/stepper-cell/index.native.js.map +1 -1
  29. package/build/mobile/bottom-sheet/switch-cell.native.js +8 -2
  30. package/build/mobile/bottom-sheet/switch-cell.native.js.map +1 -1
  31. package/build/mobile/bottom-sheet-select-control/index.native.js +4 -2
  32. package/build/mobile/bottom-sheet-select-control/index.native.js.map +1 -1
  33. package/build/mobile/bottom-sheet-text-control/index.native.js +4 -2
  34. package/build/mobile/bottom-sheet-text-control/index.native.js.map +1 -1
  35. package/build/modal/index.js +1 -2
  36. package/build/modal/index.js.map +1 -1
  37. package/build/private-apis.js +13 -1
  38. package/build/private-apis.js.map +1 -1
  39. package/build/range-control/index.native.js +5 -2
  40. package/build/range-control/index.native.js.map +1 -1
  41. package/build/snackbar/list.js +0 -2
  42. package/build/snackbar/list.js.map +1 -1
  43. package/build/toggle-group-control/toggle-group-control/styles.js +7 -7
  44. package/build/toggle-group-control/toggle-group-control/styles.js.map +1 -1
  45. package/build-module/color-picker/styles.js +8 -8
  46. package/build-module/color-picker/styles.js.map +1 -1
  47. package/build-module/date-time/date-time/index.js +6 -81
  48. package/build-module/date-time/date-time/index.js.map +1 -1
  49. package/build-module/date-time/date-time/styles.js +3 -17
  50. package/build-module/date-time/date-time/styles.js.map +1 -1
  51. package/build-module/dropdown-menu/index.js +87 -10
  52. package/build-module/dropdown-menu/index.js.map +1 -1
  53. package/build-module/dropdown-menu/types.js +2 -0
  54. package/build-module/dropdown-menu/types.js.map +1 -0
  55. package/build-module/dropdown-menu-v2/index.js +149 -0
  56. package/build-module/dropdown-menu-v2/index.js.map +1 -0
  57. package/build-module/dropdown-menu-v2/styles.js +153 -0
  58. package/build-module/dropdown-menu-v2/styles.js.map +1 -0
  59. package/build-module/dropdown-menu-v2/types.js +2 -0
  60. package/build-module/dropdown-menu-v2/types.js.map +1 -0
  61. package/build-module/index.native.js +0 -1
  62. package/build-module/index.native.js.map +1 -1
  63. package/build-module/input-control/styles/input-control-styles.js +30 -23
  64. package/build-module/input-control/styles/input-control-styles.js.map +1 -1
  65. package/build-module/mobile/bottom-sheet/cell.native.js +16 -8
  66. package/build-module/mobile/bottom-sheet/cell.native.js.map +1 -1
  67. package/build-module/mobile/bottom-sheet/range-cell.native.js +3 -2
  68. package/build-module/mobile/bottom-sheet/range-cell.native.js.map +1 -1
  69. package/build-module/mobile/bottom-sheet/stepper-cell/index.native.js +4 -2
  70. package/build-module/mobile/bottom-sheet/stepper-cell/index.native.js.map +1 -1
  71. package/build-module/mobile/bottom-sheet/switch-cell.native.js +7 -2
  72. package/build-module/mobile/bottom-sheet/switch-cell.native.js.map +1 -1
  73. package/build-module/mobile/bottom-sheet-select-control/index.native.js +4 -2
  74. package/build-module/mobile/bottom-sheet-select-control/index.native.js.map +1 -1
  75. package/build-module/mobile/bottom-sheet-text-control/index.native.js +4 -2
  76. package/build-module/mobile/bottom-sheet-text-control/index.native.js.map +1 -1
  77. package/build-module/modal/index.js +1 -2
  78. package/build-module/modal/index.js.map +1 -1
  79. package/build-module/private-apis.js +12 -1
  80. package/build-module/private-apis.js.map +1 -1
  81. package/build-module/range-control/index.native.js +5 -2
  82. package/build-module/range-control/index.native.js.map +1 -1
  83. package/build-module/snackbar/list.js +0 -2
  84. package/build-module/snackbar/list.js.map +1 -1
  85. package/build-module/toggle-group-control/toggle-group-control/styles.js +7 -7
  86. package/build-module/toggle-group-control/toggle-group-control/styles.js.map +1 -1
  87. package/build-style/style-rtl.css +11 -14
  88. package/build-style/style.css +11 -14
  89. package/build-types/color-picker/styles.d.ts.map +1 -1
  90. package/build-types/date-time/date-time/index.d.ts +3 -4
  91. package/build-types/date-time/date-time/index.d.ts.map +1 -1
  92. package/build-types/date-time/date-time/styles.d.ts +0 -4
  93. package/build-types/date-time/date-time/styles.d.ts.map +1 -1
  94. package/build-types/date-time/stories/date-time.d.ts.map +1 -1
  95. package/build-types/date-time/types.d.ts +0 -14
  96. package/build-types/date-time/types.d.ts.map +1 -1
  97. package/build-types/dropdown-menu/index.d.ts +83 -1
  98. package/build-types/dropdown-menu/index.d.ts.map +1 -1
  99. package/build-types/dropdown-menu/stories/index.d.ts +13 -0
  100. package/build-types/dropdown-menu/stories/index.d.ts.map +1 -0
  101. package/build-types/dropdown-menu/test/index.d.ts +2 -0
  102. package/build-types/dropdown-menu/test/index.d.ts.map +1 -0
  103. package/build-types/dropdown-menu/types.d.ts +134 -0
  104. package/build-types/dropdown-menu/types.d.ts.map +1 -0
  105. package/build-types/dropdown-menu-v2/index.d.ts +17 -0
  106. package/build-types/dropdown-menu-v2/index.d.ts.map +1 -0
  107. package/build-types/dropdown-menu-v2/stories/index.d.ts +13 -0
  108. package/build-types/dropdown-menu-v2/stories/index.d.ts.map +1 -0
  109. package/build-types/dropdown-menu-v2/styles.d.ts +41 -0
  110. package/build-types/dropdown-menu-v2/styles.d.ts.map +1 -0
  111. package/build-types/dropdown-menu-v2/test/index.d.ts +2 -0
  112. package/build-types/dropdown-menu-v2/test/index.d.ts.map +1 -0
  113. package/build-types/dropdown-menu-v2/types.d.ts +242 -0
  114. package/build-types/dropdown-menu-v2/types.d.ts.map +1 -0
  115. package/build-types/input-control/styles/input-control-styles.d.ts.map +1 -1
  116. package/build-types/modal/index.d.ts.map +1 -1
  117. package/build-types/private-apis.d.ts.map +1 -1
  118. package/build-types/snackbar/list.d.ts.map +1 -1
  119. package/build-types/toggle-group-control/toggle-group-control/styles.d.ts.map +1 -1
  120. package/build-types/toolbar/stories/index.d.ts.map +1 -1
  121. package/build-types/ui/context/get-styled-class-name-from-key.d.ts +1 -10
  122. package/build-types/ui/context/get-styled-class-name-from-key.d.ts.map +1 -1
  123. package/package.json +21 -20
  124. package/src/button/style.scss +5 -12
  125. package/src/color-picker/styles.ts +7 -2
  126. package/src/date-time/README.md +0 -16
  127. package/src/date-time/date-time/index.tsx +17 -155
  128. package/src/date-time/date-time/styles.ts +0 -4
  129. package/src/date-time/stories/date-time.tsx +0 -4
  130. package/src/date-time/types.ts +0 -16
  131. package/src/dropdown-menu/README.md +12 -22
  132. package/src/dropdown-menu/{index.js → index.tsx} +111 -25
  133. package/src/dropdown-menu/stories/{index.js → index.tsx} +14 -22
  134. package/src/dropdown-menu/test/{index.js → index.tsx} +6 -5
  135. package/src/dropdown-menu/types.ts +143 -0
  136. package/src/dropdown-menu-v2/README.md +392 -0
  137. package/src/dropdown-menu-v2/index.tsx +241 -0
  138. package/src/dropdown-menu-v2/stories/index.tsx +193 -0
  139. package/src/dropdown-menu-v2/styles.ts +263 -0
  140. package/src/dropdown-menu-v2/test/index.tsx +816 -0
  141. package/src/dropdown-menu-v2/types.ts +250 -0
  142. package/src/index.native.js +0 -1
  143. package/src/input-control/styles/input-control-styles.tsx +7 -0
  144. package/src/mobile/bottom-sheet/cell.native.js +26 -5
  145. package/src/mobile/bottom-sheet/range-cell.native.js +2 -1
  146. package/src/mobile/bottom-sheet/stepper-cell/index.native.js +2 -0
  147. package/src/mobile/bottom-sheet/styles.native.scss +13 -1
  148. package/src/mobile/bottom-sheet/switch-cell.native.js +10 -2
  149. package/src/mobile/bottom-sheet-select-control/index.native.js +2 -0
  150. package/src/mobile/bottom-sheet-text-control/index.native.js +2 -0
  151. package/src/modal/index.tsx +1 -6
  152. package/src/private-apis.ts +22 -0
  153. package/src/range-control/index.native.js +3 -0
  154. package/src/search-control/style.scss +2 -0
  155. package/src/snackbar/list.tsx +0 -1
  156. package/src/toggle-group-control/test/__snapshots__/index.tsx.snap +6 -2
  157. package/src/toggle-group-control/toggle-group-control/styles.ts +6 -1
  158. package/src/toolbar/stories/index.tsx +25 -28
  159. package/src/tooltip/style.scss +2 -2
  160. package/tsconfig.tsbuildinfo +1 -1
  161. package/build/mobile/readable-content-view/index.native.js +0 -97
  162. package/build/mobile/readable-content-view/index.native.js.map +0 -1
  163. package/build-module/mobile/readable-content-view/index.native.js +0 -81
  164. package/build-module/mobile/readable-content-view/index.native.js.map +0 -1
  165. package/src/mobile/readable-content-view/index.native.js +0 -85
  166. package/src/mobile/readable-content-view/style.native.scss +0 -30
@@ -0,0 +1,392 @@
1
+ # `DropdownMenu` (v2)
2
+
3
+ <div class="callout callout-alert">
4
+ This feature is still experimental. “Experimental” means this is an early implementation subject to drastic and breaking changes.
5
+ </div>
6
+
7
+ `DropdownMenu` displays a menu to the user (such as a set of actions or functions) triggered by a button.
8
+
9
+
10
+ ## Design guidelines
11
+
12
+ ### Usage
13
+
14
+ #### When to use a DropdownMenu
15
+
16
+ Use a DropdownMenu when you want users to:
17
+
18
+ - Choose an action or change a setting from a list, AND
19
+ - Only see the available choices contextually.
20
+
21
+ `DropdownMenu` is a React component to render an expandable menu of buttons. It is similar in purpose to a `<select>` element, with the distinction that it does not maintain a value. Instead, each option behaves as an action button.
22
+
23
+ If you need to display all the available options at all times, consider using a Toolbar instead. Use a `DropdownMenu` to display a list of actions after the user interacts with a button.
24
+
25
+ **Do**
26
+ Use a `DropdownMenu` to display a list of actions after the user interacts with an icon.
27
+
28
+ **Don’t** use a `DropdownMenu` for important actions that should always be visible. Use a `Toolbar` instead.
29
+
30
+ **Don’t**
31
+ Don’t use a `DropdownMenu` for frequently used actions. Use a `Toolbar` instead.
32
+
33
+ #### Behavior
34
+
35
+ Generally, the parent button should indicate that interacting with it will show a `DropdownMenu`.
36
+
37
+ The parent button should retain the same visual styling regardless of whether the `DropdownMenu` is displayed or not.
38
+
39
+ #### Placement
40
+
41
+ The `DropdownMenu` should typically appear directly below, or below and to the left of, the parent button. If there isn’t enough space below to display the full `DropdownMenu`, it can be displayed instead above the parent button.
42
+
43
+ ## Development guidelines
44
+
45
+ This component is still highly experimental, and it's not normally accessible to consumers of the `@wordpress/components` package.
46
+
47
+ The component exposes a set of components that are meant to be used in combination with each other in order to implement a `DropdownMenu` correctly.
48
+
49
+ ### `DropdownMenu`
50
+
51
+ The root component, used to specify the menu's trigger and its contents.
52
+
53
+ #### Props
54
+
55
+ The component accepts the following props:
56
+
57
+ ##### `trigger`: `React.ReactNode`
58
+
59
+ The trigger button
60
+
61
+ - Required: yes
62
+
63
+ ##### `children`: `React.ReactNode`
64
+
65
+ The contents of the dropdown
66
+
67
+ - Required: yes
68
+
69
+ ##### `defaultOpen`: `boolean`
70
+
71
+ The open state of the dropdown menu when it is initially rendered. Use when you do not need to control its open state.
72
+
73
+ - Required: no
74
+
75
+ ##### `open`: `boolean`
76
+
77
+ The controlled open state of the dropdown menu. Must be used in conjunction with `onOpenChange`
78
+
79
+ - Required: no
80
+
81
+ ##### `onOpenChange`: `(open: boolean) => void`
82
+
83
+ Event handler called when the open state of the dropdown menu changes.
84
+
85
+ - Required: no
86
+
87
+ ##### `modal`: `boolean`
88
+
89
+ The modality of the dropdown menu. When set to true, interaction with outside elements will be disabled and only menu content will be visible to screen readers.
90
+
91
+ - Required: no
92
+ - Default: `true`
93
+
94
+ ##### `side`: `"bottom" | "left" | "right" | "top"`
95
+
96
+ The preferred side of the trigger to render against when open. Will be reversed when collisions occur and avoidCollisions is enabled.
97
+
98
+ - Required: no
99
+ - Default: `"bottom"`
100
+
101
+ ##### `sideOffset`: `number`
102
+
103
+ The distance in pixels from the trigger.
104
+
105
+ - Required: no
106
+ - Default: `0`
107
+
108
+ ##### `align`: `"end" | "start" | "center"`
109
+
110
+ The preferred alignment against the trigger. May change when collisions occur.
111
+
112
+ - Required: no
113
+ - Default: `"center"`
114
+
115
+ ##### `alignOffset`: `number`
116
+
117
+ An offset in pixels from the "start" or "end" alignment options.
118
+
119
+ - Required: no
120
+ - Default: `0`
121
+
122
+ ### `DropdownMenuItem`
123
+
124
+ Used to render a menu item.
125
+
126
+ #### Props
127
+
128
+ The component accepts the following props:
129
+
130
+ ##### `children`: `React.ReactNode`
131
+
132
+ The contents of the item
133
+
134
+ - Required: yes
135
+
136
+ ##### `disabled`: `boolean`
137
+
138
+ - Required: no
139
+ - Default: `false`
140
+
141
+ ##### `onSelect`: `(event: Event) => void`
142
+
143
+ Event handler called when the user selects an item (via mouse or keyboard). Calling `event.preventDefault` in this handler will prevent the dropdown menu from closing when selecting that item.
144
+
145
+ - Required: no
146
+
147
+ ##### `textValue`: `string`
148
+
149
+ Optional text used for typeahead purposes. By default the typeahead behavior will use the `.textContent` of the item. Use this when the content is complex, or you have non-textual content inside.
150
+
151
+ - Required: no
152
+
153
+ ##### `prefix`: `React.ReactNode`
154
+
155
+ The contents of the item's prefix.
156
+
157
+ - Required: no
158
+
159
+ ##### `suffix`: `React.ReactNode`
160
+
161
+ The contents of the item's suffix.
162
+
163
+ - Required: no
164
+
165
+ ### `DropdownSubMenu`
166
+
167
+ Used to render a nested submenu.
168
+
169
+ #### Props
170
+
171
+ The component accepts the following props:
172
+ ##### `trigger`: `React.ReactNode`
173
+
174
+ The contents rendered inside the trigger. The trigger should be an instance of the `DropdownSubMenuTrigger` component.
175
+
176
+ - Required: yes
177
+
178
+ ##### `children`: `React.ReactNode`
179
+
180
+ The contents of the dropdown
181
+
182
+ - Required: yes
183
+
184
+ ##### `defaultOpen`: `boolean`
185
+
186
+ The open state of the dropdown menu when it is initially rendered. Use when you do not need to control its open state.
187
+
188
+ - Required: no
189
+
190
+ ##### `open`: `boolean`
191
+
192
+ The controlled open state of the dropdown menu. Must be used in conjunction with `onOpenChange`
193
+
194
+ - Required: no
195
+
196
+ ##### `onOpenChange`: `(open: boolean) => void`
197
+
198
+ Event handler called when the open state of the dropdown menu changes.
199
+
200
+ - Required: no
201
+
202
+ ##### `disabled`: `boolean`
203
+
204
+ When `true`, prevents the user from interacting with the item.
205
+
206
+ - Required: no
207
+
208
+ ##### `textValue`: `string`
209
+
210
+ Optional text used for typeahead purposes for the trigger. By default the typeahead behavior will use the `.textContent` of the trigger. Use this when the content is complex, or you have non-textual content inside.
211
+
212
+ - Required: no
213
+
214
+ ### `DropdownSubMenuTrigger`
215
+
216
+ Used to render a submenu trigger.
217
+
218
+ #### Props
219
+
220
+ The component accepts the following props:
221
+
222
+ ##### `children`: `React.ReactNode`
223
+
224
+ The contents of the item
225
+
226
+ - Required: yes
227
+
228
+ ##### `prefix`: `React.ReactNode`
229
+
230
+ The contents of the item's prefix.
231
+
232
+ - Required: no
233
+
234
+ ##### `suffix`: `React.ReactNode`
235
+
236
+ The contents of the item's suffix.
237
+
238
+ - Default: a chevron icon
239
+ - Required: The standard chevron icon for a submenu trigger
240
+
241
+ ### `DropdownMenuCheckboxItem`
242
+
243
+ Used to render a checkbox item.
244
+
245
+ #### Props
246
+
247
+ The component accepts the following props:
248
+
249
+ ##### `children`: `React.ReactNode`
250
+
251
+ The contents of the checkbox item
252
+
253
+ - Required: yes
254
+
255
+ ##### `checked`: `boolean`
256
+
257
+ The controlled checked state of the item. Must be used in conjunction with `onCheckedChange`.
258
+
259
+ - Required: no
260
+ - Default: `false`
261
+
262
+ ##### `onCheckedChange`: `(checked: boolean) => void)`
263
+
264
+ Event handler called when the checked state changes.
265
+
266
+ - Required: no
267
+
268
+ ##### `disabled`: `boolean`
269
+
270
+ When `true`, prevents the user from interacting with the item.
271
+
272
+ - Required: no
273
+
274
+ ##### `onSelect`: `(event: Event) => void`
275
+
276
+ Event handler called when the user selects an item (via mouse or keyboard). Calling `event.preventDefault` in this handler will prevent the dropdown menu from closing when selecting that item.
277
+
278
+ - Required: no
279
+
280
+ ##### `textValue`: `string`
281
+
282
+ Optional text used for typeahead purposes. By default the typeahead behavior will use the `.textContent` of the item. Use this when the content is complex, or you have non-textual content inside.
283
+
284
+ - Required: no
285
+
286
+ ##### `suffix`: `React.ReactNode`
287
+
288
+ The contents of the checkbox item's suffix.
289
+
290
+ - Required: no
291
+
292
+ ### `DropdownMenuRadioGroup`
293
+
294
+ Used to render a radio group.
295
+
296
+ #### Props
297
+
298
+ The component accepts the following props:
299
+
300
+ ##### `children`: `React.ReactNode`
301
+
302
+ The contents of the radio group
303
+
304
+ - Required: yes
305
+
306
+ ##### `value`: `string`
307
+
308
+ The value of the selected item in the group.
309
+
310
+ - Required: no
311
+
312
+ ##### `onValueChange`: `(value: string) => void`
313
+
314
+ Event handler called when the value changes.
315
+
316
+ - Required: no
317
+
318
+ ### `DropdownMenuRadioItem`
319
+
320
+ Used to render a radio item.
321
+
322
+ #### Props
323
+
324
+ The component accepts the following props:
325
+
326
+ ##### `children`: `React.ReactNode`
327
+
328
+ The contents of the item.
329
+
330
+ - Required: yes
331
+
332
+ ##### `value`: `string`
333
+
334
+ The unique value of the item.
335
+
336
+ - Required: yes
337
+
338
+ ##### `disabled`: `boolean`
339
+
340
+ When `true`, prevents the user from interacting with the item.
341
+
342
+ - Required: no
343
+
344
+ ##### `onSelect`: `(event: Event) => void`
345
+
346
+ Event handler called when the user selects an item (via mouse or keyboard). Calling `event.preventDefault` in this handler will prevent the dropdown menu from closing when selecting that item.
347
+
348
+ - Required: no
349
+
350
+ ##### `textValue`: `string`
351
+
352
+ Optional text used for typeahead purposes. By default the typeahead behavior will use the `.textContent` of the item. Use this when the content is complex, or you have non-textual content inside.
353
+
354
+ - Required: no
355
+
356
+ ##### `suffix`: `React.ReactNode
357
+
358
+ The contents of the radio item's suffix.
359
+
360
+ - Required: no
361
+
362
+ ### `DropdownMenuLabel`
363
+
364
+ Used to render a group label.
365
+
366
+ #### Props
367
+
368
+ The component accepts the following props:
369
+
370
+ ##### `children`: `React.ReactNode`
371
+
372
+ The contents of the group.
373
+
374
+ - Required: yes
375
+
376
+ ### `DropdownMenuGroup`
377
+
378
+ Used to group menu items.
379
+
380
+ #### Props
381
+
382
+ The component accepts the following props:
383
+
384
+ ##### `children`: `React.ReactNode`
385
+
386
+ The contents of the group.
387
+
388
+ - Required: yes
389
+
390
+ ### `DropdownMenuSeparatorProps`
391
+
392
+ Used to render a visual separator.
@@ -0,0 +1,241 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import { forwardRef } from '@wordpress/element';
10
+ import { isRTL } from '@wordpress/i18n';
11
+ import { check, chevronRightSmall, lineSolid } from '@wordpress/icons';
12
+ import { SVG, Circle } from '@wordpress/primitives';
13
+
14
+ /**
15
+ * Internal dependencies
16
+ */
17
+ import Icon from '../icon';
18
+ import * as DropdownMenuStyled from './styles';
19
+ import type {
20
+ DropdownMenuProps,
21
+ DropdownSubMenuProps,
22
+ DropdownMenuItemProps,
23
+ DropdownMenuLabelProps,
24
+ DropdownMenuGroupProps,
25
+ DropdownMenuCheckboxItemProps,
26
+ DropdownMenuRadioGroupProps,
27
+ DropdownMenuRadioItemProps,
28
+ DropdownMenuSeparatorProps,
29
+ DropdownSubMenuTriggerProps,
30
+ } from './types';
31
+
32
+ // Menu content's side padding + 4px
33
+ const SUB_MENU_OFFSET_SIDE = 12;
34
+ // Opposite amount of the top padding of the menu item
35
+ const SUB_MENU_OFFSET_ALIGN = -8;
36
+
37
+ /**
38
+ * `DropdownMenu` displays a menu to the user (such as a set of actions
39
+ * or functions) triggered by a button.
40
+ */
41
+ export const DropdownMenu = ( {
42
+ // Root props
43
+ defaultOpen,
44
+ open,
45
+ onOpenChange,
46
+ modal = true,
47
+ // Content positioning props
48
+ side = 'bottom',
49
+ sideOffset = 0,
50
+ align = 'center',
51
+ alignOffset = 0,
52
+ // Render props
53
+ children,
54
+ trigger,
55
+ }: DropdownMenuProps ) => {
56
+ return (
57
+ <DropdownMenuPrimitive.Root
58
+ defaultOpen={ defaultOpen }
59
+ open={ open }
60
+ onOpenChange={ onOpenChange }
61
+ modal={ modal }
62
+ dir={ isRTL() ? 'rtl' : 'ltr' }
63
+ >
64
+ <DropdownMenuPrimitive.Trigger asChild>
65
+ { trigger }
66
+ </DropdownMenuPrimitive.Trigger>
67
+ <DropdownMenuPrimitive.Portal>
68
+ <DropdownMenuStyled.Content
69
+ side={ side }
70
+ align={ align }
71
+ sideOffset={ sideOffset }
72
+ alignOffset={ alignOffset }
73
+ loop={ true }
74
+ >
75
+ { children }
76
+ </DropdownMenuStyled.Content>
77
+ </DropdownMenuPrimitive.Portal>
78
+ </DropdownMenuPrimitive.Root>
79
+ );
80
+ };
81
+
82
+ export const DropdownSubMenuTrigger = ( {
83
+ prefix,
84
+ suffix = (
85
+ <DropdownMenuStyled.SubmenuRtlChevronIcon
86
+ icon={ chevronRightSmall }
87
+ size={ 24 }
88
+ />
89
+ ),
90
+ children,
91
+ }: DropdownSubMenuTriggerProps ) => {
92
+ return (
93
+ <>
94
+ { prefix && (
95
+ <DropdownMenuStyled.ItemPrefixWrapper>
96
+ { prefix }
97
+ </DropdownMenuStyled.ItemPrefixWrapper>
98
+ ) }
99
+ { children }
100
+ { suffix && (
101
+ <DropdownMenuStyled.ItemSuffixWrapper>
102
+ { suffix }
103
+ </DropdownMenuStyled.ItemSuffixWrapper>
104
+ ) }
105
+ </>
106
+ );
107
+ };
108
+
109
+ export const DropdownSubMenu = ( {
110
+ // Sub props
111
+ defaultOpen,
112
+ open,
113
+ onOpenChange,
114
+ // Sub trigger props
115
+ disabled,
116
+ textValue,
117
+ // Render props
118
+ children,
119
+ trigger,
120
+ }: DropdownSubMenuProps ) => {
121
+ return (
122
+ <DropdownMenuPrimitive.Sub
123
+ defaultOpen={ defaultOpen }
124
+ open={ open }
125
+ onOpenChange={ onOpenChange }
126
+ >
127
+ <DropdownMenuStyled.SubTrigger
128
+ disabled={ disabled }
129
+ textValue={ textValue }
130
+ >
131
+ { trigger }
132
+ </DropdownMenuStyled.SubTrigger>
133
+ <DropdownMenuPrimitive.Portal>
134
+ <DropdownMenuStyled.SubContent
135
+ loop
136
+ sideOffset={ SUB_MENU_OFFSET_SIDE }
137
+ alignOffset={ SUB_MENU_OFFSET_ALIGN }
138
+ >
139
+ { children }
140
+ </DropdownMenuStyled.SubContent>
141
+ </DropdownMenuPrimitive.Portal>
142
+ </DropdownMenuPrimitive.Sub>
143
+ );
144
+ };
145
+
146
+ export const DropdownMenuLabel = ( props: DropdownMenuLabelProps ) => (
147
+ <DropdownMenuStyled.Label { ...props } />
148
+ );
149
+
150
+ export const DropdownMenuGroup = ( props: DropdownMenuGroupProps ) => (
151
+ <DropdownMenuPrimitive.Group { ...props } />
152
+ );
153
+
154
+ export const DropdownMenuItem = forwardRef(
155
+ (
156
+ { children, prefix, suffix, ...props }: DropdownMenuItemProps,
157
+ forwardedRef: React.ForwardedRef< any >
158
+ ) => {
159
+ return (
160
+ <DropdownMenuStyled.Item { ...props } ref={ forwardedRef }>
161
+ { prefix && (
162
+ <DropdownMenuStyled.ItemPrefixWrapper>
163
+ { prefix }
164
+ </DropdownMenuStyled.ItemPrefixWrapper>
165
+ ) }
166
+ { children }
167
+ { suffix && (
168
+ <DropdownMenuStyled.ItemSuffixWrapper>
169
+ { suffix }
170
+ </DropdownMenuStyled.ItemSuffixWrapper>
171
+ ) }
172
+ </DropdownMenuStyled.Item>
173
+ );
174
+ }
175
+ );
176
+
177
+ export const DropdownMenuCheckboxItem = ( {
178
+ children,
179
+ checked = false,
180
+ suffix,
181
+ ...props
182
+ }: DropdownMenuCheckboxItemProps ) => {
183
+ return (
184
+ <DropdownMenuStyled.CheckboxItem { ...props } checked={ checked }>
185
+ <DropdownMenuStyled.ItemPrefixWrapper>
186
+ <DropdownMenuStyled.ItemIndicator>
187
+ { ( checked === 'indeterminate' || checked === true ) && (
188
+ <Icon
189
+ icon={
190
+ checked === 'indeterminate' ? lineSolid : check
191
+ }
192
+ size={ 24 }
193
+ />
194
+ ) }
195
+ </DropdownMenuStyled.ItemIndicator>
196
+ </DropdownMenuStyled.ItemPrefixWrapper>
197
+ { children }
198
+ { suffix && (
199
+ <DropdownMenuStyled.ItemSuffixWrapper>
200
+ { suffix }
201
+ </DropdownMenuStyled.ItemSuffixWrapper>
202
+ ) }
203
+ </DropdownMenuStyled.CheckboxItem>
204
+ );
205
+ };
206
+
207
+ export const DropdownMenuRadioGroup = (
208
+ props: DropdownMenuRadioGroupProps
209
+ ) => <DropdownMenuPrimitive.RadioGroup { ...props } />;
210
+
211
+ const radioDot = (
212
+ <SVG viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
213
+ <Circle cx={ 12 } cy={ 12 } r={ 3 } fill="currentColor"></Circle>
214
+ </SVG>
215
+ );
216
+
217
+ export const DropdownMenuRadioItem = ( {
218
+ children,
219
+ suffix,
220
+ ...props
221
+ }: DropdownMenuRadioItemProps ) => {
222
+ return (
223
+ <DropdownMenuStyled.RadioItem { ...props }>
224
+ <DropdownMenuStyled.ItemPrefixWrapper>
225
+ <DropdownMenuStyled.ItemIndicator>
226
+ <Icon icon={ radioDot } size={ 22 } />
227
+ </DropdownMenuStyled.ItemIndicator>
228
+ </DropdownMenuStyled.ItemPrefixWrapper>
229
+ { children }
230
+ { suffix && (
231
+ <DropdownMenuStyled.ItemSuffixWrapper>
232
+ { suffix }
233
+ </DropdownMenuStyled.ItemSuffixWrapper>
234
+ ) }
235
+ </DropdownMenuStyled.RadioItem>
236
+ );
237
+ };
238
+
239
+ export const DropdownMenuSeparator = ( props: DropdownMenuSeparatorProps ) => (
240
+ <DropdownMenuStyled.Separator { ...props } />
241
+ );