@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/native/index.d.mts +14 -1
- package/native/index.d.ts +14 -1
- package/native/index.js +32 -10
- package/native/index.js.map +1 -1
- package/native/index.mjs +41 -19
- 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 +32 -10
- package/web/index.js.map +1 -1
- package/web/index.mjs +41 -19
- package/web/index.mjs.map +1 -1
package/native/index.d.mts
CHANGED
|
@@ -87,6 +87,11 @@ interface ContextMenuProps extends ThemeOverrideProps {
|
|
|
87
87
|
emptyMessage?: string;
|
|
88
88
|
empty?: ReactNode;
|
|
89
89
|
trigger?: ReactNode;
|
|
90
|
+
/**
|
|
91
|
+
* When `true`, the trigger fills the full width of its parent instead of
|
|
92
|
+
* shrinking to its content width. Defaults to `false`.
|
|
93
|
+
*/
|
|
94
|
+
triggerFullWidth?: boolean;
|
|
90
95
|
/**
|
|
91
96
|
* Menu placement relative to the trigger element. The `*-center` variants
|
|
92
97
|
* horizontally center the panel on the trigger; every variant auto-flips on
|
|
@@ -95,6 +100,13 @@ interface ContextMenuProps extends ThemeOverrideProps {
|
|
|
95
100
|
* when `position` is set). Defaults to `"bottom-start"`.
|
|
96
101
|
*/
|
|
97
102
|
placement?: ContextMenuPlacement;
|
|
103
|
+
/**
|
|
104
|
+
* Gap in pixels between the trigger and the menu. When `withArrow` is set
|
|
105
|
+
* this is measured to the arrow's tip; otherwise to the panel edge. Only
|
|
106
|
+
* applies to trigger-anchored menus (ignored when `position` is set).
|
|
107
|
+
* Defaults to `4`.
|
|
108
|
+
*/
|
|
109
|
+
offset?: number;
|
|
98
110
|
position?: ContextMenuPosition;
|
|
99
111
|
isOpen?: boolean;
|
|
100
112
|
onOpenChange?: (open: boolean) => void;
|
|
@@ -174,6 +186,7 @@ declare const useContextMenuRequired: () => ContextMenuContextValue;
|
|
|
174
186
|
interface UseContextMenuPositionOptions {
|
|
175
187
|
triggerRef: RefObject<HTMLElement | null>;
|
|
176
188
|
panelRef: RefObject<HTMLElement | null>;
|
|
189
|
+
containerRef: RefObject<HTMLElement | null>;
|
|
177
190
|
isOpen: boolean;
|
|
178
191
|
placement?: ContextMenuPlacement;
|
|
179
192
|
offset?: number;
|
|
@@ -183,6 +196,6 @@ interface ResolvedPosition {
|
|
|
183
196
|
left: number;
|
|
184
197
|
placement: ContextMenuPlacement;
|
|
185
198
|
}
|
|
186
|
-
declare const useContextMenuPosition: ({ triggerRef, panelRef, isOpen, placement, offset, }: UseContextMenuPositionOptions) => ResolvedPosition | undefined;
|
|
199
|
+
declare const useContextMenuPosition: ({ triggerRef, panelRef, containerRef, isOpen, placement, offset, }: UseContextMenuPositionOptions) => ResolvedPosition | undefined;
|
|
187
200
|
|
|
188
201
|
export { ContextMenu, ContextMenuContext, type ContextMenuContextValue, type ContextMenuDividerItemProps, type ContextMenuHeadingItemProps, ContextMenuItem, type ContextMenuItemProps, type ContextMenuOptionItemProps, type ContextMenuPlacement, type ContextMenuPosition, type ContextMenuPresetType, type ContextMenuProps, type ContextMenuSearchItemProps, type ContextMenuSize, type ContextMenuSizing, ContextMenuSubmenu, type ContextMenuSubmenuProps, useContextMenu, useContextMenuPosition, useContextMenuRequired, useKeyboardNavigation };
|
package/native/index.d.ts
CHANGED
|
@@ -87,6 +87,11 @@ interface ContextMenuProps extends ThemeOverrideProps {
|
|
|
87
87
|
emptyMessage?: string;
|
|
88
88
|
empty?: ReactNode;
|
|
89
89
|
trigger?: ReactNode;
|
|
90
|
+
/**
|
|
91
|
+
* When `true`, the trigger fills the full width of its parent instead of
|
|
92
|
+
* shrinking to its content width. Defaults to `false`.
|
|
93
|
+
*/
|
|
94
|
+
triggerFullWidth?: boolean;
|
|
90
95
|
/**
|
|
91
96
|
* Menu placement relative to the trigger element. The `*-center` variants
|
|
92
97
|
* horizontally center the panel on the trigger; every variant auto-flips on
|
|
@@ -95,6 +100,13 @@ interface ContextMenuProps extends ThemeOverrideProps {
|
|
|
95
100
|
* when `position` is set). Defaults to `"bottom-start"`.
|
|
96
101
|
*/
|
|
97
102
|
placement?: ContextMenuPlacement;
|
|
103
|
+
/**
|
|
104
|
+
* Gap in pixels between the trigger and the menu. When `withArrow` is set
|
|
105
|
+
* this is measured to the arrow's tip; otherwise to the panel edge. Only
|
|
106
|
+
* applies to trigger-anchored menus (ignored when `position` is set).
|
|
107
|
+
* Defaults to `4`.
|
|
108
|
+
*/
|
|
109
|
+
offset?: number;
|
|
98
110
|
position?: ContextMenuPosition;
|
|
99
111
|
isOpen?: boolean;
|
|
100
112
|
onOpenChange?: (open: boolean) => void;
|
|
@@ -174,6 +186,7 @@ declare const useContextMenuRequired: () => ContextMenuContextValue;
|
|
|
174
186
|
interface UseContextMenuPositionOptions {
|
|
175
187
|
triggerRef: RefObject<HTMLElement | null>;
|
|
176
188
|
panelRef: RefObject<HTMLElement | null>;
|
|
189
|
+
containerRef: RefObject<HTMLElement | null>;
|
|
177
190
|
isOpen: boolean;
|
|
178
191
|
placement?: ContextMenuPlacement;
|
|
179
192
|
offset?: number;
|
|
@@ -183,6 +196,6 @@ interface ResolvedPosition {
|
|
|
183
196
|
left: number;
|
|
184
197
|
placement: ContextMenuPlacement;
|
|
185
198
|
}
|
|
186
|
-
declare const useContextMenuPosition: ({ triggerRef, panelRef, isOpen, placement, offset, }: UseContextMenuPositionOptions) => ResolvedPosition | undefined;
|
|
199
|
+
declare const useContextMenuPosition: ({ triggerRef, panelRef, containerRef, isOpen, placement, offset, }: UseContextMenuPositionOptions) => ResolvedPosition | undefined;
|
|
187
200
|
|
|
188
201
|
export { ContextMenu, ContextMenuContext, type ContextMenuContextValue, type ContextMenuDividerItemProps, type ContextMenuHeadingItemProps, ContextMenuItem, type ContextMenuItemProps, type ContextMenuOptionItemProps, type ContextMenuPlacement, type ContextMenuPosition, type ContextMenuPresetType, type ContextMenuProps, type ContextMenuSearchItemProps, type ContextMenuSize, type ContextMenuSizing, ContextMenuSubmenu, type ContextMenuSubmenuProps, useContextMenu, useContextMenuPosition, useContextMenuRequired, useKeyboardNavigation };
|
package/native/index.js
CHANGED
|
@@ -1079,12 +1079,13 @@ var joinPlacement = (vertical, horizontal) => `${vertical}-${horizontal}`;
|
|
|
1079
1079
|
var useContextMenuPosition = ({
|
|
1080
1080
|
triggerRef,
|
|
1081
1081
|
panelRef,
|
|
1082
|
+
containerRef,
|
|
1082
1083
|
isOpen,
|
|
1083
1084
|
placement = "bottom-start",
|
|
1084
1085
|
offset = 4
|
|
1085
1086
|
}) => {
|
|
1086
1087
|
const [resolved, setResolved] = (0, import_react4.useState)();
|
|
1087
|
-
(0, import_react4.
|
|
1088
|
+
(0, import_react4.useLayoutEffect)(() => {
|
|
1088
1089
|
if (!isOpen) {
|
|
1089
1090
|
setResolved(void 0);
|
|
1090
1091
|
return;
|
|
@@ -1092,6 +1093,7 @@ var useContextMenuPosition = ({
|
|
|
1092
1093
|
const compute = () => {
|
|
1093
1094
|
const trigger = triggerRef.current;
|
|
1094
1095
|
const panel = panelRef.current;
|
|
1096
|
+
const container = containerRef.current;
|
|
1095
1097
|
if (!trigger || !panel) return;
|
|
1096
1098
|
const triggerRect = trigger.getBoundingClientRect();
|
|
1097
1099
|
const panelRect = panel.getBoundingClientRect();
|
|
@@ -1131,6 +1133,15 @@ var useContextMenuPosition = ({
|
|
|
1131
1133
|
}
|
|
1132
1134
|
}
|
|
1133
1135
|
}
|
|
1136
|
+
if (container) {
|
|
1137
|
+
const containerRect = container.getBoundingClientRect();
|
|
1138
|
+
const cOffsetW = container.offsetWidth;
|
|
1139
|
+
const cOffsetH = container.offsetHeight;
|
|
1140
|
+
const scaleX = cOffsetW > 0 ? containerRect.width / cOffsetW : 1;
|
|
1141
|
+
const scaleY = cOffsetH > 0 ? containerRect.height / cOffsetH : 1;
|
|
1142
|
+
left = (left - containerRect.left) / (scaleX || 1);
|
|
1143
|
+
top = (top - containerRect.top) / (scaleY || 1);
|
|
1144
|
+
}
|
|
1134
1145
|
const next = {
|
|
1135
1146
|
top,
|
|
1136
1147
|
left,
|
|
@@ -1140,14 +1151,13 @@ var useContextMenuPosition = ({
|
|
|
1140
1151
|
(prev) => prev && prev.top === next.top && prev.left === next.left && prev.placement === next.placement ? prev : next
|
|
1141
1152
|
);
|
|
1142
1153
|
};
|
|
1143
|
-
|
|
1154
|
+
compute();
|
|
1144
1155
|
const onResize = () => compute();
|
|
1145
1156
|
window.addEventListener("resize", onResize);
|
|
1146
1157
|
return () => {
|
|
1147
|
-
window.cancelAnimationFrame(rafId);
|
|
1148
1158
|
window.removeEventListener("resize", onResize);
|
|
1149
1159
|
};
|
|
1150
|
-
}, [isOpen, placement, offset, triggerRef, panelRef]);
|
|
1160
|
+
}, [isOpen, placement, offset, triggerRef, panelRef, containerRef]);
|
|
1151
1161
|
return resolved;
|
|
1152
1162
|
};
|
|
1153
1163
|
|
|
@@ -1279,6 +1289,7 @@ var SEARCH_DEBOUNCE_MS = 200;
|
|
|
1279
1289
|
var ARROW_SIZE = 10;
|
|
1280
1290
|
var ARROW_HALF = ARROW_SIZE / 2;
|
|
1281
1291
|
var ARROW_EDGE_OFFSET = 12;
|
|
1292
|
+
var ARROW_TIP_PROTRUSION = ARROW_HALF * Math.SQRT2;
|
|
1282
1293
|
var PANEL_SHADOW = "0 4px 12px rgba(0,0,0,0.15)";
|
|
1283
1294
|
var textFromNode = (node) => {
|
|
1284
1295
|
if (node === null || node === void 0 || typeof node === "boolean")
|
|
@@ -1328,7 +1339,9 @@ var ContextMenuRoot = (0, import_react6.forwardRef)(
|
|
|
1328
1339
|
isOpen: propIsOpen,
|
|
1329
1340
|
onOpenChange,
|
|
1330
1341
|
trigger,
|
|
1342
|
+
triggerFullWidth = false,
|
|
1331
1343
|
placement = "bottom-start",
|
|
1344
|
+
offset = 4,
|
|
1332
1345
|
position,
|
|
1333
1346
|
width,
|
|
1334
1347
|
maxHeight = 300,
|
|
@@ -1362,11 +1375,14 @@ var ContextMenuRoot = (0, import_react6.forwardRef)(
|
|
|
1362
1375
|
const sizeStyles = xuiTheme.sizing.contextMenu(size);
|
|
1363
1376
|
const borderRadius = xuiTheme.shape?.contextMenu?.[size]?.borderRadius ?? 8;
|
|
1364
1377
|
const shouldCloseOnSelect = closeOnSelect ?? (type === "checkbox" ? false : true);
|
|
1378
|
+
const positionOffset = withArrow ? offset + ARROW_TIP_PROTRUSION : offset;
|
|
1365
1379
|
const positioned = useContextMenuPosition({
|
|
1366
1380
|
triggerRef,
|
|
1367
1381
|
panelRef,
|
|
1382
|
+
containerRef,
|
|
1368
1383
|
isOpen: isOpen && !!trigger && !position,
|
|
1369
|
-
placement
|
|
1384
|
+
placement,
|
|
1385
|
+
offset: positionOffset
|
|
1370
1386
|
});
|
|
1371
1387
|
const resolvedPlacement = positioned?.placement ?? placement;
|
|
1372
1388
|
const getArrowStyle = (arrowPlacement) => {
|
|
@@ -1622,7 +1638,10 @@ var ContextMenuRoot = (0, import_react6.forwardRef)(
|
|
|
1622
1638
|
onClick: (event) => {
|
|
1623
1639
|
if (!event.defaultPrevented) toggleMenu();
|
|
1624
1640
|
},
|
|
1625
|
-
style: {
|
|
1641
|
+
style: {
|
|
1642
|
+
display: "inline-flex",
|
|
1643
|
+
width: triggerFullWidth ? "100%" : "auto"
|
|
1644
|
+
},
|
|
1626
1645
|
children: (0, import_react6.cloneElement)(trigger, {
|
|
1627
1646
|
"aria-haspopup": "menu",
|
|
1628
1647
|
"aria-expanded": isOpen ? "true" : "false"
|
|
@@ -1644,10 +1663,13 @@ var ContextMenuRoot = (0, import_react6.forwardRef)(
|
|
|
1644
1663
|
position: "fixed",
|
|
1645
1664
|
left: position.x,
|
|
1646
1665
|
top: position.y
|
|
1647
|
-
} : trigger ? {
|
|
1648
|
-
position: "
|
|
1649
|
-
left: positioned
|
|
1650
|
-
top: positioned
|
|
1666
|
+
} : trigger ? positioned ? {
|
|
1667
|
+
position: "absolute",
|
|
1668
|
+
left: positioned.left,
|
|
1669
|
+
top: positioned.top
|
|
1670
|
+
} : {
|
|
1671
|
+
position: "absolute",
|
|
1672
|
+
visibility: "hidden"
|
|
1651
1673
|
} : void 0;
|
|
1652
1674
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ContextMenuContext.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1653
1675
|
"div",
|