@vuu-ui/vuu-popups 0.8.10-debug → 0.8.11-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 CHANGED
@@ -34,114 +34,116 @@ __export(src_exports, {
34
34
  ContextMenuContext: () => ContextMenuContext,
35
35
  ContextMenuProvider: () => ContextMenuProvider,
36
36
  Dialog: () => Dialog,
37
+ DialogHeader: () => DialogHeader,
37
38
  DialogService: () => DialogService,
38
39
  MenuItem: () => MenuItem,
39
40
  MenuItemGroup: () => MenuItemGroup,
40
41
  MenuList: () => MenuList,
41
- Popup: () => Popup,
42
- PopupComponent: () => PopupComponent2,
42
+ NotificationLevel: () => NotificationLevel,
43
+ NotificationsContext: () => NotificationsContext,
44
+ NotificationsProvider: () => NotificationsProvider,
45
+ PopupComponent: () => PopupComponent,
43
46
  PopupMenu: () => PopupMenu,
44
47
  PopupService: () => PopupService,
45
- Portal: () => Portal2,
46
- PortalDeprecated: () => PortalDeprecated,
48
+ Portal: () => Portal,
47
49
  Prompt: () => Prompt,
48
50
  Separator: () => Separator,
51
+ ToastNotification: () => ToastNotification,
49
52
  Tooltip: () => Tooltip,
50
53
  createContainer: () => createContainer,
51
- installTheme: () => installTheme,
52
54
  isMenuItemLabel: () => isMenuItemLabel,
53
55
  reasonIsClickAway: () => reasonIsClickAway,
54
56
  reasonIsMenuAction: () => reasonIsMenuAction,
55
57
  renderPortal: () => renderPortal,
56
58
  useAnchoredPosition: () => useAnchoredPosition,
57
59
  useContextMenu: () => useContextMenu,
60
+ useNotifications: () => useNotifications,
58
61
  useTooltip: () => useTooltip
59
62
  });
60
63
  module.exports = __toCommonJS(src_exports);
61
64
 
62
65
  // src/dialog/Dialog.tsx
63
66
  var import_lab = require("@salt-ds/lab");
64
- var import_core = require("@salt-ds/core");
65
- var import_classnames3 = __toESM(require("classnames"));
67
+ var import_classnames2 = __toESM(require("classnames"));
66
68
  var import_react2 = require("react");
67
69
 
68
- // src/portal-deprecated/PortalDeprecated.tsx
69
- var import_react = require("react");
70
- var ReactDOM2 = __toESM(require("react-dom"));
71
-
72
- // src/portal-deprecated/render-portal.tsx
73
- var ReactDOM = __toESM(require("react-dom"));
74
- var import_classnames = __toESM(require("classnames"));
75
- var containerId = 1;
76
- var getPortalContainer = ({
77
- className,
78
- dataMode,
79
- x = 0,
80
- y = 0,
81
- win = window
82
- }) => {
83
- const el = win.document.createElement("div");
84
- el.className = (0, import_classnames.default)(`vuuPopup ${containerId++}`, className);
85
- el.style.cssText = `left:${x}px; top:${y}px;`;
86
- if (dataMode) {
87
- el.dataset.mode = dataMode;
88
- }
89
- win.document.body.appendChild(el);
90
- return el;
91
- };
92
- var createContainer = (props) => getPortalContainer(props);
93
- var renderPortal = (component, container, x, y, onRender) => {
94
- container.style.cssText = `left:${x}px; top:${y}px;position: absolute;`;
95
- ReactDOM.render(component, container, onRender);
96
- };
97
-
98
- // src/portal-deprecated/PortalDeprecated.tsx
70
+ // src/portal/Portal.tsx
99
71
  var import_vuu_shell = require("@vuu-ui/vuu-shell");
100
- var import_classnames2 = __toESM(require("classnames"));
101
- var PortalDeprecated = function Portal({
72
+ var import_react = require("react");
73
+ var import_react_dom = require("react-dom");
74
+ function getContainer(container) {
75
+ return typeof container === "function" ? container() : container;
76
+ }
77
+ var DEFAULT_ID = "vuu-portal-root";
78
+ var Portal = ({
102
79
  children,
103
- x = 0,
104
- y = 0,
105
- onRender
106
- }) {
107
- const [themeClass, densityClass, dataMode] = (0, import_vuu_shell.useThemeAttributes)();
108
- const renderContainer = (0, import_react.useMemo)(() => {
109
- return createContainer({
110
- className: (0, import_classnames2.default)(themeClass, densityClass),
111
- dataMode
112
- });
113
- }, [dataMode, densityClass, themeClass]);
80
+ container: containerProp = document.body,
81
+ id = DEFAULT_ID,
82
+ onRender,
83
+ open = true,
84
+ themeAttributes
85
+ }) => {
86
+ var _a;
87
+ const [mounted, setMounted] = (0, import_react.useState)(false);
88
+ const portalRef = (0, import_react.useRef)(null);
89
+ const container = (_a = getContainer(containerProp)) != null ? _a : document.body;
90
+ const [themeClass, densityClass, dataMode] = (0, import_vuu_shell.useThemeAttributes)(themeAttributes);
114
91
  (0, import_react.useLayoutEffect)(() => {
115
- renderPortal(children, renderContainer, x, y, onRender);
116
- }, [children, onRender, renderContainer, x, y]);
92
+ const root = document.getElementById(id);
93
+ if (root) {
94
+ portalRef.current = root;
95
+ } else {
96
+ portalRef.current = document.createElement("div");
97
+ portalRef.current.id = id;
98
+ }
99
+ const el = portalRef.current;
100
+ if (!container.contains(el)) {
101
+ container.appendChild(el);
102
+ }
103
+ el.classList.add(themeClass, densityClass);
104
+ el.dataset.mode = dataMode;
105
+ setMounted(true);
106
+ }, [id, container, themeClass, densityClass, dataMode]);
117
107
  (0, import_react.useLayoutEffect)(() => {
118
- return () => {
119
- var _a;
120
- if (renderContainer) {
121
- ReactDOM2.unmountComponentAtNode(renderContainer);
122
- if (renderContainer.classList.contains("vuuPopup")) {
123
- (_a = renderContainer.parentElement) == null ? void 0 : _a.removeChild(renderContainer);
124
- }
125
- }
126
- };
127
- }, [renderContainer]);
108
+ requestAnimationFrame(() => {
109
+ onRender == null ? void 0 : onRender();
110
+ });
111
+ }, [onRender]);
112
+ if (open && mounted && portalRef.current && children) {
113
+ return (0, import_react_dom.createPortal)(children, portalRef.current);
114
+ }
128
115
  return null;
129
116
  };
130
117
 
131
- // src/portal-deprecated/portal-utils.ts
132
- var installTheme = (themeId) => {
133
- const installedThemes = getComputedStyle(document.body).getPropertyValue(
134
- "--installed-themes"
135
- );
136
- document.body.style.setProperty(
137
- "--installed-themes",
138
- `${installedThemes} ${themeId}`
139
- );
118
+ // src/dialog-header/DialogHeader.tsx
119
+ var import_core = require("@salt-ds/core");
120
+ var import_classnames = __toESM(require("classnames"));
121
+ var import_jsx_runtime = require("react/jsx-runtime");
122
+ var classBase = "vuuDialogHeader";
123
+ var DialogHeader = ({
124
+ hideCloseButton = false,
125
+ title,
126
+ onClose,
127
+ ...htmlAttributes
128
+ }) => {
129
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { ...htmlAttributes, className: (0, import_classnames.default)(classBase, "vuuToolbarProxy"), children: [
130
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_core.Text, { className: "dialogHeader", children: title }),
131
+ !hideCloseButton && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
132
+ import_core.Button,
133
+ {
134
+ onClick: onClose,
135
+ "data-align": "end",
136
+ "data-icon": "close",
137
+ variant: "secondary"
138
+ },
139
+ "close"
140
+ )
141
+ ] });
140
142
  };
141
143
 
142
144
  // src/dialog/Dialog.tsx
