@hanzogui/context-menu 2.0.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.
Files changed (44) hide show
  1. package/dist/cjs/ContextMenu.cjs +182 -0
  2. package/dist/cjs/ContextMenu.native.js +191 -0
  3. package/dist/cjs/ContextMenu.native.js.map +1 -0
  4. package/dist/cjs/createNonNativeContextMenu.cjs +417 -0
  5. package/dist/cjs/createNonNativeContextMenu.native.js +443 -0
  6. package/dist/cjs/createNonNativeContextMenu.native.js.map +1 -0
  7. package/dist/cjs/index.cjs +39 -0
  8. package/dist/cjs/index.native.js +42 -0
  9. package/dist/cjs/index.native.js.map +1 -0
  10. package/dist/esm/ContextMenu.mjs +148 -0
  11. package/dist/esm/ContextMenu.mjs.map +1 -0
  12. package/dist/esm/ContextMenu.native.js +154 -0
  13. package/dist/esm/ContextMenu.native.js.map +1 -0
  14. package/dist/esm/createNonNativeContextMenu.mjs +382 -0
  15. package/dist/esm/createNonNativeContextMenu.mjs.map +1 -0
  16. package/dist/esm/createNonNativeContextMenu.native.js +405 -0
  17. package/dist/esm/createNonNativeContextMenu.native.js.map +1 -0
  18. package/dist/esm/index.js +15 -0
  19. package/dist/esm/index.js.map +1 -0
  20. package/dist/esm/index.mjs +15 -0
  21. package/dist/esm/index.mjs.map +1 -0
  22. package/dist/esm/index.native.js +15 -0
  23. package/dist/esm/index.native.js.map +1 -0
  24. package/dist/jsx/ContextMenu.mjs +148 -0
  25. package/dist/jsx/ContextMenu.mjs.map +1 -0
  26. package/dist/jsx/ContextMenu.native.js +191 -0
  27. package/dist/jsx/ContextMenu.native.js.map +1 -0
  28. package/dist/jsx/createNonNativeContextMenu.mjs +382 -0
  29. package/dist/jsx/createNonNativeContextMenu.mjs.map +1 -0
  30. package/dist/jsx/createNonNativeContextMenu.native.js +443 -0
  31. package/dist/jsx/createNonNativeContextMenu.native.js.map +1 -0
  32. package/dist/jsx/index.js +15 -0
  33. package/dist/jsx/index.js.map +1 -0
  34. package/dist/jsx/index.mjs +15 -0
  35. package/dist/jsx/index.mjs.map +1 -0
  36. package/dist/jsx/index.native.js +42 -0
  37. package/dist/jsx/index.native.js.map +1 -0
  38. package/package.json +53 -0
  39. package/src/ContextMenu.tsx +187 -0
  40. package/src/createNonNativeContextMenu.tsx +641 -0
  41. package/src/index.tsx +17 -0
  42. package/types/ContextMenu.d.ts +134 -0
  43. package/types/createNonNativeContextMenu.d.ts +180 -0
  44. package/types/index.d.ts +132 -0
