@xsolla/xui-context-menu 0.183.0 → 0.185.0

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
@@ -1156,12 +1156,13 @@ var joinPlacement = (vertical, horizontal) => `${vertical}-${horizontal}`;
1156
1156
  var useContextMenuPosition = ({
1157
1157
  triggerRef,
1158
1158
  panelRef,
1159
+ containerRef,
1159
1160
  isOpen,
1160
1161
  placement = "bottom-start",
1161
1162
  offset = 4
1162
1163
  }) => {
1163
1164
  const [resolved, setResolved] = (0, import_react6.useState)();
1164
- (0, import_react6.useEffect)(() => {
1165
+ (0, import_react6.useLayoutEffect)(() => {
1165
1166
  if (!isOpen) {
1166
1167
  setResolved(void 0);
1167
1168
  return;
@@ -1169,6 +1170,7 @@ var useContextMenuPosition = ({
1169
1170
  const compute = () => {
1170
1171
  const trigger = triggerRef.current;
1171
1172
  const panel = panelRef.current;
1173
+ const container = containerRef.current;
1172
1174
  if (!trigger || !panel) return;
1173
1175
  const triggerRect = trigger.getBoundingClientRect();
1174
1176
  const panelRect = panel.getBoundingClientRect();
@@ -1208,6 +1210,15 @@ var useContextMenuPosition = ({
1208
1210
  }
1209
1211
  }
1210
1212
  }
1213
+ if (container) {
1214
+ const containerRect = container.getBoundingClientRect();
1215
+ const cOffsetW = container.offsetWidth;
1216
+ const cOffsetH = container.offsetHeight;
1217
+ const scaleX = cOffsetW > 0 ? containerRect.width / cOffsetW : 1;
1218
+ const scaleY = cOffsetH > 0 ? containerRect.height / cOffsetH : 1;
1219
+ left = (left - containerRect.left) / (scaleX || 1);
1220
+ top = (top - containerRect.top) / (scaleY || 1);
1221
+ }
1211
1222
  const next = {
1212
1223
  top,
1213
1224
  left,
@@ -1217,14 +1228,13 @@ var useContextMenuPosition = ({
1217
1228
  (prev) => prev && prev.top === next.top && prev.left === next.left && prev.placement === next.placement ? prev : next
1218
1229
  );
1219
1230
  };
1220
- const rafId = window.requestAnimationFrame(compute);
1231
+ compute();
1221
1232
  const onResize = () => compute();
1222
1233
  window.addEventListener("resize", onResize);
1223
1234
  return () => {
1224
- window.cancelAnimationFrame(rafId);
1225
1235
  window.removeEventListener("resize", onResize);
1226
1236
  };
1227
- }, [isOpen, placement, offset, triggerRef, panelRef]);
1237
+ }, [isOpen, placement, offset, triggerRef, panelRef, containerRef]);
1228
1238
  return resolved;
1229
1239
  };
1230
1240
 
@@ -1356,6 +1366,7 @@ var SEARCH_DEBOUNCE_MS = 200;
1356
1366
  var ARROW_SIZE = 10;
1357
1367
  var ARROW_HALF = ARROW_SIZE / 2;
1358
1368
  var ARROW_EDGE_OFFSET = 12;
1369
+ var ARROW_TIP_PROTRUSION = ARROW_HALF * Math.SQRT2;
1359
1370
  var PANEL_SHADOW = "0 4px 12px rgba(0,0,0,0.15)";
1360
1371
  var textFromNode = (node) => {
1361
1372
  if (node === null || node === void 0 || typeof node === "boolean")
@@ -1405,7 +1416,9 @@ var ContextMenuRoot = (0, import_react8.forwardRef)(
1405
1416
  isOpen: propIsOpen,
1406
1417
  onOpenChange,
1407
1418
  trigger,
1419
+ triggerFullWidth = false,
1408
1420
  placement = "bottom-start",
1421
+ offset = 4,
1409
1422
  position,
1410
1423
  width,
1411
1424
  maxHeight = 300,
@@ -1439,11 +1452,14 @@ var ContextMenuRoot = (0, import_react8.forwardRef)(
1439
1452
  const sizeStyles = xuiTheme.sizing.contextMenu(size);
1440
1453
  const borderRadius = xuiTheme.shape?.contextMenu?.[size]?.borderRadius ?? 8;
1441
1454
  const shouldCloseOnSelect = closeOnSelect ?? (type === "checkbox" ? false : true);
1455
+ const positionOffset = withArrow ? offset + ARROW_TIP_PROTRUSION : offset;
1442
1456
  const positioned = useContextMenuPosition({
1443
1457
  triggerRef,
1444
1458
  panelRef,
1459
+ containerRef,
1445
1460
  isOpen: isOpen && !!trigger && !position,
1446
- placement
1461
+ placement,
1462
+ offset: positionOffset
1447
1463
  });
1448
1464
  const resolvedPlacement = positioned?.placement ?? placement;
1449
1465
  const getArrowStyle = (arrowPlacement) => {
@@ -1699,7 +1715,10 @@ var ContextMenuRoot = (0, import_react8.forwardRef)(
1699
1715
  onClick: (event) => {
1700
1716
  if (!event.defaultPrevented) toggleMenu();
1701
1717
  },
1702
- style: { display: "inline-flex" },
1718
+ style: {
1719
+ display: "inline-flex",
1720
+ width: triggerFullWidth ? "100%" : "auto"
1721
+ },
1703
1722
  children: (0, import_react8.cloneElement)(trigger, {
1704
1723
  "aria-haspopup": "menu",
1705
1724
  "aria-expanded": isOpen ? "true" : "false"
@@ -1721,10 +1740,13 @@ var ContextMenuRoot = (0, import_react8.forwardRef)(
1721
1740
  position: "fixed",
1722
1741
  left: position.x,
1723
1742
  top: position.y
1724
- } : trigger ? {
1725
- position: "fixed",
1726
- left: positioned?.left ?? 0,
1727
- top: positioned?.top ?? 0
1743
+ } : trigger ? positioned ? {
1744
+ position: "absolute",
1745
+ left: positioned.left,
1746
+ top: positioned.top
1747
+ } : {
1748
+ position: "absolute",
1749
+ visibility: "hidden"
1728
1750
  } : void 0;
1729
1751
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ContextMenuContext.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1730
1752
  "div",