143
- var import_jsx_runtime = require("react/jsx-runtime");
144
- var classBase = "vuuDialog";
145
+ var import_jsx_runtime2 = require("react/jsx-runtime");
146
+ var classBase2 = "vuuDialog";
145
147
  var Dialog = ({
146
148
  children,
147
149
  className,
@@ -152,29 +154,21 @@ var Dialog = ({
152
154
  ...props
153
155
  }) => {
154
156
  const root = (0, import_react2.useRef)(null);
155
- const [posX] = (0, import_react2.useState)(0);
156
- const [posY] = (0, import_react2.useState)(0);
157
157
  const close = (0, import_react2.useCallback)(() => {
158
158
  onClose == null ? void 0 : onClose();
159
159
  }, [onClose]);
160
- const handleRender = (0, import_react2.useCallback)(() => {
161
- }, []);
162
160
  if (!isOpen) {
163
161
  return null;
164
162
  }
165
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PortalDeprecated, { onRender: handleRender, x: posX, y: posY, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lab.Scrim, { className: `${classBase}-scrim`, open: isOpen, autoFocusRef: root, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { ...props, className: (0, import_classnames3.default)(classBase, className), ref: root, children: [
166
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: (0, import_classnames3.default)("vuuToolbarProxy", `${classBase}-header`), children: [
167
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_core.Text, { className: "dialogHeader", children: title }),
168
- !hideCloseButton && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
169
- import_core.Button,
170
- {
171
- onClick: close,
172
- "data-align": "end",
173
- "data-icon": "close"
174
- },
175
- "close"
176
- )
177
- ] }),
163
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lab.Scrim, { className: `${classBase2}-scrim`, open: isOpen, autoFocusRef: root, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { ...props, className: (0, import_classnames2.default)(classBase2, className), ref: root, children: [
164
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
165
+ DialogHeader,
166
+ {
167
+ hideCloseButton,
168
+ onClose: close,
169
+ title
170
+ }
171
+ ),
178
172
  children
179
173
  ] }) }) });
180
174
  };
@@ -184,7 +178,7 @@ var import_react7 = require("react");
184
178
 
185
179
  // src/menu/MenuList.tsx
186
180
  var import_react5 = __toESM(require("react"));
187
- var import_classnames4 = __toESM(require("classnames"));
181
+ var import_classnames3 = __toESM(require("classnames"));
188
182
  var import_vuu_layout = require("@vuu-ui/vuu-layout");
189
183
 
190
184
  // src/menu/use-keyboard-navigation.ts
@@ -194,7 +188,7 @@ var import_react3 = require("react");
194
188
  var isRoot = (el) => el.closest(`[data-root='true']`) !== null;
195
189
  var hasPopup = (el, idx) => {
196
190
  var _a;
197
- return el.ariaHasPopup === "true" && ((_a = el.dataset) == null ? void 0 : _a.idx) === `${idx}` || el.querySelector(`:scope > [data-idx='${idx}'][aria-haspopup='true']`) !== null;
191
+ return el.ariaHasPopup === "true" && ((_a = el.dataset) == null ? void 0 : _a.idx) === `${idx}` || el.querySelector(`:scope > [data-index='${idx}'][aria-haspopup='true']`) !== null;
198
192
  };
199
193
 
200
194
  // src/menu/key-code.ts
@@ -311,10 +305,10 @@ var useKeyboardNavigation = ({
311
305
  } else if ((e.key === "ArrowRight" || e.key === "Enter") && hasPopup(e.target, highlightedIndex)) {
312
306
  const menuEl = e.target;
313
307
  const menuItemEl = menuEl.querySelector(
314
- `:scope > [data-idx='${highlightedIndex}']`
308
+ `:scope > [data-index='${highlightedIndex}']`
315
309
  );
316
310
  if (menuItemEl) {
317
- onOpenMenu == null ? void 0 : onOpenMenu(menuItemEl);
311
+ onOpenMenu == null ? void 0 : onOpenMenu(menuItemEl, true);
318
312
  }
319
313
  } else if (e.key === "ArrowLeft" && !isRoot(e.target)) {
320
314
  onCloseMenu(highlightedIndex);
@@ -454,14 +448,19 @@ var useItemsWithIdsNext = (childrenProp, rootId) => {
454
448
  };
455
449
 
456
450
  // src/menu/MenuList.tsx
457
- var import_jsx_runtime2 = require("react/jsx-runtime");
458
- var classBase2 = "vuuMenuList";
459
- var Separator = () => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("li", { className: "vuuMenuItem-divider" });
451
+ var import_jsx_runtime3 = require("react/jsx-runtime");
452
+ var classBase3 = "vuuMenuList";
453
+ var Separator = () => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("li", { className: "vuuMenuItem-divider" });
460
454
  var MenuItemGroup = () => null;
461
- var MenuItem = ({ children, idx, ...props }) => {
462
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ...props, children });
455
+ var MenuItem = ({
456
+ children,
457
+ idx,
458
+ options,
459
+ ...props
460
+ }) => {
461
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ...props, children });
463
462
  };
464
- var MenuItemLabel = ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children });
463
+ var MenuItemLabel = ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children });
465
464
  MenuItemLabel.displayName = "MenuItemLabel";
466
465
  MenuItem.Label = MenuItemLabel;
467
466
  var getDisplayName = (item) => import_react5.default.isValidElement(item) && typeof item.type !== "string" && "displayName" in item.type ? item.type.displayName : void 0;
