@xsolla/xui-context-menu 0.185.0 → 0.185.2

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/web/index.js CHANGED
@@ -456,6 +456,7 @@ var OptionCell = ({
456
456
  const closeTimerRef = import_react4.default.useRef(
457
457
  null
458
458
  );
459
+ const ownsSubmenu = Boolean(hasSubmenu && submenu != null);
459
460
  const cancelClose = () => {
460
461
  if (closeTimerRef.current) {
461
462
  clearTimeout(closeTimerRef.current);
@@ -464,9 +465,22 @@ var OptionCell = ({
464
465
  };
465
466
  const scheduleClose = () => {
466
467
  cancelClose();
467
- closeTimerRef.current = setTimeout(() => setSubmenuOpen(false), 120);
468
+ closeTimerRef.current = setTimeout(() => {
469
+ setSubmenuOpen(false);
470
+ if (ownsSubmenu && ctx?.activeSubmenuId === id) {
471
+ ctx.setActiveSubmenuId?.(null);
472
+ }
473
+ }, 120);
468
474
  };
469
475
  (0, import_react4.useEffect)(() => () => cancelClose(), []);
476
+ (0, import_react4.useEffect)(() => {
477
+ if (!ownsSubmenu || !submenuOpen) return;
478
+ const activeId = ctx?.activeSubmenuId;
479
+ if (activeId != null && activeId !== id) {
480
+ cancelClose();
481
+ setSubmenuOpen(false);
482
+ }
483
+ }, [ctx?.activeSubmenuId, ownsSubmenu, submenuOpen, id]);
470
484
  (0, import_react4.useEffect)(() => {
471
485
  if (!hasSubmenu || !submenuOpen) return;
472
486
  const onMouseDown = (e) => {
@@ -475,13 +489,16 @@ var OptionCell = ({
475
489
  const inOption = optionRef.current?.contains(target);
476
490
  const inSubmenu = submenuWrapperRef.current?.contains(target);
477
491
  if (!inOption && !inSubmenu) {
492
+ if (target.closest("[data-xui-context-menu-portal]")) return;
478
493
  setSubmenuOpen(false);
479
494
  return;
480
495
  }
481
- if (inSubmenu && target.closest(
482
- '[role="menuitem"],[role="menuitemcheckbox"],[role="menuitemradio"]'
483
- )) {
484
- setSubmenuOpen(false);
496
+ if (inSubmenu) {
497
+ const activated = target.closest(
498
+ '[role="menuitem"],[role="menuitemcheckbox"],[role="menuitemradio"]'
499
+ );
500
+ const isLeafAction = activated?.getAttribute("role") === "menuitem" && activated.getAttribute("aria-haspopup") !== "menu";
501
+ if (isLeafAction) setSubmenuOpen(false);
485
502
  }
486
503
  };
487
504
  document.addEventListener("mousedown", onMouseDown);
@@ -557,6 +574,7 @@ var OptionCell = ({
557
574
  if (ctx && index2 >= 0) ctx.setActiveIndex(index2);
558
575
  if (!ctx) setIsHovered(true);
559
576
  if (hasSubmenu) setSubmenuOpen(true);
577
+ if (ownsSubmenu) ctx?.setActiveSubmenuId?.(id);
560
578
  };
561
579
  const handleLeave = () => {
562
580
  if (!ctx) setIsHovered(false);
@@ -1368,6 +1386,7 @@ var ARROW_HALF = ARROW_SIZE / 2;
1368
1386
  var ARROW_EDGE_OFFSET = 12;
1369
1387
  var ARROW_TIP_PROTRUSION = ARROW_HALF * Math.SQRT2;
1370
1388
  var PANEL_SHADOW = "0 4px 12px rgba(0,0,0,0.15)";
1389
+ var PORTALED_LAYER_SELECTOR = '[data-modal-id],[role="listbox"],[data-xui-context-menu-portal]';
1371
1390
  var textFromNode = (node) => {
1372
1391
  if (node === null || node === void 0 || typeof node === "boolean")
1373
1392
  return "";
@@ -1554,7 +1573,13 @@ var ContextMenuRoot = (0, import_react8.forwardRef)(
1554
1573
  if (!isOpen || !trigger) return;
1555
1574
  const onMouseDown = (event) => {
1556
1575
  const target = event.target;
1557
- if (!target || containerRef.current?.contains(target)) return;
1576
+ if (!target) return;
1577
+ if (containerRef.current?.contains(target)) return;
1578
+ const path = typeof event.composedPath === "function" ? event.composedPath() : [];
1579
+ const isInsidePortaledLayer = path.length ? path.some(
1580
+ (node) => node instanceof Element && node.matches(PORTALED_LAYER_SELECTOR)
1581
+ ) : target instanceof Element && !!target.closest(PORTALED_LAYER_SELECTOR);
1582
+ if (isInsidePortaledLayer) return;
1558
1583
  closeMenu();
1559
1584
  };
1560
1585
  const onScroll = () => closeMenu();