@salt-ds/lab 1.0.0-alpha.93 → 1.0.0-alpha.94

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 (131) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/css/salt-lab.css +163 -122
  3. package/dist-cjs/index.js +6 -8
  4. package/dist-cjs/index.js.map +1 -1
  5. package/dist-cjs/toolbar-next/ToolbarContentNext.css.js +6 -0
  6. package/dist-cjs/toolbar-next/ToolbarContentNext.css.js.map +1 -0
  7. package/dist-cjs/toolbar-next/ToolbarContentNext.js +32 -0
  8. package/dist-cjs/toolbar-next/ToolbarContentNext.js.map +1 -0
  9. package/dist-cjs/toolbar-next/ToolbarNext.css.js +6 -0
  10. package/dist-cjs/toolbar-next/ToolbarNext.css.js.map +1 -0
  11. package/dist-cjs/toolbar-next/ToolbarNext.js +394 -0
  12. package/dist-cjs/toolbar-next/ToolbarNext.js.map +1 -0
  13. package/dist-cjs/toolbar-next/ToolbarNextOverflow.css.js +6 -0
  14. package/dist-cjs/toolbar-next/ToolbarNextOverflow.css.js.map +1 -0
  15. package/dist-cjs/toolbar-next/ToolbarNextOverflow.js +705 -0
  16. package/dist-cjs/toolbar-next/ToolbarNextOverflow.js.map +1 -0
  17. package/dist-cjs/toolbar-next/ToolbarNextOverflowFloatingBoundary.js +165 -0
  18. package/dist-cjs/toolbar-next/ToolbarNextOverflowFloatingBoundary.js.map +1 -0
  19. package/dist-cjs/toolbar-next/TooltrayNext.css.js +6 -0
  20. package/dist-cjs/toolbar-next/TooltrayNext.css.js.map +1 -0
  21. package/dist-cjs/toolbar-next/TooltrayNext.js +55 -0
  22. package/dist-cjs/toolbar-next/TooltrayNext.js.map +1 -0
  23. package/dist-cjs/toolbar-next/toolbarNextKeyboardUtils.js +391 -0
  24. package/dist-cjs/toolbar-next/toolbarNextKeyboardUtils.js.map +1 -0
  25. package/dist-cjs/toolbar-next/toolbarNextUtils.js +215 -0
  26. package/dist-cjs/toolbar-next/toolbarNextUtils.js.map +1 -0
  27. package/dist-cjs/toolbar-next/useToolbarNextKeyboardNavigation.js +334 -0
  28. package/dist-cjs/toolbar-next/useToolbarNextKeyboardNavigation.js.map +1 -0
  29. package/dist-cjs/toolbar-next/useToolbarNextOverflow.js +743 -0
  30. package/dist-cjs/toolbar-next/useToolbarNextOverflow.js.map +1 -0
  31. package/dist-es/index.js +3 -4
  32. package/dist-es/index.js.map +1 -1
  33. package/dist-es/toolbar-next/ToolbarContentNext.css.js +4 -0
  34. package/dist-es/toolbar-next/ToolbarContentNext.css.js.map +1 -0
  35. package/dist-es/toolbar-next/ToolbarContentNext.js +30 -0
  36. package/dist-es/toolbar-next/ToolbarContentNext.js.map +1 -0
  37. package/dist-es/toolbar-next/ToolbarNext.css.js +4 -0
  38. package/dist-es/toolbar-next/ToolbarNext.css.js.map +1 -0
  39. package/dist-es/toolbar-next/ToolbarNext.js +392 -0
  40. package/dist-es/toolbar-next/ToolbarNext.js.map +1 -0
  41. package/dist-es/toolbar-next/ToolbarNextOverflow.css.js +4 -0
  42. package/dist-es/toolbar-next/ToolbarNextOverflow.css.js.map +1 -0
  43. package/dist-es/toolbar-next/ToolbarNextOverflow.js +700 -0
  44. package/dist-es/toolbar-next/ToolbarNextOverflow.js.map +1 -0
  45. package/dist-es/toolbar-next/ToolbarNextOverflowFloatingBoundary.js +159 -0
  46. package/dist-es/toolbar-next/ToolbarNextOverflowFloatingBoundary.js.map +1 -0
  47. package/dist-es/toolbar-next/TooltrayNext.css.js +4 -0
  48. package/dist-es/toolbar-next/TooltrayNext.css.js.map +1 -0
  49. package/dist-es/toolbar-next/TooltrayNext.js +53 -0
  50. package/dist-es/toolbar-next/TooltrayNext.js.map +1 -0
  51. package/dist-es/toolbar-next/toolbarNextKeyboardUtils.js +372 -0
  52. package/dist-es/toolbar-next/toolbarNextKeyboardUtils.js.map +1 -0
  53. package/dist-es/toolbar-next/toolbarNextUtils.js +211 -0
  54. package/dist-es/toolbar-next/toolbarNextUtils.js.map +1 -0
  55. package/dist-es/toolbar-next/useToolbarNextKeyboardNavigation.js +332 -0
  56. package/dist-es/toolbar-next/useToolbarNextKeyboardNavigation.js.map +1 -0
  57. package/dist-es/toolbar-next/useToolbarNextOverflow.js +741 -0
  58. package/dist-es/toolbar-next/useToolbarNextOverflow.js.map +1 -0
  59. package/dist-types/index.d.ts +1 -1
  60. package/dist-types/toolbar-next/ToolbarContentNext.d.ts +11 -0
  61. package/dist-types/toolbar-next/ToolbarNext.d.ts +12 -0
  62. package/dist-types/toolbar-next/ToolbarNextOverflow.d.ts +34 -0
  63. package/dist-types/toolbar-next/ToolbarNextOverflowFloatingBoundary.d.ts +16 -0
  64. package/dist-types/toolbar-next/TooltrayNext.d.ts +37 -0
  65. package/dist-types/toolbar-next/index.d.ts +3 -0
  66. package/dist-types/toolbar-next/toolbarNextKeyboardUtils.d.ts +39 -0
  67. package/dist-types/toolbar-next/toolbarNextUtils.d.ts +42 -0
  68. package/dist-types/toolbar-next/useToolbarNextKeyboardNavigation.d.ts +41 -0
  69. package/dist-types/toolbar-next/useToolbarNextOverflow.d.ts +37 -0
  70. package/package.json +2 -2
  71. package/dist-cjs/tree/Tree.css.js +0 -6
  72. package/dist-cjs/tree/Tree.css.js.map +0 -1
  73. package/dist-cjs/tree/Tree.js +0 -303
  74. package/dist-cjs/tree/Tree.js.map +0 -1
  75. package/dist-cjs/tree/TreeContext.js +0 -31
  76. package/dist-cjs/tree/TreeContext.js.map +0 -1
  77. package/dist-cjs/tree/TreeNode.css.js +0 -6
  78. package/dist-cjs/tree/TreeNode.css.js.map +0 -1
  79. package/dist-cjs/tree/TreeNode.js +0 -103
  80. package/dist-cjs/tree/TreeNode.js.map +0 -1
  81. package/dist-cjs/tree/TreeNodeExpansionIcon.css.js +0 -6
  82. package/dist-cjs/tree/TreeNodeExpansionIcon.css.js.map +0 -1
  83. package/dist-cjs/tree/TreeNodeExpansionIcon.js +0 -62
  84. package/dist-cjs/tree/TreeNodeExpansionIcon.js.map +0 -1
  85. package/dist-cjs/tree/TreeNodeLabel.css.js +0 -6
  86. package/dist-cjs/tree/TreeNodeLabel.css.js.map +0 -1
  87. package/dist-cjs/tree/TreeNodeLabel.js +0 -26
  88. package/dist-cjs/tree/TreeNodeLabel.js.map +0 -1
  89. package/dist-cjs/tree/TreeNodeTrigger.css.js +0 -6
  90. package/dist-cjs/tree/TreeNodeTrigger.css.js.map +0 -1
  91. package/dist-cjs/tree/TreeNodeTrigger.js +0 -153
  92. package/dist-cjs/tree/TreeNodeTrigger.js.map +0 -1
  93. package/dist-cjs/tree/treeModel.js +0 -61
  94. package/dist-cjs/tree/treeModel.js.map +0 -1
  95. package/dist-cjs/tree/useTree.js +0 -337
  96. package/dist-cjs/tree/useTree.js.map +0 -1
  97. package/dist-es/tree/Tree.css.js +0 -4
  98. package/dist-es/tree/Tree.css.js.map +0 -1
  99. package/dist-es/tree/Tree.js +0 -301
  100. package/dist-es/tree/Tree.js.map +0 -1
  101. package/dist-es/tree/TreeContext.js +0 -26
  102. package/dist-es/tree/TreeContext.js.map +0 -1
  103. package/dist-es/tree/TreeNode.css.js +0 -4
  104. package/dist-es/tree/TreeNode.css.js.map +0 -1
  105. package/dist-es/tree/TreeNode.js +0 -101
  106. package/dist-es/tree/TreeNode.js.map +0 -1
  107. package/dist-es/tree/TreeNodeExpansionIcon.css.js +0 -4
  108. package/dist-es/tree/TreeNodeExpansionIcon.css.js.map +0 -1
  109. package/dist-es/tree/TreeNodeExpansionIcon.js +0 -60
  110. package/dist-es/tree/TreeNodeExpansionIcon.js.map +0 -1
  111. package/dist-es/tree/TreeNodeLabel.css.js +0 -4
  112. package/dist-es/tree/TreeNodeLabel.css.js.map +0 -1
  113. package/dist-es/tree/TreeNodeLabel.js +0 -24
  114. package/dist-es/tree/TreeNodeLabel.js.map +0 -1
  115. package/dist-es/tree/TreeNodeTrigger.css.js +0 -4
  116. package/dist-es/tree/TreeNodeTrigger.css.js.map +0 -1
  117. package/dist-es/tree/TreeNodeTrigger.js +0 -151
  118. package/dist-es/tree/TreeNodeTrigger.js.map +0 -1
  119. package/dist-es/tree/treeModel.js +0 -57
  120. package/dist-es/tree/treeModel.js.map +0 -1
  121. package/dist-es/tree/useTree.js +0 -335
  122. package/dist-es/tree/useTree.js.map +0 -1
  123. package/dist-types/tree/Tree.d.ts +0 -36
  124. package/dist-types/tree/TreeContext.d.ts +0 -77
  125. package/dist-types/tree/TreeNode.d.ts +0 -25
  126. package/dist-types/tree/TreeNodeExpansionIcon.d.ts +0 -4
  127. package/dist-types/tree/TreeNodeLabel.d.ts +0 -4
  128. package/dist-types/tree/TreeNodeTrigger.d.ts +0 -8
  129. package/dist-types/tree/index.d.ts +0 -4
  130. package/dist-types/tree/treeModel.d.ts +0 -24
  131. package/dist-types/tree/useTree.d.ts +0 -68
