@vuu-ui/vuu-popups 0.8.17-debug → 0.8.18-debug
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.
- package/cjs/index.js +1294 -1239
- package/cjs/index.js.map +4 -4
- package/esm/index.js +1318 -1260
- package/esm/index.js.map +4 -4
- package/index.css +41 -38
- package/index.css.map +3 -3
- package/package.json +8 -11
- package/types/dialog/Dialog.d.ts +4 -2
- package/types/menu/ContextMenu.d.ts +2 -2
- package/types/popup/Popup.d.ts +1 -1
- package/types/popup-menu/PopupMenu.d.ts +2 -2
- package/types/portal/Portal.d.ts +5 -3
package/esm/index.js
CHANGED
|
@@ -1,59 +1,11 @@
|
|
|
1
1
|
// src/dialog/Dialog.tsx
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import { useCallback, useRef as useRef2 } from "react";
|
|
5
|
-
|
|
6
|
-
// src/portal/Portal.tsx
|
|
7
|
-
import { useThemeAttributes } from "@vuu-ui/vuu-shell";
|
|
8
|
-
import { useLayoutEffect, useRef, useState } from "react";
|
|
9
|
-
import { createPortal } from "react-dom";
|
|
10
|
-
function getContainer(container) {
|
|
11
|
-
return typeof container === "function" ? container() : container;
|
|
12
|
-
}
|
|
13
|
-
var DEFAULT_ID = "vuu-portal-root";
|
|
14
|
-
var Portal = ({
|
|
15
|
-
children,
|
|
16
|
-
container: containerProp = document.body,
|
|
17
|
-
id = DEFAULT_ID,
|
|
18
|
-
onRender,
|
|
19
|
-
open = true,
|
|
20
|
-
themeAttributes
|
|
21
|
-
}) => {
|
|
22
|
-
var _a;
|
|
23
|
-
const [mounted, setMounted] = useState(false);
|
|
24
|
-
const portalRef = useRef(null);
|
|
25
|
-
const container = (_a = getContainer(containerProp)) != null ? _a : document.body;
|
|
26
|
-
const [themeClass, densityClass, dataMode] = useThemeAttributes(themeAttributes);
|
|
27
|
-
useLayoutEffect(() => {
|
|
28
|
-
const root = document.getElementById(id);
|
|
29
|
-
if (root) {
|
|
30
|
-
portalRef.current = root;
|
|
31
|
-
} else {
|
|
32
|
-
portalRef.current = document.createElement("div");
|
|
33
|
-
portalRef.current.id = id;
|
|
34
|
-
}
|
|
35
|
-
const el = portalRef.current;
|
|
36
|
-
if (!container.contains(el)) {
|
|
37
|
-
container.appendChild(el);
|
|
38
|
-
}
|
|
39
|
-
el.classList.add(themeClass, densityClass);
|
|
40
|
-
el.dataset.mode = dataMode;
|
|
41
|
-
setMounted(true);
|
|
42
|
-
}, [id, container, themeClass, densityClass, dataMode]);
|
|
43
|
-
useLayoutEffect(() => {
|
|
44
|
-
requestAnimationFrame(() => {
|
|
45
|
-
onRender == null ? void 0 : onRender();
|
|
46
|
-
});
|
|
47
|
-
}, [onRender]);
|
|
48
|
-
if (open && mounted && portalRef.current && children) {
|
|
49
|
-
return createPortal(children, portalRef.current);
|
|
50
|
-
}
|
|
51
|
-
return null;
|
|
52
|
-
};
|
|
2
|
+
import cx5 from "clsx";
|
|
3
|
+
import { useThemeAttributes } from "@vuu-ui/vuu-utils";
|
|
4
|
+
import { useCallback as useCallback2, useLayoutEffect as useLayoutEffect2, useRef as useRef2 } from "react";
|
|
53
5
|
|
|
54
6
|
// src/dialog-header/DialogHeader.tsx
|
|
55
7
|
import { Button, Text } from "@salt-ds/core";
|
|
56
|
-
import cx from "
|
|
8
|
+
import cx from "clsx";
|
|
57
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
58
10
|
var classBase = "vuuDialogHeader";
|
|
59
11
|
var DialogHeader = ({
|
|
@@ -77,1302 +29,1408 @@ var DialogHeader = ({
|
|
|
77
29
|
] });
|
|
78
30
|
};
|
|
79
31
|
|
|
80
|
-
// src/
|
|
81
|
-
import
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
32
|
+
// src/popup/popup-service.ts
|
|
33
|
+
import cx3 from "clsx";
|
|
34
|
+
import React, {
|
|
35
|
+
createElement
|
|
36
|
+
} from "react";
|
|
37
|
+
import ReactDOM2 from "react-dom";
|
|
38
|
+
|
|
39
|
+
// src/portal-deprecated/render-portal.tsx
|
|
40
|
+
import * as ReactDOM from "react-dom";
|
|
41
|
+
import cx2 from "clsx";
|
|
42
|
+
var containerId = 1;
|
|
43
|
+
var getPortalContainer = ({
|
|
85
44
|
className,
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
...props
|
|
45
|
+
dataMode,
|
|
46
|
+
x = 0,
|
|
47
|
+
y = 0,
|
|
48
|
+
win = window
|
|
91
49
|
}) => {
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
return null;
|
|
50
|
+
const el = win.document.createElement("div");
|
|
51
|
+
el.className = cx2(`vuuPopup ${containerId++}`, className);
|
|
52
|
+
el.style.cssText = `left:${x}px; top:${y}px;`;
|
|
53
|
+
if (dataMode) {
|
|
54
|
+
el.dataset.mode = dataMode;
|
|
98
55
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
DialogHeader,
|
|
102
|
-
{
|
|
103
|
-
hideCloseButton,
|
|
104
|
-
onClose: close,
|
|
105
|
-
title
|
|
106
|
-
}
|
|
107
|
-
),
|
|
108
|
-
/* @__PURE__ */ jsx2("div", { className: `${classBase2}-body`, children })
|
|
109
|
-
] }) }) });
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
// src/dialog/useDialog.tsx
|
|
113
|
-
import { useCallback as useCallback2, useState as useState2 } from "react";
|
|
114
|
-
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
115
|
-
var useDialog = () => {
|
|
116
|
-
const [dialogState, setDialogState] = useState2();
|
|
117
|
-
const handleClose = useCallback2(() => {
|
|
118
|
-
setDialogState(void 0);
|
|
119
|
-
}, []);
|
|
120
|
-
const dialog = dialogState ? /* @__PURE__ */ jsx3(
|
|
121
|
-
Dialog,
|
|
122
|
-
{
|
|
123
|
-
className: "vuDialog",
|
|
124
|
-
isOpen: true,
|
|
125
|
-
onClose: handleClose,
|
|
126
|
-
style: { maxHeight: 500 },
|
|
127
|
-
title: dialogState.title,
|
|
128
|
-
hideCloseButton: dialogState.hideCloseButton,
|
|
129
|
-
children: dialogState.content
|
|
130
|
-
}
|
|
131
|
-
) : null;
|
|
132
|
-
return {
|
|
133
|
-
dialog,
|
|
134
|
-
setDialogState
|
|
135
|
-
};
|
|
56
|
+
win.document.body.appendChild(el);
|
|
57
|
+
return el;
|
|
136
58
|
};
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
// src/menu/MenuList.tsx
|
|
142
|
-
import React2, {
|
|
143
|
-
useLayoutEffect as useLayoutEffect2,
|
|
144
|
-
useMemo as useMemo3,
|
|
145
|
-
useRef as useRef4
|
|
146
|
-
} from "react";
|
|
147
|
-
import cx3 from "classnames";
|
|
148
|
-
import { useId } from "@vuu-ui/vuu-layout";
|
|
149
|
-
|
|
150
|
-
// src/menu/use-keyboard-navigation.ts
|
|
151
|
-
import {
|
|
152
|
-
useCallback as useCallback3,
|
|
153
|
-
useMemo,
|
|
154
|
-
useRef as useRef3,
|
|
155
|
-
useState as useState3
|
|
156
|
-
} from "react";
|
|
157
|
-
|
|
158
|
-
// src/menu/utils.ts
|
|
159
|
-
var isRoot = (el) => el.closest(`[data-root='true']`) !== null;
|
|
160
|
-
var hasPopup = (el, idx) => {
|
|
161
|
-
var _a;
|
|
162
|
-
return el.ariaHasPopup === "true" && ((_a = el.dataset) == null ? void 0 : _a.idx) === `${idx}` || el.querySelector(`:scope > [data-index='${idx}'][aria-haspopup='true']`) !== null;
|
|
59
|
+
var createContainer = (props) => getPortalContainer(props);
|
|
60
|
+
var renderPortal = (component, container, x, y, onRender) => {
|
|
61
|
+
container.style.cssText = `left:${x}px; top:${y}px;position: absolute;`;
|
|
62
|
+
ReactDOM.render(component, container, onRender);
|
|
163
63
|
};
|
|
164
64
|
|
|
165
|
-
// src/
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
65
|
+
// src/popup/popup-service.ts
|
|
66
|
+
var _dialogOpen = false;
|
|
67
|
+
var _popups = [];
|
|
68
|
+
var reasonIsMenuAction = (reason) => (reason == null ? void 0 : reason.type) === "menu-action";
|
|
69
|
+
var reasonIsClickAway = (reason) => (reason == null ? void 0 : reason.type) === "click-away";
|
|
70
|
+
function specialKeyHandler(e) {
|
|
71
|
+
if (e.key === "Esc") {
|
|
72
|
+
if (_popups.length) {
|
|
73
|
+
closeAllPopups();
|
|
74
|
+
} else if (_dialogOpen) {
|
|
75
|
+
const dialogRoot = document.body.querySelector(".vuuDialog");
|
|
76
|
+
if (dialogRoot) {
|
|
77
|
+
ReactDOM2.unmountComponentAtNode(dialogRoot);
|
|
78
|
+
}
|
|
171
79
|
}
|
|
172
80
|
}
|
|
173
|
-
return result;
|
|
174
81
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
var arrowLeftRightKeys = /* @__PURE__ */ new Set(["ArrowRight", "ArrowLeft"]);
|
|
180
|
-
var verticalNavigationKeys = /* @__PURE__ */ new Set(["Home", "End", "ArrowDown", "ArrowUp"]);
|
|
181
|
-
var horizontalNavigationKeys = /* @__PURE__ */ new Set([
|
|
182
|
-
"Home",
|
|
183
|
-
"End",
|
|
184
|
-
"ArrowRight",
|
|
185
|
-
"ArrowLeft"
|
|
186
|
-
]);
|
|
187
|
-
var functionKeys = /* @__PURE__ */ new Set([
|
|
188
|
-
"F1",
|
|
189
|
-
"F2",
|
|
190
|
-
"F3",
|
|
191
|
-
"F4",
|
|
192
|
-
"F5",
|
|
193
|
-
"F6",
|
|
194
|
-
"F7",
|
|
195
|
-
"F8",
|
|
196
|
-
"F9",
|
|
197
|
-
"F10",
|
|
198
|
-
"F11",
|
|
199
|
-
"F12"
|
|
200
|
-
]);
|
|
201
|
-
var specialKeys = union(
|
|
202
|
-
actionKeys,
|
|
203
|
-
horizontalNavigationKeys,
|
|
204
|
-
verticalNavigationKeys,
|
|
205
|
-
arrowLeftRightKeys,
|
|
206
|
-
functionKeys,
|
|
207
|
-
focusKeys
|
|
208
|
-
);
|
|
209
|
-
var isNavigationKey = ({ key }, orientation = "vertical") => {
|
|
210
|
-
const navigationKeys = orientation === "vertical" ? verticalNavigationKeys : horizontalNavigationKeys;
|
|
211
|
-
return navigationKeys.has(key);
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
// src/menu/use-keyboard-navigation.ts
|
|
215
|
-
import { isValidNumber } from "@vuu-ui/vuu-utils";
|
|
216
|
-
var useKeyboardNavigation = ({
|
|
217
|
-
autoHighlightFirstItem = false,
|
|
218
|
-
count,
|
|
219
|
-
defaultHighlightedIdx,
|
|
220
|
-
highlightedIndex: highlightedIndexProp,
|
|
221
|
-
onActivate,
|
|
222
|
-
onHighlight,
|
|
223
|
-
// onKeyDown,
|
|
224
|
-
onCloseMenu,
|
|
225
|
-
onOpenMenu
|
|
226
|
-
}) => {
|
|
227
|
-
var _a;
|
|
228
|
-
if (isValidNumber(highlightedIndexProp) && isValidNumber(defaultHighlightedIdx)) {
|
|
229
|
-
throw Error(
|
|
230
|
-
"useKeyboardNavigation do not pass values for both highlightedIndex and defaultHighlightedIdx"
|
|
82
|
+
function outsideClickHandler(e) {
|
|
83
|
+
if (_popups.length) {
|
|
84
|
+
const popupContainers = document.body.querySelectorAll(
|
|
85
|
+
".vuuPopup,#vuu-portal-root"
|
|
231
86
|
);
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
(_a = defaultHighlightedIdx != null ? defaultHighlightedIdx : highlightedIndexProp) != null ? _a : autoHighlightFirstItem ? 0 : -1
|
|
236
|
-
);
|
|
237
|
-
const [, forceRender] = useState3(null);
|
|
238
|
-
const setHighlightedIdx = useCallback3(
|
|
239
|
-
(idx) => {
|
|
240
|
-
highlightedIndexRef.current = idx;
|
|
241
|
-
onHighlight == null ? void 0 : onHighlight(idx);
|
|
242
|
-
forceRender({});
|
|
243
|
-
},
|
|
244
|
-
[onHighlight]
|
|
245
|
-
);
|
|
246
|
-
const setHighlightedIndex = useCallback3(
|
|
247
|
-
(idx) => {
|
|
248
|
-
if (idx !== highlightedIndexRef.current) {
|
|
249
|
-
if (!controlledHighlighting) {
|
|
250
|
-
setHighlightedIdx(idx);
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
},
|
|
254
|
-
[controlledHighlighting, setHighlightedIdx]
|
|
255
|
-
);
|
|
256
|
-
const keyBoardNavigation = useRef3(true);
|
|
257
|
-
const ignoreFocus = useRef3(false);
|
|
258
|
-
const setIgnoreFocus = (value) => ignoreFocus.current = value;
|
|
259
|
-
const highlightedIndex = controlledHighlighting ? highlightedIndexProp : highlightedIndexRef.current;
|
|
260
|
-
const navigateChildldItems = useCallback3(
|
|
261
|
-
(e) => {
|
|
262
|
-
const nextIdx = nextItemIdx(count, e.key, highlightedIndexRef.current);
|
|
263
|
-
if (nextIdx !== highlightedIndexRef.current) {
|
|
264
|
-
setHighlightedIndex(nextIdx);
|
|
265
|
-
}
|
|
266
|
-
},
|
|
267
|
-
[count, setHighlightedIndex]
|
|
268
|
-
);
|
|
269
|
-
const handleKeyDown = useCallback3(
|
|
270
|
-
(e) => {
|
|
271
|
-
if (isNavigationKey(e)) {
|
|
272
|
-
e.preventDefault();
|
|
273
|
-
e.stopPropagation();
|
|
274
|
-
keyBoardNavigation.current = true;
|
|
275
|
-
navigateChildldItems(e);
|
|
276
|
-
} else if ((e.key === "ArrowRight" || e.key === "Enter") && hasPopup(e.target, highlightedIndex)) {
|
|
277
|
-
const menuEl = e.target;
|
|
278
|
-
const menuItemEl = menuEl.querySelector(
|
|
279
|
-
`:scope > [data-index='${highlightedIndex}']`
|
|
280
|
-
);
|
|
281
|
-
if (menuItemEl) {
|
|
282
|
-
onOpenMenu == null ? void 0 : onOpenMenu(menuItemEl, true);
|
|
283
|
-
}
|
|
284
|
-
} else if (e.key === "ArrowLeft" && !isRoot(e.target)) {
|
|
285
|
-
onCloseMenu(highlightedIndex);
|
|
286
|
-
} else if (e.key === "Enter") {
|
|
287
|
-
e.preventDefault();
|
|
288
|
-
e.stopPropagation();
|
|
289
|
-
onActivate && onActivate(highlightedIndex);
|
|
290
|
-
} else if (e.key === "Tab") {
|
|
291
|
-
onCloseMenu(-1);
|
|
87
|
+
for (let i = 0; i < popupContainers.length; i++) {
|
|
88
|
+
if (popupContainers[i].contains(e.target)) {
|
|
89
|
+
return;
|
|
292
90
|
}
|
|
293
|
-
},
|
|
294
|
-
[
|
|
295
|
-
highlightedIndex,
|
|
296
|
-
navigateChildldItems,
|
|
297
|
-
onActivate,
|
|
298
|
-
onCloseMenu,
|
|
299
|
-
onOpenMenu
|
|
300
|
-
]
|
|
301
|
-
);
|
|
302
|
-
const listProps = useMemo(
|
|
303
|
-
() => ({
|
|
304
|
-
onFocus: () => {
|
|
305
|
-
if (highlightedIndex === -1) {
|
|
306
|
-
setHighlightedIdx(0);
|
|
307
|
-
}
|
|
308
|
-
},
|
|
309
|
-
onKeyDown: handleKeyDown,
|
|
310
|
-
onMouseDownCapture: () => {
|
|
311
|
-
keyBoardNavigation.current = false;
|
|
312
|
-
setIgnoreFocus(true);
|
|
313
|
-
},
|
|
314
|
-
// onMouseEnter would seem less expensive but it misses some cases
|
|
315
|
-
onMouseMove: () => {
|
|
316
|
-
if (keyBoardNavigation.current) {
|
|
317
|
-
keyBoardNavigation.current = false;
|
|
318
|
-
}
|
|
319
|
-
},
|
|
320
|
-
onMouseLeave: () => {
|
|
321
|
-
keyBoardNavigation.current = true;
|
|
322
|
-
setIgnoreFocus(false);
|
|
323
|
-
setHighlightedIndex(-1);
|
|
324
|
-
}
|
|
325
|
-
}),
|
|
326
|
-
[handleKeyDown, highlightedIndex, setHighlightedIdx, setHighlightedIndex]
|
|
327
|
-
);
|
|
328
|
-
return {
|
|
329
|
-
focusVisible: keyBoardNavigation.current ? highlightedIndex : -1,
|
|
330
|
-
controlledHighlighting,
|
|
331
|
-
highlightedIndex,
|
|
332
|
-
setHighlightedIndex,
|
|
333
|
-
// keyBoardNavigation,
|
|
334
|
-
listProps,
|
|
335
|
-
setIgnoreFocus
|
|
336
|
-
};
|
|
337
|
-
};
|
|
338
|
-
function nextItemIdx(count, key, idx) {
|
|
339
|
-
if (key === "ArrowUp") {
|
|
340
|
-
if (idx > 0) {
|
|
341
|
-
return idx - 1;
|
|
342
|
-
} else {
|
|
343
|
-
return idx;
|
|
344
91
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
92
|
+
closeAllPopups({ mouseEvt: e, type: "click-away" });
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function closeAllPopups(reason) {
|
|
96
|
+
if (_popups.length === 1) {
|
|
97
|
+
PopupService.hidePopup(reason, "anon", "all");
|
|
98
|
+
} else if (_popups.length) {
|
|
99
|
+
const popupContainers = document.body.querySelectorAll(".vuuPopup");
|
|
100
|
+
for (let i = 0; i < popupContainers.length; i++) {
|
|
101
|
+
ReactDOM2.unmountComponentAtNode(popupContainers[i]);
|
|
352
102
|
}
|
|
103
|
+
popupClosed("*");
|
|
353
104
|
}
|
|
354
105
|
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
var getLabelFromChildren = (children) => {
|
|
360
|
-
if (Array.isArray(children) && isMenuItemLabel(children[0])) {
|
|
361
|
-
return children[0];
|
|
106
|
+
function dialogOpened() {
|
|
107
|
+
if (_dialogOpen === false) {
|
|
108
|
+
_dialogOpen = true;
|
|
109
|
+
window.addEventListener("keydown", specialKeyHandler, true);
|
|
362
110
|
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
childPath,
|
|
397
|
-
hasChildItems,
|
|
398
|
-
hasSeparator
|
|
399
|
-
);
|
|
400
|
-
list.push(childWithId);
|
|
401
|
-
if (grandChildren) {
|
|
402
|
-
collectChildren(grandChildren, childPath, menus2, actions2);
|
|
403
|
-
} else {
|
|
404
|
-
actions2[childPath] = { action, options };
|
|
405
|
-
}
|
|
406
|
-
idx += 1;
|
|
407
|
-
hasSeparator = false;
|
|
408
|
-
}
|
|
409
|
-
});
|
|
410
|
-
return [menus2, actions2];
|
|
411
|
-
};
|
|
412
|
-
return collectChildren(childrenProp);
|
|
413
|
-
}, [rootId, childrenProp]);
|
|
414
|
-
const [menus, actions] = useMemo2(
|
|
415
|
-
() => normalizeChildren(),
|
|
416
|
-
[normalizeChildren]
|
|
417
|
-
);
|
|
418
|
-
return [menus, actions];
|
|
419
|
-
};
|
|
420
|
-
|
|
421
|
-
// src/menu/MenuList.tsx
|
|
422
|
-
import { Fragment, jsx as jsx4 } from "react/jsx-runtime";
|
|
423
|
-
var classBase3 = "vuuMenuList";
|
|
424
|
-
var Separator = () => /* @__PURE__ */ jsx4("li", { className: "vuuMenuItem-divider" });
|
|
425
|
-
var MenuItemGroup = () => null;
|
|
426
|
-
var MenuItem = ({
|
|
111
|
+
}
|
|
112
|
+
function dialogClosed() {
|
|
113
|
+
if (_dialogOpen) {
|
|
114
|
+
_dialogOpen = false;
|
|
115
|
+
window.removeEventListener("keydown", specialKeyHandler, true);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function popupOpened(name) {
|
|
119
|
+
if (_popups.indexOf(name) === -1) {
|
|
120
|
+
_popups.push(name);
|
|
121
|
+
if (_dialogOpen === false) {
|
|
122
|
+
window.addEventListener("keydown", specialKeyHandler, true);
|
|
123
|
+
window.addEventListener("click", outsideClickHandler, true);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function popupClosed(name) {
|
|
128
|
+
if (_popups.length) {
|
|
129
|
+
if (name === "*") {
|
|
130
|
+
_popups.length = 0;
|
|
131
|
+
} else {
|
|
132
|
+
const pos = _popups.indexOf(name);
|
|
133
|
+
if (pos !== -1) {
|
|
134
|
+
_popups.splice(pos, 1);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (_popups.length === 0 && _dialogOpen === false) {
|
|
138
|
+
window.removeEventListener("keydown", specialKeyHandler, true);
|
|
139
|
+
window.removeEventListener("click", outsideClickHandler, true);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
var PopupComponent = ({
|
|
427
144
|
children,
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
...props
|
|
145
|
+
position,
|
|
146
|
+
style
|
|
431
147
|
}) => {
|
|
432
|
-
|
|
148
|
+
const className = cx3("hwPopup", "hwPopupContainer", position);
|
|
149
|
+
return createElement("div", { className, style }, children);
|
|
433
150
|
};
|
|
434
|
-
var
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
151
|
+
var incrementingKey = 1;
|
|
152
|
+
var PopupService = class _PopupService {
|
|
153
|
+
static showPopup({
|
|
154
|
+
group = "all",
|
|
155
|
+
name = "anon",
|
|
156
|
+
left = 0,
|
|
157
|
+
position = "",
|
|
158
|
+
right = "auto",
|
|
159
|
+
top = 0,
|
|
160
|
+
width = "auto",
|
|
161
|
+
component
|
|
162
|
+
}) {
|
|
163
|
+
if (!component) {
|
|
164
|
+
throw Error(`PopupService showPopup, no component supplied`);
|
|
165
|
+
}
|
|
166
|
+
if (typeof component.props.onClose === "function") {
|
|
167
|
+
_PopupService.onClose = component.props.onClose;
|
|
168
|
+
} else {
|
|
169
|
+
_PopupService.onClose = void 0;
|
|
170
|
+
}
|
|
171
|
+
popupOpened(name);
|
|
172
|
+
document.addEventListener("keydown", _PopupService.escapeKeyListener, true);
|
|
173
|
+
let el = document.body.querySelector(".vuuPopup." + group);
|
|
174
|
+
if (el === null) {
|
|
175
|
+
el = document.createElement("div");
|
|
176
|
+
el.className = "vuuPopup " + group;
|
|
177
|
+
document.body.appendChild(el);
|
|
178
|
+
}
|
|
179
|
+
const style = { width };
|
|
180
|
+
renderPortal(
|
|
181
|
+
createElement(
|
|
182
|
+
PopupComponent,
|
|
183
|
+
{ key: incrementingKey++, position, style },
|
|
184
|
+
component
|
|
185
|
+
),
|
|
186
|
+
el,
|
|
187
|
+
left,
|
|
188
|
+
top,
|
|
189
|
+
() => {
|
|
190
|
+
_PopupService.keepWithinThePage(el, right);
|
|
191
|
+
}
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
static escapeKeyListener(evt) {
|
|
195
|
+
if (evt.key === "Escape") {
|
|
196
|
+
_PopupService.hidePopup({ type: "escape", event: evt });
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
static hidePopup(reason, name = "anon", group = "all") {
|
|
475
200
|
var _a;
|
|
476
|
-
if (
|
|
477
|
-
(
|
|
201
|
+
if (_popups.indexOf(name) !== -1) {
|
|
202
|
+
popupClosed(name);
|
|
203
|
+
const popupRoot = document.body.querySelector(`.vuuPopup.${group}`);
|
|
204
|
+
if (popupRoot) {
|
|
205
|
+
ReactDOM2.unmountComponentAtNode(popupRoot);
|
|
206
|
+
}
|
|
478
207
|
}
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
{
|
|
490
|
-
className: "vuuIconContainer",
|
|
491
|
-
"data-icon": iconName
|
|
492
|
-
},
|
|
493
|
-
"icon"
|
|
494
|
-
)
|
|
495
|
-
].concat(childElement) : childElement;
|
|
496
|
-
function addClonedChild(list, child, idx, withIcon) {
|
|
497
|
-
var _a;
|
|
208
|
+
document.removeEventListener(
|
|
209
|
+
"keydown",
|
|
210
|
+
_PopupService.escapeKeyListener,
|
|
211
|
+
true
|
|
212
|
+
);
|
|
213
|
+
(_a = _PopupService == null ? void 0 : _PopupService.onClose) == null ? void 0 : _a.call(_PopupService, reason);
|
|
214
|
+
}
|
|
215
|
+
static keepWithinThePage(el, right = "auto") {
|
|
216
|
+
const target = el.querySelector(".vuuPopupContainer > *");
|
|
217
|
+
if (target) {
|
|
498
218
|
const {
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
const
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
(_a = child.key) != null ? _a : itemId,
|
|
520
|
-
highlightedIndex,
|
|
521
|
-
appliedFocusVisible,
|
|
522
|
-
className2,
|
|
523
|
-
hasSeparator
|
|
524
|
-
),
|
|
525
|
-
"aria-controls": ariaControls,
|
|
526
|
-
"aria-haspopup": hasSubMenu || void 0,
|
|
527
|
-
"aria-expanded": subMenuShowing || void 0,
|
|
528
|
-
children: hasSubMenu ? maybeIcon(label != null ? label : children2, withIcon, iconName) : maybeIcon(children2, withIcon, iconName)
|
|
529
|
-
}
|
|
530
|
-
)
|
|
531
|
-
);
|
|
532
|
-
}
|
|
533
|
-
const listItems = [];
|
|
534
|
-
if (children.length > 0) {
|
|
535
|
-
const withIcon = children.some(hasIcon);
|
|
536
|
-
children.forEach((child, idx) => {
|
|
537
|
-
addClonedChild(listItems, child, idx, withIcon);
|
|
538
|
-
});
|
|
219
|
+
top,
|
|
220
|
+
left,
|
|
221
|
+
width,
|
|
222
|
+
height,
|
|
223
|
+
right: currentRight
|
|
224
|
+
} = target.getBoundingClientRect();
|
|
225
|
+
const w = window.innerWidth;
|
|
226
|
+
const h = window.innerHeight;
|
|
227
|
+
const overflowH = h - (top + height);
|
|
228
|
+
if (overflowH < 0) {
|
|
229
|
+
target.style.top = Math.round(top) + overflowH + "px";
|
|
230
|
+
}
|
|
231
|
+
const overflowW = w - (left + width);
|
|
232
|
+
if (overflowW < 0) {
|
|
233
|
+
target.style.left = Math.round(left) + overflowW + "px";
|
|
234
|
+
}
|
|
235
|
+
if (typeof right === "number" && right !== currentRight) {
|
|
236
|
+
const adjustment = right - currentRight;
|
|
237
|
+
target.style.left = left + adjustment + "px";
|
|
238
|
+
}
|
|
539
239
|
}
|
|
540
|
-
return listItems;
|
|
541
240
|
}
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
241
|
+
};
|
|
242
|
+
var DialogService = class _DialogService {
|
|
243
|
+
static showDialog(dialog) {
|
|
244
|
+
const containerEl = ".vuuDialog";
|
|
245
|
+
const onClose = dialog.props.onClose;
|
|
246
|
+
dialogOpened();
|
|
247
|
+
ReactDOM2.render(
|
|
248
|
+
React.cloneElement(dialog, {
|
|
249
|
+
container: containerEl,
|
|
250
|
+
onClose: () => {
|
|
251
|
+
_DialogService.closeDialog();
|
|
252
|
+
if (onClose) {
|
|
253
|
+
onClose();
|
|
254
|
+
}
|
|
255
|
+
}
|
|
550
256
|
}),
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
257
|
+
document.body.querySelector(containerEl)
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
static closeDialog() {
|
|
261
|
+
dialogClosed();
|
|
262
|
+
const dialogRoot = document.body.querySelector(".vuuDialog");
|
|
263
|
+
if (dialogRoot) {
|
|
264
|
+
ReactDOM2.unmountComponentAtNode(dialogRoot);
|
|
556
265
|
}
|
|
557
|
-
|
|
266
|
+
}
|
|
558
267
|
};
|
|
559
|
-
var getMenuItemProps = (itemId, idx, key, highlightedIdx, focusVisible, className, hasSeparator) => ({
|
|
560
|
-
id: `menuitem-${itemId}`,
|
|
561
|
-
key: key != null ? key : idx,
|
|
562
|
-
"data-index": idx,
|
|
563
|
-
"data-highlighted": idx === highlightedIdx || void 0,
|
|
564
|
-
className: cx3("vuuMenuItem", className, {
|
|
565
|
-
"vuuMenuItem-separator": hasSeparator,
|
|
566
|
-
focusVisible: focusVisible === idx
|
|
567
|
-
})
|
|
568
|
-
});
|
|
569
|
-
MenuList.displayName = "MenuList";
|
|
570
|
-
|
|
571
|
-
// src/menu/use-cascade.ts
|
|
572
|
-
import {
|
|
573
|
-
useCallback as useCallback5,
|
|
574
|
-
useMemo as useMemo4,
|
|
575
|
-
useRef as useRef5,
|
|
576
|
-
useState as useState4
|
|
577
|
-
} from "react";
|
|
578
268
|
|
|
579
|
-
// src/
|
|
580
|
-
|
|
269
|
+
// src/popup/Popup.tsx
|
|
270
|
+
import cx4 from "clsx";
|
|
581
271
|
|
|
582
|
-
// src/
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
};
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
var getTargetMenuId = (id) => id.slice(9);
|
|
621
|
-
var getMenuItemDetails = ({ ariaExpanded, ariaHasPopup, id }, rootId) => {
|
|
622
|
-
if (id.startsWith("menuitem")) {
|
|
623
|
-
return {
|
|
624
|
-
hostMenuId: getHostMenuId(id, rootId),
|
|
625
|
-
targetMenuId: getTargetMenuId(id),
|
|
626
|
-
menuItemId: id,
|
|
627
|
-
isGroup: ariaHasPopup === "true",
|
|
628
|
-
isOpen: ariaExpanded === "true"
|
|
629
|
-
};
|
|
630
|
-
} else {
|
|
631
|
-
throw Error(`getMenuItemDetails #${id} is not a menuitem`);
|
|
272
|
+
// src/popup/useAnchoredPosition.ts
|
|
273
|
+
import { useCallback, useLayoutEffect, useRef, useState } from "react";
|
|
274
|
+
var getPositionRelativeToAnchor = (anchorElement, placement, offsetLeft, offsetTop, minWidth, dimensions) => {
|
|
275
|
+
const { bottom, height, left, right, top, width } = anchorElement.getBoundingClientRect();
|
|
276
|
+
switch (placement) {
|
|
277
|
+
case "below":
|
|
278
|
+
return { left: left + offsetLeft, top: bottom + offsetTop };
|
|
279
|
+
case "right":
|
|
280
|
+
return { left: right + offsetLeft, top: top + offsetTop };
|
|
281
|
+
case "below-center":
|
|
282
|
+
return { left: left + width / 2 + offsetLeft, top: bottom + offsetTop };
|
|
283
|
+
case "below-right":
|
|
284
|
+
return { left, minWidth, top: bottom + offsetTop };
|
|
285
|
+
case "below-full-width":
|
|
286
|
+
return {
|
|
287
|
+
left: left + offsetLeft,
|
|
288
|
+
minWidth,
|
|
289
|
+
top: bottom + offsetTop,
|
|
290
|
+
width
|
|
291
|
+
};
|
|
292
|
+
case "center":
|
|
293
|
+
if (dimensions) {
|
|
294
|
+
return {
|
|
295
|
+
left: width / 2 - dimensions.width / 2 + offsetLeft,
|
|
296
|
+
top: height / 2 - dimensions.height / 2 + offsetTop,
|
|
297
|
+
visibility: "visible"
|
|
298
|
+
};
|
|
299
|
+
} else {
|
|
300
|
+
return {
|
|
301
|
+
left: width / 2 + offsetLeft,
|
|
302
|
+
top: height / 2 + offsetTop,
|
|
303
|
+
visibility: "hidden"
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
default:
|
|
307
|
+
throw Error(
|
|
308
|
+
"Popup getPositionRelativeToAnchor only supported placement values are below and right"
|
|
309
|
+
);
|
|
632
310
|
}
|
|
633
311
|
};
|
|
634
|
-
var
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
312
|
+
var useAnchoredPosition = ({
|
|
313
|
+
anchorElement,
|
|
314
|
+
minWidth,
|
|
315
|
+
offsetLeft = 0,
|
|
316
|
+
offsetTop = 0,
|
|
317
|
+
placement,
|
|
318
|
+
position: positionProp
|
|
639
319
|
}) => {
|
|
640
|
-
const
|
|
641
|
-
const
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
openMenus.current = menus;
|
|
657
|
-
forceRefresh({});
|
|
658
|
-
}, []);
|
|
659
|
-
const menuOpenPendingTimeout = useRef5();
|
|
660
|
-
const menuClosePendingTimeout = useRef5();
|
|
661
|
-
const menuState = useRef5({ [rootId]: "no-popup" });
|
|
662
|
-
const openMenu = useCallback5(
|
|
663
|
-
(hostMenuId = rootId, targetMenuId, itemId = null) => {
|
|
664
|
-
if (hostMenuId === rootId && itemId === null) {
|
|
665
|
-
setOpenMenus([{ id: rootId, left: posX, top: posY }]);
|
|
666
|
-
} else {
|
|
667
|
-
menuState.current[hostMenuId] = "popup-open";
|
|
668
|
-
const el = document.getElementById(itemId);
|
|
669
|
-
if (el !== null) {
|
|
670
|
-
const { left, top } = getPosition(el, openMenus.current);
|
|
671
|
-
setOpenMenus(
|
|
672
|
-
openMenus.current.concat({ id: targetMenuId, left, top })
|
|
673
|
-
);
|
|
674
|
-
} else {
|
|
675
|
-
throw Error(`openMenu no menuItem ${itemId}`);
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
},
|
|
679
|
-
[rootId, posX, posY, setOpenMenus]
|
|
680
|
-
);
|
|
681
|
-
const closeMenu = useCallback5(
|
|
682
|
-
(menuId) => {
|
|
683
|
-
if (menuId === rootId) {
|
|
684
|
-
setOpenMenus([]);
|
|
685
|
-
} else {
|
|
686
|
-
const menus = openMenus.current.slice();
|
|
687
|
-
const lastMenu = menus.pop();
|
|
688
|
-
menuState.current[lastMenu.id] = "no-popup";
|
|
689
|
-
const parentMenu = menus.at(-1);
|
|
690
|
-
if (parentMenu) {
|
|
691
|
-
menuState.current[parentMenu.id] = "no-popup";
|
|
692
|
-
}
|
|
693
|
-
setOpenMenus(menus);
|
|
694
|
-
}
|
|
695
|
-
},
|
|
696
|
-
[rootId, setOpenMenus]
|
|
697
|
-
);
|
|
698
|
-
const closeMenus = useCallback5(
|
|
699
|
-
(menuItemId) => {
|
|
700
|
-
const menus = openMenus.current.slice();
|
|
701
|
-
const menuItemMenuId = menuItemId.slice(9);
|
|
702
|
-
let { id: lastMenuId } = menus.at(-1);
|
|
703
|
-
while (menus.length > 1 && !menuItemMenuId.startsWith(lastMenuId)) {
|
|
704
|
-
const parentMenuId = getHostMenuId(lastMenuId, rootId);
|
|
705
|
-
menus.pop();
|
|
706
|
-
menuState.current[lastMenuId] = "no-popup";
|
|
707
|
-
menuState.current[parentMenuId] = "no-popup";
|
|
708
|
-
({ id: lastMenuId } = menus[menus.length - 1]);
|
|
709
|
-
}
|
|
710
|
-
if (menus.length < openMenus.current.length) {
|
|
711
|
-
setOpenMenus(menus);
|
|
712
|
-
}
|
|
713
|
-
},
|
|
714
|
-
[rootId, setOpenMenus]
|
|
715
|
-
);
|
|
716
|
-
const clearAnyScheduledOpenTasks = useCallback5(() => {
|
|
717
|
-
if (menuOpenPendingTimeout.current) {
|
|
718
|
-
clearTimeout(menuOpenPendingTimeout.current);
|
|
719
|
-
menuOpenPendingTimeout.current = void 0;
|
|
720
|
-
}
|
|
721
|
-
}, []);
|
|
722
|
-
const scheduleOpen = useCallback5(
|
|
723
|
-
(hostMenuId, targetMenuId, menuItemId, delay = 300) => {
|
|
724
|
-
clearAnyScheduledOpenTasks();
|
|
725
|
-
menuOpenPendingTimeout.current = window.setTimeout(() => {
|
|
726
|
-
closeMenus(menuItemId);
|
|
727
|
-
menuState.current[hostMenuId] = "popup-open";
|
|
728
|
-
menuState.current[targetMenuId] = "no-popup";
|
|
729
|
-
openMenu(hostMenuId, targetMenuId, menuItemId);
|
|
730
|
-
}, delay);
|
|
731
|
-
},
|
|
732
|
-
[clearAnyScheduledOpenTasks, closeMenus, openMenu]
|
|
733
|
-
);
|
|
734
|
-
const scheduleClose = useCallback5(
|
|
735
|
-
(hostMenuId, openMenuId, itemId) => {
|
|
736
|
-
menuState.current[openMenuId] = "pending-close";
|
|
737
|
-
menuClosePendingTimeout.current = window.setTimeout(() => {
|
|
738
|
-
closeMenus(itemId);
|
|
739
|
-
}, 400);
|
|
740
|
-
},
|
|
741
|
-
[closeMenus]
|
|
742
|
-
);
|
|
743
|
-
const handleRender = useCallback5(() => {
|
|
744
|
-
const { current: menus } = openMenus;
|
|
745
|
-
const menu = menus.at(-1);
|
|
746
|
-
const el = menu ? document.getElementById(menu.id) : void 0;
|
|
747
|
-
if (el) {
|
|
748
|
-
const { right, bottom } = el.getBoundingClientRect();
|
|
749
|
-
const { clientHeight, clientWidth } = document.body;
|
|
750
|
-
if (right > clientWidth) {
|
|
751
|
-
const newMenus = menus.length > 1 ? flipSides(rootId, menus) : nudgeLeft(menus, right - clientWidth);
|
|
752
|
-
setOpenMenus(newMenus);
|
|
753
|
-
} else if (bottom > clientHeight) {
|
|
754
|
-
const newMenus = nudgeUp(menus, bottom - clientHeight);
|
|
755
|
-
setOpenMenus(newMenus);
|
|
756
|
-
}
|
|
757
|
-
if (typeof el.tabIndex === "number") {
|
|
758
|
-
el.focus();
|
|
759
|
-
}
|
|
320
|
+
const popupRef = useRef(null);
|
|
321
|
+
const [position, setPosition] = useState(positionProp);
|
|
322
|
+
useLayoutEffect(() => {
|
|
323
|
+
if (placement === "absolute" && positionProp) {
|
|
324
|
+
setPosition(positionProp);
|
|
325
|
+
} else if (anchorElement.current && placement !== "auto") {
|
|
326
|
+
const dimensions = popupRef.current === null ? void 0 : popupRef.current.getBoundingClientRect();
|
|
327
|
+
const position2 = getPositionRelativeToAnchor(
|
|
328
|
+
anchorElement.current,
|
|
329
|
+
placement,
|
|
330
|
+
offsetLeft,
|
|
331
|
+
offsetTop,
|
|
332
|
+
minWidth,
|
|
333
|
+
dimensions
|
|
334
|
+
);
|
|
335
|
+
setPosition(position2);
|
|
760
336
|
}
|
|
761
|
-
}, [
|
|
762
|
-
const
|
|
763
|
-
(
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
clearTimeout(menuOpenPendingTimeout.current);
|
|
778
|
-
scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);
|
|
779
|
-
} else if (state === "popup-open") {
|
|
780
|
-
if (menuIsOpen(targetMenuId)) {
|
|
781
|
-
const menuStatus = getOpenMenuStatus(targetMenuId);
|
|
782
|
-
closeMenus(menuItemId);
|
|
783
|
-
switch (menuStatus) {
|
|
784
|
-
case "pending-close":
|
|
785
|
-
clearTimeout(menuClosePendingTimeout.current);
|
|
786
|
-
menuClosePendingTimeout.current = void 0;
|
|
787
|
-
menuState.current[targetMenuId] = "no-popup";
|
|
788
|
-
clearAnyScheduledOpenTasks();
|
|
789
|
-
break;
|
|
790
|
-
default:
|
|
791
|
-
}
|
|
792
|
-
} else {
|
|
793
|
-
const [parentOfLastOpenedMenu, lastOpenedMenu] = openMenus.current.slice(-2);
|
|
794
|
-
if (parentOfLastOpenedMenu.id === hostMenuId && menuState.current[lastOpenedMenu.id] !== "pending-close") {
|
|
795
|
-
scheduleClose(hostMenuId, lastOpenedMenu.id, menuItemId);
|
|
796
|
-
if (isGroup && !isOpen) {
|
|
797
|
-
scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);
|
|
798
|
-
}
|
|
799
|
-
} else if (parentOfLastOpenedMenu.id === hostMenuId && isGroup && menuItemId !== lastOpenedMenu.id && menuState.current[lastOpenedMenu.id] === "pending-close") {
|
|
800
|
-
scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);
|
|
801
|
-
} else if (isGroup) {
|
|
802
|
-
scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);
|
|
803
|
-
} else if (!(menuState.current[lastOpenedMenu.id] === "pending-close")) {
|
|
804
|
-
closeMenus(menuItemId);
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
}
|
|
808
|
-
if (state === "pending-close") {
|
|
809
|
-
clearAnyScheduledOpenTasks();
|
|
810
|
-
clearTimeout(menuClosePendingTimeout.current);
|
|
811
|
-
menuClosePendingTimeout.current = void 0;
|
|
812
|
-
menuState.current[hostMenuId] = "popup-open";
|
|
337
|
+
}, [anchorElement, minWidth, offsetLeft, offsetTop, placement, positionProp]);
|
|
338
|
+
const popupCallbackRef = useCallback(
|
|
339
|
+
(el) => {
|
|
340
|
+
popupRef.current = el;
|
|
341
|
+
if (el && placement === "center" && anchorElement.current) {
|
|
342
|
+
const { height, width } = el.getBoundingClientRect();
|
|
343
|
+
setPosition(
|
|
344
|
+
getPositionRelativeToAnchor(
|
|
345
|
+
anchorElement.current,
|
|
346
|
+
placement,
|
|
347
|
+
offsetLeft,
|
|
348
|
+
offsetTop,
|
|
349
|
+
void 0,
|
|
350
|
+
{ height, width }
|
|
351
|
+
)
|
|
352
|
+
);
|
|
813
353
|
}
|
|
814
354
|
},
|
|
815
|
-
[
|
|
816
|
-
clearAnyScheduledOpenTasks,
|
|
817
|
-
closeMenus,
|
|
818
|
-
getOpenMenuStatus,
|
|
819
|
-
menuIsOpen,
|
|
820
|
-
rootId,
|
|
821
|
-
scheduleClose,
|
|
822
|
-
scheduleOpen
|
|
823
|
-
]
|
|
824
|
-
);
|
|
825
|
-
const listItemProps = useMemo4(
|
|
826
|
-
() => ({
|
|
827
|
-
onMouseEnter: (evt) => {
|
|
828
|
-
const menuItemEl = closestListItem(evt.target);
|
|
829
|
-
triggerChildMenu(menuItemEl);
|
|
830
|
-
onMouseEnterItem(evt, menuItemEl.id);
|
|
831
|
-
},
|
|
832
|
-
onClick: (evt) => {
|
|
833
|
-
const listItemEl = closestListItem(evt.target);
|
|
834
|
-
const { isGroup, menuItemId } = getMenuItemDetails(listItemEl, rootId);
|
|
835
|
-
if (isGroup) {
|
|
836
|
-
triggerChildMenu(listItemEl);
|
|
837
|
-
} else {
|
|
838
|
-
onActivate(menuItemId);
|
|
839
|
-
}
|
|
840
|
-
}
|
|
841
|
-
}),
|
|
842
|
-
[onActivate, onMouseEnterItem, rootId, triggerChildMenu]
|
|
355
|
+
[anchorElement, offsetLeft, offsetTop, placement]
|
|
843
356
|
);
|
|
844
357
|
return {
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
listItemProps,
|
|
848
|
-
openMenu: triggerChildMenu,
|
|
849
|
-
openMenus: openMenus.current
|
|
358
|
+
position,
|
|
359
|
+
popupRef: placement === "center" ? popupCallbackRef : void 0
|
|
850
360
|
};
|
|
851
361
|
};
|
|
852
362
|
|
|
853
|
-
// src/
|
|
854
|
-
import {
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
var noop = () => void 0;
|
|
858
|
-
var ContextMenu = ({
|
|
859
|
-
PortalProps: PortalProps2,
|
|
860
|
-
activatedByKeyboard,
|
|
861
|
-
children: childrenProp,
|
|
363
|
+
// src/popup/Popup.tsx
|
|
364
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
365
|
+
var PopupComponent2 = ({
|
|
366
|
+
children,
|
|
862
367
|
className,
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
...menuListProps
|
|
368
|
+
anchorElement,
|
|
369
|
+
minWidth,
|
|
370
|
+
placement,
|
|
371
|
+
position: positionProp
|
|
868
372
|
}) => {
|
|
869
|
-
const
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
const navigatingWithKeyboard = useRef6(activatedByKeyboard);
|
|
875
|
-
const handleMouseEnterItem = useCallback6(() => {
|
|
876
|
-
navigatingWithKeyboard.current = false;
|
|
877
|
-
}, []);
|
|
878
|
-
const handleActivate = useCallback6(
|
|
879
|
-
(menuItemId) => {
|
|
880
|
-
const actionId = menuItemId.slice(9);
|
|
881
|
-
const { action, options } = actions[actionId];
|
|
882
|
-
closeMenuRef.current(id);
|
|
883
|
-
onClose({
|
|
884
|
-
type: "menu-action",
|
|
885
|
-
menuId: action,
|
|
886
|
-
options
|
|
887
|
-
});
|
|
888
|
-
},
|
|
889
|
-
[actions, id, onClose]
|
|
890
|
-
);
|
|
891
|
-
const {
|
|
892
|
-
closeMenu,
|
|
893
|
-
listItemProps,
|
|
894
|
-
openMenu: onOpenMenu,
|
|
895
|
-
openMenus,
|
|
896
|
-
handleRender
|
|
897
|
-
} = useCascade({
|
|
898
|
-
// FIXME
|
|
899
|
-
id: `${id}`,
|
|
900
|
-
onActivate: handleActivate,
|
|
901
|
-
onMouseEnterItem: handleMouseEnterItem,
|
|
902
|
-
position
|
|
373
|
+
const { popupRef, position } = useAnchoredPosition({
|
|
374
|
+
anchorElement,
|
|
375
|
+
minWidth,
|
|
376
|
+
placement,
|
|
377
|
+
position: positionProp
|
|
903
378
|
});
|
|
904
|
-
|
|
905
|
-
const handleCloseMenu = () => {
|
|
906
|
-
navigatingWithKeyboard.current = true;
|
|
907
|
-
closeMenu();
|
|
908
|
-
};
|
|
909
|
-
const handleHighlightMenuItem = () => {
|
|
910
|
-
};
|
|
911
|
-
const lastMenu = openMenus.length - 1;
|
|
912
|
-
const getChildMenuId = (i) => {
|
|
913
|
-
if (i >= lastMenu) {
|
|
914
|
-
return void 0;
|
|
915
|
-
} else {
|
|
916
|
-
const { id: id2 } = openMenus[i + 1];
|
|
917
|
-
return id2;
|
|
918
|
-
}
|
|
919
|
-
};
|
|
920
|
-
return /* @__PURE__ */ jsx5(Fragment2, { children: openMenus.map(({ id: menuId, left, top }, i, all) => {
|
|
921
|
-
const childMenuId = getChildMenuId(i);
|
|
922
|
-
return /* @__PURE__ */ createElement(Portal, { ...PortalProps2, key: i, onRender: handleRender }, /* @__PURE__ */ jsx5(
|
|
923
|
-
PopupComponent,
|
|
924
|
-
{
|
|
925
|
-
anchorElement: { current: document.body },
|
|
926
|
-
placement: "absolute",
|
|
927
|
-
position: { left, top },
|
|
928
|
-
children: /* @__PURE__ */ createElement(
|
|
929
|
-
MenuList,
|
|
930
|
-
{
|
|
931
|
-
...menuListProps,
|
|
932
|
-
activatedByKeyboard: navigatingWithKeyboard.current,
|
|
933
|
-
childMenuShowing: childMenuId,
|
|
934
|
-
className,
|
|
935
|
-
id: menuId,
|
|
936
|
-
isRoot: i === 0,
|
|
937
|
-
key: i,
|
|
938
|
-
listItemProps,
|
|
939
|
-
onActivate: handleActivate,
|
|
940
|
-
onHighlightMenuItem: handleHighlightMenuItem,
|
|
941
|
-
onCloseMenu: handleCloseMenu,
|
|
942
|
-
openMenu: onOpenMenu,
|
|
943
|
-
style,
|
|
944
|
-
tabIndex: i === all.length - 1 ? 0 : void 0
|
|
945
|
-
},
|
|
946
|
-
menus[menuId]
|
|
947
|
-
)
|
|
948
|
-
}
|
|
949
|
-
));
|
|
950
|
-
}) });
|
|
379
|
+
return position === void 0 ? null : /* @__PURE__ */ jsx2("div", { className: cx4(`vuuPortal`, className), ref: popupRef, style: position, children });
|
|
951
380
|
};
|
|
952
|
-
ContextMenu.displayName = "ContextMenu";
|
|
953
381
|
|
|
954
|
-
// src/
|
|
955
|
-
import {
|
|
956
|
-
|
|
957
|
-
var
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
382
|
+
// src/dialog/Dialog.tsx
|
|
383
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
384
|
+
var classBase2 = "vuuDialog";
|
|
385
|
+
var AnchorBody = { current: document.body };
|
|
386
|
+
var EMPTY_PROPS = {};
|
|
387
|
+
var Dialog = ({
|
|
388
|
+
PopupProps = EMPTY_PROPS,
|
|
961
389
|
children,
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
390
|
+
className,
|
|
391
|
+
isOpen = false,
|
|
392
|
+
onClose,
|
|
393
|
+
style,
|
|
394
|
+
title,
|
|
395
|
+
hideCloseButton = false,
|
|
396
|
+
...htmlAttributes
|
|
965
397
|
}) => {
|
|
966
|
-
const
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
const
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
398
|
+
const {
|
|
399
|
+
anchorElement = AnchorBody,
|
|
400
|
+
offsetLeft = 0,
|
|
401
|
+
offsetTop = 0,
|
|
402
|
+
placement = "auto"
|
|
403
|
+
} = PopupProps;
|
|
404
|
+
const rootRef = useRef2(null);
|
|
405
|
+
const portalRef = useRef2(null);
|
|
406
|
+
const [themeClass, densityClass, dataMode] = useThemeAttributes();
|
|
407
|
+
const { position } = useAnchoredPosition({
|
|
408
|
+
anchorElement,
|
|
409
|
+
offsetLeft,
|
|
410
|
+
offsetTop,
|
|
411
|
+
placement
|
|
412
|
+
});
|
|
413
|
+
const close = useCallback2(() => {
|
|
414
|
+
onClose == null ? void 0 : onClose();
|
|
415
|
+
}, [onClose]);
|
|
416
|
+
useLayoutEffect2(() => {
|
|
417
|
+
if (rootRef.current) {
|
|
418
|
+
if (isOpen) {
|
|
419
|
+
rootRef.current.showModal();
|
|
420
|
+
const { left, top } = rootRef.current.getBoundingClientRect();
|
|
421
|
+
if (portalRef.current) {
|
|
422
|
+
portalRef.current.style.cssText = `left:-${left}px;position:absolute;top:-${top}px;`;
|
|
423
|
+
}
|
|
424
|
+
} else {
|
|
425
|
+
rootRef.current.close();
|
|
980
426
|
}
|
|
981
|
-
if (
|
|
982
|
-
|
|
427
|
+
if (placement.endsWith("center")) {
|
|
428
|
+
const { width } = rootRef.current.getBoundingClientRect();
|
|
429
|
+
rootRef.current.style.marginLeft = `-${width / 2}px`;
|
|
983
430
|
}
|
|
984
|
-
}
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
ContextMenuContext.Provider,
|
|
431
|
+
}
|
|
432
|
+
}, [isOpen, placement]);
|
|
433
|
+
return /* @__PURE__ */ jsxs2(
|
|
434
|
+
"dialog",
|
|
989
435
|
{
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
436
|
+
...htmlAttributes,
|
|
437
|
+
className: cx5(classBase2, themeClass),
|
|
438
|
+
"data-mode": dataMode,
|
|
439
|
+
onClose: close,
|
|
440
|
+
id: "vuu-dialog",
|
|
441
|
+
ref: rootRef,
|
|
442
|
+
style: { ...style, ...position },
|
|
443
|
+
children: [
|
|
444
|
+
/* @__PURE__ */ jsx3(
|
|
445
|
+
DialogHeader,
|
|
446
|
+
{
|
|
447
|
+
hideCloseButton,
|
|
448
|
+
onClose: close,
|
|
449
|
+
title
|
|
450
|
+
}
|
|
451
|
+
),
|
|
452
|
+
/* @__PURE__ */ jsx3("div", { className: `${classBase2}-body`, children }),
|
|
453
|
+
/* @__PURE__ */ jsx3("div", { id: "vuu-dialog-portal-root", ref: portalRef })
|
|
454
|
+
]
|
|
995
455
|
}
|
|
996
456
|
);
|
|
997
457
|
};
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
458
|
+
|
|
459
|
+
// src/dialog/useDialog.tsx
|
|
460
|
+
import { useCallback as useCallback3, useState as useState2 } from "react";
|
|
461
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
462
|
+
var useDialog = () => {
|
|
463
|
+
const [dialogState, setDialogState] = useState2();
|
|
464
|
+
const handleClose = useCallback3(() => {
|
|
465
|
+
setDialogState(void 0);
|
|
466
|
+
}, []);
|
|
467
|
+
const dialog = dialogState ? /* @__PURE__ */ jsx4(
|
|
468
|
+
Dialog,
|
|
1006
469
|
{
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
470
|
+
className: "vuDialog",
|
|
471
|
+
isOpen: true,
|
|
472
|
+
onClose: handleClose,
|
|
473
|
+
style: { maxHeight: 500 },
|
|
474
|
+
title: dialogState.title,
|
|
475
|
+
hideCloseButton: dialogState.hideCloseButton,
|
|
476
|
+
children: dialogState.content
|
|
1012
477
|
}
|
|
1013
|
-
)
|
|
478
|
+
) : null;
|
|
479
|
+
return {
|
|
480
|
+
dialog,
|
|
481
|
+
setDialogState
|
|
482
|
+
};
|
|
1014
483
|
};
|
|
1015
484
|
|
|
1016
|
-
// src/menu/
|
|
1017
|
-
import {
|
|
1018
|
-
import {
|
|
1019
|
-
|
|
1020
|
-
// src/popup/popup-service.ts
|
|
1021
|
-
import cx5 from "classnames";
|
|
1022
|
-
import React3, {
|
|
1023
|
-
createElement as createElement2
|
|
1024
|
-
} from "react";
|
|
1025
|
-
import ReactDOM2 from "react-dom";
|
|
1026
|
-
|
|
1027
|
-
// src/portal-deprecated/render-portal.tsx
|
|
1028
|
-
import * as ReactDOM from "react-dom";
|
|
1029
|
-
import cx4 from "classnames";
|
|
1030
|
-
var containerId = 1;
|
|
1031
|
-
var getPortalContainer = ({
|
|
1032
|
-
className,
|
|
1033
|
-
dataMode,
|
|
1034
|
-
x = 0,
|
|
1035
|
-
y = 0,
|
|
1036
|
-
win = window
|
|
1037
|
-
}) => {
|
|
1038
|
-
const el = win.document.createElement("div");
|
|
1039
|
-
el.className = cx4(`vuuPopup ${containerId++}`, className);
|
|
1040
|
-
el.style.cssText = `left:${x}px; top:${y}px;`;
|
|
1041
|
-
if (dataMode) {
|
|
1042
|
-
el.dataset.mode = dataMode;
|
|
1043
|
-
}
|
|
1044
|
-
win.document.body.appendChild(el);
|
|
1045
|
-
return el;
|
|
1046
|
-
};
|
|
1047
|
-
var createContainer = (props) => getPortalContainer(props);
|
|
1048
|
-
var renderPortal = (component, container, x, y, onRender) => {
|
|
1049
|
-
container.style.cssText = `left:${x}px; top:${y}px;position: absolute;`;
|
|
1050
|
-
ReactDOM.render(component, container, onRender);
|
|
1051
|
-
};
|
|
485
|
+
// src/menu/ContextMenu.tsx
|
|
486
|
+
import { useId as useId2 } from "@vuu-ui/vuu-utils";
|
|
487
|
+
import { useCallback as useCallback7, useRef as useRef7 } from "react";
|
|
1052
488
|
|
|
1053
|
-
// src/
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
function
|
|
1059
|
-
if (e.key === "Esc") {
|
|
1060
|
-
if (_popups.length) {
|
|
1061
|
-
closeAllPopups();
|
|
1062
|
-
} else if (_dialogOpen) {
|
|
1063
|
-
const dialogRoot = document.body.querySelector(".vuuDialog");
|
|
1064
|
-
if (dialogRoot) {
|
|
1065
|
-
ReactDOM2.unmountComponentAtNode(dialogRoot);
|
|
1066
|
-
}
|
|
1067
|
-
}
|
|
1068
|
-
}
|
|
489
|
+
// src/portal/Portal.tsx
|
|
490
|
+
import { useThemeAttributes as useThemeAttributes2 } from "@vuu-ui/vuu-utils";
|
|
491
|
+
import { useLayoutEffect as useLayoutEffect3, useRef as useRef3, useState as useState3 } from "react";
|
|
492
|
+
import { createPortal } from "react-dom";
|
|
493
|
+
function getContainer(container) {
|
|
494
|
+
return typeof container === "function" ? container() : container;
|
|
1069
495
|
}
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
return;
|
|
496
|
+
var DEFAULT_ID = ["vuu-dialog-portal-root", "vuu-portal-root"];
|
|
497
|
+
var getFirstAvailableElementById = (id) => {
|
|
498
|
+
if (Array.isArray(id)) {
|
|
499
|
+
for (const i of id) {
|
|
500
|
+
const element = document.getElementById(i);
|
|
501
|
+
if (element) {
|
|
502
|
+
return element;
|
|
1078
503
|
}
|
|
1079
504
|
}
|
|
1080
|
-
|
|
505
|
+
} else {
|
|
506
|
+
return document.getElementById(id);
|
|
1081
507
|
}
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
508
|
+
return null;
|
|
509
|
+
};
|
|
510
|
+
var Portal = ({
|
|
511
|
+
children,
|
|
512
|
+
container: containerProp = document.body,
|
|
513
|
+
id = DEFAULT_ID,
|
|
514
|
+
onRender,
|
|
515
|
+
open = true,
|
|
516
|
+
themeAttributes
|
|
517
|
+
}) => {
|
|
518
|
+
var _a;
|
|
519
|
+
const [mounted, setMounted] = useState3(false);
|
|
520
|
+
const portalRef = useRef3(null);
|
|
521
|
+
const container = (_a = getContainer(containerProp)) != null ? _a : document.body;
|
|
522
|
+
const [themeClass, densityClass, dataMode] = useThemeAttributes2(themeAttributes);
|
|
523
|
+
useLayoutEffect3(() => {
|
|
524
|
+
const root = getFirstAvailableElementById(id);
|
|
525
|
+
if (root) {
|
|
526
|
+
portalRef.current = root;
|
|
527
|
+
} else {
|
|
528
|
+
portalRef.current = document.createElement("div");
|
|
529
|
+
portalRef.current.id = typeof id === "string" ? id : id.length > 0 ? id.at(-1) : "vuu-portal-root";
|
|
1090
530
|
}
|
|
1091
|
-
|
|
531
|
+
const el = portalRef.current;
|
|
532
|
+
if (!container.contains(el)) {
|
|
533
|
+
container.appendChild(el);
|
|
534
|
+
}
|
|
535
|
+
el.classList.add(themeClass, densityClass);
|
|
536
|
+
el.dataset.mode = dataMode;
|
|
537
|
+
setMounted(true);
|
|
538
|
+
}, [id, container, themeClass, densityClass, dataMode]);
|
|
539
|
+
useLayoutEffect3(() => {
|
|
540
|
+
requestAnimationFrame(() => {
|
|
541
|
+
onRender == null ? void 0 : onRender();
|
|
542
|
+
});
|
|
543
|
+
}, [onRender]);
|
|
544
|
+
if (open && mounted && portalRef.current && children) {
|
|
545
|
+
return createPortal(children, portalRef.current);
|
|
1092
546
|
}
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
547
|
+
return null;
|
|
548
|
+
};
|
|
549
|
+
|
|
550
|
+
// src/menu/MenuList.tsx
|
|
551
|
+
import cx6 from "clsx";
|
|
552
|
+
import React3, {
|
|
553
|
+
useLayoutEffect as useLayoutEffect4,
|
|
554
|
+
useMemo as useMemo3,
|
|
555
|
+
useRef as useRef5
|
|
556
|
+
} from "react";
|
|
557
|
+
import { useId } from "@vuu-ui/vuu-utils";
|
|
558
|
+
|
|
559
|
+
// src/menu/use-items-with-ids-next.ts
|
|
560
|
+
import React2, { useCallback as useCallback4, useMemo } from "react";
|
|
561
|
+
var isMenuItemGroup = (child) => child.type === MenuItemGroup || !!child.props["data-group"];
|
|
562
|
+
var getLabelFromChildren = (children) => {
|
|
563
|
+
if (Array.isArray(children) && isMenuItemLabel(children[0])) {
|
|
564
|
+
return children[0];
|
|
1104
565
|
}
|
|
1105
|
-
}
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
566
|
+
};
|
|
567
|
+
var assignId = (child, path, group, hasSeparator = false) => {
|
|
568
|
+
const {
|
|
569
|
+
props: { children }
|
|
570
|
+
} = child;
|
|
571
|
+
return {
|
|
572
|
+
childWithId: React2.cloneElement(child, {
|
|
573
|
+
hasSeparator,
|
|
574
|
+
id: `${path}`,
|
|
575
|
+
key: path,
|
|
576
|
+
children: group ? getLabelFromChildren(children) : children
|
|
577
|
+
}),
|
|
578
|
+
grandChildren: group ? children : void 0
|
|
579
|
+
};
|
|
580
|
+
};
|
|
581
|
+
var useItemsWithIdsNext = (childrenProp, rootId) => {
|
|
582
|
+
const normalizeChildren = useCallback4(() => {
|
|
583
|
+
const collectChildren = (children, path = rootId, menus2 = {}, actions2 = {}) => {
|
|
584
|
+
const list = menus2[path] = [];
|
|
585
|
+
let idx = 0;
|
|
586
|
+
let hasSeparator = false;
|
|
587
|
+
React2.Children.forEach(children, (child) => {
|
|
588
|
+
if (isMenuItemLabel(child)) {
|
|
589
|
+
} else if (child.type === Separator) {
|
|
590
|
+
hasSeparator = true;
|
|
591
|
+
} else {
|
|
592
|
+
const hasChildItems = isMenuItemGroup(child);
|
|
593
|
+
const childPath = `${path}-${idx}`;
|
|
594
|
+
const {
|
|
595
|
+
props: { action, options }
|
|
596
|
+
} = child;
|
|
597
|
+
const { childWithId, grandChildren } = assignId(
|
|
598
|
+
child,
|
|
599
|
+
childPath,
|
|
600
|
+
hasChildItems,
|
|
601
|
+
hasSeparator
|
|
602
|
+
);
|
|
603
|
+
list.push(childWithId);
|
|
604
|
+
if (grandChildren) {
|
|
605
|
+
collectChildren(grandChildren, childPath, menus2, actions2);
|
|
606
|
+
} else {
|
|
607
|
+
actions2[childPath] = { action, options };
|
|
608
|
+
}
|
|
609
|
+
idx += 1;
|
|
610
|
+
hasSeparator = false;
|
|
611
|
+
}
|
|
612
|
+
});
|
|
613
|
+
return [menus2, actions2];
|
|
614
|
+
};
|
|
615
|
+
return collectChildren(childrenProp);
|
|
616
|
+
}, [rootId, childrenProp]);
|
|
617
|
+
const [menus, actions] = useMemo(
|
|
618
|
+
() => normalizeChildren(),
|
|
619
|
+
[normalizeChildren]
|
|
620
|
+
);
|
|
621
|
+
return [menus, actions];
|
|
622
|
+
};
|
|
623
|
+
|
|
624
|
+
// src/menu/use-keyboard-navigation.ts
|
|
625
|
+
import {
|
|
626
|
+
useCallback as useCallback5,
|
|
627
|
+
useMemo as useMemo2,
|
|
628
|
+
useRef as useRef4,
|
|
629
|
+
useState as useState4
|
|
630
|
+
} from "react";
|
|
631
|
+
|
|
632
|
+
// src/menu/utils.ts
|
|
633
|
+
var isRoot = (el) => el.closest(`[data-root='true']`) !== null;
|
|
634
|
+
var hasPopup = (el, idx) => {
|
|
635
|
+
var _a;
|
|
636
|
+
return el.ariaHasPopup === "true" && ((_a = el.dataset) == null ? void 0 : _a.idx) === `${idx}` || el.querySelector(`:scope > [data-index='${idx}'][aria-haspopup='true']`) !== null;
|
|
637
|
+
};
|
|
638
|
+
|
|
639
|
+
// src/menu/key-code.ts
|
|
640
|
+
function union(set1, ...sets) {
|
|
641
|
+
const result = new Set(set1);
|
|
642
|
+
for (const set of sets) {
|
|
643
|
+
for (const element of set) {
|
|
644
|
+
result.add(element);
|
|
1112
645
|
}
|
|
1113
646
|
}
|
|
647
|
+
return result;
|
|
1114
648
|
}
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
649
|
+
var Enter = "Enter";
|
|
650
|
+
var Delete = "Delete";
|
|
651
|
+
var actionKeys = /* @__PURE__ */ new Set([Enter, Delete]);
|
|
652
|
+
var focusKeys = /* @__PURE__ */ new Set(["Tab"]);
|
|
653
|
+
var arrowLeftRightKeys = /* @__PURE__ */ new Set(["ArrowRight", "ArrowLeft"]);
|
|
654
|
+
var verticalNavigationKeys = /* @__PURE__ */ new Set(["Home", "End", "ArrowDown", "ArrowUp"]);
|
|
655
|
+
var horizontalNavigationKeys = /* @__PURE__ */ new Set([
|
|
656
|
+
"Home",
|
|
657
|
+
"End",
|
|
658
|
+
"ArrowRight",
|
|
659
|
+
"ArrowLeft"
|
|
660
|
+
]);
|
|
661
|
+
var functionKeys = /* @__PURE__ */ new Set([
|
|
662
|
+
"F1",
|
|
663
|
+
"F2",
|
|
664
|
+
"F3",
|
|
665
|
+
"F4",
|
|
666
|
+
"F5",
|
|
667
|
+
"F6",
|
|
668
|
+
"F7",
|
|
669
|
+
"F8",
|
|
670
|
+
"F9",
|
|
671
|
+
"F10",
|
|
672
|
+
"F11",
|
|
673
|
+
"F12"
|
|
674
|
+
]);
|
|
675
|
+
var specialKeys = union(
|
|
676
|
+
actionKeys,
|
|
677
|
+
horizontalNavigationKeys,
|
|
678
|
+
verticalNavigationKeys,
|
|
679
|
+
arrowLeftRightKeys,
|
|
680
|
+
functionKeys,
|
|
681
|
+
focusKeys
|
|
682
|
+
);
|
|
683
|
+
var isNavigationKey = ({ key }, orientation = "vertical") => {
|
|
684
|
+
const navigationKeys = orientation === "vertical" ? verticalNavigationKeys : horizontalNavigationKeys;
|
|
685
|
+
return navigationKeys.has(key);
|
|
686
|
+
};
|
|
687
|
+
|
|
688
|
+
// src/menu/use-keyboard-navigation.ts
|
|
689
|
+
import { isValidNumber } from "@vuu-ui/vuu-utils";
|
|
690
|
+
var useKeyboardNavigation = ({
|
|
691
|
+
autoHighlightFirstItem = false,
|
|
692
|
+
count,
|
|
693
|
+
defaultHighlightedIdx,
|
|
694
|
+
highlightedIndex: highlightedIndexProp,
|
|
695
|
+
onActivate,
|
|
696
|
+
onHighlight,
|
|
697
|
+
// onKeyDown,
|
|
698
|
+
onCloseMenu,
|
|
699
|
+
onOpenMenu
|
|
700
|
+
}) => {
|
|
701
|
+
var _a;
|
|
702
|
+
if (isValidNumber(highlightedIndexProp) && isValidNumber(defaultHighlightedIdx)) {
|
|
703
|
+
throw Error(
|
|
704
|
+
"useKeyboardNavigation do not pass values for both highlightedIndex and defaultHighlightedIdx"
|
|
705
|
+
);
|
|
706
|
+
}
|
|
707
|
+
const controlledHighlighting = isValidNumber(highlightedIndexProp);
|
|
708
|
+
const highlightedIndexRef = useRef4(
|
|
709
|
+
(_a = defaultHighlightedIdx != null ? defaultHighlightedIdx : highlightedIndexProp) != null ? _a : autoHighlightFirstItem ? 0 : -1
|
|
710
|
+
);
|
|
711
|
+
const [, forceRender] = useState4(null);
|
|
712
|
+
const setHighlightedIdx = useCallback5(
|
|
713
|
+
(idx) => {
|
|
714
|
+
highlightedIndexRef.current = idx;
|
|
715
|
+
onHighlight == null ? void 0 : onHighlight(idx);
|
|
716
|
+
forceRender({});
|
|
717
|
+
},
|
|
718
|
+
[onHighlight]
|
|
719
|
+
);
|
|
720
|
+
const setHighlightedIndex = useCallback5(
|
|
721
|
+
(idx) => {
|
|
722
|
+
if (idx !== highlightedIndexRef.current) {
|
|
723
|
+
if (!controlledHighlighting) {
|
|
724
|
+
setHighlightedIdx(idx);
|
|
725
|
+
}
|
|
1123
726
|
}
|
|
727
|
+
},
|
|
728
|
+
[controlledHighlighting, setHighlightedIdx]
|
|
729
|
+
);
|
|
730
|
+
const keyBoardNavigation = useRef4(true);
|
|
731
|
+
const ignoreFocus = useRef4(false);
|
|
732
|
+
const setIgnoreFocus = (value) => ignoreFocus.current = value;
|
|
733
|
+
const highlightedIndex = controlledHighlighting ? highlightedIndexProp : highlightedIndexRef.current;
|
|
734
|
+
const navigateChildldItems = useCallback5(
|
|
735
|
+
(e) => {
|
|
736
|
+
const nextIdx = nextItemIdx(count, e.key, highlightedIndexRef.current);
|
|
737
|
+
if (nextIdx !== highlightedIndexRef.current) {
|
|
738
|
+
setHighlightedIndex(nextIdx);
|
|
739
|
+
}
|
|
740
|
+
},
|
|
741
|
+
[count, setHighlightedIndex]
|
|
742
|
+
);
|
|
743
|
+
const handleKeyDown = useCallback5(
|
|
744
|
+
(e) => {
|
|
745
|
+
if (isNavigationKey(e)) {
|
|
746
|
+
e.preventDefault();
|
|
747
|
+
e.stopPropagation();
|
|
748
|
+
keyBoardNavigation.current = true;
|
|
749
|
+
navigateChildldItems(e);
|
|
750
|
+
} else if ((e.key === "ArrowRight" || e.key === "Enter") && hasPopup(e.target, highlightedIndex)) {
|
|
751
|
+
const menuEl = e.target;
|
|
752
|
+
const menuItemEl = menuEl.querySelector(
|
|
753
|
+
`:scope > [data-index='${highlightedIndex}']`
|
|
754
|
+
);
|
|
755
|
+
if (menuItemEl) {
|
|
756
|
+
onOpenMenu == null ? void 0 : onOpenMenu(menuItemEl, true);
|
|
757
|
+
}
|
|
758
|
+
} else if (e.key === "ArrowLeft" && !isRoot(e.target)) {
|
|
759
|
+
onCloseMenu(highlightedIndex);
|
|
760
|
+
} else if (e.key === "Enter") {
|
|
761
|
+
e.preventDefault();
|
|
762
|
+
e.stopPropagation();
|
|
763
|
+
onActivate && onActivate(highlightedIndex);
|
|
764
|
+
} else if (e.key === "Tab") {
|
|
765
|
+
onCloseMenu(-1);
|
|
766
|
+
}
|
|
767
|
+
},
|
|
768
|
+
[
|
|
769
|
+
highlightedIndex,
|
|
770
|
+
navigateChildldItems,
|
|
771
|
+
onActivate,
|
|
772
|
+
onCloseMenu,
|
|
773
|
+
onOpenMenu
|
|
774
|
+
]
|
|
775
|
+
);
|
|
776
|
+
const listProps = useMemo2(
|
|
777
|
+
() => ({
|
|
778
|
+
onFocus: () => {
|
|
779
|
+
if (highlightedIndex === -1) {
|
|
780
|
+
setHighlightedIdx(0);
|
|
781
|
+
}
|
|
782
|
+
},
|
|
783
|
+
onKeyDown: handleKeyDown,
|
|
784
|
+
onMouseDownCapture: () => {
|
|
785
|
+
keyBoardNavigation.current = false;
|
|
786
|
+
setIgnoreFocus(true);
|
|
787
|
+
},
|
|
788
|
+
// onMouseEnter would seem less expensive but it misses some cases
|
|
789
|
+
onMouseMove: () => {
|
|
790
|
+
if (keyBoardNavigation.current) {
|
|
791
|
+
keyBoardNavigation.current = false;
|
|
792
|
+
}
|
|
793
|
+
},
|
|
794
|
+
onMouseLeave: () => {
|
|
795
|
+
keyBoardNavigation.current = true;
|
|
796
|
+
setIgnoreFocus(false);
|
|
797
|
+
setHighlightedIndex(-1);
|
|
798
|
+
}
|
|
799
|
+
}),
|
|
800
|
+
[handleKeyDown, highlightedIndex, setHighlightedIdx, setHighlightedIndex]
|
|
801
|
+
);
|
|
802
|
+
return {
|
|
803
|
+
focusVisible: keyBoardNavigation.current ? highlightedIndex : -1,
|
|
804
|
+
controlledHighlighting,
|
|
805
|
+
highlightedIndex,
|
|
806
|
+
setHighlightedIndex,
|
|
807
|
+
// keyBoardNavigation,
|
|
808
|
+
listProps,
|
|
809
|
+
setIgnoreFocus
|
|
810
|
+
};
|
|
811
|
+
};
|
|
812
|
+
function nextItemIdx(count, key, idx) {
|
|
813
|
+
if (key === "ArrowUp") {
|
|
814
|
+
if (idx > 0) {
|
|
815
|
+
return idx - 1;
|
|
816
|
+
} else {
|
|
817
|
+
return idx;
|
|
1124
818
|
}
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
819
|
+
} else {
|
|
820
|
+
if (idx === null) {
|
|
821
|
+
return 0;
|
|
822
|
+
} else if (idx === count - 1) {
|
|
823
|
+
return idx;
|
|
824
|
+
} else {
|
|
825
|
+
return idx + 1;
|
|
1128
826
|
}
|
|
1129
827
|
}
|
|
1130
828
|
}
|
|
1131
|
-
|
|
829
|
+
|
|
830
|
+
// src/menu/MenuList.tsx
|
|
831
|
+
import { Fragment, jsx as jsx5 } from "react/jsx-runtime";
|
|
832
|
+
var classBase3 = "vuuMenuList";
|
|
833
|
+
var Separator = () => /* @__PURE__ */ jsx5("li", { className: "vuuMenuItem-divider" });
|
|
834
|
+
var MenuItemGroup = () => null;
|
|
835
|
+
var MenuItem = ({
|
|
1132
836
|
children,
|
|
1133
|
-
|
|
1134
|
-
|
|
837
|
+
idx,
|
|
838
|
+
options,
|
|
839
|
+
...props
|
|
1135
840
|
}) => {
|
|
1136
|
-
|
|
1137
|
-
return createElement2("div", { className, style }, children);
|
|
841
|
+
return /* @__PURE__ */ jsx5("div", { ...props, children });
|
|
1138
842
|
};
|
|
1139
|
-
var
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
843
|
+
var MenuItemLabel = ({ children }) => /* @__PURE__ */ jsx5(Fragment, { children });
|
|
844
|
+
MenuItemLabel.displayName = "MenuItemLabel";
|
|
845
|
+
MenuItem.Label = MenuItemLabel;
|
|
846
|
+
var getDisplayName = (item) => React3.isValidElement(item) && typeof item.type !== "string" && "displayName" in item.type ? item.type.displayName : void 0;
|
|
847
|
+
var isMenuItemLabel = (item) => getDisplayName(item) === "MenuItemLabel";
|
|
848
|
+
var hasIcon = (child) => child.props["data-icon"];
|
|
849
|
+
var MenuList = ({
|
|
850
|
+
activatedByKeyboard,
|
|
851
|
+
childMenuShowing,
|
|
852
|
+
children,
|
|
853
|
+
className,
|
|
854
|
+
defaultHighlightedIdx,
|
|
855
|
+
highlightedIdx: highlightedIdxProp,
|
|
856
|
+
id: idProp,
|
|
857
|
+
isRoot: isRoot2,
|
|
858
|
+
listItemProps,
|
|
859
|
+
onHighlightMenuItem,
|
|
860
|
+
onActivate,
|
|
861
|
+
onCloseMenu,
|
|
862
|
+
openMenu: onOpenMenu,
|
|
863
|
+
...props
|
|
864
|
+
}) => {
|
|
865
|
+
const id = useId(idProp);
|
|
866
|
+
const root = useRef5(null);
|
|
867
|
+
const mapIdxToId = useMemo3(() => /* @__PURE__ */ new Map(), []);
|
|
868
|
+
const handleActivate = (idx) => {
|
|
869
|
+
var _a;
|
|
870
|
+
const el = (_a = root.current) == null ? void 0 : _a.querySelector(`:scope > [data-index='${idx}']`);
|
|
871
|
+
(el == null ? void 0 : el.id) && (onActivate == null ? void 0 : onActivate(el.id));
|
|
872
|
+
};
|
|
873
|
+
const { focusVisible, highlightedIndex, listProps } = useKeyboardNavigation({
|
|
874
|
+
count: React3.Children.count(children),
|
|
875
|
+
defaultHighlightedIdx,
|
|
876
|
+
highlightedIndex: highlightedIdxProp,
|
|
877
|
+
onActivate: handleActivate,
|
|
878
|
+
onHighlight: onHighlightMenuItem,
|
|
879
|
+
onOpenMenu,
|
|
880
|
+
onCloseMenu
|
|
881
|
+
});
|
|
882
|
+
const appliedFocusVisible = childMenuShowing == void 0 ? focusVisible : -1;
|
|
883
|
+
useLayoutEffect4(() => {
|
|
884
|
+
var _a;
|
|
885
|
+
if (childMenuShowing === void 0 && activatedByKeyboard) {
|
|
886
|
+
(_a = root.current) == null ? void 0 : _a.focus();
|
|
1153
887
|
}
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
888
|
+
}, [activatedByKeyboard, childMenuShowing]);
|
|
889
|
+
const getActiveDescendant = () => highlightedIndex === void 0 || highlightedIndex === -1 ? void 0 : mapIdxToId.get(highlightedIndex);
|
|
890
|
+
function renderContent() {
|
|
891
|
+
const propsCommonToAllListItems = {
|
|
892
|
+
...listItemProps,
|
|
893
|
+
role: "menuitem"
|
|
894
|
+
};
|
|
895
|
+
const maybeIcon = (childElement, withIcon, iconName) => withIcon ? [
|
|
896
|
+
/* @__PURE__ */ jsx5(
|
|
897
|
+
"span",
|
|
898
|
+
{
|
|
899
|
+
className: "vuuIconContainer",
|
|
900
|
+
"data-icon": iconName
|
|
901
|
+
},
|
|
902
|
+
"icon"
|
|
903
|
+
)
|
|
904
|
+
].concat(childElement) : childElement;
|
|
905
|
+
function addClonedChild(list, child, idx, withIcon) {
|
|
906
|
+
var _a;
|
|
907
|
+
const {
|
|
908
|
+
children: children2,
|
|
909
|
+
className: className2,
|
|
910
|
+
"data-icon": iconName,
|
|
911
|
+
id: itemId,
|
|
912
|
+
hasSeparator,
|
|
913
|
+
label,
|
|
914
|
+
...props2
|
|
915
|
+
} = child.props;
|
|
916
|
+
const hasSubMenu = isMenuItemGroup(child);
|
|
917
|
+
const subMenuShowing = hasSubMenu && childMenuShowing === itemId;
|
|
918
|
+
const ariaControls = subMenuShowing ? `${id}-${itemId}` : void 0;
|
|
919
|
+
list.push(
|
|
920
|
+
/* @__PURE__ */ jsx5(
|
|
921
|
+
MenuItem,
|
|
922
|
+
{
|
|
923
|
+
...props2,
|
|
924
|
+
...propsCommonToAllListItems,
|
|
925
|
+
...getMenuItemProps(
|
|
926
|
+
itemId,
|
|
927
|
+
idx,
|
|
928
|
+
(_a = child.key) != null ? _a : itemId,
|
|
929
|
+
highlightedIndex,
|
|
930
|
+
appliedFocusVisible,
|
|
931
|
+
className2,
|
|
932
|
+
hasSeparator
|
|
933
|
+
),
|
|
934
|
+
"aria-controls": ariaControls,
|
|
935
|
+
"aria-haspopup": hasSubMenu || void 0,
|
|
936
|
+
"aria-expanded": subMenuShowing || void 0,
|
|
937
|
+
children: hasSubMenu ? maybeIcon(label != null ? label : children2, withIcon, iconName) : maybeIcon(children2, withIcon, iconName)
|
|
938
|
+
}
|
|
939
|
+
)
|
|
940
|
+
);
|
|
1158
941
|
}
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
document.body.appendChild(el);
|
|
942
|
+
const listItems = [];
|
|
943
|
+
if (children.length > 0) {
|
|
944
|
+
const withIcon = children.some(hasIcon);
|
|
945
|
+
children.forEach((child, idx) => {
|
|
946
|
+
addClonedChild(listItems, child, idx, withIcon);
|
|
947
|
+
});
|
|
1166
948
|
}
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
949
|
+
return listItems;
|
|
950
|
+
}
|
|
951
|
+
return /* @__PURE__ */ jsx5(
|
|
952
|
+
"div",
|
|
953
|
+
{
|
|
954
|
+
...props,
|
|
955
|
+
...listProps,
|
|
956
|
+
"aria-activedescendant": getActiveDescendant(),
|
|
957
|
+
className: cx6(classBase3, className, {
|
|
958
|
+
[`${classBase3}-childMenuShowing`]: childMenuShowing !== void 0
|
|
959
|
+
}),
|
|
960
|
+
"data-root": isRoot2 || void 0,
|
|
961
|
+
id,
|
|
962
|
+
ref: root,
|
|
963
|
+
role: "menu",
|
|
964
|
+
children: renderContent()
|
|
965
|
+
}
|
|
966
|
+
);
|
|
967
|
+
};
|
|
968
|
+
var getMenuItemProps = (itemId, idx, key, highlightedIdx, focusVisible, className, hasSeparator) => ({
|
|
969
|
+
id: `menuitem-${itemId}`,
|
|
970
|
+
key: key != null ? key : idx,
|
|
971
|
+
"data-index": idx,
|
|
972
|
+
"data-highlighted": idx === highlightedIdx || void 0,
|
|
973
|
+
className: cx6("vuuMenuItem", className, {
|
|
974
|
+
"vuuMenuItem-separator": hasSeparator,
|
|
975
|
+
focusVisible: focusVisible === idx
|
|
976
|
+
})
|
|
977
|
+
});
|
|
978
|
+
MenuList.displayName = "MenuList";
|
|
979
|
+
|
|
980
|
+
// src/menu/use-cascade.ts
|
|
981
|
+
import {
|
|
982
|
+
useCallback as useCallback6,
|
|
983
|
+
useMemo as useMemo4,
|
|
984
|
+
useRef as useRef6,
|
|
985
|
+
useState as useState5
|
|
986
|
+
} from "react";
|
|
987
|
+
|
|
988
|
+
// src/menu/list-dom-utils.ts
|
|
989
|
+
var closestListItem = (el) => el == null ? void 0 : el.closest("[data-index],[aria-posinset]");
|
|
990
|
+
|
|
991
|
+
// src/menu/use-cascade.ts
|
|
992
|
+
var nudge = (menus, distance, pos) => {
|
|
993
|
+
return menus.map(
|
|
994
|
+
(m, i) => i === menus.length - 1 ? {
|
|
995
|
+
...m,
|
|
996
|
+
[pos]: m[pos] - distance
|
|
997
|
+
} : m
|
|
998
|
+
);
|
|
999
|
+
};
|
|
1000
|
+
var nudgeLeft = (menus, distance) => nudge(menus, distance, "left");
|
|
1001
|
+
var nudgeUp = (menus, distance) => nudge(menus, distance, "top");
|
|
1002
|
+
var flipSides = (id, menus) => {
|
|
1003
|
+
const [parentMenu, menu] = menus.slice(-2);
|
|
1004
|
+
const el = document.getElementById(`${id}-${menu.id}`);
|
|
1005
|
+
if (el === null) {
|
|
1006
|
+
throw Error(`useCascade.flipSides element with id ${menu.id} not found`);
|
|
1007
|
+
}
|
|
1008
|
+
const { width } = el.getBoundingClientRect();
|
|
1009
|
+
return menus.map(
|
|
1010
|
+
(m) => m === menu ? {
|
|
1011
|
+
...m,
|
|
1012
|
+
left: parentMenu.left - (width - 2)
|
|
1013
|
+
} : m
|
|
1014
|
+
);
|
|
1015
|
+
};
|
|
1016
|
+
var getPosition = (el, openMenus) => {
|
|
1017
|
+
const [{ left, top: menuTop }] = openMenus.slice(-1);
|
|
1018
|
+
const { offsetWidth: width, offsetTop: top } = el;
|
|
1019
|
+
return { left: left + width, top: top + menuTop };
|
|
1020
|
+
};
|
|
1021
|
+
var getHostMenuId = (id, rootId) => {
|
|
1022
|
+
const pos = id.lastIndexOf("-");
|
|
1023
|
+
if (id.startsWith("menuitem")) {
|
|
1024
|
+
return pos > -1 ? id.slice(9, pos) : rootId;
|
|
1025
|
+
} else {
|
|
1026
|
+
return pos > -1 ? id.slice(0, pos) : rootId;
|
|
1181
1027
|
}
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1028
|
+
};
|
|
1029
|
+
var getTargetMenuId = (id) => id.slice(9);
|
|
1030
|
+
var getMenuItemDetails = ({ ariaExpanded, ariaHasPopup, id }, rootId) => {
|
|
1031
|
+
if (id.startsWith("menuitem")) {
|
|
1032
|
+
return {
|
|
1033
|
+
hostMenuId: getHostMenuId(id, rootId),
|
|
1034
|
+
targetMenuId: getTargetMenuId(id),
|
|
1035
|
+
menuItemId: id,
|
|
1036
|
+
isGroup: ariaHasPopup === "true",
|
|
1037
|
+
isOpen: ariaExpanded === "true"
|
|
1038
|
+
};
|
|
1039
|
+
} else {
|
|
1040
|
+
throw Error(`getMenuItemDetails #${id} is not a menuitem`);
|
|
1186
1041
|
}
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1042
|
+
};
|
|
1043
|
+
var useCascade = ({
|
|
1044
|
+
id: rootId,
|
|
1045
|
+
onActivate,
|
|
1046
|
+
onMouseEnterItem,
|
|
1047
|
+
position: { x: posX, y: posY }
|
|
1048
|
+
}) => {
|
|
1049
|
+
const [, forceRefresh] = useState5({});
|
|
1050
|
+
const openMenus = useRef6([
|
|
1051
|
+
{ id: rootId, left: posX, top: posY }
|
|
1052
|
+
]);
|
|
1053
|
+
const menuIsOpen = useCallback6(
|
|
1054
|
+
(menuId) => openMenus.current.findIndex((menu) => menu.id === menuId) !== -1,
|
|
1055
|
+
[]
|
|
1056
|
+
);
|
|
1057
|
+
const getOpenMenuStatus = useCallback6((menuId) => {
|
|
1058
|
+
const state = menuState.current[menuId];
|
|
1059
|
+
if (state === void 0) {
|
|
1060
|
+
throw Error(`getOpenMenuState no entry for menu ${menuId}`);
|
|
1195
1061
|
}
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
);
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
left,
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1062
|
+
return state;
|
|
1063
|
+
}, []);
|
|
1064
|
+
const setOpenMenus = useCallback6((menus) => {
|
|
1065
|
+
openMenus.current = menus;
|
|
1066
|
+
forceRefresh({});
|
|
1067
|
+
}, []);
|
|
1068
|
+
const menuOpenPendingTimeout = useRef6();
|
|
1069
|
+
const menuClosePendingTimeout = useRef6();
|
|
1070
|
+
const menuState = useRef6({ [rootId]: "no-popup" });
|
|
1071
|
+
const openMenu = useCallback6(
|
|
1072
|
+
(hostMenuId = rootId, targetMenuId, itemId = null) => {
|
|
1073
|
+
if (hostMenuId === rootId && itemId === null) {
|
|
1074
|
+
setOpenMenus([{ id: rootId, left: posX, top: posY }]);
|
|
1075
|
+
} else {
|
|
1076
|
+
menuState.current[hostMenuId] = "popup-open";
|
|
1077
|
+
const el = document.getElementById(itemId);
|
|
1078
|
+
if (el !== null) {
|
|
1079
|
+
const { left, top } = getPosition(el, openMenus.current);
|
|
1080
|
+
setOpenMenus(
|
|
1081
|
+
openMenus.current.concat({ id: targetMenuId, left, top })
|
|
1082
|
+
);
|
|
1083
|
+
} else {
|
|
1084
|
+
throw Error(`openMenu no menuItem ${itemId}`);
|
|
1085
|
+
}
|
|
1218
1086
|
}
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1087
|
+
},
|
|
1088
|
+
[rootId, posX, posY, setOpenMenus]
|
|
1089
|
+
);
|
|
1090
|
+
const closeMenu = useCallback6(
|
|
1091
|
+
(menuId) => {
|
|
1092
|
+
if (menuId === rootId) {
|
|
1093
|
+
setOpenMenus([]);
|
|
1094
|
+
} else {
|
|
1095
|
+
const menus = openMenus.current.slice();
|
|
1096
|
+
const lastMenu = menus.pop();
|
|
1097
|
+
menuState.current[lastMenu.id] = "no-popup";
|
|
1098
|
+
const parentMenu = menus.at(-1);
|
|
1099
|
+
if (parentMenu) {
|
|
1100
|
+
menuState.current[parentMenu.id] = "no-popup";
|
|
1101
|
+
}
|
|
1102
|
+
setOpenMenus(menus);
|
|
1222
1103
|
}
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1104
|
+
},
|
|
1105
|
+
[rootId, setOpenMenus]
|
|
1106
|
+
);
|
|
1107
|
+
const closeMenus = useCallback6(
|
|
1108
|
+
(menuItemId) => {
|
|
1109
|
+
const menus = openMenus.current.slice();
|
|
1110
|
+
const menuItemMenuId = menuItemId.slice(9);
|
|
1111
|
+
let { id: lastMenuId } = menus.at(-1);
|
|
1112
|
+
while (menus.length > 1 && !menuItemMenuId.startsWith(lastMenuId)) {
|
|
1113
|
+
const parentMenuId = getHostMenuId(lastMenuId, rootId);
|
|
1114
|
+
menus.pop();
|
|
1115
|
+
menuState.current[lastMenuId] = "no-popup";
|
|
1116
|
+
menuState.current[parentMenuId] = "no-popup";
|
|
1117
|
+
({ id: lastMenuId } = menus[menus.length - 1]);
|
|
1118
|
+
}
|
|
1119
|
+
if (menus.length < openMenus.current.length) {
|
|
1120
|
+
setOpenMenus(menus);
|
|
1226
1121
|
}
|
|
1122
|
+
},
|
|
1123
|
+
[rootId, setOpenMenus]
|
|
1124
|
+
);
|
|
1125
|
+
const clearAnyScheduledOpenTasks = useCallback6(() => {
|
|
1126
|
+
if (menuOpenPendingTimeout.current) {
|
|
1127
|
+
clearTimeout(menuOpenPendingTimeout.current);
|
|
1128
|
+
menuOpenPendingTimeout.current = void 0;
|
|
1227
1129
|
}
|
|
1228
|
-
}
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1130
|
+
}, []);
|
|
1131
|
+
const scheduleOpen = useCallback6(
|
|
1132
|
+
(hostMenuId, targetMenuId, menuItemId, delay = 300) => {
|
|
1133
|
+
clearAnyScheduledOpenTasks();
|
|
1134
|
+
menuOpenPendingTimeout.current = window.setTimeout(() => {
|
|
1135
|
+
closeMenus(menuItemId);
|
|
1136
|
+
menuState.current[hostMenuId] = "popup-open";
|
|
1137
|
+
menuState.current[targetMenuId] = "no-popup";
|
|
1138
|
+
openMenu(hostMenuId, targetMenuId, menuItemId);
|
|
1139
|
+
}, delay);
|
|
1140
|
+
},
|
|
1141
|
+
[clearAnyScheduledOpenTasks, closeMenus, openMenu]
|
|
1142
|
+
);
|
|
1143
|
+
const scheduleClose = useCallback6(
|
|
1144
|
+
(hostMenuId, openMenuId, itemId) => {
|
|
1145
|
+
menuState.current[openMenuId] = "pending-close";
|
|
1146
|
+
menuClosePendingTimeout.current = window.setTimeout(() => {
|
|
1147
|
+
closeMenus(itemId);
|
|
1148
|
+
}, 400);
|
|
1149
|
+
},
|
|
1150
|
+
[closeMenus]
|
|
1151
|
+
);
|
|
1152
|
+
const handleRender = useCallback6(() => {
|
|
1153
|
+
const { current: menus } = openMenus;
|
|
1154
|
+
const menu = menus.at(-1);
|
|
1155
|
+
const el = menu ? document.getElementById(menu.id) : void 0;
|
|
1156
|
+
if (el) {
|
|
1157
|
+
const { right, bottom } = el.getBoundingClientRect();
|
|
1158
|
+
const { clientHeight, clientWidth } = document.body;
|
|
1159
|
+
if (right > clientWidth) {
|
|
1160
|
+
const newMenus = menus.length > 1 ? flipSides(rootId, menus) : nudgeLeft(menus, right - clientWidth);
|
|
1161
|
+
setOpenMenus(newMenus);
|
|
1162
|
+
} else if (bottom > clientHeight) {
|
|
1163
|
+
const newMenus = nudgeUp(menus, bottom - clientHeight);
|
|
1164
|
+
setOpenMenus(newMenus);
|
|
1165
|
+
}
|
|
1166
|
+
if (typeof el.tabIndex === "number") {
|
|
1167
|
+
el.focus();
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
}, [rootId, setOpenMenus]);
|
|
1171
|
+
const triggerChildMenu = useCallback6(
|
|
1172
|
+
(menuItemEl, immediate = false) => {
|
|
1173
|
+
const { hostMenuId, targetMenuId, menuItemId, isGroup, isOpen } = getMenuItemDetails(menuItemEl, rootId);
|
|
1174
|
+
const {
|
|
1175
|
+
current: { [hostMenuId]: state }
|
|
1176
|
+
} = menuState;
|
|
1177
|
+
const delay = immediate ? 0 : void 0;
|
|
1178
|
+
if (state === "no-popup" && isGroup) {
|
|
1179
|
+
menuState.current[hostMenuId] = "popup-pending";
|
|
1180
|
+
scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);
|
|
1181
|
+
} else if (state === "popup-pending" && !isGroup) {
|
|
1182
|
+
menuState.current[hostMenuId] = "no-popup";
|
|
1183
|
+
clearTimeout(menuOpenPendingTimeout.current);
|
|
1184
|
+
menuOpenPendingTimeout.current = void 0;
|
|
1185
|
+
} else if (state === "popup-pending" && isGroup) {
|
|
1186
|
+
clearTimeout(menuOpenPendingTimeout.current);
|
|
1187
|
+
scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);
|
|
1188
|
+
} else if (state === "popup-open") {
|
|
1189
|
+
if (menuIsOpen(targetMenuId)) {
|
|
1190
|
+
const menuStatus = getOpenMenuStatus(targetMenuId);
|
|
1191
|
+
closeMenus(menuItemId);
|
|
1192
|
+
switch (menuStatus) {
|
|
1193
|
+
case "pending-close":
|
|
1194
|
+
clearTimeout(menuClosePendingTimeout.current);
|
|
1195
|
+
menuClosePendingTimeout.current = void 0;
|
|
1196
|
+
menuState.current[targetMenuId] = "no-popup";
|
|
1197
|
+
clearAnyScheduledOpenTasks();
|
|
1198
|
+
break;
|
|
1199
|
+
default:
|
|
1200
|
+
}
|
|
1201
|
+
} else {
|
|
1202
|
+
const [parentOfLastOpenedMenu, lastOpenedMenu] = openMenus.current.slice(-2);
|
|
1203
|
+
if (parentOfLastOpenedMenu.id === hostMenuId && menuState.current[lastOpenedMenu.id] !== "pending-close") {
|
|
1204
|
+
scheduleClose(hostMenuId, lastOpenedMenu.id, menuItemId);
|
|
1205
|
+
if (isGroup && !isOpen) {
|
|
1206
|
+
scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);
|
|
1207
|
+
}
|
|
1208
|
+
} else if (parentOfLastOpenedMenu.id === hostMenuId && isGroup && menuItemId !== lastOpenedMenu.id && menuState.current[lastOpenedMenu.id] === "pending-close") {
|
|
1209
|
+
scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);
|
|
1210
|
+
} else if (isGroup) {
|
|
1211
|
+
scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);
|
|
1212
|
+
} else if (!(menuState.current[lastOpenedMenu.id] === "pending-close")) {
|
|
1213
|
+
closeMenus(menuItemId);
|
|
1242
1214
|
}
|
|
1243
1215
|
}
|
|
1244
|
-
}
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1216
|
+
}
|
|
1217
|
+
if (state === "pending-close") {
|
|
1218
|
+
clearAnyScheduledOpenTasks();
|
|
1219
|
+
clearTimeout(menuClosePendingTimeout.current);
|
|
1220
|
+
menuClosePendingTimeout.current = void 0;
|
|
1221
|
+
menuState.current[hostMenuId] = "popup-open";
|
|
1222
|
+
}
|
|
1223
|
+
},
|
|
1224
|
+
[
|
|
1225
|
+
clearAnyScheduledOpenTasks,
|
|
1226
|
+
closeMenus,
|
|
1227
|
+
getOpenMenuStatus,
|
|
1228
|
+
menuIsOpen,
|
|
1229
|
+
rootId,
|
|
1230
|
+
scheduleClose,
|
|
1231
|
+
scheduleOpen
|
|
1232
|
+
]
|
|
1233
|
+
);
|
|
1234
|
+
const listItemProps = useMemo4(
|
|
1235
|
+
() => ({
|
|
1236
|
+
onMouseEnter: (evt) => {
|
|
1237
|
+
const menuItemEl = closestListItem(evt.target);
|
|
1238
|
+
triggerChildMenu(menuItemEl);
|
|
1239
|
+
onMouseEnterItem(evt, menuItemEl.id);
|
|
1240
|
+
},
|
|
1241
|
+
onClick: (evt) => {
|
|
1242
|
+
const listItemEl = closestListItem(evt.target);
|
|
1243
|
+
const { isGroup, menuItemId } = getMenuItemDetails(listItemEl, rootId);
|
|
1244
|
+
if (isGroup) {
|
|
1245
|
+
triggerChildMenu(listItemEl);
|
|
1246
|
+
} else {
|
|
1247
|
+
onActivate(menuItemId);
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
}),
|
|
1251
|
+
[onActivate, onMouseEnterItem, rootId, triggerChildMenu]
|
|
1252
|
+
);
|
|
1253
|
+
return {
|
|
1254
|
+
closeMenu,
|
|
1255
|
+
handleRender,
|
|
1256
|
+
listItemProps,
|
|
1257
|
+
openMenu: triggerChildMenu,
|
|
1258
|
+
openMenus: openMenus.current
|
|
1259
|
+
};
|
|
1255
1260
|
};
|
|
1256
1261
|
|
|
1257
|
-
// src/
|
|
1258
|
-
import
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1262
|
+
// src/menu/ContextMenu.tsx
|
|
1263
|
+
import { Fragment as Fragment2, jsx as jsx6 } from "react/jsx-runtime";
|
|
1264
|
+
import { createElement as createElement2 } from "react";
|
|
1265
|
+
var noop = () => void 0;
|
|
1266
|
+
var ContextMenu = ({
|
|
1267
|
+
PortalProps: PortalProps2,
|
|
1268
|
+
activatedByKeyboard,
|
|
1269
|
+
children: childrenProp,
|
|
1270
|
+
className,
|
|
1271
|
+
id: idProp,
|
|
1272
|
+
onClose = () => void 0,
|
|
1273
|
+
position = { x: 0, y: 0 },
|
|
1274
|
+
style,
|
|
1275
|
+
...menuListProps
|
|
1276
|
+
}) => {
|
|
1277
|
+
const closeHandlerRef = useRef7(onClose);
|
|
1278
|
+
closeHandlerRef.current = onClose;
|
|
1279
|
+
const id = useId2(idProp);
|
|
1280
|
+
const closeMenuRef = useRef7(noop);
|
|
1281
|
+
const [menus, actions] = useItemsWithIdsNext(childrenProp, id);
|
|
1282
|
+
const navigatingWithKeyboard = useRef7(activatedByKeyboard);
|
|
1283
|
+
const handleMouseEnterItem = useCallback7(() => {
|
|
1284
|
+
navigatingWithKeyboard.current = false;
|
|
1285
|
+
}, []);
|
|
1286
|
+
const handleActivate = useCallback7(
|
|
1287
|
+
(menuItemId) => {
|
|
1288
|
+
const actionId = menuItemId.slice(9);
|
|
1289
|
+
const { action, options } = actions[actionId];
|
|
1290
|
+
closeMenuRef.current(id);
|
|
1291
|
+
onClose({
|
|
1292
|
+
type: "menu-action",
|
|
1293
|
+
menuId: action,
|
|
1294
|
+
options
|
|
1295
|
+
});
|
|
1296
|
+
},
|
|
1297
|
+
[actions, id, onClose]
|
|
1298
|
+
);
|
|
1299
|
+
const {
|
|
1300
|
+
closeMenu,
|
|
1301
|
+
listItemProps,
|
|
1302
|
+
openMenu: onOpenMenu,
|
|
1303
|
+
openMenus,
|
|
1304
|
+
handleRender
|
|
1305
|
+
} = useCascade({
|
|
1306
|
+
// FIXME
|
|
1307
|
+
id: `${id}`,
|
|
1308
|
+
onActivate: handleActivate,
|
|
1309
|
+
onMouseEnterItem: handleMouseEnterItem,
|
|
1310
|
+
position
|
|
1311
|
+
});
|
|
1312
|
+
closeMenuRef.current = closeMenu;
|
|
1313
|
+
const handleCloseMenu = () => {
|
|
1314
|
+
navigatingWithKeyboard.current = true;
|
|
1315
|
+
closeMenu();
|
|
1316
|
+
};
|
|
1317
|
+
const handleHighlightMenuItem = () => {
|
|
1318
|
+
};
|
|
1319
|
+
const lastMenu = openMenus.length - 1;
|
|
1320
|
+
const getChildMenuId = (i) => {
|
|
1321
|
+
if (i >= lastMenu) {
|
|
1322
|
+
return void 0;
|
|
1323
|
+
} else {
|
|
1324
|
+
const { id: id2 } = openMenus[i + 1];
|
|
1325
|
+
return id2;
|
|
1326
|
+
}
|
|
1327
|
+
};
|
|
1328
|
+
return /* @__PURE__ */ jsx6(Fragment2, { children: openMenus.map(({ id: menuId, left, top }, i, all) => {
|
|
1329
|
+
const childMenuId = getChildMenuId(i);
|
|
1330
|
+
return /* @__PURE__ */ createElement2(Portal, { ...PortalProps2, key: i, onRender: handleRender }, /* @__PURE__ */ jsx6(
|
|
1331
|
+
PopupComponent2,
|
|
1332
|
+
{
|
|
1333
|
+
anchorElement: { current: document.body },
|
|
1334
|
+
placement: "absolute",
|
|
1335
|
+
position: { left, top },
|
|
1336
|
+
children: /* @__PURE__ */ createElement2(
|
|
1337
|
+
MenuList,
|
|
1338
|
+
{
|
|
1339
|
+
...menuListProps,
|
|
1340
|
+
activatedByKeyboard: navigatingWithKeyboard.current,
|
|
1341
|
+
childMenuShowing: childMenuId,
|
|
1342
|
+
className,
|
|
1343
|
+
id: menuId,
|
|
1344
|
+
isRoot: i === 0,
|
|
1345
|
+
key: i,
|
|
1346
|
+
listItemProps,
|
|
1347
|
+
onActivate: handleActivate,
|
|
1348
|
+
onHighlightMenuItem: handleHighlightMenuItem,
|
|
1349
|
+
onCloseMenu: handleCloseMenu,
|
|
1350
|
+
openMenu: onOpenMenu,
|
|
1351
|
+
style,
|
|
1352
|
+
tabIndex: i === all.length - 1 ? 0 : void 0
|
|
1353
|
+
},
|
|
1354
|
+
menus[menuId]
|
|
1355
|
+
)
|
|
1293
1356
|
}
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
"Popup getPositionRelativeToAnchor only supported placement values are below and right"
|
|
1297
|
-
);
|
|
1298
|
-
}
|
|
1357
|
+
));
|
|
1358
|
+
}) });
|
|
1299
1359
|
};
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1360
|
+
ContextMenu.displayName = "ContextMenu";
|
|
1361
|
+
|
|
1362
|
+
// src/menu/context-menu-provider.tsx
|
|
1363
|
+
import { createContext, useCallback as useCallback8, useMemo as useMemo5 } from "react";
|
|
1364
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
1365
|
+
var ContextMenuContext = createContext(
|
|
1366
|
+
null
|
|
1367
|
+
);
|
|
1368
|
+
var Provider = ({
|
|
1369
|
+
children,
|
|
1370
|
+
context,
|
|
1371
|
+
menuActionHandler,
|
|
1372
|
+
menuBuilder
|
|
1307
1373
|
}) => {
|
|
1308
|
-
const
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
if (
|
|
1312
|
-
|
|
1313
|
-
} else
|
|
1314
|
-
|
|
1315
|
-
const position2 = getPositionRelativeToAnchor(
|
|
1316
|
-
anchorElement.current,
|
|
1317
|
-
placement,
|
|
1318
|
-
offsetLeft,
|
|
1319
|
-
offsetTop,
|
|
1320
|
-
minWidth,
|
|
1321
|
-
dimensions
|
|
1322
|
-
);
|
|
1323
|
-
setPosition(position2);
|
|
1374
|
+
const menuBuilders = useMemo5(() => {
|
|
1375
|
+
if ((context == null ? void 0 : context.menuBuilders) && menuBuilder) {
|
|
1376
|
+
return context.menuBuilders.concat(menuBuilder);
|
|
1377
|
+
} else if (menuBuilder) {
|
|
1378
|
+
return [menuBuilder];
|
|
1379
|
+
} else {
|
|
1380
|
+
return (context == null ? void 0 : context.menuBuilders) || [];
|
|
1324
1381
|
}
|
|
1325
|
-
}, [
|
|
1326
|
-
const
|
|
1327
|
-
(
|
|
1328
|
-
|
|
1329
|
-
if (
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
placement,
|
|
1335
|
-
offsetLeft,
|
|
1336
|
-
offsetTop,
|
|
1337
|
-
void 0,
|
|
1338
|
-
{ height, width }
|
|
1339
|
-
)
|
|
1340
|
-
);
|
|
1382
|
+
}, [context, menuBuilder]);
|
|
1383
|
+
const handleMenuAction = useCallback8(
|
|
1384
|
+
(reason) => {
|
|
1385
|
+
var _a;
|
|
1386
|
+
if (menuActionHandler == null ? void 0 : menuActionHandler(reason)) {
|
|
1387
|
+
return true;
|
|
1388
|
+
}
|
|
1389
|
+
if ((_a = context == null ? void 0 : context.menuActionHandler) == null ? void 0 : _a.call(context, reason)) {
|
|
1390
|
+
return true;
|
|
1341
1391
|
}
|
|
1342
1392
|
},
|
|
1343
|
-
[
|
|
1393
|
+
[context, menuActionHandler]
|
|
1394
|
+
);
|
|
1395
|
+
return /* @__PURE__ */ jsx7(
|
|
1396
|
+
ContextMenuContext.Provider,
|
|
1397
|
+
{
|
|
1398
|
+
value: {
|
|
1399
|
+
menuActionHandler: handleMenuAction,
|
|
1400
|
+
menuBuilders
|
|
1401
|
+
},
|
|
1402
|
+
children
|
|
1403
|
+
}
|
|
1344
1404
|
);
|
|
1345
|
-
return {
|
|
1346
|
-
position,
|
|
1347
|
-
popupRef: placement === "center" ? popupCallbackRef : void 0
|
|
1348
|
-
};
|
|
1349
1405
|
};
|
|
1350
|
-
|
|
1351
|
-
// src/popup/Popup.tsx
|
|
1352
|
-
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
1353
|
-
var PopupComponent = ({
|
|
1406
|
+
var ContextMenuProvider = ({
|
|
1354
1407
|
children,
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
placement,
|
|
1359
|
-
position: positionProp
|
|
1408
|
+
label,
|
|
1409
|
+
menuActionHandler,
|
|
1410
|
+
menuBuilder
|
|
1360
1411
|
}) => {
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1412
|
+
return /* @__PURE__ */ jsx7(ContextMenuContext.Consumer, { children: (parentContext) => /* @__PURE__ */ jsx7(
|
|
1413
|
+
Provider,
|
|
1414
|
+
{
|
|
1415
|
+
context: parentContext,
|
|
1416
|
+
label,
|
|
1417
|
+
menuActionHandler,
|
|
1418
|
+
menuBuilder,
|
|
1419
|
+
children
|
|
1420
|
+
}
|
|
1421
|
+
) });
|
|
1368
1422
|
};
|
|
1369
1423
|
|
|
1370
1424
|
// src/menu/useContextMenu.tsx
|
|
1371
|
-
import {
|
|
1425
|
+
import {
|
|
1426
|
+
isGroupMenuItemDescriptor,
|
|
1427
|
+
useThemeAttributes as useThemeAttributes3
|
|
1428
|
+
} from "@vuu-ui/vuu-utils";
|
|
1429
|
+
import { cloneElement, useCallback as useCallback9, useContext, useMemo as useMemo6 } from "react";
|
|
1372
1430
|
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
1373
1431
|
var useContextMenu = (menuBuilder, menuActionHandler) => {
|
|
1374
1432
|
const ctx = useContext(ContextMenuContext);
|
|
1375
|
-
const [themeClass, densityClass, dataMode] =
|
|
1433
|
+
const [themeClass, densityClass, dataMode] = useThemeAttributes3();
|
|
1376
1434
|
const themeAttributes = useMemo6(
|
|
1377
1435
|
() => ({
|
|
1378
1436
|
themeClass,
|
|
@@ -1498,14 +1556,14 @@ var showContextMenu = (e, menuDescriptors, handleContextMenuAction, {
|
|
|
1498
1556
|
};
|
|
1499
1557
|
|
|
1500
1558
|
// src/popup-menu/PopupMenu.tsx
|
|
1559
|
+
import { useId as useId3 } from "@vuu-ui/vuu-utils";
|
|
1560
|
+
import { Button as Button2 } from "@salt-ds/core";
|
|
1561
|
+
import cx7 from "clsx";
|
|
1501
1562
|
import {
|
|
1502
1563
|
useCallback as useCallback10,
|
|
1503
1564
|
useRef as useRef8,
|
|
1504
1565
|
useState as useState6
|
|
1505
1566
|
} from "react";
|
|
1506
|
-
import cx7 from "classnames";
|
|
1507
|
-
import { Button as Button2 } from "@salt-ds/core";
|
|
1508
|
-
import { useId as useId3 } from "@vuu-ui/vuu-layout";
|
|
1509
1567
|
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
1510
1568
|
var classBase4 = "vuuPopupMenu";
|
|
1511
1569
|
var getPosition2 = (element) => {
|
|
@@ -1606,16 +1664,16 @@ var PopupMenu = ({
|
|
|
1606
1664
|
};
|
|
1607
1665
|
|
|
1608
1666
|
// src/prompt/Prompt.tsx
|
|
1609
|
-
import { useThemeAttributes as
|
|
1667
|
+
import { useThemeAttributes as useThemeAttributes4 } from "@vuu-ui/vuu-utils";
|
|
1610
1668
|
import { Button as Button3 } from "@salt-ds/core";
|
|
1611
|
-
import cx8 from "
|
|
1612
|
-
import { useLayoutEffect as
|
|
1669
|
+
import cx8 from "clsx";
|
|
1670
|
+
import { useLayoutEffect as useLayoutEffect5, useRef as useRef9 } from "react";
|
|
1613
1671
|
import { jsx as jsx10, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1614
1672
|
var classBase5 = "vuuPrompt";
|
|
1615
|
-
var
|
|
1616
|
-
var
|
|
1673
|
+
var AnchorBody2 = { current: document.body };
|
|
1674
|
+
var EMPTY_PROPS2 = {};
|
|
1617
1675
|
var Prompt = ({
|
|
1618
|
-
PopupProps =
|
|
1676
|
+
PopupProps = EMPTY_PROPS2,
|
|
1619
1677
|
cancelButtonLabel = "Cancel",
|
|
1620
1678
|
confirmButtonLabel = "Confirm",
|
|
1621
1679
|
icon,
|
|
@@ -1628,12 +1686,12 @@ var Prompt = ({
|
|
|
1628
1686
|
...htmlAttributes
|
|
1629
1687
|
}) => {
|
|
1630
1688
|
const {
|
|
1631
|
-
anchorElement =
|
|
1689
|
+
anchorElement = AnchorBody2,
|
|
1632
1690
|
offsetLeft = 0,
|
|
1633
1691
|
offsetTop = 0,
|
|
1634
1692
|
placement = "below"
|
|
1635
1693
|
} = PopupProps;
|
|
1636
|
-
const [themeClass, densityClass, dataMode] =
|
|
1694
|
+
const [themeClass, densityClass, dataMode] = useThemeAttributes4();
|
|
1637
1695
|
const { position } = useAnchoredPosition({
|
|
1638
1696
|
anchorElement,
|
|
1639
1697
|
offsetLeft,
|
|
@@ -1642,7 +1700,7 @@ var Prompt = ({
|
|
|
1642
1700
|
});
|
|
1643
1701
|
const rootRef = useRef9(null);
|
|
1644
1702
|
const confirmRef = useRef9(null);
|
|
1645
|
-
|
|
1703
|
+
useLayoutEffect5(() => {
|
|
1646
1704
|
if (rootRef.current) {
|
|
1647
1705
|
rootRef.current.showModal();
|
|
1648
1706
|
if (confirmRef.current) {
|
|
@@ -1675,7 +1733,7 @@ var Prompt = ({
|
|
|
1675
1733
|
};
|
|
1676
1734
|
|
|
1677
1735
|
// src/tooltip/useAnchoredPosition.ts
|
|
1678
|
-
import { useLayoutEffect as
|
|
1736
|
+
import { useLayoutEffect as useLayoutEffect6, useState as useState7 } from "react";
|
|
1679
1737
|
var getPositionRelativeToAnchor2 = (anchorElement, placement, offsetLeft, offsetTop) => {
|
|
1680
1738
|
const { bottom, height, left, right, top, width } = anchorElement.getBoundingClientRect();
|
|
1681
1739
|
const midX = left + width / 2;
|
|
@@ -1702,7 +1760,7 @@ var useAnchoredPosition2 = ({
|
|
|
1702
1760
|
placement
|
|
1703
1761
|
}) => {
|
|
1704
1762
|
const [position, setPosition] = useState7();
|
|
1705
|
-
|
|
1763
|
+
useLayoutEffect6(() => {
|
|
1706
1764
|
if (anchorElement.current) {
|
|
1707
1765
|
const position2 = getPositionRelativeToAnchor2(
|
|
1708
1766
|
anchorElement.current,
|
|
@@ -1717,7 +1775,7 @@ var useAnchoredPosition2 = ({
|
|
|
1717
1775
|
};
|
|
1718
1776
|
|
|
1719
1777
|
// src/tooltip/Tooltip.tsx
|
|
1720
|
-
import cx9 from "
|
|
1778
|
+
import cx9 from "clsx";
|
|
1721
1779
|
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
1722
1780
|
var classBase6 = "vuuTooltip";
|
|
1723
1781
|
var Tooltip = ({
|
|
@@ -1757,8 +1815,8 @@ var Tooltip = ({
|
|
|
1757
1815
|
};
|
|
1758
1816
|
|
|
1759
1817
|
// src/tooltip/useTooltip.ts
|
|
1818
|
+
import { useId as useId4 } from "@vuu-ui/vuu-utils";
|
|
1760
1819
|
import { useCallback as useCallback11, useRef as useRef10, useState as useState8 } from "react";
|
|
1761
|
-
import { useId as useId4 } from "@vuu-ui/vuu-layout";
|
|
1762
1820
|
var useTooltip = ({
|
|
1763
1821
|
id: idProp,
|
|
1764
1822
|
placement = "right",
|
|
@@ -1846,7 +1904,7 @@ var useTooltip = ({
|
|
|
1846
1904
|
|
|
1847
1905
|
// src/notifications/NotificationsProvider.tsx
|
|
1848
1906
|
import React4, { useState as useState9, useContext as useContext2, useCallback as useCallback12, useEffect } from "react";
|
|
1849
|
-
import classNames from "
|
|
1907
|
+
import classNames from "clsx";
|
|
1850
1908
|
import { getUniqueId } from "@vuu-ui/vuu-utils";
|
|
1851
1909
|
import { jsx as jsx12, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1852
1910
|
var toastOffsetTop = 60;
|
|
@@ -1953,7 +2011,7 @@ export {
|
|
|
1953
2011
|
NotificationLevel,
|
|
1954
2012
|
NotificationsContext,
|
|
1955
2013
|
NotificationsProvider,
|
|
1956
|
-
PopupComponent,
|
|
2014
|
+
PopupComponent2 as PopupComponent,
|
|
1957
2015
|
PopupMenu,
|
|
1958
2016
|
PopupService,
|
|
1959
2017
|
Portal,
|