@xsolla/xui-context-menu 0.181.0 → 0.182.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/native/index.d.mts +14 -1
- package/native/index.d.ts +14 -1
- package/native/index.js +92 -22
- package/native/index.js.map +1 -1
- package/native/index.mjs +93 -23
- package/native/index.mjs.map +1 -1
- package/package.json +10 -10
- package/web/index.d.mts +14 -1
- package/web/index.d.ts +14 -1
- package/web/index.js +92 -22
- package/web/index.js.map +1 -1
- package/web/index.mjs +93 -23
- package/web/index.mjs.map +1 -1
package/web/index.js
CHANGED
|
@@ -1176,7 +1176,11 @@ var useContextMenuPosition = ({
|
|
|
1176
1176
|
const viewportHeight = window.innerHeight;
|
|
1177
1177
|
let { vertical, horizontal } = splitPlacement(placement);
|
|
1178
1178
|
const computeTop = (v) => v === "bottom" ? triggerRect.bottom + offset : triggerRect.top - panelRect.height - offset;
|
|
1179
|
-
const computeLeft = (h) =>
|
|
1179
|
+
const computeLeft = (h) => {
|
|
1180
|
+
if (h === "center")
|
|
1181
|
+
return triggerRect.left + triggerRect.width / 2 - panelRect.width / 2;
|
|
1182
|
+
return h === "start" ? triggerRect.left : triggerRect.right - panelRect.width;
|
|
1183
|
+
};
|
|
1180
1184
|
let top = computeTop(vertical);
|
|
1181
1185
|
const wantedBottom = top + panelRect.height;
|
|
1182
1186
|
if (top < 0 || wantedBottom > viewportHeight) {
|
|
@@ -1189,14 +1193,19 @@ var useContextMenuPosition = ({
|
|
|
1189
1193
|
}
|
|
1190
1194
|
}
|
|
1191
1195
|
let left = computeLeft(horizontal);
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
const
|
|
1197
|
-
if (
|
|
1198
|
-
|
|
1199
|
-
|
|
1196
|
+
if (horizontal === "center") {
|
|
1197
|
+
const maxLeft = viewportWidth - panelRect.width;
|
|
1198
|
+
left = maxLeft >= 0 ? Math.min(Math.max(left, 0), maxLeft) : 0;
|
|
1199
|
+
} else {
|
|
1200
|
+
const wantedRight = left + panelRect.width;
|
|
1201
|
+
if (left < 0 || wantedRight > viewportWidth) {
|
|
1202
|
+
const flipped = horizontal === "start" ? "end" : "start";
|
|
1203
|
+
const flippedLeft = computeLeft(flipped);
|
|
1204
|
+
const flippedRight = flippedLeft + panelRect.width;
|
|
1205
|
+
if (flippedLeft >= 0 && flippedRight <= viewportWidth) {
|
|
1206
|
+
horizontal = flipped;
|
|
1207
|
+
left = flippedLeft;
|
|
1208
|
+
}
|
|
1200
1209
|
}
|
|
1201
1210
|
}
|
|
1202
1211
|
const next = {
|
|
@@ -1344,6 +1353,10 @@ var useKeyboardNavigation = ({
|
|
|
1344
1353
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
1345
1354
|
var DEFAULT_EMPTY_MESSAGE = "No results";
|
|
1346
1355
|
var SEARCH_DEBOUNCE_MS = 200;
|
|
1356
|
+
var ARROW_SIZE = 10;
|
|
1357
|
+
var ARROW_HALF = ARROW_SIZE / 2;
|
|
1358
|
+
var ARROW_EDGE_OFFSET = 12;
|
|
1359
|
+
var PANEL_SHADOW = "0 4px 12px rgba(0,0,0,0.15)";
|
|
1347
1360
|
var textFromNode = (node) => {
|
|
1348
1361
|
if (node === null || node === void 0 || typeof node === "boolean")
|
|
1349
1362
|
return "";
|
|
@@ -1396,6 +1409,7 @@ var ContextMenuRoot = (0, import_react8.forwardRef)(
|
|
|
1396
1409
|
position,
|
|
1397
1410
|
width,
|
|
1398
1411
|
maxHeight = 300,
|
|
1412
|
+
withArrow = false,
|
|
1399
1413
|
onSelect,
|
|
1400
1414
|
closeOnSelect,
|
|
1401
1415
|
"aria-label": ariaLabel,
|
|
@@ -1431,6 +1445,33 @@ var ContextMenuRoot = (0, import_react8.forwardRef)(
|
|
|
1431
1445
|
isOpen: isOpen && !!trigger && !position,
|
|
1432
1446
|
placement
|
|
1433
1447
|
});
|
|
1448
|
+
const resolvedPlacement = positioned?.placement ?? placement;
|
|
1449
|
+
const getArrowStyle = (arrowPlacement) => {
|
|
1450
|
+
const isTop = arrowPlacement.startsWith("top");
|
|
1451
|
+
const arrowStyle = {
|
|
1452
|
+
position: "absolute",
|
|
1453
|
+
width: ARROW_SIZE,
|
|
1454
|
+
height: ARROW_SIZE,
|
|
1455
|
+
backgroundColor: xuiTheme.colors.background.secondary,
|
|
1456
|
+
borderStyle: "solid",
|
|
1457
|
+
borderColor: xuiTheme.colors.border.secondary,
|
|
1458
|
+
// 1px outline only on the two outward-facing edges of the rotated square
|
|
1459
|
+
borderWidth: isTop ? "0 1px 1px 0" : "1px 0 0 1px",
|
|
1460
|
+
transform: "rotate(45deg)",
|
|
1461
|
+
pointerEvents: "none"
|
|
1462
|
+
};
|
|
1463
|
+
if (isTop) arrowStyle.bottom = -ARROW_HALF;
|
|
1464
|
+
else arrowStyle.top = -ARROW_HALF;
|
|
1465
|
+
if (arrowPlacement.endsWith("center")) {
|
|
1466
|
+
arrowStyle.left = "50%";
|
|
1467
|
+
arrowStyle.marginLeft = -ARROW_HALF;
|
|
1468
|
+
} else if (arrowPlacement.endsWith("end")) {
|
|
1469
|
+
arrowStyle.right = ARROW_EDGE_OFFSET;
|
|
1470
|
+
} else {
|
|
1471
|
+
arrowStyle.left = ARROW_EDGE_OFFSET;
|
|
1472
|
+
}
|
|
1473
|
+
return arrowStyle;
|
|
1474
|
+
};
|
|
1434
1475
|
const setOpen = (0, import_react8.useCallback)(
|
|
1435
1476
|
(nextOpen) => {
|
|
1436
1477
|
if (propIsOpen === void 0) setInternalIsOpen(nextOpen);
|
|
@@ -1641,15 +1682,30 @@ var ContextMenuRoot = (0, import_react8.forwardRef)(
|
|
|
1641
1682
|
const assignTriggerRef = (node) => {
|
|
1642
1683
|
triggerRef.current = node;
|
|
1643
1684
|
};
|
|
1644
|
-
const
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
onClick: (event) => {
|
|
1649
|
-
trigger.props.onClick?.(event);
|
|
1650
|
-
if (!event.defaultPrevented) toggleMenu();
|
|
1685
|
+
const assignTriggerWrapperRef = (node) => {
|
|
1686
|
+
if (!node) {
|
|
1687
|
+
assignTriggerRef(null);
|
|
1688
|
+
return;
|
|
1651
1689
|
}
|
|
1652
|
-
|
|
1690
|
+
const firstChild = node.firstElementChild;
|
|
1691
|
+
assignTriggerRef(
|
|
1692
|
+
firstChild instanceof HTMLElement ? firstChild : node
|
|
1693
|
+
);
|
|
1694
|
+
};
|
|
1695
|
+
const triggerNode = trigger && (0, import_react8.isValidElement)(trigger) ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1696
|
+
"span",
|
|
1697
|
+
{
|
|
1698
|
+
ref: assignTriggerWrapperRef,
|
|
1699
|
+
onClick: (event) => {
|
|
1700
|
+
if (!event.defaultPrevented) toggleMenu();
|
|
1701
|
+
},
|
|
1702
|
+
style: { display: "inline-flex" },
|
|
1703
|
+
children: (0, import_react8.cloneElement)(trigger, {
|
|
1704
|
+
"aria-haspopup": "menu",
|
|
1705
|
+
"aria-expanded": isOpen ? "true" : "false"
|
|
1706
|
+
})
|
|
1707
|
+
}
|
|
1708
|
+
) : trigger ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1653
1709
|
"span",
|
|
1654
1710
|
{
|
|
1655
1711
|
ref: assignTriggerRef,
|
|
@@ -1687,7 +1743,7 @@ var ContextMenuRoot = (0, import_react8.forwardRef)(
|
|
|
1687
1743
|
role: "menu",
|
|
1688
1744
|
"aria-label": ariaLabel,
|
|
1689
1745
|
"data-testid": dataTestId ?? testID ?? "context-menu",
|
|
1690
|
-
"data-placement":
|
|
1746
|
+
"data-placement": resolvedPlacement,
|
|
1691
1747
|
backgroundColor: xuiTheme.colors.background.secondary,
|
|
1692
1748
|
borderColor: xuiTheme.colors.border.secondary,
|
|
1693
1749
|
borderWidth: 1,
|
|
@@ -1702,12 +1758,26 @@ var ContextMenuRoot = (0, import_react8.forwardRef)(
|
|
|
1702
1758
|
...positionStyle,
|
|
1703
1759
|
...style,
|
|
1704
1760
|
zIndex: 1e3,
|
|
1705
|
-
boxShadow:
|
|
1706
|
-
|
|
1707
|
-
|
|
1761
|
+
boxShadow: PANEL_SHADOW,
|
|
1762
|
+
...withArrow ? {
|
|
1763
|
+
overflow: "visible"
|
|
1764
|
+
} : {
|
|
1765
|
+
maxHeight,
|
|
1766
|
+
overflowY: "auto"
|
|
1767
|
+
},
|
|
1708
1768
|
outline: "none"
|
|
1709
1769
|
},
|
|
1710
|
-
children:
|
|
1770
|
+
children: withArrow ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
1771
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1772
|
+
"span",
|
|
1773
|
+
{
|
|
1774
|
+
"aria-hidden": "true",
|
|
1775
|
+
"data-testid": "context-menu-arrow",
|
|
1776
|
+
style: getArrowStyle(resolvedPlacement)
|
|
1777
|
+
}
|
|
1778
|
+
),
|
|
1779
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { maxHeight, overflowY: "auto", borderRadius }, children: renderContent() })
|
|
1780
|
+
] }) : renderContent()
|
|
1711
1781
|
}
|
|
1712
1782
|
)
|
|
1713
1783
|
]
|