@@ -0,0 +1,700 @@
1
+ import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
2
+ import { offset, size, flip, shift, useInteractions, useClick, useDismiss } from '@floating-ui/react';
3
+ import { makePrefixer, useIcon, useForkRef, useId, useFloatingUI, useFloatingComponent, useIsomorphicLayoutEffect, Button } from '@salt-ds/core';
4
+ import { useComponentCssInjection } from '@salt-ds/styles';
5
+ import { useWindow } from '@salt-ds/window';
6
+ import { clsx } from 'clsx';
7
+ import { compute } from 'compute-scroll-into-view';
8
+ import { useState, useRef, useCallback, useEffect, cloneElement, Children, isValidElement } from 'react';
9
+ import { createPortal } from 'react-dom';
10
+ import { ToolbarContentNext } from './ToolbarContentNext.js';
11
+ import css_248z from './ToolbarNextOverflow.css.js';
12
+ import { useToolbarNextOverflowFloatingBoundary, isTargetInsideOverflowBoundary, getToolbarNextOverflowBoundaryKey, ToolbarNextOverflowFloatingComponentProvider } from './ToolbarNextOverflowFloatingBoundary.js';
13
+ import { scheduleToolbarNextFocus, shouldToolbarNextPreserveNativeTab, getDocumentFocusableElements, TOOLBAR_NEXT_SCOPE_ROOT_ATTR, getToolbarNextTabMoveTarget, getToolbarNextFocusMemory, TOOLBAR_NEXT_OVERFLOW_TRIGGER_ATTR, TOOLBAR_NEXT_GROUP_KEY_ATTR, toolbarNextFocusableSelector, TOOLBAR_NEXT_ITEM_ATTR, getToolbarNextScopeFocusableElements } from './toolbarNextKeyboardUtils.js';
14
+ import { buildContentOverflowRenderSlots } from './toolbarNextUtils.js';
15
+ import { useToolbarNextKeyboardNavigation } from './useToolbarNextKeyboardNavigation.js';
16
+
17
+ const withBaseName = makePrefixer("saltToolbarNextOverflow");
18
+ const toolbarNextStatefulFocusRootSelector = [
19
+ ".saltDateInput-focused",
20
+ ".saltInput-focused"
21
+ ].join(", ");
22
+ const toolbarNextOverflowFocusScrollRootSelector = [
23
+ ".saltComboBox",
24
+ ".saltDateInput",
25
+ ".saltDropdown",
26
+ ".saltInput",
27
+ ".saltSwitch"
28
+ ].join(", ");
29
+ function createToolbarNextFocusEvent(eventName, target, relatedTarget) {
30
+ var _a;
31
+ const FocusEventCtor = (_a = target.ownerDocument.defaultView) == null ? void 0 : _a.FocusEvent;
32
+ const eventInit = {
33
+ bubbles: eventName === "focusout",
34
+ relatedTarget
35
+ };
36
+ return FocusEventCtor ? new FocusEventCtor(eventName, eventInit) : new Event(eventName, eventInit);
37
+ }
38
+ function notifyToolbarNextReparentedFocusLoss(mountNode) {
39
+ const activeElement = mountNode.ownerDocument.activeElement;
40
+ if (mountNode.contains(activeElement)) {
41
+ return;
42
+ }
43
+ const staleFocusTargets = Array.from(
44
+ mountNode.querySelectorAll(
45
+ toolbarNextStatefulFocusRootSelector
46
+ )
47
+ ).map(
48
+ (root) => root.querySelector(toolbarNextFocusableSelector)
49
+ ).filter((target) => target != null);
50
+ for (const target of staleFocusTargets) {
51
+ const relatedTarget = activeElement instanceof Element ? activeElement : null;
52
+ target.dispatchEvent(
53
+ createToolbarNextFocusEvent("blur", target, relatedTarget)
54
+ );
55
+ target.dispatchEvent(
56
+ createToolbarNextFocusEvent("focusout", target, relatedTarget)
57
+ );
58
+ }
59
+ }
60
+ function getToolbarNextOverflowFocusScrollTarget(target) {
61
+ const itemRoot = target.closest(`[${TOOLBAR_NEXT_ITEM_ATTR}]`);
62
+ const controlRoot = target.closest(
63
+ toolbarNextOverflowFocusScrollRootSelector
64
+ );
65
+ return controlRoot && (itemRoot == null ? void 0 : itemRoot.contains(controlRoot)) ? controlRoot : target;
66
+ }
67
+ function getToolbarNextOverflowPanelInlinePadding(target) {
68
+ var _a;
69
+ const panelContent = target.closest(
70
+ `[${TOOLBAR_NEXT_SCOPE_ROOT_ATTR}]`
71
+ );
72
+ const styles = (_a = panelContent == null ? void 0 : panelContent.ownerDocument.defaultView) == null ? void 0 : _a.getComputedStyle(panelContent);
73
+ return {
74
+ left: Number.parseFloat((styles == null ? void 0 : styles.paddingLeft) ?? "0") || 0,
75
+ right: Number.parseFloat((styles == null ? void 0 : styles.paddingRight) ?? "0") || 0
76
+ };
77
+ }
78
+ function scrollToolbarNextOverflowTargetIntoView(panel, target) {
79
+ if (!panel || !panel.contains(target)) {
80
+ return;
81
+ }
82
+ const scrollTarget = getToolbarNextOverflowFocusScrollTarget(target);
83
+ const actions = compute(scrollTarget, {
84
+ block: "nearest",
85
+ boundary: panel,
86
+ inline: "nearest",
87
+ scrollMode: "if-needed"
88
+ });
89
+ for (const { el, left, top } of actions) {
90
+ if (el === panel) {
91
+ const targetRect = scrollTarget.getBoundingClientRect();
92
+ const panelRect = panel.getBoundingClientRect();
93
+ const viewportLeft = panelRect.left + panel.clientLeft;
94
+ const viewportRight = viewportLeft + panel.clientWidth;
95
+ const padding = getToolbarNextOverflowPanelInlinePadding(scrollTarget);
96
+ const nextLeft = targetRect.left < viewportLeft + padding.left ? left - padding.left : targetRect.right > viewportRight - padding.right ? left + padding.right : left;
97
+ el.scrollLeft = Math.max(0, nextLeft);
98
+ } else {
99
+ el.scrollLeft = left;
100
+ }
101
+ el.scrollTop = top;
102
+ }
103
+ }
104
+ function canSeedOverflowFocusMemory(focusMemory, group) {
105
+ return (focusMemory == null ? void 0 : focusMemory.type) === "item" && group.items.some((item) => item.id === focusMemory.itemId);
106
+ }
107
+ function ToolbarNextOverflowItemOwner({
108
+ host,
109
+ item
110
+ }) {
111
+ const targetWindow = useWindow();
112
+ const [mountNode, setMountNode] = useState(null);
113
+ const mainToolbarTabIndexMemoryRef = useRef(
114
+ /* @__PURE__ */ new WeakMap()
115
+ );
116
+ const lastOverflowBoundaryKeyRef = useRef(null);
117
+ const currentOverflowBoundaryKey = getToolbarNextOverflowBoundaryKey(host);
118
+ if (host) {
119
+ lastOverflowBoundaryKeyRef.current = currentOverflowBoundaryKey;
120
+ }
121
+ const boundaryKey = host ? currentOverflowBoundaryKey : lastOverflowBoundaryKeyRef.current;
122
+ useIsomorphicLayoutEffect(() => {
123
+ const nextMountNode = targetWindow == null ? void 0 : targetWindow.document.createElement("div");
124
+ if (!nextMountNode) {
125
+ return;
126
+ }
127
+ nextMountNode.className = withBaseName("contentHost");
128
+ setMountNode(nextMountNode);
129
+ return () => {
130
+ var _a;
131
+ (_a = nextMountNode.parentElement) == null ? void 0 : _a.removeChild(nextMountNode);
132
+ };
133
+ }, [targetWindow]);
134
+ useIsomorphicLayoutEffect(() => {
135
+ var _a, _b;
136
+ if (!mountNode) {
137
+ return;
138
+ }
139
+ if (host) {
140
+ if (mountNode.parentElement !== host) {
141
+ host.appendChild(mountNode);
142
+ notifyToolbarNextReparentedFocusLoss(mountNode);
143
+ }
144
+ const isMainToolbarHost = ((_a = host.closest(`[${TOOLBAR_NEXT_SCOPE_ROOT_ATTR}]`)) == null ? void 0 : _a.getAttribute(TOOLBAR_NEXT_SCOPE_ROOT_ATTR)) === "main";
145
+ if (isMainToolbarHost) {
146
+ const focusableElements = Array.from(
147
+ mountNode.querySelectorAll(toolbarNextFocusableSelector)
148
+ );
149
+ for (const element of focusableElements) {
150
+ const rememberedTabIndex = mainToolbarTabIndexMemoryRef.current.get(element);
151
+ if (rememberedTabIndex !== void 0) {
152
+ if (rememberedTabIndex == null) {
153
+ element.removeAttribute("tabindex");
154
+ } else {
155
+ element.setAttribute("tabindex", rememberedTabIndex);
156
+ }
157
+ }
158
+ }
159
+ for (const element of focusableElements) {
160
+ mainToolbarTabIndexMemoryRef.current.set(
161
+ element,
162
+ element.getAttribute("tabindex")
163
+ );
164
+ }
165
+ }
166
+ return;
167
+ }
168
+ notifyToolbarNextReparentedFocusLoss(mountNode);
169
+ (_b = mountNode.parentElement) == null ? void 0 : _b.removeChild(mountNode);
170
+ }, [host, mountNode]);
171
+ if (!mountNode) {
172
+ return null;
173
+ }
174
+ const clonedItem = cloneElement(
175
+ item.element,
176
+ {
177
+ [TOOLBAR_NEXT_GROUP_KEY_ATTR]: item.overflowGroupKey,
178
+ [TOOLBAR_NEXT_ITEM_ATTR]: item.id
179
+ }
180
+ );
181
+ const itemContent = /* @__PURE__ */ jsx(ToolbarNextOverflowFloatingComponentProvider, { boundaryKey, children: clonedItem });
182
+ return createPortal(itemContent, mountNode);
183
+ }
184
+ function ToolbarNextOverflowOwners({
185
+ hostNodes,
186
+ items
187
+ }) {
188
+ return /* @__PURE__ */ jsx(Fragment, { children: items.map((item) => /* @__PURE__ */ jsx(
189
+ ToolbarNextOverflowItemOwner,
190
+ {
191
+ host: hostNodes[item.id] ?? null,
192
+ item
193
+ },
194
+ item.id
195
+ )) });
196
+ }
197
+ function cloneDecorations(itemId, decorations, slot) {
198
+ return Children.toArray(decorations).flatMap((decoration) => {
199
+ if (!isValidElement(decoration)) {
200
+ return [];
201
+ }
202
+ return [
203
+ cloneElement(decoration, {
204
+ key: `${itemId}-${slot}-${String(
205
+ decoration.key ?? (typeof decoration.type === "string" ? decoration.type : "decoration")
206
+ )}`
207
+ })
208
+ ];
209
+ });
210
+ }
211
+ function ToolbarNextOverflowTriggerContent({
212
+ label,
213
+ named
214
+ }) {
215
+ const { OverflowIcon } = useIcon();
216
+ if (named) {
217
+ return /* @__PURE__ */ jsx(Fragment, { children: label });
218
+ }
219
+ return /* @__PURE__ */ jsx(OverflowIcon, { "aria-hidden": true });
220
+ }
221
+ function getOverflowTriggerLabel(group) {
222
+ return group.named ? `${group.label} overflow. Hidden controls.` : "Overflow. Hidden controls.";
223
+ }
224
+ function ToolbarNextOverflowMenu({
225
+ focusMemoryRef,
226
+ getItemHostRef,
227
+ group,
228
+ onItemFocus
229
+ }) {
230
+ var _a, _b;
231
+ const panelId = useId();
232
+ const [open, setOpen] = useState(false);
233
+ const triggerRef = useRef(null);
234
+ const panelRef = useRef(null);
235
+ const panelContentRef = useRef(null);
236
+ const [panelContentNode, setPanelContentNode] = useState(null);
237
+ const wasOpenRef = useRef(false);
238
+ const focusedOpenPanelRef = useRef(false);
239
+ const openModalityRef = useRef(null);
240
+ const floatingBoundary = useToolbarNextOverflowFloatingBoundary();
241
+ const {
242
+ focusEntryTarget,
243
+ handleScopeBlur,
244
+ handleScopeFocus,
245
+ handleScopeKeyDown,
246
+ handleScopePointerDown,
247
+ rememberedFocusRef
248
+ } = useToolbarNextKeyboardNavigation({
249
+ includeTabIndexMinusOne: true,
250
+ items: group.items,
251
+ scopeRef: panelContentRef
252
+ });
253
+ const { refs, x, y, strategy, context, elements } = useFloatingUI({
254
+ open,
255
+ onOpenChange(nextOpen, _, reason) {
256
+ setOpen(nextOpen);
257
+ if (!nextOpen) {
258
+ openModalityRef.current = null;
259
+ }
260
+ if (!nextOpen && reason === "escape-key") {
261
+ scheduleToolbarNextFocus(triggerRef.current);
262
+ }
263
+ },
264
+ placement: "bottom-end",
265
+ middleware: [
266
+ offset(1),
267
+ size({
268
+ apply({ elements: elements2, availableHeight }) {
269
+ Object.assign(elements2.floating.style, {
270
+ maxHeight: `${availableHeight}px`
271
+ });
272
+ }
273
+ }),
274
+ flip(),
275
+ shift({
276
+ padding: 8
277
+ })
278
+ ]
279
+ });
280
+ const { getFloatingProps, getReferenceProps } = useInteractions([
281
+ useClick(context),
282
+ useDismiss(context, {
283
+ escapeKey: false,
284
+ outsidePress(event) {
285
+ return !isTargetInsideOverflowBoundary(
286
+ panelContentRef.current,
287
+ floatingBoundary,
288
+ group.key,
289
+ event.target
290
+ );
291
+ }
292
+ })
293
+ ]);
294
+ const handleTriggerKeyDown = useCallback(
295
+ (event) => {
296
+ if (!open && ["Enter", " "].includes(event.key)) {
297
+ event.preventDefault();
298
+ openModalityRef.current = "keyboard";
299
+ setOpen(true);
300
+ return;
301
+ }
302
+ if (open && event.key === "Escape") {
303
+ event.preventDefault();
304
+ setOpen(false);
305
+ scheduleToolbarNextFocus(triggerRef.current);
306
+ }
307
+ },
308
+ [open]
309
+ );
310
+ const handleTriggerPointerDown = useCallback(
311
+ (event) => {
312
+ if (!open && event.button === 0) {
313
+ openModalityRef.current = "pointer";
314
+ }
315
+ },
316
+ [open]
317
+ );
318
+ const handleTriggerMouseDown = useCallback(
319
+ (event) => {
320
+ if (!open && event.button === 0) {
321
+ openModalityRef.current = "pointer";
322
+ }
323
+ },
324
+ [open]
325
+ );
326
+ const handlePanelKeyDown = useCallback((event) => {
327
+ var _a2;
328
+ if (event.key === "Tab") {
329
+ const panelContent = panelContentRef.current;
330
+ const target = event.target;
331
+ if (panelContent && target instanceof HTMLElement && shouldToolbarNextPreserveNativeTab(target)) {
332
+ const focusableElements = getDocumentFocusableElements(
333
+ panelContent.ownerDocument
334
+ );
335
+ const currentIndex = focusableElements.indexOf(target);
336
+ const nextFocusTarget = focusableElements[currentIndex + (event.shiftKey ? -1 : 1)];
337
+ if (currentIndex !== -1 && nextFocusTarget && panelContent.contains(nextFocusTarget)) {
338
+ return;
339
+ }
340
+ }
341
+ }
342
+ if (event.key === "Tab" && !event.shiftKey) {
343
+ const toolbarRoot = (_a2 = triggerRef.current) == null ? void 0 : _a2.closest(
344
+ `[${TOOLBAR_NEXT_SCOPE_ROOT_ATTR}]`
345
+ );
346
+ const nextFocusTarget = toolbarRoot ? getToolbarNextTabMoveTarget(toolbarRoot, false) : null;
347
+ if (nextFocusTarget) {
348
+ event.preventDefault();
349
+ event.stopPropagation();
350
+ setOpen(false);
351
+ scheduleToolbarNextFocus(nextFocusTarget);
352
+ }
353
+ return;
354
+ }
355
+ if (event.key === "Tab" && event.shiftKey) {
356
+ event.preventDefault();
357
+ event.stopPropagation();
358
+ setOpen(false);
359
+ scheduleToolbarNextFocus(triggerRef.current);
360
+ return;
361
+ }
362
+ if (event.key === "Escape") {
363
+ event.preventDefault();
364
+ event.stopPropagation();
365
+ setOpen(false);
366
+ scheduleToolbarNextFocus(triggerRef.current);
367
+ }
368
+ }, []);
369
+ const handleTriggerRef = useForkRef(
370
+ triggerRef,
371
+ refs.setReference
372
+ );
373
+ const handlePanelRef = useForkRef(panelRef, refs.setFloating);
374
+ const handlePanelContentRef = useForkRef(
375
+ panelContentRef,
376
+ setPanelContentNode
377
+ );
378
+ const handlePanelFocus = useCallback(
379
+ (event) => {
380
+ handleScopeFocus(event);
381
+ const panelContent = panelContentRef.current;
382
+ const target = event.target;
383
+ if (!panelContent || !(target instanceof HTMLElement)) {
384
+ return;
385
+ }
386
+ const focusMemory = getToolbarNextFocusMemory(panelContent, target, {
387
+ includeTabIndexMinusOne: true
388
+ });
389
+ if ((focusMemory == null ? void 0 : focusMemory.type) !== "item") {
390
+ return;
391
+ }
392
+ scrollToolbarNextOverflowTargetIntoView(panelRef.current, target);
393
+ onItemFocus == null ? void 0 : onItemFocus(focusMemory.itemId, focusMemory.controlIndex);
394
+ },
395
+ [handleScopeFocus, onItemFocus]
396
+ );
397
+ const { Component: FloatingComponent } = useFloatingComponent();
398
+ useEffect(() => {
399
+ if (open && !wasOpenRef.current) {
400
+ const externalFocusMemory = focusMemoryRef == null ? void 0 : focusMemoryRef.current;
401
+ if (canSeedOverflowFocusMemory(externalFocusMemory, group)) {
402
+ rememberedFocusRef.current = externalFocusMemory;
403
+ }
404
+ if (openModalityRef.current !== "pointer") {
405
+ focusEntryTarget();
406
+ }
407
+ }
408
+ wasOpenRef.current = open;
409
+ }, [focusEntryTarget, focusMemoryRef, group, open, rememberedFocusRef]);
410
+ useEffect(() => {
411
+ if (!open || !panelContentNode) {
412
+ return;
413
+ }
414
+ const handleFocusIn = (event) => {
415
+ handlePanelFocus(event);
416
+ };
417
+ const handleFocusOut = (event) => {
418
+ if (isTargetInsideOverflowBoundary(
419
+ panelContentRef.current,
420
+ floatingBoundary,
421
+ group.key,
422
+ event.relatedTarget
423
+ )) {
424
+ return;
425
+ }
426
+ handleScopeBlur(event);
427
+ };
428
+ const handleKeyDownCapture = (event) => {
429
+ handleScopeKeyDown(event);
430
+ };
431
+ const handlePointerDownCapture = (event) => {
432
+ handleScopePointerDown(event);
433
+ };
434
+ const handleKeyDown = (event) => {
435
+ if (!event.defaultPrevented) {
436
+ handlePanelKeyDown(event);
437
+ }
438
+ };
439
+ panelContentNode.addEventListener("focusin", handleFocusIn);
440
+ panelContentNode.addEventListener("focusout", handleFocusOut);
441
+ panelContentNode.addEventListener("keydown", handleKeyDownCapture, true);
442
+ panelContentNode.addEventListener(
443
+ "pointerdown",
444
+ handlePointerDownCapture,
445
+ true
446
+ );
447
+ panelContentNode.addEventListener("keydown", handleKeyDown);
448
+ return () => {
449
+ panelContentNode.removeEventListener("focusin", handleFocusIn);
450
+ panelContentNode.removeEventListener("focusout", handleFocusOut);
451
+ panelContentNode.removeEventListener(
452
+ "keydown",
453
+ handleKeyDownCapture,
454
+ true
455
+ );
456
+ panelContentNode.removeEventListener(
457
+ "pointerdown",
458
+ handlePointerDownCapture,
459
+ true
460
+ );
461
+ panelContentNode.removeEventListener("keydown", handleKeyDown);
462
+ };
463
+ }, [
464
+ handlePanelFocus,
465
+ handlePanelKeyDown,
466
+ handleScopeBlur,
467
+ handleScopeKeyDown,
468
+ handleScopePointerDown,
469
+ floatingBoundary,
470
+ group.key,
471
+ open,
472
+ panelContentNode
473
+ ]);
474
+ useIsomorphicLayoutEffect(() => {
475
+ if (!open) {
476
+ focusedOpenPanelRef.current = false;
477
+ return;
478
+ }
479
+ if (!panelContentNode || focusedOpenPanelRef.current || openModalityRef.current === "pointer") {
480
+ return;
481
+ }
482
+ const getPanelFocusables = () => getToolbarNextScopeFocusableElements(panelContentNode, {
483
+ includeTabIndexMinusOne: true
484
+ });
485
+ const focusEntryWhenReady = () => {
486
+ const panelFocusables = getPanelFocusables();
487
+ if (panelFocusables.length === 0) {
488
+ return false;
489
+ }
490
+ focusedOpenPanelRef.current = true;
491
+ focusEntryTarget();
492
+ return true;
493
+ };
494
+ if (focusEntryWhenReady()) {
495
+ return;
496
+ }
497
+ const panelWindow = panelContentNode.ownerDocument.defaultView;
498
+ const mutationObserverCtor = panelWindow == null ? void 0 : panelWindow.MutationObserver;
499
+ const resizeObserverCtor = panelWindow == null ? void 0 : panelWindow.ResizeObserver;
500
+ let mutationObserver = null;
501
+ let resizeObserver = null;
502
+ mutationObserver = mutationObserverCtor != null ? new mutationObserverCtor(() => {
503
+ if (focusEntryWhenReady()) {
504
+ mutationObserver == null ? void 0 : mutationObserver.disconnect();
505
+ resizeObserver == null ? void 0 : resizeObserver.disconnect();
506
+ }
507
+ }) : null;
508
+ resizeObserver = resizeObserverCtor != null ? new resizeObserverCtor(() => {
509
+ if (focusEntryWhenReady()) {
510
+ mutationObserver == null ? void 0 : mutationObserver.disconnect();
511
+ resizeObserver == null ? void 0 : resizeObserver.disconnect();
512
+ }
513
+ }) : null;
514
+ mutationObserver == null ? void 0 : mutationObserver.observe(panelContentNode, {
515
+ childList: true,
516
+ subtree: true
517
+ });
518
+ resizeObserver == null ? void 0 : resizeObserver.observe(panelContentNode);
519
+ return () => {
520
+ mutationObserver == null ? void 0 : mutationObserver.disconnect();
521
+ resizeObserver == null ? void 0 : resizeObserver.disconnect();
522
+ };
523
+ }, [focusEntryTarget, open, panelContentNode]);
524
+ return /* @__PURE__ */ jsxs(
525
+ "div",
526
+ {
527
+ className: withBaseName("menu"),
528
+ "data-overflowgroup": group.overflowGroup,
529
+ children: [
530
+ /* @__PURE__ */ jsx(
531
+ Button,
532
+ {
533
+ appearance: "transparent",
534
+ "aria-controls": panelId,
535
+ "aria-expanded": open,
536
+ "aria-label": getOverflowTriggerLabel(group),
537
+ className: withBaseName("trigger"),
538
+ ...{
539
+ [TOOLBAR_NEXT_GROUP_KEY_ATTR]: group.key,
540
+ [TOOLBAR_NEXT_OVERFLOW_TRIGGER_ATTR]: ""
541
+ },
542
+ ...getReferenceProps({
543
+ onKeyDown: handleTriggerKeyDown,
544
+ onMouseDown: handleTriggerMouseDown,
545
+ onPointerDown: handleTriggerPointerDown
546
+ }),
547
+ ref: handleTriggerRef,
548
+ sentiment: "neutral",
549
+ children: /* @__PURE__ */ jsx(
550
+ ToolbarNextOverflowTriggerContent,
551
+ {
552
+ label: group.label,
553
+ named: group.named
554
+ }
555
+ )
556
+ }
557
+ ),
558
+ /* @__PURE__ */ jsx(
559
+ FloatingComponent,
560
+ {
561
+ ...getFloatingProps({
562
+ role: "presentation"
563
+ }),
564
+ className: withBaseName("panel"),
565
+ focusManagerProps: context ? {
566
+ context,
567
+ initialFocus: -1,
568
+ returnFocus: false,
569
+ modal: false,
570
+ closeOnFocusOut: false
571
+ } : void 0,
572
+ id: panelId,
573
+ left: x ?? 0,
574
+ open,
575
+ position: strategy,
576
+ ref: handlePanelRef,
577
+ top: y ?? 0,
578
+ width: (_a = elements.floating) == null ? void 0 : _a.offsetWidth,
579
+ height: (_b = elements.floating) == null ? void 0 : _b.offsetHeight,
580
+ children: /* @__PURE__ */ jsx(
581
+ "div",
582
+ {
583
+ "aria-label": `${group.label} overflow`,
584
+ "aria-orientation": "horizontal",
585
+ className: withBaseName("panelContent"),
586
+ ...{ [TOOLBAR_NEXT_SCOPE_ROOT_ATTR]: group.key },
587
+ role: "toolbar",
588
+ ref: handlePanelContentRef,
589
+ children: group.items.map((item, index) => /* @__PURE__ */ jsxs(
590
+ "div",
591
+ {
592
+ className: withBaseName("panelItem"),
593
+ children: [
594
+ index > 0 && item.leadingDecorations.length > 0 && cloneDecorations(item.id, item.leadingDecorations, "leading"),
595
+ /* @__PURE__ */ jsx(
596
+ "div",
597
+ {
598
+ className: withBaseName("itemHost"),
599
+ ref: open ? getItemHostRef(item.id, "overflow") : null
600
+ }
601
+ ),
602
+ cloneDecorations(item.id, item.trailingDecorations, "trailing")
603
+ ]
604
+ },
605
+ `${group.id}-${item.id}`
606
+ ))
607
+ }
608
+ )
609
+ }
610
+ )
611
+ ]
612
+ }
613
+ );
614
+ }
615
+ function ToolbarNextOverflowContent({
616
+ content,
617
+ focusMemoryRef,
618
+ getItemHostRef,
619
+ getItemRef,
620
+ getNamedTriggerRef,
621
+ getContentRef,
622
+ onItemFocus,
623
+ overflowGroups,
624
+ overflowedIds
625
+ }) {
626
+ const targetWindow = useWindow();
627
+ useComponentCssInjection({
628
+ testId: "salt-toolbar-next-overflow",
629
+ css: css_248z,
630
+ window: targetWindow
631
+ });
632
+ const { className, ...contentProps } = content.props;
633
+ const handleContentRef = useForkRef(content.ref, getContentRef(content.key));
634
+ const overflowGroupByKey = new Map(
635
+ overflowGroups.map((group) => [group.key, group])
636
+ );
637
+ const renderSlots = buildContentOverflowRenderSlots(
638
+ content.items,
639
+ overflowedIds,
640
+ new Set(overflowGroups.map((group) => group.key))
641
+ );
642
+ return /* @__PURE__ */ jsx(
643
+ ToolbarContentNext,
644
+ {
645
+ ...contentProps,
646
+ "data-implicit": content.implicit || void 0,
647
+ className: clsx(className, withBaseName("content")),
648
+ position: content.position,
649
+ ref: handleContentRef,
650
+ children: renderSlots.map(
651
+ ({
652
+ item,
653
+ overflowed,
654
+ showLeadingDecorations,
655
+ showTrailingDecorations,
656
+ triggerGroupKey
657
+ }) => {
658
+ const triggerGroup = triggerGroupKey != null ? overflowGroupByKey.get(triggerGroupKey) : void 0;
659
+ return /* @__PURE__ */ jsxs(
660
+ "div",
661
+ {
662
+ className: withBaseName("slot"),
663
+ "data-align": item.align,
664
+ "data-priority": item.overflowPriority,
665
+ ref: triggerGroup ? getNamedTriggerRef(item.id) : getItemRef(item.id),
666
+ children: [
667
+ showLeadingDecorations ? cloneDecorations(item.id, item.leadingDecorations, "leading") : null,
668
+ !overflowed ? /* @__PURE__ */ jsx("div", { className: withBaseName("item"), children: /* @__PURE__ */ jsx(
669
+ "div",
670
+ {
671
+ className: withBaseName("itemHost"),
672
+ ref: getItemHostRef(item.id, "main")
673
+ }
674
+ ) }) : null,
675
+ triggerGroup ? /* @__PURE__ */ jsx("div", { className: withBaseName("item"), children: /* @__PURE__ */ jsx(
676
+ ToolbarNextOverflowMenu,
677
+ {
678
+ focusMemoryRef,
679
+ getItemHostRef,
680
+ group: triggerGroup,
681
+ onItemFocus
682
+ }
683
+ ) }) : null,
684
+ showTrailingDecorations ? cloneDecorations(
685
+ item.id,
686
+ item.trailingDecorations,
687
+ "trailing"
688
+ ) : null
689
+ ]
690
+ },
691
+ triggerGroup ? `${content.key}-${triggerGroup.id}-anchor-${item.id}` : item.id
692
+ );
693
+ }
694
+ )
695
+ }
696
+ );
697
+ }
698
+
699
+ export { ToolbarNextOverflowContent, ToolbarNextOverflowMenu, ToolbarNextOverflowOwners, ToolbarNextOverflowTriggerContent };
700
+ //# sourceMappingURL=ToolbarNextOverflow.js.map