@astryxdesign/core 0.5.2-canary.c9c8564 → 0.5.2-canary.e4f8e4e

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 (146) hide show
  1. package/dist/BottomSheet/BottomSheet.d.ts +3 -1
  2. package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
  3. package/dist/BottomSheet/BottomSheet.js +4 -3
  4. package/dist/BottomSheet/BottomSheetEdgeTint.d.ts +2 -2
  5. package/dist/BottomSheet/BottomSheetEdgeTint.d.ts.map +1 -1
  6. package/dist/BottomSheet/BottomSheetEdgeTint.js +7 -10
  7. package/dist/BottomSheet/BottomSheetSwitcher.d.ts.map +1 -1
  8. package/dist/BottomSheet/BottomSheetSwitcher.js +1 -1
  9. package/dist/Button/Button.d.ts +2 -1
  10. package/dist/Button/Button.d.ts.map +1 -1
  11. package/dist/Button/Button.js +11 -4
  12. package/dist/Carousel/Carousel.d.ts.map +1 -1
  13. package/dist/Carousel/Carousel.js +2 -2
  14. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  15. package/dist/Chat/ChatToolCalls.js +34 -17
  16. package/dist/ContextMenu/ContextMenu.d.ts +14 -3
  17. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  18. package/dist/ContextMenu/ContextMenu.js +149 -26
  19. package/dist/ContextMenu/index.d.ts +1 -0
  20. package/dist/ContextMenu/index.d.ts.map +1 -1
  21. package/dist/DropdownMenu/DropdownMenu.d.ts +24 -5
  22. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  23. package/dist/DropdownMenu/DropdownMenu.js +340 -26
  24. package/dist/DropdownMenu/DropdownMenuContext.d.ts +1 -1
  25. package/dist/DropdownMenu/DropdownMenuContext.d.ts.map +1 -1
  26. package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
  27. package/dist/DropdownMenu/DropdownMenuItem.js +1 -1
  28. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts +6 -2
  29. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
  30. package/dist/DropdownMenu/DropdownMenuSubMenu.js +43 -14
  31. package/dist/DropdownMenu/MenuBottomSheet.d.ts +20 -0
  32. package/dist/DropdownMenu/MenuBottomSheet.d.ts.map +1 -0
  33. package/dist/DropdownMenu/MenuBottomSheet.js +36 -0
  34. package/dist/DropdownMenu/MenuBottomSheetActionList.d.ts +10 -0
  35. package/dist/DropdownMenu/MenuBottomSheetActionList.d.ts.map +1 -0
  36. package/dist/DropdownMenu/MenuBottomSheetActionList.js +111 -0
  37. package/dist/DropdownMenu/index.d.ts +2 -1
  38. package/dist/DropdownMenu/index.d.ts.map +1 -1
  39. package/dist/DropdownMenu/menuWidth.d.ts +14 -0
  40. package/dist/DropdownMenu/menuWidth.d.ts.map +1 -0
  41. package/dist/DropdownMenu/menuWidth.js +35 -0
  42. package/dist/DropdownMenu/useMenuOverflow.d.ts +10 -0
  43. package/dist/DropdownMenu/useMenuOverflow.d.ts.map +1 -0
  44. package/dist/DropdownMenu/useMenuOverflow.js +60 -0
  45. package/dist/MoreMenu/MoreMenu.d.ts +8 -2
  46. package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
  47. package/dist/MoreMenu/MoreMenu.js +2 -0
  48. package/dist/MultiSelector/MultiSelector.d.ts +11 -1
  49. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  50. package/dist/MultiSelector/MultiSelector.js +97 -68
  51. package/dist/MultiSelector/index.d.ts +1 -1
  52. package/dist/MultiSelector/index.d.ts.map +1 -1
  53. package/dist/Popover/Popover.d.ts +10 -6
  54. package/dist/Popover/Popover.d.ts.map +1 -1
  55. package/dist/Popover/Popover.js +141 -16
  56. package/dist/Popover/usePopover.d.ts +4 -0
  57. package/dist/Popover/usePopover.d.ts.map +1 -1
  58. package/dist/Popover/usePopover.js +52 -5
  59. package/dist/Selector/Selector.d.ts +10 -0
  60. package/dist/Selector/Selector.d.ts.map +1 -1
  61. package/dist/Selector/Selector.js +106 -80
  62. package/dist/Selector/SelectorBottomSheet.d.ts +21 -0
  63. package/dist/Selector/SelectorBottomSheet.d.ts.map +1 -0
  64. package/dist/Selector/SelectorBottomSheet.js +83 -0
  65. package/dist/Selector/index.d.ts +1 -1
  66. package/dist/Selector/index.d.ts.map +1 -1
  67. package/dist/Selector/selectorPresentation.stylex.d.ts +16 -0
  68. package/dist/Selector/selectorPresentation.stylex.d.ts.map +1 -0
  69. package/dist/Selector/selectorPresentation.stylex.js +21 -0
  70. package/dist/Selector/useSelectorPresentation.d.ts +32 -0
  71. package/dist/Selector/useSelectorPresentation.d.ts.map +1 -0
  72. package/dist/Selector/useSelectorPresentation.js +90 -0
  73. package/dist/Toast/useToastGesture.d.ts.map +1 -1
  74. package/dist/Toast/useToastGesture.js +46 -9
  75. package/dist/astryx.css +19 -1
  76. package/dist/hooks/useAdaptivePresentation.d.ts +5 -0
  77. package/dist/hooks/useAdaptivePresentation.d.ts.map +1 -0
  78. package/dist/hooks/useAdaptivePresentation.js +19 -0
  79. package/dist/hooks/useFocusReturnVisibility.d.ts +7 -0
  80. package/dist/hooks/useFocusReturnVisibility.d.ts.map +1 -0
  81. package/dist/hooks/useFocusReturnVisibility.js +35 -0
  82. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  83. package/dist/hooks/useFocusTrap.js +12 -0
  84. package/locales/en.json +20 -0
  85. package/locales/pseudo.json +15 -0
  86. package/package.json +2 -2
  87. package/src/BottomSheet/BottomSheet.doc.mjs +6 -0
  88. package/src/BottomSheet/BottomSheet.test.tsx +29 -0
  89. package/src/BottomSheet/BottomSheet.tsx +7 -4
  90. package/src/BottomSheet/BottomSheetEdgeTint.test.tsx +4 -6
  91. package/src/BottomSheet/BottomSheetEdgeTint.tsx +7 -10
  92. package/src/BottomSheet/BottomSheetSwitcher.tsx +1 -2
  93. package/src/Button/Button.doc.mjs +56 -0
  94. package/src/Button/Button.test.tsx +10 -0
  95. package/src/Button/Button.tsx +13 -5
  96. package/src/ButtonGroup/ButtonGroup.doc.mjs +47 -0
  97. package/src/Carousel/Carousel.test.tsx +83 -0
  98. package/src/Carousel/Carousel.tsx +8 -2
  99. package/src/Chat/ChatToolCalls.test.tsx +44 -0
  100. package/src/Chat/ChatToolCalls.tsx +36 -15
  101. package/src/ContextMenu/ContextMenu.doc.mjs +13 -1
  102. package/src/ContextMenu/ContextMenu.test.tsx +131 -1
  103. package/src/ContextMenu/ContextMenu.tsx +199 -32
  104. package/src/ContextMenu/index.ts +1 -0
  105. package/src/DropdownMenu/DropdownMenu.doc.mjs +201 -40
  106. package/src/DropdownMenu/DropdownMenu.test.tsx +518 -7
  107. package/src/DropdownMenu/DropdownMenu.tsx +459 -28
  108. package/src/DropdownMenu/DropdownMenuContext.tsx +1 -1
  109. package/src/DropdownMenu/DropdownMenuItem.tsx +2 -0
  110. package/src/DropdownMenu/DropdownMenuSubMenu.doc.mjs +4 -2
  111. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +124 -0
  112. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +72 -17
  113. package/src/DropdownMenu/MenuBottomSheet.tsx +46 -0
  114. package/src/DropdownMenu/MenuBottomSheetActionList.tsx +141 -0
  115. package/src/DropdownMenu/index.ts +2 -0
  116. package/src/DropdownMenu/menuWidth.ts +51 -0
  117. package/src/DropdownMenu/useMenuOverflow.ts +77 -0
  118. package/src/IconButton/IconButton.doc.mjs +38 -0
  119. package/src/MoreMenu/MoreMenu.doc.mjs +17 -0
  120. package/src/MoreMenu/MoreMenu.test.tsx +47 -0
  121. package/src/MoreMenu/MoreMenu.tsx +13 -1
  122. package/src/MultiSelector/MultiSelector.doc.mjs +16 -0
  123. package/src/MultiSelector/MultiSelector.test.tsx +127 -0
  124. package/src/MultiSelector/MultiSelector.tsx +121 -73
  125. package/src/MultiSelector/index.ts +1 -0
  126. package/src/Popover/Popover.doc.mjs +11 -11
  127. package/src/Popover/Popover.test.tsx +397 -2
  128. package/src/Popover/Popover.tsx +228 -21
  129. package/src/Popover/usePopover.tsx +92 -15
  130. package/src/ProgressBar/ProgressBar.spec.md +208 -0
  131. package/src/SegmentedControl/SegmentedControl.doc.mjs +56 -0
  132. package/src/Selector/Selector.doc.mjs +12 -0
  133. package/src/Selector/Selector.test.tsx +135 -0
  134. package/src/Selector/Selector.tsx +141 -82
  135. package/src/Selector/SelectorBottomSheet.tsx +97 -0
  136. package/src/Selector/index.ts +1 -0
  137. package/src/Selector/selectorPresentation.stylex.ts +20 -0
  138. package/src/Selector/useSelectorPresentation.ts +147 -0
  139. package/src/Toast/ToastViewport.test.tsx +118 -4
  140. package/src/Toast/useToastGesture.ts +61 -8
  141. package/src/ToggleButton/ToggleButton.doc.mjs +56 -0
  142. package/src/hooks/useAdaptivePresentation.ts +35 -0
  143. package/src/hooks/useFocusReturnVisibility.ts +45 -0
  144. package/src/hooks/useFocusTrap.test.tsx +40 -0
  145. package/src/hooks/useFocusTrap.ts +13 -0
  146. package/src/theme/themingTargets.test.ts +91 -25