@@ -0,0 +1,417 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf,
6
+ __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all) __defProp(target, name, {
9
+ get: all[name],
10
+ enumerable: !0
11
+ });
12
+ },
13
+ __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from == "object" || typeof from == "function") for (let key of __getOwnPropNames(from)) !__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, {
15
+ get: () => from[key],
16
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
17
+ });
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
26
+ value: mod,
27
+ enumerable: !0
28
+ }) : target, mod)),
29
+ __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", {
30
+ value: !0
31
+ }), mod);
32
+ var createNonNativeContextMenu_exports = {};
33
+ __export(createNonNativeContextMenu_exports, {
34
+ CONTEXTMENU_CONTEXT: () => CONTEXTMENU_CONTEXT,
35
+ createNonNativeContextMenu: () => createNonNativeContextMenu
36
+ });
37
+ module.exports = __toCommonJS(createNonNativeContextMenu_exports);
38
+ var import_gui_create_menu = require("@hanzo/gui-create-menu"),
39
+ import_gui_use_controllable_state = require("@hanzo/gui-use-controllable-state"),
40
+ import_gui_web = require("@hanzo/gui-web"),
41
+ import_react = __toESM(require("react"), 1),
42
+ import_jsx_runtime = require("react/jsx-runtime");
43
+ const CONTEXTMENU_CONTEXT = "ContextMenuContext";
44
+ function createNonNativeContextMenu(params) {
45
+ const {
46
+ Menu
47
+ } = (0, import_gui_create_menu.createBaseMenu)(params),
48
+ CONTEXT_MENU_NAME = "ContextMenu",
49
+ {
50
+ Provider: ContextMenuProvider,
51
+ useStyledContext: useContextMenuContext
52
+ } = (0, import_gui_web.createStyledContext)(),
53
+ ContextMenuComp = props => {
54
+ const {
55
+ scope,
56
+ children,
57
+ onOpenChange,
58
+ dir,
59
+ modal = !0,
60
+ ...rest
61
+ } = props,
62
+ [open, setOpen] = import_react.default.useState(!1),
63
+ triggerRef = import_react.default.useRef(null),
64
+ handleOpenChange = import_react.default.useCallback((open2, event) => {
65
+ onOpenChange?.(open2, event), !event?.defaultPrevented && setOpen(open2);
66
+ }, [onOpenChange]);
67
+ return /* @__PURE__ */(0, import_jsx_runtime.jsx)(ContextMenuProvider, {
68
+ scope,
69
+ triggerId: (0, import_react.useId)(),
70
+ triggerRef,
71
+ contentId: (0, import_react.useId)(),
72
+ open,
73
+ onOpenChange: handleOpenChange,
74
+ modal,
75
+ children: /* @__PURE__ */(0, import_jsx_runtime.jsx)(Menu, {
76
+ scope: scope || CONTEXTMENU_CONTEXT,
77
+ dir,
78
+ open,
79
+ onOpenChange: handleOpenChange,
80
+ modal,
81
+ ...rest,
82
+ children
83
+ })
84
+ });
85
+ };
86
+ ContextMenuComp.displayName = CONTEXT_MENU_NAME;
87
+ const TRIGGER_NAME = "ContextMenuTrigger",
88
+ ContextMenuTrigger = import_gui_web.View.styleable((props, forwardedRef) => {
89
+ const {
90
+ scope,
91
+ style,
92
+ disabled = !1,
93
+ asChild,
94
+ children,
95
+ ...triggerProps
96
+ } = props,
97
+ context = useContextMenuContext(scope),
98
+ pointRef = import_react.default.useRef({
99
+ x: 0,
100
+ y: 0
101
+ }),
102
+ virtualRef = import_react.default.useMemo(() => ({
103
+ current: {
104
+ getBoundingClientRect: () => {
105
+ if (import_gui_web.isWeb) {
106
+ const scrollX = window.scrollX || document.documentElement.scrollLeft,
107
+ scrollY = window.scrollY || document.documentElement.scrollTop;
108
+ return DOMRect.fromRect({
109
+ width: 0,
110
+ height: 0,
111
+ x: pointRef.current.x - scrollX,
112
+ y: pointRef.current.y - scrollY
113
+ });
114
+ }
115
+ return {
116
+ width: 0,
117
+ height: 0,
118
+ top: 0,
119
+ left: 0,
120
+ ...pointRef.current
121
+ };
122
+ },
123
+ ...(!import_gui_web.isWeb && {
124
+ measure: c => c(pointRef.current.x, pointRef.current.y, 0, 0),
125
+ measureInWindow: c => c(pointRef.current.x, pointRef.current.y, 0, 0)
126
+ })
127
+ }
128
+ }), [pointRef.current.x, pointRef.current.y]),
129
+ longPressTimerRef = import_react.default.useRef(0),
130
+ clearLongPress = import_react.default.useCallback(() => window.clearTimeout(longPressTimerRef.current), []),
131
+ createOpenChangeEvent = () => {
132
+ let defaultPrevented = !1;
133
+ return {
134
+ get defaultPrevented() {
135
+ return defaultPrevented;
136
+ },
137
+ preventDefault() {
138
+ defaultPrevented = !0;
139
+ }
140
+ };
141
+ },
142
+ handleOpen = event => {
143
+ import_gui_web.isWeb && (event instanceof MouseEvent || event instanceof PointerEvent) ? pointRef.current = {
144
+ x: event.clientX,
145
+ y: event.clientY
146
+ } : pointRef.current = {
147
+ x: event.nativeEvent.pageX,
148
+ y: event.nativeEvent.pageY
149
+ };
150
+ const openChangeEvent = createOpenChangeEvent();
151
+ return context.onOpenChange(!0, openChangeEvent), openChangeEvent;
152
+ };
153
+ import_react.default.useEffect(() => clearLongPress, [clearLongPress]), import_react.default.useEffect(() => {
154
+ disabled && clearLongPress();
155
+ }, [disabled, clearLongPress]);
156
+ const Comp = asChild ? import_gui_web.Slot : import_gui_web.View;
157
+ return /* @__PURE__ */(0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, {
158
+ children: [/* @__PURE__ */(0, import_jsx_runtime.jsx)(Menu.Anchor, {
159
+ scope: scope || CONTEXTMENU_CONTEXT,
160
+ virtualRef
161
+ }), /* @__PURE__ */(0, import_jsx_runtime.jsx)(Comp, {
162
+ render: "span",
163
+ componentName: TRIGGER_NAME,
164
+ id: context.triggerId,
165
+ "data-state": context.open ? "open" : "closed",
166
+ "data-disabled": disabled ? "" : void 0,
167
+ ...triggerProps,
168
+ ref: (0, import_gui_web.composeRefs)(forwardedRef, context.triggerRef),
169
+ style: import_gui_web.isWeb ? {
170
+ WebkitTouchCallout: "none",
171
+ ...style
172
+ } : null,
173
+ ...(import_gui_web.isWeb && {
174
+ onContextMenu: disabled ? props.onContextMenu : (0, import_gui_web.composeEventHandlers)(props.onContextMenu, event => {
175
+ clearLongPress(), handleOpen(event).defaultPrevented || event.preventDefault();
176
+ }),
177
+ onPointerDown: disabled ? props.onPointerDown : (0, import_gui_web.composeEventHandlers)(props.onPointerDown, event => {
178
+ event.pointerType !== "mouse" && (clearLongPress(), longPressTimerRef.current = window.setTimeout(() => handleOpen(event), 700));
179
+ }),
180
+ onPointerMove: disabled ? props.onPointerMove : (0, import_gui_web.composeEventHandlers)(props.onPointerMove, event => {
181
+ event.pointerType !== "mouse" && clearLongPress();
182
+ }),
183
+ onPointerCancel: disabled ? props.onPointerCancel : (0, import_gui_web.composeEventHandlers)(props.onPointerCancel, event => {
184
+ event.pointerType !== "mouse" && clearLongPress();
185
+ }),
186
+ onPointerUp: disabled ? props.onPointerUp : (0, import_gui_web.composeEventHandlers)(props.onPointerUp, event => {
187
+ event.pointerType !== "mouse" && clearLongPress();
188
+ })
189
+ }),
190
+ ...(!import_gui_web.isWeb && {
191
+ onLongPress: disabled ? props.onLongPress : (0, import_gui_web.composeEventHandlers)(props.onLongPress, event => {
192
+ clearLongPress(), handleOpen(event).defaultPrevented || event.preventDefault();
193
+ })
194
+ }),
195
+ children
196
+ })]
197
+ });
198
+ });
199
+ ContextMenuTrigger.displayName = TRIGGER_NAME;
200
+ const PORTAL_NAME = "ContextMenuPortal",
201
+ ContextMenuPortal = props => {
202
+ const {
203
+ scope,
204
+ children,
205
+ ...portalProps
206
+ } = props,
207
+ context = import_gui_web.isAndroid ? useContextMenuContext(scope) : null,
208
+ content = import_gui_web.isAndroid ? /* @__PURE__ */(0, import_jsx_runtime.jsx)(ContextMenuProvider, {
209
+ ...context,
210
+ children
211
+ }) : children;
212
+ return /* @__PURE__ */(0, import_jsx_runtime.jsx)(Menu.Portal, {
213
+ scope: scope || CONTEXTMENU_CONTEXT,
214
+ ...portalProps,
215
+ children: content
216
+ });
217
+ };
218
+ ContextMenuPortal.displayName = PORTAL_NAME;
219
+ const CONTENT_NAME = "ContextMenuContent",
220
+ ContextMenuContent = import_react.default.forwardRef((props, forwardedRef) => {
221
+ const {
222
+ scope,
223
+ ...contentProps
224
+ } = props,
225
+ context = useContextMenuContext(scope),
226
+ hasInteractedOutsideRef = import_react.default.useRef(!1);
227
+ return /* @__PURE__ */(0, import_jsx_runtime.jsx)(Menu.Content, {
228
+ id: context.contentId,
229
+ "aria-labelledby": context.triggerId,
230
+ scope: scope || CONTEXTMENU_CONTEXT,
231
+ ...contentProps,
232
+ ref: forwardedRef,
233
+ onCloseAutoFocus: (0, import_gui_web.composeEventHandlers)(props.onCloseAutoFocus, event => {
234
+ hasInteractedOutsideRef.current || context.triggerRef.current?.focus(), hasInteractedOutsideRef.current = !1, event.preventDefault();
235
+ }),
236
+ onInteractOutside: (0, import_gui_web.composeEventHandlers)(props.onInteractOutside, event => {
237
+ const originalEvent = event.detail.originalEvent,
238
+ ctrlLeftClick = originalEvent.button === 0 && originalEvent.ctrlKey === !0,
239
+ isRightClick = originalEvent.button === 2 || ctrlLeftClick;
240
+ (!context.modal || isRightClick) && (hasInteractedOutsideRef.current = !0);
241
+ })
242
+ });
243
+ });
244
+ ContextMenuContent.displayName = CONTENT_NAME;
245
+ const ITEM_NAME = "ContextMenuItem",
246
+ ContextMenuItem = import_react.default.forwardRef((props, forwardedRef) => {
247
+ const {
248
+ scope,
249
+ ...itemProps
250
+ } = props;
251
+ return /* @__PURE__ */(0, import_jsx_runtime.jsx)(Menu.Item, {
252
+ componentName: ITEM_NAME,
253
+ scope: scope || CONTEXTMENU_CONTEXT,
254
+ ...itemProps,
255
+ ref: forwardedRef
256
+ });
257
+ });
258
+ ContextMenuItem.displayName = ITEM_NAME;
259
+ const CHECKBOX_ITEM_NAME = "ContextMenuCheckboxItem",
260
+ ContextMenuCheckboxItem = import_react.default.forwardRef((props, forwardedRef) => {
261
+ const {
262
+ scope,
263
+ ...checkboxItemProps
264
+ } = props;
265
+ return /* @__PURE__ */(0, import_jsx_runtime.jsx)(Menu.CheckboxItem, {
266
+ componentName: CHECKBOX_ITEM_NAME,
267
+ scope: scope || CONTEXTMENU_CONTEXT,
268
+ ...checkboxItemProps,
269
+ ref: forwardedRef
270
+ });
271
+ });
272
+ ContextMenuCheckboxItem.displayName = CHECKBOX_ITEM_NAME;
273
+ const RADIO_GROUP_NAME = "ContextMenuRadioGroup",
274
+ ContextMenuRadioGroup = import_react.default.forwardRef((props, forwardedRef) => {
275
+ const {
276
+ scope,
277
+ ...radioGroupProps
278
+ } = props;
279
+ return /* @__PURE__ */(0, import_jsx_runtime.jsx)(Menu.RadioGroup, {
280
+ scope: scope || CONTEXTMENU_CONTEXT,
281
+ ...radioGroupProps,
282
+ ref: forwardedRef
283
+ });
284
+ });
285
+ ContextMenuRadioGroup.displayName = RADIO_GROUP_NAME;
286
+ const RADIO_ITEM_NAME = "ContextMenuRadioItem",
287
+ ContextMenuRadioItem = import_react.default.forwardRef((props, forwardedRef) => {
288
+ const {
289
+ scope,
290
+ ...radioItemProps
291
+ } = props;
292
+ return /* @__PURE__ */(0, import_jsx_runtime.jsx)(Menu.RadioItem, {
293
+ componentName: RADIO_ITEM_NAME,
294
+ scope: scope || CONTEXTMENU_CONTEXT,
295
+ ...radioItemProps,
296
+ ref: forwardedRef
297
+ });
298
+ });
299
+ ContextMenuRadioItem.displayName = RADIO_ITEM_NAME;
300
+ const INDICATOR_NAME = "ContextMenuItemIndicator",
301
+ ContextMenuItemIndicator = Menu.ItemIndicator.styleable((props, forwardedRef) => {
302
+ const {
303
+ scope,
304
+ ...itemIndicatorProps
305
+ } = props;
306
+ return /* @__PURE__ */(0, import_jsx_runtime.jsx)(Menu.ItemIndicator, {
307
+ componentName: INDICATOR_NAME,
308
+ scope: scope || CONTEXTMENU_CONTEXT,
309
+ ...itemIndicatorProps,
310
+ ref: forwardedRef
311
+ });
312
+ });
313
+ ContextMenuItemIndicator.displayName = INDICATOR_NAME;
314
+ const SUB_NAME = "ContextMenuSub",
315
+ ContextMenuSub = props => {
316
+ const {
317
+ scope,
318
+ children,
319
+ onOpenChange,
320
+ open: openProp,
321
+ defaultOpen,
322
+ ...rest
323
+ } = props,
324
+ [open, setOpen] = (0, import_gui_use_controllable_state.useControllableState)({
325
+ prop: openProp,
326
+ defaultProp: defaultOpen,
327
+ onChange: onOpenChange
328
+ });
329
+ return /* @__PURE__ */(0, import_jsx_runtime.jsx)(Menu.Sub, {
330
+ scope: scope || CONTEXTMENU_CONTEXT,
331
+ open,
332
+ onOpenChange: setOpen,
333
+ ...rest,
334
+ children
335
+ });
336
+ };
337
+ ContextMenuSub.displayName = SUB_NAME;
338
+ const SUB_TRIGGER_NAME = "ContextMenuSubTrigger",
339
+ ContextMenuSubTrigger = import_gui_web.View.styleable((props, forwardedRef) => {
340
+ const {
341
+ scope,
342
+ ...subTriggerProps
343
+ } = props;
344
+ return /* @__PURE__ */(0, import_jsx_runtime.jsx)(Menu.SubTrigger, {
345
+ componentName: SUB_TRIGGER_NAME,
346
+ scope: scope || CONTEXTMENU_CONTEXT,
347
+ ...subTriggerProps,
348
+ ref: forwardedRef
349
+ });
350
+ });
351
+ ContextMenuSubTrigger.displayName = SUB_TRIGGER_NAME;
352
+ const SUB_CONTENT_NAME = "ContextMenuSubContent",
353
+ ContextMenuSubContent = import_react.default.forwardRef((props, forwardedRef) => {
354
+ const {
355
+ scope,
356
+ ...subContentProps
357
+ } = props;
358
+ return /* @__PURE__ */(0, import_jsx_runtime.jsx)(Menu.SubContent, {
359
+ scope: scope || CONTEXTMENU_CONTEXT,
360
+ ...subContentProps,
361
+ ref: forwardedRef,
362
+ style: import_gui_web.isWeb ? {
363
+ ...props.style,
364
+ "--tamagui-context-menu-content-transform-origin": "var(--tamagui-popper-transform-origin)",
365
+ "--tamagui-context-menu-content-available-width": "var(--tamagui-popper-available-width)",
366
+ "--tamagui-context-menu-content-available-height": "var(--tamagui-popper-available-height)",
367
+ "--tamagui-context-menu-trigger-width": "var(--tamagui-popper-anchor-width)",
368
+ "--tamagui-context-menu-trigger-height": "var(--tamagui-popper-anchor-height)"
369
+ } : null
370
+ });
371
+ });
372
+ ContextMenuSubContent.displayName = SUB_CONTENT_NAME;
373
+ const ARROW_NAME = "ContextMenuArrow",
374
+ ContextMenuArrow = import_react.default.forwardRef((props, forwardedRef) => {
375
+ const {
376
+ scope,
377
+ ...arrowProps
378
+ } = props;
379
+ return /* @__PURE__ */(0, import_jsx_runtime.jsx)(Menu.Arrow, {
380
+ componentName: ARROW_NAME,
381
+ scope: scope || CONTEXTMENU_CONTEXT,
382
+ ...arrowProps,
383
+ ref: forwardedRef
384
+ });
385
+ });
386
+ ContextMenuArrow.displayName = ARROW_NAME;
387
+ const ContextMenuGroup = Menu.Group,
388
+ ContextMenuLabel = Menu.Label,
389
+ ContextMenuSeparator = Menu.Separator,
390
+ ContextMenuItemTitle = Menu.ItemTitle,
391
+ ContextMenuItemSubTitle = Menu.ItemSubtitle,
392
+ ContextMenuItemImage = Menu.ItemImage,
393
+ ContextMenuItemIcon = Menu.ItemIcon;
394
+ return (0, import_gui_web.withStaticProperties)(ContextMenuComp, {
395
+ Root: ContextMenuComp,
396
+ Trigger: ContextMenuTrigger,
397
+ Portal: ContextMenuPortal,
398
+ Content: ContextMenuContent,
399
+ Group: ContextMenuGroup,
400
+ Label: ContextMenuLabel,
401
+ Item: ContextMenuItem,
402
+ CheckboxItem: ContextMenuCheckboxItem,
403
+ RadioGroup: ContextMenuRadioGroup,
404
+ RadioItem: ContextMenuRadioItem,
405
+ ItemIndicator: ContextMenuItemIndicator,
406
+ Separator: ContextMenuSeparator,
407
+ Arrow: ContextMenuArrow,
408
+ Sub: ContextMenuSub,
409
+ SubTrigger: ContextMenuSubTrigger,
410
+ SubContent: ContextMenuSubContent,
411
+ ItemTitle: ContextMenuItemTitle,
412
+ ItemSubtitle: ContextMenuItemSubTitle,
413
+ ItemIcon: ContextMenuItemIcon,
414
+ ItemImage: ContextMenuItemImage,
415
+ Preview: () => null
416
+ });
417
+ }