@@ -480,7 +479,7 @@ var MenuList = ({
480
479
  onHighlightMenuItem,
481
480
  onActivate,
482
481
  onCloseMenu,
483
- onOpenMenu,
482
+ openMenu: onOpenMenu,
484
483
  ...props
485
484
  }) => {
486
485
  const id = (0, import_vuu_layout.useId)(idProp);
@@ -488,7 +487,7 @@ var MenuList = ({
488
487
  const mapIdxToId = (0, import_react5.useMemo)(() => /* @__PURE__ */ new Map(), []);
489
488
  const handleActivate = (idx) => {
490
489
  var _a;
491
- const el = (_a = root.current) == null ? void 0 : _a.querySelector(`:scope > [data-idx='${idx}']`);
490
+ const el = (_a = root.current) == null ? void 0 : _a.querySelector(`:scope > [data-index='${idx}']`);
492
491
  (el == null ? void 0 : el.id) && (onActivate == null ? void 0 : onActivate(el.id));
493
492
  };
494
493
  const { focusVisible, highlightedIndex, listProps } = useKeyboardNavigation({
@@ -514,7 +513,7 @@ var MenuList = ({
514
513
  role: "menuitem"
515
514
  };
516
515
  const maybeIcon = (childElement, withIcon, iconName) => withIcon ? [
517
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
516
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
518
517
  "span",
519
518
  {
520
519
  className: "vuuIconContainer",
@@ -538,7 +537,7 @@ var MenuList = ({
538
537
  const subMenuShowing = hasSubMenu && childMenuShowing === itemId;
539
538
  const ariaControls = subMenuShowing ? `${id}-${itemId}` : void 0;
540
539
  list.push(
541
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
540
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
542
541
  MenuItem,
543
542
  {
544
543
  ...props2,
@@ -569,14 +568,14 @@ var MenuList = ({
569
568
  }
570
569
  return listItems;
571
570
  }
572
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
571
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
573
572
  "div",
574
573
  {
575
574
  ...props,
576
575
  ...listProps,
577
576
  "aria-activedescendant": getActiveDescendant(),
578
- className: (0, import_classnames4.default)(classBase2, className, {
579
- [`${classBase2}-childMenuShowing`]: childMenuShowing !== void 0
577
+ className: (0, import_classnames3.default)(classBase3, className, {
578
+ [`${classBase3}-childMenuShowing`]: childMenuShowing !== void 0
580
579
  }),
581
580
  "data-root": isRoot2 || void 0,
582
581
  id,
@@ -589,9 +588,9 @@ var MenuList = ({
589
588
  var getMenuItemProps = (itemId, idx, key, highlightedIdx, focusVisible, className, hasSeparator) => ({
590
589
  id: `menuitem-${itemId}`,
591
590
  key: key != null ? key : idx,
592
- "data-idx": idx,
591
+ "data-index": idx,
593
592
  "data-highlighted": idx === highlightedIdx || void 0,
594
- className: (0, import_classnames4.default)("vuuMenuItem", className, {
593
+ className: (0, import_classnames3.default)("vuuMenuItem", className, {
595
594
  "vuuMenuItem-separator": hasSeparator,
596
595
  focusVisible: focusVisible === idx
597
596
  })
@@ -602,7 +601,7 @@ MenuList.displayName = "MenuList";
602
601
  var import_react6 = require("react");
603
602
 
604
603
  // src/menu/list-dom-utils.ts
605
- var closestListItem = (el) => el == null ? void 0 : el.closest("[data-idx],[aria-posinset]");
604
+ var closestListItem = (el) => el == null ? void 0 : el.closest("[data-index],[aria-posinset]");
606
605
 
607
606
  // src/menu/use-cascade.ts
608
607
  var nudge = (menus, distance, pos) => {
@@ -635,8 +634,13 @@ var getPosition = (el, openMenus) => {
635
634
  return { left: left + width, top: top + menuTop };
636
635
  };
637
636
  var getHostMenuId = (id, rootId) => {
637
+ console.log(`getHostMenuId from ${id} and ${rootId}`);
638
638
  const pos = id.lastIndexOf("-");
639
- return pos > -1 ? id.slice(9, pos) : rootId;
639
+ if (id.startsWith("menuitem")) {
640
+ return pos > -1 ? id.slice(9, pos) : rootId;
641
+ } else {
642
+ return pos > -1 ? id.slice(0, pos) : rootId;
643
+ }
640
644
  };
641
645
  var getTargetMenuId = (id) => id.slice(9);
642
646
  var getMenuItemDetails = ({ ariaExpanded, ariaHasPopup, id }, rootId) => {
@@ -674,6 +678,9 @@ var useCascade = ({
674
678
  return state;
675
679
  }, []);
676
680
  const setOpenMenus = (0, import_react6.useCallback)((menus) => {
681
+ console.log(`setOpenMenus`, {
682
+ menus
683
+ });
677
684
  openMenus.current = menus;
678
685
  forceRefresh({});
679
686
  }, []);
@@ -682,9 +689,13 @@ var useCascade = ({
682
689
  const menuState = (0, import_react6.useRef)({ [rootId]: "no-popup" });
683
690
  const openMenu = (0, import_react6.useCallback)(
684
691
  (hostMenuId = rootId, targetMenuId, itemId = null) => {
692
+ console.log(
693
+ `open menu hostMenuId ${hostMenuId} targetMenuId ${targetMenuId} itemId ${itemId}`
694
+ );
685
695
  if (hostMenuId === rootId && itemId === null) {
686
696
  setOpenMenus([{ id: rootId, left: posX, top: posY }]);
687
697
  } else {
698
+ console.log(`openMenu set ${hostMenuId} status to popup-open`);
688
699
  menuState.current[hostMenuId] = "popup-open";
689
700
  const el = document.getElementById(itemId);
690
701
  if (el !== null) {
@@ -701,7 +712,9 @@ var useCascade = ({
701
712
  );
702
713
  const closeMenu = (0, import_react6.useCallback)(
703
714
  (menuId) => {
715
+ console.log(`closeMenu ${menuId}`);
704
716
  if (menuId === rootId) {
717
+ console.log("close child menu of root");
705
718
  setOpenMenus([]);
706
719
  } else {
707
720
  const menus = openMenus.current.slice();
@@ -711,6 +724,9 @@ var useCascade = ({
711
724
  if (parentMenu) {
712
725
  menuState.current[parentMenu.id] = "no-popup";
713
726
  }
727
+ console.log(`closeMenu setOpenMenus`, {
728
+ menus
729
+ });
714
730
  setOpenMenus(menus);
715
731
  }
716
732
  },
@@ -718,17 +734,27 @@ var useCascade = ({
718
734
  );
719
735
  const closeMenus = (0, import_react6.useCallback)(
720
736
  (menuItemId) => {
737
+ console.log(`closeMenus ${menuItemId}`);
721
738
  const menus = openMenus.current.slice();
722
739
  const menuItemMenuId = menuItemId.slice(9);
723
740
  let { id: lastMenuId } = menus.at(-1);
724
741
  while (menus.length > 1 && !menuItemMenuId.startsWith(lastMenuId)) {
725
742
  const parentMenuId = getHostMenuId(lastMenuId, rootId);
743
+ console.log(
744
+ `parentMenuId of lastMenuId ${lastMenuId} and rootId ${rootId} is ${parentMenuId}`
745
+ );
726
746
  menus.pop();
747
+ console.log(
748
+ `set state to no-popup for ${lastMenuId} and ${parentMenuId}`
749
+ );
727
750
  menuState.current[lastMenuId] = "no-popup";
728
751
  menuState.current[parentMenuId] = "no-popup";
729
752
  ({ id: lastMenuId } = menus[menus.length - 1]);
730
753
  }
731
754
  if (menus.length < openMenus.current.length) {
755
+ console.log(`closeMenus setOpenMenus`, {
756
+ menus
757
+ });
732
758
  setOpenMenus(menus);
733
759
  }
734
760
  },
@@ -741,14 +767,14 @@ var useCascade = ({
741
767
  }
742
768
  }, []);
743
769
  const scheduleOpen = (0, import_react6.useCallback)(
744
- (hostMenuId, targetMenuId, menuItemId) => {
770
+ (hostMenuId, targetMenuId, menuItemId, delay = 300) => {
745
771
  clearAnyScheduledOpenTasks();
746
772
  menuOpenPendingTimeout.current = window.setTimeout(() => {
747
773
  closeMenus(menuItemId);
748
774
  menuState.current[hostMenuId] = "popup-open";
749
775
  menuState.current[targetMenuId] = "no-popup";
750
776
  openMenu(hostMenuId, targetMenuId, menuItemId);
751
- }, 400);
777
+ }, delay);
752
778
  },
753
779
  [clearAnyScheduledOpenTasks, closeMenus, openMenu]
754
780
  );
@@ -763,8 +789,8 @@ var useCascade = ({
763
789
  );
764
790
  const handleRender = (0, import_react6.useCallback)(() => {
765
791
  const { current: menus } = openMenus;
766
- const [menu] = menus.slice(-1);
767
- const el = document.getElementById(menu.id);
792
+ const menu = menus.at(-1);
793
+ const el = menu ? document.getElementById(menu.id) : void 0;
768
794
  if (el) {
769
795
  const { right, bottom } = el.getBoundingClientRect();
770
796
  const { clientHeight, clientWidth } = document.body;
@@ -779,25 +805,26 @@ var useCascade = ({
779
805
  el.focus();
780
806
  }
781
807
  } else {
782
- console.log(`no element found with if ${menu.id}`);
808
+ console.log(`useCascade no element found with if ${menu == null ? void 0 : menu.id}`);
783
809
  }
784
810
  }, [rootId, setOpenMenus]);
785
811
  const triggerChildMenu = (0, import_react6.useCallback)(
786
- (menuItemEl) => {
812
+ (menuItemEl, immediate = false) => {
787
813
  const { hostMenuId, targetMenuId, menuItemId, isGroup, isOpen } = getMenuItemDetails(menuItemEl, rootId);
788
814
  const {
789
815
  current: { [hostMenuId]: state }
790
816
  } = menuState;
817
+ const delay = immediate ? 0 : void 0;
791
818
  if (state === "no-popup" && isGroup) {
792
819
  menuState.current[hostMenuId] = "popup-pending";
793
- scheduleOpen(hostMenuId, targetMenuId, menuItemId);
820
+ scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);
794
821
  } else if (state === "popup-pending" && !isGroup) {
795
822
  menuState.current[hostMenuId] = "no-popup";
796
823
  clearTimeout(menuOpenPendingTimeout.current);
797
824
  menuOpenPendingTimeout.current = void 0;
798
825
  } else if (state === "popup-pending" && isGroup) {
799
826
  clearTimeout(menuOpenPendingTimeout.current);
800
- scheduleOpen(hostMenuId, targetMenuId, menuItemId);
827
+ scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);
801
828
  } else if (state === "popup-open") {
802
829
  if (menuIsOpen(targetMenuId)) {
803
830
  const menuStatus = getOpenMenuStatus(targetMenuId);
@@ -813,15 +840,20 @@ var useCascade = ({
813
840
  }
814
841
  } else {
815
842
  const [parentOfLastOpenedMenu, lastOpenedMenu] = openMenus.current.slice(-2);
843
+ console.log(`about to check id on `, {
844
+ openMenus,
845
+ parentOfLastOpenedMenu,
846
+ lastOpenedMenu
847
+ });
816
848
  if (parentOfLastOpenedMenu.id === hostMenuId && menuState.current[lastOpenedMenu.id] !== "pending-close") {
817
849
  scheduleClose(hostMenuId, lastOpenedMenu.id, menuItemId);
818
850
  if (isGroup && !isOpen) {
819
- scheduleOpen(hostMenuId, targetMenuId, menuItemId);
851
+ scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);
820
852
  }
821
853
  } else if (parentOfLastOpenedMenu.id === hostMenuId && isGroup && menuItemId !== lastOpenedMenu.id && menuState.current[lastOpenedMenu.id] === "pending-close") {
822
- scheduleOpen(hostMenuId, targetMenuId, menuItemId);
854
+ scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);
823
855
  } else if (isGroup) {
824
- scheduleOpen(hostMenuId, targetMenuId, menuItemId);
856
+ scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);
825
857
  } else if (!(menuState.current[lastOpenedMenu.id] === "pending-close")) {
826
858
  closeMenus(menuItemId);
827
859
  }
@@ -848,10 +880,12 @@ var useCascade = ({
848
880
  () => ({
849
881
  onMouseEnter: (evt) => {
850
882
  const menuItemEl = closestListItem(evt.target);
883
+ console.log(`onMouseEnter ${menuItemEl == null ? void 0 : menuItemEl.id}`);
851
884
  triggerChildMenu(menuItemEl);
852
885
  onMouseEnterItem(evt, menuItemEl.id);
853
886
  },
854
887
  onClick: (evt) => {
888
+ console.log("click");
855
889
  const listItemEl = closestListItem(evt.target);
856
890
  const { isGroup, menuItemId } = getMenuItemDetails(listItemEl, rootId);
857
891
  if (isGroup) {
@@ -874,10 +908,11 @@ var useCascade = ({
874
908
 
875
909
  // src/menu/ContextMenu.tsx
876
910
  var import_vuu_layout2 = require("@vuu-ui/vuu-layout");
877
- var import_jsx_runtime3 = require("react/jsx-runtime");
911
+ var import_jsx_runtime4 = require("react/jsx-runtime");
878
912
  var import_react8 = require("react");
879
913
  var noop = () => void 0;
880
914
  var ContextMenu = ({
915
+ PortalProps: PortalProps2,
881
916
  activatedByKeyboard,
882
917
  children: childrenProp,
883
918
  className,
@@ -909,7 +944,13 @@ var ContextMenu = ({
909
944
  },
910
945
  [actions, id, onClose]
911
946
  );
912
- const { closeMenu, listItemProps, openMenu, openMenus, handleRender } = useCascade({
947
+ const {
948
+ closeMenu,
949
+ listItemProps,
950
+ openMenu: onOpenMenu,
951
+ openMenus,
952
+ handleRender
953
+ } = useCascade({
913
954
  // FIXME
914
955
  id: `${id}`,
915
956
  onActivate: handleActivate,
@@ -932,35 +973,43 @@ var ContextMenu = ({
932
973
  return id2;
933
974
  }
934
975
  };
935
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: openMenus.map(({ id: menuId, left, top }, i, all) => {
976
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: openMenus.map(({ id: menuId, left, top }, i, all) => {
936
977
  const childMenuId = getChildMenuId(i);
937
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PortalDeprecated, { x: left, y: top, onRender: handleRender, children: /* @__PURE__ */ (0, import_react8.createElement)(
938
- MenuList,
978
+ return /* @__PURE__ */ (0, import_react8.createElement)(Portal, { ...PortalProps2, key: i, onRender: handleRender }, /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
979
+ PopupComponent,
939
980
  {
940
- ...menuListProps,
941
- activatedByKeyboard: navigatingWithKeyboard.current,
942
- childMenuShowing: childMenuId,
943
- className,
944
- id: menuId,
945
- isRoot: i === 0,
946
- key: i,
947
- listItemProps,
948
- onActivate: handleActivate,
949
- onHighlightMenuItem: handleHighlightMenuItem,
950
- onCloseMenu: handleCloseMenu,
951
- onOpenMenu: openMenu,
952
- style,
953
- tabIndex: i === all.length - 1 ? 0 : void 0
954
- },
955
- menus[menuId]
956
- ) }, i);
981
+ anchorElement: { current: document.body },
982
+ placement: "absolute",
983
+ position: { left, top },
984
+ children: /* @__PURE__ */ (0, import_react8.createElement)(
985
+ MenuList,
986
+ {
987
+ ...menuListProps,
988
+ activatedByKeyboard: navigatingWithKeyboard.current,
989
+ childMenuShowing: childMenuId,
990
+ className,
991
+ id: menuId,
992
+ isRoot: i === 0,
993
+ key: i,
994
+ listItemProps,
995
+ onActivate: handleActivate,
996
+ onHighlightMenuItem: handleHighlightMenuItem,
997
+ onCloseMenu: handleCloseMenu,
998
+ openMenu: onOpenMenu,
999
+ style,
1000
+ tabIndex: i === all.length - 1 ? 0 : void 0
1001
+ },
1002
+ menus[menuId]
1003
+ )
1004
+ }
1005
+ ));
957
1006
  }) });
958
1007
  };
959
1008
  ContextMenu.displayName = "ContextMenu";
960
1009
 
961
1010
  // src/menu/context-menu-provider.tsx
962
1011
  var import_react9 = require("react");
963
- var import_jsx_runtime4 = require("react/jsx-runtime");
1012
+ var import_jsx_runtime5 = require("react/jsx-runtime");
964
1013
  var ContextMenuContext = (0, import_react9.createContext)(
965
1014
  null
966
1015
  );
@@ -991,7 +1040,7 @@ var Provider = ({
991
1040
  },
992
1041
  [context, menuActionHandler]
993
1042
  );
994
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1043
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
995
1044
  ContextMenuContext.Provider,
996
1045
  {
997
1046
  value: {
@@ -1008,7 +1057,7 @@ var ContextMenuProvider = ({
1008
1057
  menuActionHandler,
1009
1058
  menuBuilder
1010
1059
  }) => {
1011
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ContextMenuContext.Consumer, { children: (parentContext) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1060
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ContextMenuContext.Consumer, { children: (parentContext) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1012
1061
  Provider,
1013
1062
  {
1014
1063
  context: parentContext,
@@ -1021,15 +1070,41 @@ var ContextMenuProvider = ({
1021
1070
  };
1022
1071
 
1023
1072
  // src/menu/useContextMenu.tsx
1024
- var import_vuu_shell3 = require("@vuu-ui/vuu-shell");
1025
1073
  var import_vuu_utils2 = require("@vuu-ui/vuu-utils");
1026
- var import_classnames7 = __toESM(require("classnames"));
1027
1074
  var import_react12 = require("react");
1028
1075
 
1029
1076
  // src/popup/popup-service.ts
1030
1077
  var import_classnames5 = __toESM(require("classnames"));
1031
1078
  var import_react10 = __toESM(require("react"));
1032
- var import_react_dom = __toESM(require("react-dom"));
1079
+ var import_react_dom2 = __toESM(require("react-dom"));
1080
+
1081
+ // src/portal-deprecated/render-portal.tsx
1082
+ var ReactDOM = __toESM(require("react-dom"));
1083
+ var import_classnames4 = __toESM(require("classnames"));
1084
+ var containerId = 1;
1085
+ var getPortalContainer = ({
1086
+ className,
1087
+ dataMode,
1088
+ x = 0,
1089
+ y = 0,
1090
+ win = window
1091
+ }) => {
1092
+ const el = win.document.createElement("div");
1093
+ el.className = (0, import_classnames4.default)(`vuuPopup ${containerId++}`, className);
1094
+ el.style.cssText = `left:${x}px; top:${y}px;`;
1095
+ if (dataMode) {
1096
+ el.dataset.mode = dataMode;
1097
+ }
1098
+ win.document.body.appendChild(el);
1099
+ return el;
1100
+ };
1101
+ var createContainer = (props) => getPortalContainer(props);
1102
+ var renderPortal = (component, container, x, y, onRender) => {
1103
+ container.style.cssText = `left:${x}px; top:${y}px;position: absolute;`;
1104
+ ReactDOM.render(component, container, onRender);
1105
+ };
1106
+
1107
+ // src/popup/popup-service.ts
1033
1108
  var _dialogOpen = false;
1034
1109
  var _popups = [];
1035
1110
  var reasonIsMenuAction = (reason) => (reason == null ? void 0 : reason.type) === "menu-action";
@@ -1041,14 +1116,16 @@ function specialKeyHandler(e) {
1041
1116
  } else if (_dialogOpen) {
1042
1117
  const dialogRoot = document.body.querySelector(".vuuDialog");
1043
1118
  if (dialogRoot) {
1044
- import_react_dom.default.unmountComponentAtNode(dialogRoot);
1119
+ import_react_dom2.default.unmountComponentAtNode(dialogRoot);
1045
1120
  }
1046
1121
  }
1047
1122
  }
1048
1123
  }
1049
1124
  function outsideClickHandler(e) {
1050
1125
  if (_popups.length) {
1051
- const popupContainers = document.body.querySelectorAll(".vuuPopup");
1126
+ const popupContainers = document.body.querySelectorAll(
1127
+ ".vuuPopup,#vuu-portal-root"
1128
+ );
1052
1129
  for (let i = 0; i < popupContainers.length; i++) {
1053
1130
  if (popupContainers[i].contains(e.target)) {
1054
1131
  return;
@@ -1063,7 +1140,7 @@ function closeAllPopups(reason) {
1063
1140
  } else if (_popups.length) {
1064
1141
  const popupContainers = document.body.querySelectorAll(".vuuPopup");
1065
1142
  for (let i = 0; i < popupContainers.length; i++) {
1066
- import_react_dom.default.unmountComponentAtNode(popupContainers[i]);
1143
+ import_react_dom2.default.unmountComponentAtNode(popupContainers[i]);
1067
1144
  }
1068
1145
  popupClosed("*");
1069
1146
  }
@@ -1105,7 +1182,7 @@ function popupClosed(name) {
1105
1182
  }
1106
1183
  }
1107
1184
  }
1108
- var PopupComponent = ({
1185
+ var PopupComponent2 = ({
1109
1186
  children,
1110
1187
  position,
1111
1188
  style
@@ -1144,7 +1221,7 @@ var PopupService = class {
1144
1221
  const style = { width };
1145
1222
  renderPortal(
1146
1223
  (0, import_react10.createElement)(
1147
- PopupComponent,
1224
+ PopupComponent2,
1148
1225
  { key: incrementingKey++, position, style },
1149
1226
  component
1150
1227
  ),
@@ -1167,7 +1244,7 @@ var PopupService = class {
1167
1244
  popupClosed(name);
1168
1245
  const popupRoot = document.body.querySelector(`.vuuPopup.${group}`);
1169
1246
  if (popupRoot) {
1170
- import_react_dom.default.unmountComponentAtNode(popupRoot);
1247
+ import_react_dom2.default.unmountComponentAtNode(popupRoot);
1171
1248
  }
1172
1249
  }
1173
1250
  document.removeEventListener(
@@ -1209,7 +1286,7 @@ var DialogService = class {
1209
1286
  const containerEl = ".vuuDialog";
1210
1287
  const onClose = dialog.props.onClose;
1211
1288
  dialogOpened();
1212
- import_react_dom.default.render(
1289
+ import_react_dom2.default.render(
1213
1290
  import_react10.default.cloneElement(dialog, {
1214
1291
  container: containerEl,
1215
1292
  onClose: () => {
@@ -1226,75 +1303,18 @@ var DialogService = class {
1226
1303
  dialogClosed();
1227
1304
  const dialogRoot = document.body.querySelector(".vuuDialog");
1228
1305
  if (dialogRoot) {
1229
- import_react_dom.default.unmountComponentAtNode(dialogRoot);
1306
+ import_react_dom2.default.unmountComponentAtNode(dialogRoot);
1230
1307
  }
1231
1308
  }
1232
1309
  };
1233
- var Popup = (props) => {
1234
- const pendingTask = (0, import_react10.useRef)();
1235
- const ref = (0, import_react10.useRef)(null);
1236
- const show = (props2, boundingClientRect) => {
1237
- const { name, group, depth, width } = props2;
1238
- let left;
1239
- let top;
1240
- if (pendingTask.current) {
1241
- window.clearTimeout(pendingTask.current);
1242
- pendingTask.current = void 0;
1243
- }
1244
- if (props2.close === true) {
1245
- PopupService.hidePopup(void 0, name, group);
1246
- } else {
1247
- const { position, children: component } = props2;
1248
- const {
1249
- left: targetLeft,
1250
- top: targetTop,
1251
- width: clientWidth,
1252
- bottom: targetBottom
1253
- } = boundingClientRect;
1254
- if (position === "below") {
1255
- left = targetLeft;
1256
- top = targetBottom;
1257
- } else if (position === "above") {
1258
- left = targetLeft;
1259
- top = targetTop;
1260
- }
1261
- pendingTask.current = window.setTimeout(() => {
1262
- PopupService.showPopup({
1263
- name,
1264
- group,
1265
- depth,
1266
- position,
1267
- left,
1268
- top,
1269
- width: width || clientWidth,
1270
- component
1271
- });
1272
- }, 10);
1273
- }
1274
- };
1275
- (0, import_react10.useEffect)(() => {
1276
- if (ref.current) {
1277
- const el = ref.current.parentElement;
1278
- const boundingClientRect = el == null ? void 0 : el.getBoundingClientRect();
1279
- if (boundingClientRect) {
1280
- show(props, boundingClientRect);
1281
- }
1282
- }
1283
- return () => {
1284
- PopupService.hidePopup(void 0, props.name, props.group);
1285
- };
1286
- }, [props]);
1287
- return import_react10.default.createElement("div", { className: "popup-proxy", ref });
1288
- };
1289
1310
 
1290
1311
  // src/popup/Popup.tsx
1291
1312
  var import_classnames6 = __toESM(require("classnames"));
1292
- var import_vuu_shell2 = require("@vuu-ui/vuu-shell");
1293
1313
 
1294
1314
  // src/popup/useAnchoredPosition.ts
1295
1315
  var import_react11 = require("react");
1296
- var getPositionRelativeToAnchor = (anchorElement, placement, offsetLeft, offsetTop) => {
1297
- const { bottom, left, right, top, width } = anchorElement.getBoundingClientRect();
1316
+ var getPositionRelativeToAnchor = (anchorElement, placement, offsetLeft, offsetTop, minWidth, dimensions) => {
1317
+ const { bottom, height, left, right, top, width } = anchorElement.getBoundingClientRect();
1298
1318
  switch (placement) {
1299
1319
  case "below":
1300
1320
  return { left: left + offsetLeft, top: bottom + offsetTop };
@@ -1303,7 +1323,26 @@ var getPositionRelativeToAnchor = (anchorElement, placement, offsetLeft, offsetT
1303
1323
  case "below-center":
1304
1324
  return { left: left + width / 2 + offsetLeft, top: bottom + offsetTop };
1305
1325
  case "below-full-width":
1306
- return { left: left + offsetLeft, top: bottom + offsetTop, width };
1326
+ return {
1327
+ left: left + offsetLeft,
1328
+ minWidth,
1329
+ top: bottom + offsetTop,
1330
+ width
1331
+ };
1332
+ case "center":
1333
+ if (dimensions) {
1334
+ return {
1335
+ left: width / 2 - dimensions.width / 2 + offsetLeft,
1336
+ top: height / 2 - dimensions.height / 2 + offsetTop,
1337
+ visibility: "visible"
1338
+ };
1339
+ } else {
1340
+ return {
1341
+ left: width / 2 + offsetLeft,
1342
+ top: height / 2 + offsetTop,
1343
+ visibility: "hidden"
1344
+ };
1345
+ }
1307
1346
  default:
1308
1347
  throw Error(
1309
1348
  "Popup getPositionRelativeToAnchor only supported placement values are below and right"
@@ -1312,51 +1351,88 @@ var getPositionRelativeToAnchor = (anchorElement, placement, offsetLeft, offsetT
1312
1351
  };
1313
1352
  var useAnchoredPosition = ({
1314
1353
  anchorElement,
1354
+ minWidth,
1315
1355
  offsetLeft = 0,
1316
1356
  offsetTop = 0,
1317
- placement
1357
+ placement,
1358
+ position: positionProp
1318
1359
  }) => {
1319
- const [position, setPosition] = (0, import_react11.useState)();
1360
+ const popupRef = (0, import_react11.useRef)(null);
1361
+ const [position, setPosition] = (0, import_react11.useState)(positionProp);
1320
1362
  (0, import_react11.useLayoutEffect)(() => {
1321
- if (anchorElement.current) {
1363
+ if (placement === "absolute" && positionProp) {
1364
+ setPosition(positionProp);
1365
+ } else if (anchorElement.current) {
1366
+ const dimensions = popupRef.current === null ? void 0 : popupRef.current.getBoundingClientRect();
1322
1367
  const position2 = getPositionRelativeToAnchor(
1323
1368
  anchorElement.current,
1324
1369
  placement,
1325
1370
  offsetLeft,
1326
- offsetTop
1371
+ offsetTop,
1372
+ minWidth,
1373
+ dimensions
1327
1374
  );
1328
1375
  setPosition(position2);
1329
1376
  }
1330
- }, [anchorElement, offsetLeft, offsetTop, placement]);
1331
- return position;
1377
+ }, [anchorElement, minWidth, offsetLeft, offsetTop, placement, positionProp]);
1378
+ const popupCallbackRef = (0, import_react11.useCallback)(
1379
+ (el) => {
1380
+ popupRef.current = el;
1381
+ if (el && placement === "center" && anchorElement.current) {
1382
+ const { height, width } = el.getBoundingClientRect();
1383
+ setPosition(
1384
+ getPositionRelativeToAnchor(
1385
+ anchorElement.current,
1386
+ placement,
1387
+ offsetLeft,
1388
+ offsetTop,
1389
+ void 0,
1390
+ { height, width }
1391
+ )
1392
+ );
1393
+ }
1394
+ },
1395
+ [anchorElement, offsetLeft, offsetTop, placement]
1396
+ );
1397
+ return {
1398
+ position,
1399
+ popupRef: placement === "center" ? popupCallbackRef : void 0
1400
+ };
1332
1401
  };
1333
1402
 
1334
1403
  // src/popup/Popup.tsx
1335
- var import_jsx_runtime5 = require("react/jsx-runtime");
1336
- var PopupComponent2 = ({
1404
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1405
+ var PopupComponent = ({
1337
1406
  children,
1338
1407
  className,
1339
1408
  anchorElement,
1340
- placement
1409
+ minWidth,
1410
+ placement,
1411
+ position: positionProp
1341
1412
  }) => {
1342
- const [themeClass, densityClass, dataMode] = (0, import_vuu_shell2.useThemeAttributes)();
1343
- const position = useAnchoredPosition({ anchorElement, placement });
1344
- return position === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1345
- "div",
1346
- {
1347
- className: (0, import_classnames6.default)(`vuuPortal`, className, themeClass, densityClass),
1348
- "data-mode": dataMode,
1349
- style: position,
1350
- children
1351
- }
1352
- );
1413
+ const { popupRef, position } = useAnchoredPosition({
1414
+ anchorElement,
1415
+ minWidth,
1416
+ placement,
1417
+ position: positionProp
1418
+ });
1419
+ return position === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: (0, import_classnames6.default)(`vuuPortal`, className), ref: popupRef, style: position, children });
1353
1420
  };
1354
1421
 
1355
1422
  // src/menu/useContextMenu.tsx
1356
- var import_jsx_runtime6 = require("react/jsx-runtime");
1423
+ var import_vuu_shell2 = require("@vuu-ui/vuu-shell");
1424
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1357
1425
  var useContextMenu = (menuBuilder, menuActionHandler) => {
1358
1426
  const ctx = (0, import_react12.useContext)(ContextMenuContext);
1359
- const [themeClass, densityClass, dataMode] = (0, import_vuu_shell3.useThemeAttributes)();
1427
+ const [themeClass, densityClass, dataMode] = (0, import_vuu_shell2.useThemeAttributes)();
1428
+ const themeAttributes = (0, import_react12.useMemo)(
1429
+ () => ({
1430
+ themeClass,
1431
+ densityClass,
1432
+ dataMode
1433
+ }),
1434
+ [dataMode, densityClass, themeClass]
1435
+ );
1360
1436
  const buildMenuOptions = (0, import_react12.useCallback)(
1361
1437
  (menuBuilders, location, options) => {
1362
1438
  let results = [];
@@ -1403,13 +1479,10 @@ var useContextMenu = (menuBuilder, menuActionHandler) => {
1403
1479
  };
1404
1480
  if (menuItemDescriptors.length && menuHandler) {
1405
1481
  showContextMenu(e, menuItemDescriptors, menuHandler, {
1406
- ...ContextMenuProps2,
1407
- className: (0, import_classnames7.default)(
1408
- ContextMenuProps2 == null ? void 0 : ContextMenuProps2.className,
1409
- themeClass,
1410
- densityClass
1411
- ),
1412
- "data-mode": dataMode
1482
+ PortalProps: {
1483
+ themeAttributes
1484
+ },
1485
+ ...ContextMenuProps2
1413
1486
  });
1414
1487
  }
1415
1488
  } else {
@@ -1418,18 +1491,10 @@ var useContextMenu = (menuBuilder, menuActionHandler) => {
1418
1491
  );
1419
1492
  }
1420
1493
  },
1421
- [
1422
- buildMenuOptions,
1423
- ctx,
1424
- dataMode,
1425
- densityClass,
1426
- menuActionHandler,
1427
- menuBuilder,
1428
- themeClass
1429
- ]
1494
+ [buildMenuOptions, ctx, menuActionHandler, menuBuilder, themeAttributes]
1430
1495
  );
1431
1496
  const hideContextMenu = (0, import_react12.useCallback)(() => {
1432
- console.log("hide comnytext menu");
1497
+ console.log("hide context menu");
1433
1498
  }, []);
1434
1499
  return [handleShowContextMenu, hideContextMenu];
1435
1500
  };
@@ -1447,7 +1512,7 @@ var showContextMenu = (e, menuDescriptors, handleContextMenuAction, {
1447
1512
  ...contextMenuProps
1448
1513
  } = NO_OPTIONS) => {
1449
1514
  const menuItems = (menuDescriptors2) => {
1450
- const fromDescriptor = (menuItem, i) => (0, import_vuu_utils2.isGroupMenuItemDescriptor)(menuItem) ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MenuItemGroup, { label: menuItem.label, children: menuItem.children.map(fromDescriptor) }, i) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1515
+ const fromDescriptor = (menuItem, i) => (0, import_vuu_utils2.isGroupMenuItemDescriptor)(menuItem) ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MenuItemGroup, { label: menuItem.label, children: menuItem.children.map(fromDescriptor) }, i) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1451
1516
  MenuItem,
1452
1517
  {
1453
1518
  action: menuItem.action,
@@ -1472,11 +1537,10 @@ var showContextMenu = (e, menuDescriptors, handleContextMenuAction, {
1472
1537
  x: e.clientX,
1473
1538
  y: e.clientY
1474
1539
  };
1475
- const component = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1540
+ const component = /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1476
1541
  ContextMenu,
1477
1542
  {
1478
1543
  ...contextMenuProps,
1479
- className: "vuuContextMenu",
1480
1544
  onClose: handleClose,
1481
1545
  position,
1482
1546
  children: menuItems(menuDescriptors)
@@ -1487,11 +1551,11 @@ var showContextMenu = (e, menuDescriptors, handleContextMenuAction, {
1487
1551
 
1488
1552
  // src/popup-menu/PopupMenu.tsx
1489
1553
  var import_react13 = require("react");
1490
- var import_classnames8 = __toESM(require("classnames"));
1554
+ var import_classnames7 = __toESM(require("classnames"));
1491
1555
  var import_core2 = require("@salt-ds/core");
1492
1556
  var import_vuu_layout3 = require("@vuu-ui/vuu-layout");
1493
- var import_jsx_runtime7 = require("react/jsx-runtime");
1494
- var classBase3 = "vuuPopupMenu";
1557
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1558
+ var classBase4 = "vuuPopupMenu";
1495
1559
  var getPosition2 = (element) => {
1496
1560
  if (element) {
1497
1561
  const { bottom, left } = element.getBoundingClientRect();
@@ -1516,6 +1580,11 @@ var PopupMenu = ({
1516
1580
  const [menuOpen, setMenuOpen] = (0, import_react13.useState)(false);
1517
1581
  const id = (0, import_vuu_layout3.useId)(idProp);
1518
1582
  const [showContextMenu2] = useContextMenu(menuBuilder, menuActionHandler);
1583
+ const handleOpenMenu = (0, import_react13.useCallback)((el) => {
1584
+ console.log(`menu Open `, {
1585
+ el
1586
+ });
1587
+ }, []);
1519
1588
  const handleMenuClose = (0, import_react13.useCallback)(
1520
1589
  (reason) => {
1521
1590
  setMenuOpen(false);
@@ -1544,27 +1613,34 @@ var PopupMenu = ({
1544
1613
  setMenuOpen(true);
1545
1614
  showContextMenu2(e, menuLocation, {
1546
1615
  ContextMenuProps: {
1547
- className: "vuuPopupMenuList",
1548
1616
  id: `${id}-menu`,
1549
1617
  onClose: handleMenuClose,
1618
+ openMenu: handleOpenMenu,
1550
1619
  position: getPosition2(rootRef.current)
1551
1620
  },
1552
1621
  ...menuOptions
1553
1622
  });
1554
1623
  }
1555
1624
  },
1556
- [handleMenuClose, id, menuLocation, menuOptions, showContextMenu2]
1625
+ [
1626
+ handleMenuClose,
1627
+ handleOpenMenu,
1628
+ id,
1629
+ menuLocation,
1630
+ menuOptions,
1631
+ showContextMenu2
1632
+ ]
1557
1633
  );
1558
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1634
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1559
1635
  import_core2.Button,
1560
1636
  {
1561
1637
  ...htmlAttributes,
1562
1638
  "aria-controls": `${id}-menu-root`,
1563
1639
  "aria-expanded": menuOpen,
1564
1640
  "aria-haspopup": "menu",
1565
- className: (0, import_classnames8.default)(classBase3, className, {
1566
- [`${classBase3}-withCaption`]: label !== void 0,
1567
- [`${classBase3}-open`]: menuOpen
1641
+ className: (0, import_classnames7.default)(classBase4, className, {
1642
+ [`${classBase4}-withCaption`]: label !== void 0,
1643
+ [`${classBase4}-open`]: menuOpen
1568
1644
  }),
1569
1645
  "data-icon": icon,
1570
1646
  id,
@@ -1577,54 +1653,13 @@ var PopupMenu = ({
1577
1653
  );
1578
1654
  };
1579
1655
 
1580
- // src/portal/Portal.tsx
1581
- var import_vuu_shell4 = require("@vuu-ui/vuu-shell");
1582
- var import_react14 = require("react");
1583
- var import_react_dom2 = require("react-dom");
1584
- function getContainer(container) {
1585
- return typeof container === "function" ? container() : container;
1586
- }
1587
- var DEFAULT_ID = "vuu-portal-root";
1588
- var Portal2 = ({
1589
- children,
1590
- container: containerProp = document.body,
1591
- id = DEFAULT_ID,
1592
- open = true
1593
- }) => {
1594
- var _a;
1595
- const [mounted, setMounted] = (0, import_react14.useState)(false);
1596
- const portalRef = (0, import_react14.useRef)(null);
1597
- const container = (_a = getContainer(containerProp)) != null ? _a : document.body;
1598
- const [themeClass, densityClass, dataMode] = (0, import_vuu_shell4.useThemeAttributes)();
1599
- (0, import_react14.useLayoutEffect)(() => {
1600
- const root = document.getElementById(id);
1601
- if (root) {
1602
- portalRef.current = root;
1603
- } else {
1604
- portalRef.current = document.createElement("div");
1605
- portalRef.current.id = id;
1606
- }
1607
- const el = portalRef.current;
1608
- if (!container.contains(el)) {
1609
- container.appendChild(el);
1610
- }
1611
- el.classList.add(themeClass, densityClass);
1612
- el.dataset.mode = dataMode;
1613
- setMounted(true);
1614
- }, [id, container, themeClass, densityClass, dataMode]);
1615
- if (open && mounted && portalRef.current && children) {
1616
- return (0, import_react_dom2.createPortal)(children, portalRef.current);
1617
- }
1618
- return null;
1619
- };
1620
-
1621
1656
  // src/prompt/Prompt.tsx
1622
- var import_vuu_shell5 = require("@vuu-ui/vuu-shell");
1657
+ var import_vuu_shell3 = require("@vuu-ui/vuu-shell");
1623
1658
  var import_core3 = require("@salt-ds/core");
1624
- var import_classnames9 = __toESM(require("classnames"));
1625
- var import_react15 = require("react");
1626
- var import_jsx_runtime8 = require("react/jsx-runtime");
1627
- var classBase4 = "vuuPrompt";
1659
+ var import_classnames8 = __toESM(require("classnames"));
1660
+ var import_react14 = require("react");
1661
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1662
+ var classBase5 = "vuuPrompt";
1628
1663
  var AnchorBody = { current: document.body };
1629
1664
  var EMPTY_PROPS = {};
1630
1665
  var Prompt = ({
@@ -1646,16 +1681,16 @@ var Prompt = ({
1646
1681
  offsetTop = 0,
1647
1682
  placement = "below"
1648
1683
  } = PopupProps;
1649
- const [themeClass, densityClass, dataMode] = (0, import_vuu_shell5.useThemeAttributes)();
1650
- const position = useAnchoredPosition({
1684
+ const [themeClass, densityClass, dataMode] = (0, import_vuu_shell3.useThemeAttributes)();
1685
+ const { position } = useAnchoredPosition({
1651
1686
  anchorElement,
1652
1687
  offsetLeft,
1653
1688
  offsetTop,
1654
1689
  placement
1655
1690
  });
1656
- const rootRef = (0, import_react15.useRef)(null);
1657
- const confirmRef = (0, import_react15.useRef)(null);
1658
- (0, import_react15.useLayoutEffect)(() => {
1691
+ const rootRef = (0, import_react14.useRef)(null);
1692
+ const confirmRef = (0, import_react14.useRef)(null);
1693
+ (0, import_react14.useLayoutEffect)(() => {
1659
1694
  if (rootRef.current) {
1660
1695
  rootRef.current.showModal();
1661
1696
  if (confirmRef.current) {
@@ -1667,20 +1702,20 @@ var Prompt = ({
1667
1702
  }
1668
1703
  }
1669
1704
  }, [placement]);
1670
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1705
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1671
1706
  "dialog",
1672
1707
  {
1673
1708
  ...htmlAttributes,
1674
- className: (0, import_classnames9.default)(classBase4, `${classBase4}-${variant}`, themeClass),
1709
+ className: (0, import_classnames8.default)(classBase5, `${classBase5}-${variant}`, themeClass),
1675
1710
  "data-mode": dataMode,
1676
1711
  ref: rootRef,
1677
1712
  style: { ...style, ...position },
1678
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("form", { className: `${classBase4}-form`, children: [
1679
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: `${classBase4}-header`, "data-icon": icon, children: title }),
1680
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: `${classBase4}-text`, children: text }),
1681
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: `${classBase4}-buttonBar`, children: [
1682
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_core3.Button, { onClick: onCancel, variant: "secondary", children: cancelButtonLabel }),
1683
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_core3.Button, { onClick: onConfirm, ref: confirmRef, value: "default", children: confirmButtonLabel })
1713
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("form", { className: `${classBase5}-form`, children: [
1714
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: `${classBase5}-header`, "data-icon": icon, children: title }),
1715
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: `${classBase5}-text`, children: text }),
1716
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: `${classBase5}-buttonBar`, children: [
1717
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_core3.Button, { onClick: onCancel, variant: "secondary", children: cancelButtonLabel }),
1718
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_core3.Button, { onClick: onConfirm, ref: confirmRef, value: "default", children: confirmButtonLabel })
1684
1719
  ] })
1685
1720
  ] })
1686
1721
  }
@@ -1688,7 +1723,7 @@ var Prompt = ({
1688
1723
  };
1689
1724
 
1690
1725
  // src/tooltip/useAnchoredPosition.ts
1691
- var import_react16 = require("react");
1726
+ var import_react15 = require("react");
1692
1727
  var getPositionRelativeToAnchor2 = (anchorElement, placement, offsetLeft, offsetTop) => {
1693
1728
  const { bottom, height, left, right, top, width } = anchorElement.getBoundingClientRect();
1694
1729
  const midX = left + width / 2;
@@ -1714,8 +1749,8 @@ var useAnchoredPosition2 = ({
1714
1749
  offsetTop = 0,
1715
1750
  placement
1716
1751
  }) => {
1717
- const [position, setPosition] = (0, import_react16.useState)();
1718
- (0, import_react16.useLayoutEffect)(() => {
1752
+ const [position, setPosition] = (0, import_react15.useState)();
1753
+ (0, import_react15.useLayoutEffect)(() => {
1719
1754
  if (anchorElement.current) {
1720
1755
  const position2 = getPositionRelativeToAnchor2(
1721
1756
  anchorElement.current,
@@ -1730,8 +1765,8 @@ var useAnchoredPosition2 = ({
1730
1765
  };
1731
1766
 
1732
1767
  // src/tooltip/Tooltip.tsx
1733
- var import_jsx_runtime9 = require("react/jsx-runtime");
1734
- var classBase5 = "vuuTooltip";
1768
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1769
+ var classBase6 = "vuuTooltip";
1735
1770
  var Tooltip = ({
1736
1771
  anchorElement,
1737
1772
  children,
@@ -1744,17 +1779,17 @@ var Tooltip = ({
1744
1779
  if (position === void 0) {
1745
1780
  return null;
1746
1781
  }
1747
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Portal2, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1782
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1748
1783
  "div",
1749
1784
  {
1750
- className: classBase5,
1785
+ className: classBase6,
1751
1786
  "data-align": placement,
1752
1787
  id,
1753
1788
  style: position,
1754
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1789
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1755
1790
  "span",
1756
1791
  {
1757
- className: `${classBase5}-content`,
1792
+ className: `${classBase6}-content`,
1758
1793
  onMouseEnter,
1759
1794
  onMouseLeave,
1760
1795
  children
@@ -1765,37 +1800,37 @@ var Tooltip = ({
1765
1800
  };
1766
1801
 
1767
1802
  // src/tooltip/useTooltip.ts
1768
- var import_react17 = require("react");
1803
+ var import_react16 = require("react");
1769
1804
  var import_vuu_layout4 = require("@vuu-ui/vuu-layout");
1770
1805
  var useTooltip = ({
1771
1806
  id: idProp,
1772
1807
  placement = "right",
1773
1808
  tooltipContent
1774
1809
  }) => {
1775
- const hideTooltipRef = (0, import_react17.useRef)();
1776
- const anchorElementRef = (0, import_react17.useRef)(null);
1777
- const mouseEnterTimerRef = (0, import_react17.useRef)();
1778
- const mouseLeaveTimerRef = (0, import_react17.useRef)();
1779
- const [tooltipProps, setTooltipProps] = (0, import_react17.useState)();
1810
+ const hideTooltipRef = (0, import_react16.useRef)();
1811
+ const anchorElementRef = (0, import_react16.useRef)(null);
1812
+ const mouseEnterTimerRef = (0, import_react16.useRef)();
1813
+ const mouseLeaveTimerRef = (0, import_react16.useRef)();
1814
+ const [tooltipProps, setTooltipProps] = (0, import_react16.useState)();
1780
1815
  const id = (0, import_vuu_layout4.useId)(idProp);
1781
- const escapeListener = (0, import_react17.useCallback)((evt) => {
1816
+ const escapeListener = (0, import_react16.useCallback)((evt) => {
1782
1817
  var _a;
1783
1818
  if (evt.key === "Escape") {
1784
1819
  (_a = hideTooltipRef.current) == null ? void 0 : _a.call(hideTooltipRef);
1785
1820
  }
1786
1821
  }, []);
1787
- hideTooltipRef.current = (0, import_react17.useCallback)(() => {
1822
+ hideTooltipRef.current = (0, import_react16.useCallback)(() => {
1788
1823
  setTooltipProps(void 0);
1789
1824
  document.removeEventListener("keydown", escapeListener);
1790
1825
  }, [escapeListener]);
1791
- const handleMouseEnterTooltip = (0, import_react17.useCallback)(() => {
1826
+ const handleMouseEnterTooltip = (0, import_react16.useCallback)(() => {
1792
1827
  window.clearTimeout(mouseLeaveTimerRef.current);
1793
1828
  }, []);
1794
- const handleMouseLeaveTooltip = (0, import_react17.useCallback)(() => {
1829
+ const handleMouseLeaveTooltip = (0, import_react16.useCallback)(() => {
1795
1830
  var _a;
1796
1831
  (_a = hideTooltipRef.current) == null ? void 0 : _a.call(hideTooltipRef);
1797
1832
  }, []);
1798
- const showTooltip = (0, import_react17.useCallback)(() => {
1833
+ const showTooltip = (0, import_react16.useCallback)(() => {
1799
1834
  const { current: anchorEl } = anchorElementRef;
1800
1835
  if (anchorEl) {
1801
1836
  setTooltipProps({
@@ -1817,7 +1852,7 @@ var useTooltip = ({
1817
1852
  placement,
1818
1853
  tooltipContent
1819
1854
  ]);
1820
- const handleMouseEnter = (0, import_react17.useCallback)(
1855
+ const handleMouseEnter = (0, import_react16.useCallback)(
1821
1856
  (evt) => {
1822
1857
  const el = evt.target;
1823
1858
  if (el) {
@@ -1827,7 +1862,7 @@ var useTooltip = ({
1827
1862
  },
1828
1863
  [showTooltip]
1829
1864
  );
1830
- const handleMouseLeave = (0, import_react17.useCallback)(() => {
1865
+ const handleMouseLeave = (0, import_react16.useCallback)(() => {
1831
1866
  if (anchorElementRef.current)
1832
1867
  if (mouseEnterTimerRef.current) {
1833
1868
  window.clearTimeout(mouseEnterTimerRef.current);
@@ -1851,4 +1886,101 @@ var useTooltip = ({
1851
1886
  tooltipProps
1852
1887
  };
1853
1888
  };
1889
+
1890
+ // src/notifications/NotificationsProvider.tsx
1891
+ var import_react17 = __toESM(require("react"));
1892
+ var import_classnames9 = __toESM(require("classnames"));
1893
+ var import_vuu_utils3 = require("@vuu-ui/vuu-utils");
1894
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1895
+ var toastDisplayDuration = 6e3;
1896
+ var horizontalTransitionDuration = 1e3;
1897
+ var verticalTransitionDuration = 300;
1898
+ var toastHeight = 56;
1899
+ var toastWidth = 300;
1900
+ var toastContainerContentGap = 10;
1901
+ var toastContainerLeftPadding = 10;
1902
+ var toastContainerRightPadding = 50;
1903
+ var classBase7 = "vuuToastNotifications";
1904
+ var NotificationLevel = /* @__PURE__ */ ((NotificationLevel2) => {
1905
+ NotificationLevel2["Info"] = "info";
1906
+ NotificationLevel2["Success"] = "success";
1907
+ NotificationLevel2["Warning"] = "warning";
1908
+ NotificationLevel2["Error"] = "error";
1909
+ return NotificationLevel2;
1910
+ })(NotificationLevel || {});
1911
+ var NotificationsContext = import_react17.default.createContext({
1912
+ notify: () => "have you forgotten to provide a NotificationProvider?"
1913
+ });
1914
+ var NotificationsProvider = (props) => {
1915
+ const [notifications, setNotifications] = (0, import_react17.useState)([]);
1916
+ const notify = (0, import_react17.useCallback)((notification) => {
1917
+ const newNotification = { ...notification, id: (0, import_vuu_utils3.getUniqueId)() };
1918
+ setNotifications((prev) => [...prev, newNotification]);
1919
+ setTimeout(() => {
1920
+ setNotifications((prev) => prev.filter((n) => n !== newNotification));
1921
+ }, toastDisplayDuration + horizontalTransitionDuration * 2);
1922
+ }, []);
1923
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(NotificationsContext.Provider, { value: { notify }, children: [
1924
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1925
+ "div",
1926
+ {
1927
+ className: `${classBase7}-toastContainer`,
1928
+ style: {
1929
+ width: toastWidth + toastContainerRightPadding + toastContainerLeftPadding
1930
+ },
1931
+ children: notifications.map((notification, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1932
+ ToastNotification,
1933
+ {
1934
+ top: (toastHeight + toastContainerContentGap) * i,
1935
+ notification
1936
+ },
1937
+ notification.id
1938
+ ))
1939
+ }
1940
+ ),
1941
+ props.children
1942
+ ] });
1943
+ };
1944
+ var useNotifications = () => (0, import_react17.useContext)(NotificationsContext);
1945
+ var ToastNotification = (props) => {
1946
+ const { top, notification, animated = true } = props;
1947
+ const [right, setRight] = (0, import_react17.useState)(-toastWidth - toastContainerRightPadding);
1948
+ (0, import_react17.useEffect)(() => {
1949
+ setRight(toastContainerRightPadding);
1950
+ if (animated) {
1951
+ setTimeout(
1952
+ () => setRight(-toastWidth - toastContainerRightPadding),
1953
+ toastDisplayDuration + horizontalTransitionDuration
1954
+ );
1955
+ }
1956
+ }, [animated]);
1957
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1958
+ "div",
1959
+ {
1960
+ className: (0, import_classnames9.default)(`${classBase7}-toast`, notification.type),
1961
+ style: {
1962
+ height: toastHeight,
1963
+ right,
1964
+ width: toastWidth,
1965
+ top,
1966
+ transition: animated ? `right ${horizontalTransitionDuration}ms, top ${verticalTransitionDuration}ms ` : "none"
1967
+ },
1968
+ children: [
1969
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1970
+ "div",
1971
+ {
1972
+ className: (0, import_classnames9.default)(
1973
+ `${classBase7}-toastIcon`,
1974
+ `${notification.type}-icon`
1975
+ )
1976
+ }
1977
+ ),
1978
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: `${classBase7}-toastContent`, children: [
1979
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("strong", { className: `${classBase7}-toastHeader`, children: notification.header }),
1980
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { children: notification.body })
1981
+ ] })
1982
+ ]
1983
+ }
1984
+ );
1985
+ };
1854
1986
  //# sourceMappingURL=index.js.map