@@ -4,8 +4,10 @@
4
4
 
5
5
  /**
6
6
  * @file DropdownMenu.tsx
7
- * @input Uses React, StyleX, usePopover, Button, Icon, useListFocus
8
- * @output Exports DropdownMenu component
7
+ * @input Uses React, StyleX, usePopover, MenuBottomSheet, Button, List,
8
+ * useListFocus, and the shared viewport-safe menu-width resolver
9
+ * @output Exports DropdownMenu with caller-selected popover or bottom-sheet
10
+ * presentation
9
11
  * @position Core implementation; consumed by index.ts
10
12
  *
11
13
  * Supports two modes with a single keyboard/focus path:
@@ -30,27 +32,54 @@ import React, { useCallback, useEffect, useId, useMemo, useRef, useState } from
30
32
  import * as stylex from '@stylexjs/stylex';
31
33
  import { usePopoverInternal } from "../Popover/usePopover.js";
32
34
  import { Button } from "../Button/index.js";
35
+ import { Heading } from "../Heading/index.js";
33
36
  import { Icon } from "../Icon/index.js";
34
37
  import { renderDropdownItems } from "./renderDropdownItems.js";
35
38
  import { MENU_ITEM_ROLES, MENU_ITEM_SELECTOR, MENU_BOUNDARY_SELECTOR } from "./menuItemRoles.js";
36
39
  import { DropdownMenuContext } from "./DropdownMenuContext.js";
37
40
  import { useListFocus } from "../hooks/useListFocus.js";
38
41
  import { useTypeahead } from "../hooks/useTypeahead.js";
42
+ import { useFocusReturnVisibility } from "../hooks/useFocusReturnVisibility.js";
43
+ import { useMenuOverflow } from "./useMenuOverflow.js";
44
+ import { resolveMenuWidth } from "./menuWidth.js";
45
+ import { useAdaptivePresentation } from "../hooks/useAdaptivePresentation.js";
46
+ import { MenuBottomSheet } from "./MenuBottomSheet.js";
47
+ import { MenuBottomSheetActionList } from "./MenuBottomSheetActionList.js";
39
48
  import { layerAnimations } from "../Layer/layerAnimations.stylex.js";
40
49
  import "../theme/tokens.stylex.js";
41
- import { spacingVars, radiusVars, durationVars, easeVars } from "../theme/tokens.stylex.js";
42
- import { mergeProps } from "../utils/index.js";
50
+ import { spacingVars, colorVars, radiusVars, durationVars, easeVars } from "../theme/tokens.stylex.js";
51
+ import { mergeProps, rtlStyles } from "../utils/index.js";
43
52
  import { themeProps } from "../utils/themeProps.js";
53
+ import { getInteractionModality, trackInteractionModality } from "../utils/interactionModality.js";
44
54
  import { useTranslator } from "../i18n/index.js";
45
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
55
+ import { focusOutlineStyles } from "../utils/focusOutline.stylex.js";
56
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
57
+ const MENU_VIEWPORT_GUTTER = spacingVars['--spacing-4'];
58
+ const MENU_MAX_INLINE_SIZE = `calc(100vi - max(${MENU_VIEWPORT_GUTTER}, env(safe-area-inset-left, 0px)) - max(${MENU_VIEWPORT_GUTTER}, env(safe-area-inset-right, 0px)))`;
59
+ const MENU_MAX_INLINE_SIZE_FALLBACK = `calc(100vw - ${MENU_VIEWPORT_GUTTER} - ${MENU_VIEWPORT_GUTTER})`;
60
+ const MENU_MAX_BLOCK_SIZE = `min(300px, calc(100dvb - max(${MENU_VIEWPORT_GUTTER}, env(safe-area-inset-top, 0px)) - max(${MENU_VIEWPORT_GUTTER}, env(safe-area-inset-bottom, 0px))))`;
61
+ const MENU_MAX_BLOCK_SIZE_FALLBACK = `min(300px, calc(100vh - ${MENU_VIEWPORT_GUTTER} - ${MENU_VIEWPORT_GUTTER}))`;
62
+ const MENU_POSITION_AREA_MAX_INLINE_SIZE = `calc(100% - max(${MENU_VIEWPORT_GUTTER}, env(safe-area-inset-left, 0px), env(safe-area-inset-right, 0px)))`;
63
+ const MENU_POSITION_AREA_MAX_INLINE_SIZE_FALLBACK = `calc(100% - ${MENU_VIEWPORT_GUTTER})`;
64
+ const MENU_INLINE_EDGE_GUTTER = `max(${MENU_VIEWPORT_GUTTER}, env(safe-area-inset-left, 0px), env(safe-area-inset-right, 0px))`;
65
+ const MENU_TRIGGER_OPEN_BACKGROUND = `linear-gradient(${colorVars['--color-overlay-pressed']}, ${colorVars['--color-overlay-pressed']})`;
66
+ const _temp = {
67
+ kzqmXN: "x1uyokj7",
68
+ "$$css": true
69
+ };
46
70
  const styles = {
71
+ triggerOpen: {
72
+ kKwaWg: "xpl5ynk",
73
+ $$css: true
74
+ },
47
75
  dropdown: {
48
76
  kB7OPa: "x9f619",
49
77
  k1xSpc: "x78zum5",
50
78
  kXwgrk: "xdt5ytf",
51
79
  kOIVth: "x1lsbc85",
52
- kskxy: "xuyqlj2",
53
- kORKVm: "x1odjw0f",
80
+ kI3sdo: "x1a2a7pz",
81
+ ks0D6T: "xs2v1xk",
82
+ kskxy: "x1hkkhfe",
54
83
  "--_dropdown-menu-radius": "x1fcsqxe",
55
84
  "--_dropdown-menu-padding": "xgory14",
56
85
  kmVPX3: "x9epnlk",
@@ -61,17 +90,81 @@ const styles = {
61
90
  kAMwcw: "xlr8y92",
62
91
  $$css: true
63
92
  },
64
- popover: {
65
- k7Eaqz: "xrzjruh",
93
+ scrollable: {
94
+ kORKVm: "x1odjw0f",
95
+ kXHlph: "x6ikm8r",
96
+ kZeWKH: "xish69e",
97
+ $$css: true
98
+ },
99
+ popoverViewport: {
100
+ kB7OPa: "x9f619",
101
+ kskxy: "x1hkkhfe",
102
+ $$css: true
103
+ },
104
+ popoverViewportAligned: {
105
+ ks0D6T: "xbd96yr",
106
+ $$css: true
107
+ },
108
+ popoverViewportStart: {
109
+ k71WvV: "xxeicf8",
110
+ $$css: true
111
+ },
112
+ popoverViewportEnd: {
113
+ keTefX: "x47fqr9",
114
+ $$css: true
115
+ },
116
+ popoverViewportBlockStart: {
117
+ k1K539: "x1kps3mo",
118
+ $$css: true
119
+ },
120
+ popoverViewportBlockEnd: {
121
+ keoZOQ: "xsoubt3",
122
+ $$css: true
123
+ },
124
+ popoverViewportCentered: {
125
+ keTefX: "x47fqr9",
126
+ k71WvV: "xxeicf8",
127
+ ks0D6T: "xs2v1xk",
128
+ $$css: true
129
+ },
130
+ popoverViewportBlockCentered: {
131
+ keoZOQ: "xsoubt3",
132
+ k1K539: "x1kps3mo",
133
+ ks0D6T: "xs2v1xk",
134
+ $$css: true
135
+ },
136
+ popoverAligned: {
137
+ k7Eaqz: "x1ks9poc",
138
+ $$css: true
139
+ },
140
+ popoverCentered: {
141
+ k7Eaqz: "xagy28z",
66
142
  $$css: true
67
143
  },
68
144
  popoverCustomWidth: width => [{
69
- k7Eaqz: (typeof width === 'number' ? `${width}px` : width) != null ? "xkj4a21" : typeof width === 'number' ? `${width}px` : width,
145
+ k7Eaqz: width != null ? "xkj4a21" : width,
70
146
  $$css: true
71
147
  }, {
72
- "--x-minWidth": (val => typeof val === "number" ? val + "px" : val != null ? val : undefined)(typeof width === 'number' ? `${width}px` : width)
148
+ "--x-minWidth": (val => typeof val === "number" ? val + "px" : val != null ? val : undefined)(width)
149
+ }],
150
+ popoverCustomIntrinsicWidth: width => [_temp, {
151
+ "--x-inlineSize": (val => typeof val === "number" ? val + "px" : val != null ? val : undefined)(width)
73
152
  }]
74
153
  };
154
+ const bottomSheetStyles = {
155
+ content: {
156
+ kzqmXN: "xh8yej3",
157
+ $$css: true
158
+ },
159
+ rootHeading: {
160
+ keTefX: "x6i7dpz",
161
+ $$css: true
162
+ },
163
+ viewHeading: {
164
+ kI3sdo: "x1a2a7pz",
165
+ $$css: true
166
+ }
167
+ };
75
168
 
76
169
  // =============================================================================
77
170
  // Types
@@ -103,15 +196,16 @@ const styles = {
103
196
  * A dropdown menu component that displays a list of actionable items.
104
197
  *
105
198
  * Supports two modes:
106
- * - **Data-driven**: pass `items` for static menus with optional custom rendering
107
- * - **Compound-component**: pass JSX children for dynamic, stateful, or lazy-loaded menus
108
- *
109
- * Both modes share the same DOM-based keyboard navigation via useListFocus.
199
+ * - **Data-driven**: pass `items` and choose either the default anchored
200
+ * popover or the modal bottom-sheet presentation.
201
+ * - **Compound-component**: pass JSX children for dynamic, stateful, or
202
+ * lazy-loaded anchored popover menus.
110
203
  *
111
204
  * @example
112
205
  * ```
113
206
  * <DropdownMenu
114
207
  * button={{ label: 'Actions' }}
208
+ * presentation={useBottomSheet ? 'bottom-sheet' : 'popover'}
115
209
  * items={[
116
210
  * { label: 'Edit', onClick: () => handleEdit() },
117
211
  * { label: 'Delete', onClick: () => handleDelete() },
@@ -123,7 +217,179 @@ const styles = {
123
217
  // at render time so it respects the active InternationalizationProvider
124
218
  // locale.
125
219
  const DEFAULT_BUTTON_I18N_KEY = '@astryx.dropdownMenu.label';
126
- export function DropdownMenu({
220
+ function DropdownMenuBottomSheet({
221
+ button: buttonFromProps,
222
+ isMenuOpen: controlledIsOpen,
223
+ onOpenChange,
224
+ onClick,
225
+ hasChevron = true,
226
+ items,
227
+ presentation: _presentation,
228
+ menuWidth: _menuWidth,
229
+ placement: _placement,
230
+ alignment: _alignment,
231
+ className,
232
+ style,
233
+ xstyle,
234
+ 'data-testid': testId,
235
+ ...rest
236
+ }) {
237
+ const t = useTranslator();
238
+ const button = buttonFromProps ?? {
239
+ label: t(DEFAULT_BUTTON_I18N_KEY)
240
+ };
241
+ const backLabel = t('@astryx.dropdownMenu.back');
242
+ const buttonRef = useRef(null);
243
+ const actionListRef = useRef(null);
244
+ const openModalityRef = useRef('pointer');
245
+ const {
246
+ isFocusRingSuppressed,
247
+ onFocusReturnTargetFocus,
248
+ prepareFocusReturn,
249
+ resetFocusReturn
250
+ } = useFocusReturnVisibility();
251
+ const viewHeadingRef = useRef(null);
252
+ const previousSubmenuDepthRef = useRef(0);
253
+ const [internalIsOpen, setInternalIsOpen] = useState(false);
254
+ const [submenuPath, setSubmenuPath] = useState([]);
255
+ const isControlled = controlledIsOpen !== undefined;
256
+ const isOpen = isControlled ? controlledIsOpen : internalIsOpen;
257
+ const [previousIsOpen, setPreviousIsOpen] = useState(isOpen);
258
+ if (previousIsOpen !== isOpen) {
259
+ setPreviousIsOpen(isOpen);
260
+ if (!isOpen && submenuPath.length > 0) {
261
+ setSubmenuPath([]);
262
+ }
263
+ }
264
+ const currentSubmenu = submenuPath.at(-1);
265
+ const currentItems = currentSubmenu?.items ?? items;
266
+ const currentTitle = currentSubmenu?.label ?? button.label;
267
+ const sheetLabel = typeof currentTitle === 'string' ? currentTitle : button.label;
268
+ const setOpen = useCallback(nextIsOpen => {
269
+ if (!nextIsOpen) {
270
+ setSubmenuPath([]);
271
+ prepareFocusReturn();
272
+ } else {
273
+ resetFocusReturn();
274
+ }
275
+ onOpenChange?.(nextIsOpen);
276
+ if (!isControlled) {
277
+ setInternalIsOpen(nextIsOpen);
278
+ }
279
+ }, [isControlled, onOpenChange, prepareFocusReturn, resetFocusReturn]);
280
+ const handleSelect = useCallback(item => {
281
+ if (item.isDisabled) {
282
+ return;
283
+ }
284
+ item.onClick?.();
285
+ if (item.hasCloseOnSelect !== false) {
286
+ setOpen(false);
287
+ }
288
+ }, [setOpen]);
289
+ const isIconOnly = button.isIconOnly === true;
290
+ const resolvedEndContent = button.endContent ?? (hasChevron && !isIconOnly ? /*#__PURE__*/_jsx(Icon, {
291
+ icon: "chevronDown",
292
+ size: "sm",
293
+ color: "inherit"
294
+ }) : undefined);
295
+ useEffect(() => {
296
+ if (!isOpen || openModalityRef.current !== 'keyboard') {
297
+ return;
298
+ }
299
+ const frame = requestAnimationFrame(() => {
300
+ actionListRef.current?.querySelector('button:not(:disabled), a[href]')?.focus({
301
+ preventScroll: true
302
+ });
303
+ });
304
+ return () => cancelAnimationFrame(frame);
305
+ }, [currentItems, isOpen]);
306
+ useEffect(() => {
307
+ if (!isOpen) {
308
+ previousSubmenuDepthRef.current = 0;
309
+ return;
310
+ }
311
+ if (submenuPath.length === previousSubmenuDepthRef.current) {
312
+ return;
313
+ }
314
+ previousSubmenuDepthRef.current = submenuPath.length;
315
+ const frame = requestAnimationFrame(() => {
316
+ viewHeadingRef.current?.focus({
317
+ preventScroll: true
318
+ });
319
+ });
320
+ return () => cancelAnimationFrame(frame);
321
+ }, [isOpen, submenuPath.length]);
322
+ return /*#__PURE__*/_jsxs(_Fragment, {
323
+ children: [/*#__PURE__*/_jsx(Button, {
324
+ ...button,
325
+ ref: buttonRef,
326
+ xstyle: [isOpen && styles.triggerOpen, button.xstyle, isFocusRingSuppressed && focusOutlineStyles.suppressed],
327
+ tooltip: isOpen ? undefined : button.tooltip,
328
+ endContent: resolvedEndContent,
329
+ onPointerDown: event => {
330
+ button.onPointerDown?.(event);
331
+ openModalityRef.current = 'pointer';
332
+ },
333
+ onKeyDown: event => {
334
+ button.onKeyDown?.(event);
335
+ if (event.key === 'ArrowDown' || event.key === 'Enter' || event.key === ' ') {
336
+ openModalityRef.current = 'keyboard';
337
+ }
338
+ },
339
+ onFocus: event => {
340
+ button.onFocus?.(event);
341
+ onFocusReturnTargetFocus();
342
+ },
343
+ onClick: () => {
344
+ onClick?.();
345
+ setOpen(!isOpen);
346
+ },
347
+ "aria-haspopup": "dialog",
348
+ "aria-expanded": isOpen,
349
+ "data-testid": testId
350
+ }), /*#__PURE__*/_jsx(MenuBottomSheet, {
351
+ isOpen: isOpen,
352
+ onOpenChange: setOpen,
353
+ finalFocusRef: buttonRef,
354
+ label: sheetLabel,
355
+ children: /*#__PURE__*/_jsxs("div", {
356
+ ref: actionListRef,
357
+ ...rest,
358
+ ...mergeProps(themeProps('dropdown-menu', {
359
+ presentation: 'bottom-sheet'
360
+ }), stylex.props(bottomSheetStyles.content, xstyle), className, style),
361
+ children: [/*#__PURE__*/_jsxs("div", {
362
+ ...{
363
+ className: "x78zum5 x1q0g3np x6s0dn4 xzye2dw x1p37lm5"
364
+ },
365
+ children: [submenuPath.length > 0 && /*#__PURE__*/_jsx(Button, {
366
+ label: backLabel,
367
+ variant: "ghost",
368
+ size: "sm",
369
+ icon: /*#__PURE__*/_jsx(Icon, {
370
+ icon: "chevronLeft",
371
+ size: "sm",
372
+ xstyle: rtlStyles.mirror
373
+ }),
374
+ isIconOnly: true,
375
+ onClick: () => setSubmenuPath(path => path.slice(0, -1))
376
+ }), /*#__PURE__*/_jsx(Heading, {
377
+ ref: viewHeadingRef,
378
+ level: 3,
379
+ tabIndex: -1,
380
+ xstyle: [bottomSheetStyles.viewHeading, submenuPath.length === 0 && bottomSheetStyles.rootHeading],
381
+ children: currentTitle
382
+ })]
383
+ }), /*#__PURE__*/_jsx(MenuBottomSheetActionList, {
384
+ items: currentItems,
385
+ onSelect: handleSelect,
386
+ onOpenSubmenu: item => setSubmenuPath(path => [...path, item])
387
+ })]
388
+ })
389
+ })]
390
+ });
391
+ }
392
+ function DropdownMenuPopover({
127
393
  button: buttonFromProps,
128
394
  isMenuOpen: controlledIsOpen,
129
395
  onOpenChange,
@@ -132,6 +398,7 @@ export function DropdownMenu({
132
398
  hasChevron = true,
133
399
  placement = 'below',
134
400
  alignment = 'start',
401
+ presentation: _presentation,
135
402
  className,
136
403
  style,
137
404
  xstyle,
@@ -160,14 +427,25 @@ export function DropdownMenu({
160
427
  const [internalIsOpen, setInternalIsOpen] = useState(false);
161
428
  const isControlled = controlledIsOpen !== undefined;
162
429
  const isOpen = isControlled ? controlledIsOpen : internalIsOpen;
430
+ useEffect(() => {
431
+ trackInteractionModality();
432
+ }, []);
163
433
 
164
- // Close menu + return focus to trigger
434
+ // Keyboard dismissal returns focus to the trigger. Pointer dismissal leaves
435
+ // focus where the browser put it; Safari can otherwise paint a focus-visible
436
+ // ring on the trigger after a touch selection. Native popover restoration
437
+ // can happen before `toggle`, so explicitly blur that pointer-restored case.
165
438
  const handleLayerHide = useCallback(() => {
166
439
  onOpenChange?.(false);
167
440
  if (!isControlled) {
168
441
  setInternalIsOpen(false);
169
442
  }
170
- buttonRef.current?.focus();
443
+ const trigger = buttonRef.current;
444
+ if (getInteractionModality() === 'keyboard') {
445
+ trigger?.focus();
446
+ } else if (document.activeElement === trigger) {
447
+ trigger?.blur();
448
+ }
171
449
  }, [isControlled, onOpenChange]);
172
450
 
173
451
  // Defer item focus until the layer has committed open, so focus restore
@@ -336,7 +614,10 @@ export function DropdownMenu({
336
614
  size: "sm",
337
615
  color: "inherit"
338
616
  }) : undefined);
339
- const popoverXstyle = menuWidth ? styles.popoverCustomWidth(menuWidth) : styles.popover;
617
+ const requestedWidthLimit = alignment === 'center' ? MENU_MAX_INLINE_SIZE_FALLBACK : MENU_POSITION_AREA_MAX_INLINE_SIZE_FALLBACK;
618
+ const resolvedMenuWidth = menuWidth ? resolveMenuWidth(menuWidth, requestedWidthLimit) : null;
619
+ const popoverXstyle = resolvedMenuWidth ? resolvedMenuWidth.property === 'inlineSize' ? styles.popoverCustomIntrinsicWidth(resolvedMenuWidth.value) : styles.popoverCustomWidth(resolvedMenuWidth.value) : alignment === 'center' ? styles.popoverCentered : styles.popoverAligned;
620
+ const isSidePlacement = placement === 'start' || placement === 'end';
340
621
  // Context for compound items
341
622
  const contextValue = useMemo(() => ({
342
623
  closeMenu,
@@ -345,6 +626,7 @@ export function DropdownMenu({
345
626
 
346
627
  // Resolve menu content: data-driven items become components
347
628
  const menuContent = props.items !== undefined ? renderDropdownItems(items) : children;
629
+ const hasOverflow = useMenuOverflow(listRef, menuContent, popover.isOpen);
348
630
  return /*#__PURE__*/_jsxs(_Fragment, {
349
631
  children: [/*#__PURE__*/_jsx(Button, {
350
632
  ...button,
@@ -360,6 +642,7 @@ export function DropdownMenu({
360
642
  /* eslint-enable react-compiler/react-compiler */
361
643
  }
362
644
  },
645
+ xstyle: [isOpen && styles.triggerOpen, button.xstyle],
363
646
  tooltip: isOpen ? undefined : button.tooltip,
364
647
  endContent: resolvedEndContent,
365
648
  onClick: handleButtonClick,
@@ -373,19 +656,19 @@ export function DropdownMenu({
373
656
  ref: listRef,
374
657
  id: menuId,
375
658
  role: "menu"
376
- // Focus target for pointer opens (not in the Tab order): holding
377
- // focus on the container keeps key events (arrows, typeahead,
378
- // Escape, Tab) inside the menu without highlighting any item.
379
- // Mirrors the DropdownMenuSubMenu flyout container.
659
+ // Pointer opens focus the container so arrows, typeahead, Escape and
660
+ // Tab remain owned by the menu without pre-highlighting an item.
661
+ // An overflowing menu joins the Tab order so its scrollable region is
662
+ // keyboard-accessible; Tab still dismisses through listKeyDown.
380
663
  ,
381
- tabIndex: -1
664
+ tabIndex: hasOverflow ? 0 : -1
382
665
  // Give the menu an accessible name from its trigger's label, so
383
666
  // screen readers announce e.g. "Actions menu" rather than an unnamed
384
667
  // menu (menus-13).
385
668
  ,
386
669
  "aria-label": button.label,
387
670
  onKeyDown: listKeyDown,
388
- ...mergeProps(themeProps('dropdown-menu'), stylex.props(styles.dropdown, xstyle), className, style),
671
+ ...mergeProps(themeProps('dropdown-menu'), stylex.props(styles.dropdown, hasOverflow && styles.scrollable, xstyle), className, style),
389
672
  children: /*#__PURE__*/_jsx(DropdownMenuContext, {
390
673
  value: contextValue,
391
674
  children: menuContent
@@ -394,8 +677,39 @@ export function DropdownMenu({
394
677
  placement,
395
678
  alignment,
396
679
  offset: spacingVars['--spacing-1'],
397
- xstyle: [popoverXstyle, layerAnimations[placement]]
680
+ xstyle: [styles.popoverViewport, alignment === 'center' ? isSidePlacement ? styles.popoverViewportBlockCentered : styles.popoverViewportCentered : [styles.popoverViewportAligned, isSidePlacement ? alignment === 'start' ? styles.popoverViewportBlockStart : styles.popoverViewportBlockEnd : alignment === 'start' ? styles.popoverViewportStart : styles.popoverViewportEnd], popoverXstyle, layerAnimations[placement]]
398
681
  })]
399
682
  });
400
683
  }
684
+ export function DropdownMenu(props) {
685
+ const {
686
+ onOpenChange
687
+ } = props;
688
+ const requestedPresentation = 'items' in props ? props.presentation ?? 'popover' : 'popover';
689
+ const resolvedPresentation = useAdaptivePresentation(requestedPresentation);
690
+ const isControlled = props.isMenuOpen !== undefined;
691
+ const [internalIsOpen, setInternalIsOpen] = useState(false);
692
+ const isOpen = isControlled ? props.isMenuOpen : internalIsOpen;
693
+ const handleOpenChange = useCallback(nextIsOpen => {
694
+ onOpenChange?.(nextIsOpen);
695
+ if (!isControlled) {
696
+ setInternalIsOpen(nextIsOpen);
697
+ }
698
+ }, [isControlled, onOpenChange]);
699
+ const sharedProps = {
700
+ ...props,
701
+ isMenuOpen: isOpen,
702
+ onOpenChange: handleOpenChange
703
+ };
704
+ if (resolvedPresentation === 'bottom-sheet' && 'items' in props && props.items !== undefined) {
705
+ return /*#__PURE__*/_jsx(DropdownMenuBottomSheet, {
706
+ ...sharedProps,
707
+ presentation: "bottom-sheet"
708
+ });
709
+ }
710
+ return /*#__PURE__*/_jsx(DropdownMenuPopover, {
711
+ ...sharedProps,
712
+ presentation: "popover"
713
+ });
714
+ }
401
715
  DropdownMenu.displayName = 'DropdownMenu';
@@ -1,7 +1,7 @@
1
1
  /** Menu size, derived from the trigger button size. */
2
2
  export type DropdownMenuSize = 'sm' | 'md' | 'lg';
3
3
  export interface DropdownMenuContextValue {
4
- /** Close the menu and return focus to trigger */
4
+ /** Close the menu; keyboard dismissal returns focus to the trigger. */
5
5
  closeMenu: () => void;
6
6
  /** Menu size derived from button size */
7
7
  menuSize: DropdownMenuSize;
@@ -1 +1 @@
1
- {"version":3,"file":"DropdownMenuContext.d.ts","sourceRoot":"","sources":["../../src/DropdownMenu/DropdownMenuContext.tsx"],"names":[],"mappings":"AAgBA,uDAAuD;AACvD,MAAM,MAAM,gBAAgB,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAElD,MAAM,WAAW,wBAAwB;IACvC,iDAAiD;IACjD,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,yCAAyC;IACzC,QAAQ,EAAE,gBAAgB,CAAC;CAC5B;AAED,eAAO,MAAM,mBAAmB,0DACsB,CAAC;AAGvD;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,wBAAwB,GAAG,IAAI,CAExE;AAMD,MAAM,WAAW,kCAAkC;IACjD,iDAAiD;IACjD,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,uEAAuE;IACvE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,qEAAqE;IACrE,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED,eAAO,MAAM,6BAA6B,oEACsB,CAAC;AAGjE;;;GAGG;AACH,wBAAgB,gCAAgC,IAAI,kCAAkC,GAAG,IAAI,CAE5F"}
1
+ {"version":3,"file":"DropdownMenuContext.d.ts","sourceRoot":"","sources":["../../src/DropdownMenu/DropdownMenuContext.tsx"],"names":[],"mappings":"AAgBA,uDAAuD;AACvD,MAAM,MAAM,gBAAgB,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAElD,MAAM,WAAW,wBAAwB;IACvC,uEAAuE;IACvE,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,yCAAyC;IACzC,QAAQ,EAAE,gBAAgB,CAAC;CAC5B;AAED,eAAO,MAAM,mBAAmB,0DACsB,CAAC;AAGvD;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,wBAAwB,GAAG,IAAI,CAExE;AAMD,MAAM,WAAW,kCAAkC;IACjD,iDAAiD;IACjD,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,uEAAuE;IACvE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,qEAAqE;IACrE,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED,eAAO,MAAM,6BAA6B,oEACsB,CAAC;AAGjE;;;GAGG;AACH,wBAAgB,gCAAgC,IAAI,kCAAkC,GAAG,IAAI,CAE5F"}
@@ -1 +1 @@
1
- {"version":3,"file":"DropdownMenuItem.d.ts","sourceRoot":"","sources":["../../src/DropdownMenu/DropdownMenuItem.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAiC,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAErE,OAAO,EAAiB,KAAK,QAAQ,EAAC,MAAM,SAAS,CAAC;AAStD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAqD5C,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CACjD,SAAS,EACT,QAAQ,GAAG,WAAW,GAAG,OAAO,CACjC;IACC,wCAAwC;IACxC,IAAI,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC5B,0BAA0B;IAC1B,KAAK,EAAE,SAAS,CAAC;IACjB,4DAA4D;IAC5D,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,mDAAmD;IACnD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gEAAgE;IAChE,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;OAGG;IACH,OAAO,CAAC,EAAE,SAAS,GAAG,aAAa,CAAC;CACrC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,IAAI,EACJ,KAAK,EACL,WAAW,EACX,OAAO,EACP,UAAkB,EAClB,UAAU,EACV,gBAAuB,EACvB,OAAmB,EACnB,MAAM,EACN,SAAS,EACT,KAAK,GACN,EAAE,qBAAqB,+BA0DvB;yBAtEe,gBAAgB"}
1
+ {"version":3,"file":"DropdownMenuItem.d.ts","sourceRoot":"","sources":["../../src/DropdownMenu/DropdownMenuItem.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAiC,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAErE,OAAO,EAAiB,KAAK,QAAQ,EAAC,MAAM,SAAS,CAAC;AAStD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAuD5C,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CACjD,SAAS,EACT,QAAQ,GAAG,WAAW,GAAG,OAAO,CACjC;IACC,wCAAwC;IACxC,IAAI,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC5B,0BAA0B;IAC1B,KAAK,EAAE,SAAS,CAAC;IACjB,4DAA4D;IAC5D,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,mDAAmD;IACnD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gEAAgE;IAChE,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;OAGG;IACH,OAAO,CAAC,EAAE,SAAS,GAAG,aAAa,CAAC;CACrC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,IAAI,EACJ,KAAK,EACL,WAAW,EACX,OAAO,EACP,UAAkB,EAClB,UAAU,EACV,gBAAuB,EACvB,OAAmB,EACnB,MAAM,EACN,SAAS,EACT,KAAK,GACN,EAAE,qBAAqB,+BA0DvB;yBAtEe,gBAAgB"}
@@ -43,7 +43,7 @@ const menuItemStyles = {
43
43
  kMv6JI: "x9ynric",
44
44
  kGuDYH: "xcr08ib",
45
45
  kMwMTN: "x1tgivj0",
46
- kWkggS: "xjbqb8w x1c52tdz",
46
+ kWkggS: "xjbqb8w x1c52tdz x1anq1lc",
47
47
  kkrTdU: "x1ypdohk x16khyan",
48
48
  k9WMMc: "x1yc453h",
49
49
  kI3sdo: "x1a2a7pz",
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * @file DropdownMenuSubMenu.tsx
3
3
  * @input React, stylex, useLayer (context mode), useListFocus, useMenuHover,
4
- * useTypeahead, Item, Icon, Spinner, DropdownMenu context + item roles.
4
+ * useTypeahead, the shared viewport-safe menu-width resolver, Item, Icon,
5
+ * Spinner, and DropdownMenu context + item roles
5
6
  * @output Exports DropdownMenuSubMenu — a single menu row that reveals a nested
6
7
  * flyout menu of its own children/items.
7
8
  * @position Sub-component; place inside a DropdownMenu (or ContextMenu)
@@ -55,7 +56,10 @@ interface DropdownMenuSubMenuBaseProps extends Pick<BaseProps, 'xstyle' | 'class
55
56
  * @default false
56
57
  */
57
58
  hasSpinner?: boolean;
58
- /** Fixed flyout width. Defaults to sizing to its content (min 160px). */
59
+ /**
60
+ * Minimum flyout width. The flyout may grow for its content but is capped to
61
+ * the available viewport space. Defaults to intrinsic sizing (min 160px).
62
+ */
59
63
  menuWidth?: number | string;
60
64
  /** Called when the flyout opens or closes. */
61
65
  onOpenChange?: (isOpen: boolean) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"DropdownMenuSubMenu.d.ts","sourceRoot":"","sources":["../../src/DropdownMenu/DropdownMenuSubMenu.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAc,EAOZ,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,OAAO,EAAuB,KAAK,QAAQ,EAAC,MAAM,SAAS,CAAC;AAoB5D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAwF5C,UAAU,4BAA6B,SAAQ,IAAI,CACjD,SAAS,EACT,QAAQ,GAAG,WAAW,GAAG,OAAO,CACjC;IACC,2DAA2D;IAC3D,IAAI,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC5B,8CAA8C;IAC9C,KAAK,EAAE,SAAS,CAAC;IACjB,4DAA4D;IAC5D,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,8CAA8C;IAC9C,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,mCAAmC;IACnC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mCAAmC;IACnC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,wBAAyB,SAAQ,4BAA4B;IAC5E;;;;;;;;OAQG;IACH,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,wBAAwB,GAC9B,SAAS,CAqVX;yBAvVe,mBAAmB"}
1
+ {"version":3,"file":"DropdownMenuSubMenu.d.ts","sourceRoot":"","sources":["../../src/DropdownMenu/DropdownMenuSubMenu.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAc,EAOZ,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,OAAO,EAAuB,KAAK,QAAQ,EAAC,MAAM,SAAS,CAAC;AAsB5D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AA4H5C,UAAU,4BAA6B,SAAQ,IAAI,CACjD,SAAS,EACT,QAAQ,GAAG,WAAW,GAAG,OAAO,CACjC;IACC,2DAA2D;IAC3D,IAAI,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC5B,8CAA8C;IAC9C,KAAK,EAAE,SAAS,CAAC;IACjB,4DAA4D;IAC5D,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,8CAA8C;IAC9C,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,mCAAmC;IACnC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mCAAmC;IACnC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,wBAAyB,SAAQ,4BAA4B;IAC5E;;;;;;;;OAQG;IACH,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,wBAAwB,GAC9B,SAAS,CAkWX;yBApWe,mBAAmB"}