@zentauri-ui/zentauri-components 1.7.5 → 1.7.6

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 (81) hide show
  1. package/README.md +8 -5
  2. package/cli/registry.json +2 -0
  3. package/dist/chunk-DEZRB6DS.mjs +83 -0
  4. package/dist/chunk-DEZRB6DS.mjs.map +1 -0
  5. package/dist/chunk-V5JTDRV5.mjs +278 -0
  6. package/dist/chunk-V5JTDRV5.mjs.map +1 -0
  7. package/dist/chunk-Z4KHAD6Y.js +295 -0
  8. package/dist/chunk-Z4KHAD6Y.js.map +1 -0
  9. package/dist/chunk-ZX2IBIZT.js +92 -0
  10. package/dist/chunk-ZX2IBIZT.js.map +1 -0
  11. package/dist/design-system/context-menu.d.ts +41 -0
  12. package/dist/design-system/context-menu.d.ts.map +1 -0
  13. package/dist/design-system/index.d.ts +2 -0
  14. package/dist/design-system/index.d.ts.map +1 -1
  15. package/dist/design-system/timeline.d.ts +56 -0
  16. package/dist/design-system/timeline.d.ts.map +1 -0
  17. package/dist/ui/context-menu/context-menu.d.ts +11 -0
  18. package/dist/ui/context-menu/context-menu.d.ts.map +1 -0
  19. package/dist/ui/context-menu/index.d.ts +4 -0
  20. package/dist/ui/context-menu/index.d.ts.map +1 -0
  21. package/dist/ui/context-menu/types.d.ts +81 -0
  22. package/dist/ui/context-menu/types.d.ts.map +1 -0
  23. package/dist/ui/context-menu/variants.d.ts +7 -0
  24. package/dist/ui/context-menu/variants.d.ts.map +1 -0
  25. package/dist/ui/context-menu.js +500 -0
  26. package/dist/ui/context-menu.js.map +1 -0
  27. package/dist/ui/context-menu.mjs +488 -0
  28. package/dist/ui/context-menu.mjs.map +1 -0
  29. package/dist/ui/dropdown.js +9 -89
  30. package/dist/ui/dropdown.js.map +1 -1
  31. package/dist/ui/dropdown.mjs +1 -81
  32. package/dist/ui/dropdown.mjs.map +1 -1
  33. package/dist/ui/scroll-area/scroll-area.d.ts.map +1 -1
  34. package/dist/ui/scroll-area.js.map +1 -1
  35. package/dist/ui/scroll-area.mjs.map +1 -1
  36. package/dist/ui/timeline/animated/animations.d.ts +8 -0
  37. package/dist/ui/timeline/animated/animations.d.ts.map +1 -0
  38. package/dist/ui/timeline/animated/index.d.ts +6 -0
  39. package/dist/ui/timeline/animated/index.d.ts.map +1 -0
  40. package/dist/ui/timeline/animated/timeline-item-animated.d.ts +8 -0
  41. package/dist/ui/timeline/animated/timeline-item-animated.d.ts.map +1 -0
  42. package/dist/ui/timeline/animated/types.d.ts +12 -0
  43. package/dist/ui/timeline/animated/types.d.ts.map +1 -0
  44. package/dist/ui/timeline/animated.js +94 -0
  45. package/dist/ui/timeline/animated.js.map +1 -0
  46. package/dist/ui/timeline/animated.mjs +71 -0
  47. package/dist/ui/timeline/animated.mjs.map +1 -0
  48. package/dist/ui/timeline/index.d.ts +4 -0
  49. package/dist/ui/timeline/index.d.ts.map +1 -0
  50. package/dist/ui/timeline/timeline-base.d.ts +37 -0
  51. package/dist/ui/timeline/timeline-base.d.ts.map +1 -0
  52. package/dist/ui/timeline/timeline.d.ts +8 -0
  53. package/dist/ui/timeline/timeline.d.ts.map +1 -0
  54. package/dist/ui/timeline/types.d.ts +38 -0
  55. package/dist/ui/timeline/types.d.ts.map +1 -0
  56. package/dist/ui/timeline/variants.d.ts +19 -0
  57. package/dist/ui/timeline/variants.d.ts.map +1 -0
  58. package/dist/ui/timeline.js +63 -0
  59. package/dist/ui/timeline.js.map +1 -0
  60. package/dist/ui/timeline.mjs +14 -0
  61. package/dist/ui/timeline.mjs.map +1 -0
  62. package/package.json +1 -1
  63. package/src/design-system/context-menu.ts +44 -0
  64. package/src/design-system/index.ts +2 -0
  65. package/src/design-system/timeline.ts +87 -0
  66. package/src/ui/context-menu/context-menu.test.tsx +176 -0
  67. package/src/ui/context-menu/context-menu.tsx +536 -0
  68. package/src/ui/context-menu/index.ts +29 -0
  69. package/src/ui/context-menu/types.ts +110 -0
  70. package/src/ui/context-menu/variants.ts +26 -0
  71. package/src/ui/scroll-area/scroll-area.tsx +0 -2
  72. package/src/ui/timeline/animated/animations.ts +16 -0
  73. package/src/ui/timeline/animated/index.ts +22 -0
  74. package/src/ui/timeline/animated/timeline-item-animated.tsx +76 -0
  75. package/src/ui/timeline/animated/types.ts +21 -0
  76. package/src/ui/timeline/index.ts +30 -0
  77. package/src/ui/timeline/timeline-base.tsx +232 -0
  78. package/src/ui/timeline/timeline.test.tsx +262 -0
  79. package/src/ui/timeline/timeline.tsx +24 -0
  80. package/src/ui/timeline/types.ts +61 -0
  81. package/src/ui/timeline/variants.ts +60 -0
@@ -0,0 +1,536 @@
1
+ "use client";
2
+
3
+ import {
4
+ Children,
5
+ cloneElement,
6
+ createContext,
7
+ isValidElement,
8
+ useCallback,
9
+ useContext,
10
+ useEffect,
11
+ useId,
12
+ useLayoutEffect,
13
+ useMemo,
14
+ useRef,
15
+ useState,
16
+ type KeyboardEvent,
17
+ type MouseEvent,
18
+ type ReactElement,
19
+ type Ref,
20
+ type RefObject,
21
+ } from "react";
22
+ import { FiChevronRight } from "react-icons/fi";
23
+
24
+ import {
25
+ zuiContextMenuLabelBase,
26
+ zuiContextMenuSeparatorBase,
27
+ } from "../../design-system/context-menu";
28
+ import { cn } from "../../lib/utils";
29
+ import type {
30
+ ContextMenuContentProps,
31
+ ContextMenuContextType,
32
+ ContextMenuItemProps,
33
+ ContextMenuLabelProps,
34
+ ContextMenuPosition,
35
+ ContextMenuProps,
36
+ ContextMenuSeparatorProps,
37
+ ContextMenuSubContentProps,
38
+ ContextMenuSubContextType,
39
+ ContextMenuSubProps,
40
+ ContextMenuSubTriggerProps,
41
+ ContextMenuTriggerProps,
42
+ GetSafePositionProps,
43
+ ReactChildSoleCandidate,
44
+ } from "./types";
45
+ import {
46
+ contextMenuContentVariants,
47
+ contextMenuItemVariants,
48
+ } from "./variants";
49
+
50
+ const ContextMenuContext = createContext<ContextMenuContextType | null>(null);
51
+ const ContextMenuSubContext = createContext<ContextMenuSubContextType | null>(
52
+ null,
53
+ );
54
+
55
+ const useContextMenu = () => {
56
+ const context = useContext(ContextMenuContext);
57
+ if (!context) {
58
+ throw new Error("ContextMenu components must be used within ContextMenu");
59
+ }
60
+ return context;
61
+ };
62
+
63
+ const useContextMenuSub = () => {
64
+ const context = useContext(ContextMenuSubContext);
65
+ if (!context) {
66
+ throw new Error(
67
+ "ContextMenuSub components must be used within ContextMenuSub",
68
+ );
69
+ }
70
+ return context;
71
+ };
72
+
73
+ function mergeRefs<T>(...refs: Array<Ref<T> | undefined>) {
74
+ return (node: T) => {
75
+ for (const ref of refs) {
76
+ if (typeof ref === "function") {
77
+ ref(node);
78
+ } else if (ref) {
79
+ (ref as RefObject<T | null>).current = node;
80
+ }
81
+ }
82
+ };
83
+ }
84
+
85
+ const getSafePosition = ({
86
+ position,
87
+ width,
88
+ height,
89
+ collisionPadding,
90
+ }: GetSafePositionProps) => {
91
+ const fallback = position ?? { x: collisionPadding, y: collisionPadding };
92
+
93
+ if (typeof window === "undefined") {
94
+ return fallback;
95
+ }
96
+
97
+ return {
98
+ x: Math.max(
99
+ collisionPadding,
100
+ Math.min(fallback.x, window.innerWidth - width - collisionPadding),
101
+ ),
102
+ y: Math.max(
103
+ collisionPadding,
104
+ Math.min(fallback.y, window.innerHeight - height - collisionPadding),
105
+ ),
106
+ };
107
+ };
108
+
109
+ export const ContextMenu = ({
110
+ children,
111
+ defaultOpen = false,
112
+ open: controlledOpen,
113
+ onOpenChange,
114
+ closeOnEscape = true,
115
+ closeOnOutsideClick = true,
116
+ }: ContextMenuProps) => {
117
+ const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
118
+ const [position, setPosition] = useState<ContextMenuPosition | null>(null);
119
+ const contentId = `${useId()}-context-menu`;
120
+ const triggerRef = useRef<HTMLElement | null>(null);
121
+ const contentRef = useRef<HTMLDivElement | null>(null);
122
+
123
+ const isControlled = controlledOpen !== undefined;
124
+ const open = isControlled ? controlledOpen : uncontrolledOpen;
125
+
126
+ const setOpen = useCallback(
127
+ (nextOpen: boolean) => {
128
+ if (!isControlled) {
129
+ setUncontrolledOpen(nextOpen);
130
+ }
131
+ onOpenChange?.(nextOpen);
132
+ },
133
+ [isControlled, onOpenChange],
134
+ );
135
+
136
+ const openAt = useCallback(
137
+ (nextPosition: ContextMenuPosition) => {
138
+ setPosition(nextPosition);
139
+ setOpen(true);
140
+ },
141
+ [setOpen],
142
+ );
143
+
144
+ useEffect(() => {
145
+ if (!open) {
146
+ return undefined;
147
+ }
148
+
149
+ const onPointerDown = (event: PointerEvent) => {
150
+ if (!closeOnOutsideClick) {
151
+ return;
152
+ }
153
+ const target = event.target as Node;
154
+ if (contentRef.current?.contains(target)) {
155
+ return;
156
+ }
157
+ if (triggerRef.current?.contains(target) && event.button !== 0) {
158
+ return;
159
+ }
160
+ setOpen(false);
161
+ };
162
+
163
+ const onKeyDown = (event: globalThis.KeyboardEvent) => {
164
+ if (event.key === "Escape" && closeOnEscape) {
165
+ setOpen(false);
166
+ triggerRef.current?.focus();
167
+ }
168
+ };
169
+
170
+ const onScroll = () => {
171
+ setOpen(false);
172
+ };
173
+
174
+ document.addEventListener("pointerdown", onPointerDown);
175
+ document.addEventListener("keydown", onKeyDown);
176
+ document.addEventListener("scroll", onScroll, { capture: true });
177
+
178
+ return () => {
179
+ document.removeEventListener("pointerdown", onPointerDown);
180
+ document.removeEventListener("keydown", onKeyDown);
181
+ document.removeEventListener("scroll", onScroll, { capture: true });
182
+ };
183
+ }, [closeOnEscape, closeOnOutsideClick, open, setOpen]);
184
+
185
+ const contextValue = useMemo(
186
+ () => ({
187
+ open,
188
+ setOpen,
189
+ openAt,
190
+ contentId,
191
+ triggerRef,
192
+ contentRef,
193
+ position,
194
+ }),
195
+ [contentId, open, openAt, setOpen, position],
196
+ );
197
+
198
+ return (
199
+ <ContextMenuContext.Provider value={contextValue}>
200
+ <div className="contents">{children}</div>
201
+ </ContextMenuContext.Provider>
202
+ );
203
+ };
204
+
205
+ export const ContextMenuTrigger = ({
206
+ children,
207
+ className,
208
+ disabled = false,
209
+ }: ContextMenuTriggerProps) => {
210
+ const { open, openAt, contentId, triggerRef } = useContextMenu();
211
+
212
+ const handleContextMenu = (event: MouseEvent<HTMLElement>) => {
213
+ if (disabled) {
214
+ return;
215
+ }
216
+ event.preventDefault();
217
+ const isKeyboardTrigger = event.clientX === 0 && event.clientY === 0;
218
+ if (isKeyboardTrigger) {
219
+ const rect = event.currentTarget.getBoundingClientRect();
220
+ openAt({ x: rect.left, y: rect.bottom });
221
+ } else {
222
+ openAt({ x: event.clientX, y: event.clientY });
223
+ }
224
+ };
225
+ const childList = Children.toArray(children).filter(
226
+ (node) => node !== null && node !== undefined && typeof node !== "boolean",
227
+ );
228
+ const soleCandidate =
229
+ childList.length === 1 && isValidElement(childList[0])
230
+ ? (childList[0] as ReactChildSoleCandidate)
231
+ : undefined;
232
+
233
+ if (soleCandidate) {
234
+ return cloneElement(soleCandidate, {
235
+ ref: mergeRefs(triggerRef, soleCandidate.props.ref),
236
+ onContextMenu: (event) => {
237
+ soleCandidate.props.onContextMenu?.(event);
238
+ if (!event.defaultPrevented) {
239
+ handleContextMenu(event);
240
+ }
241
+ },
242
+ className: cn(className, soleCandidate.props.className),
243
+ tabIndex: soleCandidate.props.tabIndex ?? 0,
244
+ "aria-controls": open ? contentId : undefined,
245
+ "aria-expanded": open,
246
+ "aria-haspopup": "menu",
247
+ });
248
+ }
249
+
250
+ return (
251
+ <span
252
+ ref={triggerRef as Ref<HTMLSpanElement>}
253
+ className={className}
254
+ tabIndex={0}
255
+ onContextMenu={handleContextMenu}
256
+ aria-controls={open ? contentId : undefined}
257
+ aria-expanded={open}
258
+ aria-haspopup="menu"
259
+ >
260
+ {children}
261
+ </span>
262
+ );
263
+ };
264
+
265
+ export const ContextMenuContent = ({
266
+ children,
267
+ className,
268
+ collisionPadding = 8,
269
+ spacing,
270
+ style,
271
+ width = 220,
272
+ ...props
273
+ }: ContextMenuContentProps) => {
274
+ const { open, contentId, contentRef, position } = useContextMenu();
275
+ const [menuSize, setMenuSize] = useState({ width, height: 0 });
276
+
277
+ useLayoutEffect(() => {
278
+ if (!open || !contentRef.current) {
279
+ return;
280
+ }
281
+
282
+ const rect = contentRef.current.getBoundingClientRect();
283
+ const nextSize = {
284
+ width: Math.max(width, rect.width),
285
+ height: rect.height,
286
+ };
287
+
288
+ setMenuSize((currentSize) =>
289
+ currentSize.width === nextSize.width &&
290
+ currentSize.height === nextSize.height
291
+ ? currentSize
292
+ : nextSize,
293
+ );
294
+ });
295
+
296
+ useEffect(() => {
297
+ if (!open) {
298
+ setMenuSize({ width, height: 0 });
299
+ }
300
+ }, [open, width]);
301
+
302
+ if (!open) {
303
+ return null;
304
+ }
305
+
306
+ const safePosition = getSafePosition({
307
+ position,
308
+ width: menuSize.width,
309
+ height: menuSize.height,
310
+ collisionPadding,
311
+ });
312
+
313
+ return (
314
+ <div
315
+ ref={contentRef}
316
+ id={contentId}
317
+ role="menu"
318
+ tabIndex={-1}
319
+ className={cn(
320
+ contextMenuContentVariants({ spacing }),
321
+ "fixed z-50",
322
+ className,
323
+ )}
324
+ style={{
325
+ left: safePosition.x,
326
+ top: safePosition.y,
327
+ minWidth: width,
328
+ ...style,
329
+ }}
330
+ {...props}
331
+ >
332
+ {children}
333
+ </div>
334
+ );
335
+ };
336
+
337
+ export const ContextMenuItem = ({
338
+ children,
339
+ className,
340
+ closeOnSelect = true,
341
+ disabled = false,
342
+ inset = false,
343
+ leftIcon,
344
+ onClick,
345
+ onKeyDown,
346
+ onSelect,
347
+ rightIcon,
348
+ variant,
349
+ ...props
350
+ }: ContextMenuItemProps) => {
351
+ const { setOpen } = useContextMenu();
352
+
353
+ const handleSelect = () => {
354
+ if (disabled) {
355
+ return;
356
+ }
357
+ onSelect?.();
358
+ if (closeOnSelect) {
359
+ setOpen(false);
360
+ }
361
+ };
362
+
363
+ const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
364
+ onKeyDown?.(event);
365
+ if (event.defaultPrevented || disabled) {
366
+ return;
367
+ }
368
+ if (event.key === "Enter" || event.key === " ") {
369
+ event.preventDefault();
370
+ handleSelect();
371
+ }
372
+ };
373
+
374
+ return (
375
+ <div
376
+ role="menuitem"
377
+ tabIndex={disabled ? undefined : 0}
378
+ aria-disabled={disabled || undefined}
379
+ className={cn(
380
+ contextMenuItemVariants({ variant }),
381
+ inset && "pl-8",
382
+ disabled && "pointer-events-none cursor-not-allowed opacity-50",
383
+ className,
384
+ )}
385
+ onClick={(event) => {
386
+ onClick?.(event);
387
+ if (!event.defaultPrevented) {
388
+ handleSelect();
389
+ }
390
+ }}
391
+ onKeyDown={handleKeyDown}
392
+ {...props}
393
+ >
394
+ <div className="flex min-w-0 items-center gap-2">
395
+ {leftIcon}
396
+ <span className="truncate">{children}</span>
397
+ </div>
398
+ {rightIcon ? (
399
+ <div className="ml-4 flex items-center">{rightIcon}</div>
400
+ ) : null}
401
+ </div>
402
+ );
403
+ };
404
+
405
+ export const ContextMenuLabel = ({
406
+ children,
407
+ className,
408
+ inset = false,
409
+ ...props
410
+ }: ContextMenuLabelProps) => {
411
+ return (
412
+ <p
413
+ className={cn(zuiContextMenuLabelBase, inset && "pl-8", className)}
414
+ {...props}
415
+ >
416
+ {children}
417
+ </p>
418
+ );
419
+ };
420
+
421
+ export const ContextMenuSeparator = ({
422
+ className,
423
+ ...props
424
+ }: ContextMenuSeparatorProps) => {
425
+ return (
426
+ <div
427
+ role="separator"
428
+ className={cn(zuiContextMenuSeparatorBase, className)}
429
+ {...props}
430
+ />
431
+ );
432
+ };
433
+
434
+ export const ContextMenuSub = ({
435
+ children,
436
+ defaultOpen = false,
437
+ }: ContextMenuSubProps) => {
438
+ const [open, setOpen] = useState(defaultOpen);
439
+ const value = useMemo(() => ({ open, setOpen }), [open]);
440
+
441
+ return (
442
+ <ContextMenuSubContext.Provider value={value}>
443
+ <div className="relative" onPointerLeave={() => setOpen(false)}>
444
+ {children}
445
+ </div>
446
+ </ContextMenuSubContext.Provider>
447
+ );
448
+ };
449
+
450
+ export const ContextMenuSubTrigger = ({
451
+ children,
452
+ className,
453
+ disabled = false,
454
+ inset = false,
455
+ onFocus,
456
+ onKeyDown,
457
+ onPointerEnter,
458
+ rightIcon = <FiChevronRight aria-hidden="true" />,
459
+ variant,
460
+ ...props
461
+ }: ContextMenuSubTriggerProps) => {
462
+ const { open, setOpen } = useContextMenuSub();
463
+
464
+ return (
465
+ <div
466
+ role="menuitem"
467
+ tabIndex={disabled ? undefined : 0}
468
+ aria-disabled={disabled || undefined}
469
+ aria-expanded={open}
470
+ aria-haspopup="menu"
471
+ className={cn(
472
+ contextMenuItemVariants({ variant }),
473
+ inset && "pl-8",
474
+ disabled && "pointer-events-none cursor-not-allowed opacity-50",
475
+ className,
476
+ )}
477
+ onFocus={(event) => {
478
+ onFocus?.(event);
479
+ }}
480
+ onPointerEnter={(event) => {
481
+ onPointerEnter?.(event);
482
+ if (!disabled) {
483
+ setOpen(true);
484
+ }
485
+ }}
486
+ onKeyDown={(event) => {
487
+ onKeyDown?.(event);
488
+ if (event.defaultPrevented || disabled) {
489
+ return;
490
+ }
491
+ if (event.key === "ArrowRight" || event.key === "Enter") {
492
+ event.preventDefault();
493
+ setOpen(true);
494
+ }
495
+ if (event.key === "ArrowLeft") {
496
+ event.preventDefault();
497
+ setOpen(false);
498
+ }
499
+ }}
500
+ {...props}
501
+ >
502
+ <div className="flex min-w-0 items-center gap-2">
503
+ <span className="truncate">{children}</span>
504
+ </div>
505
+ <div className="ml-4 flex items-center">{rightIcon}</div>
506
+ </div>
507
+ );
508
+ };
509
+
510
+ export const ContextMenuSubContent = ({
511
+ children,
512
+ className,
513
+ spacing,
514
+ ...props
515
+ }: ContextMenuSubContentProps) => {
516
+ const { open } = useContextMenuSub();
517
+
518
+ if (!open) {
519
+ return null;
520
+ }
521
+
522
+ return (
523
+ <div
524
+ role="menu"
525
+ tabIndex={-1}
526
+ className={cn(
527
+ contextMenuContentVariants({ spacing }),
528
+ "absolute left-full top-0 z-50 ml-2",
529
+ className,
530
+ )}
531
+ {...props}
532
+ >
533
+ {children}
534
+ </div>
535
+ );
536
+ };
@@ -0,0 +1,29 @@
1
+ "use client";
2
+
3
+ export {
4
+ ContextMenu,
5
+ ContextMenuContent,
6
+ ContextMenuItem,
7
+ ContextMenuLabel,
8
+ ContextMenuSeparator,
9
+ ContextMenuSub,
10
+ ContextMenuSubContent,
11
+ ContextMenuSubTrigger,
12
+ ContextMenuTrigger,
13
+ } from "./context-menu";
14
+ export type {
15
+ ContextMenuContentProps,
16
+ ContextMenuItemProps,
17
+ ContextMenuLabelProps,
18
+ ContextMenuPosition,
19
+ ContextMenuProps,
20
+ ContextMenuSeparatorProps,
21
+ ContextMenuSubContentProps,
22
+ ContextMenuSubProps,
23
+ ContextMenuSubTriggerProps,
24
+ ContextMenuTriggerProps,
25
+ } from "./types";
26
+ export {
27
+ contextMenuContentVariants,
28
+ contextMenuItemVariants,
29
+ } from "./variants";
@@ -0,0 +1,110 @@
1
+ import type { VariantProps } from "class-variance-authority";
2
+ import type {
3
+ ComponentPropsWithRef,
4
+ HTMLAttributes,
5
+ MouseEvent,
6
+ ReactElement,
7
+ ReactNode,
8
+ Ref,
9
+ RefObject,
10
+ } from "react";
11
+
12
+ import type {
13
+ contextMenuContentVariants,
14
+ contextMenuItemVariants,
15
+ } from "./variants";
16
+
17
+ export type ContextMenuPosition = {
18
+ x: number;
19
+ y: number;
20
+ };
21
+
22
+ export type ContextMenuContextType = {
23
+ open: boolean;
24
+ setOpen: (open: boolean) => void;
25
+ openAt: (position: ContextMenuPosition) => void;
26
+ position: ContextMenuPosition | null;
27
+ contentId: string;
28
+ triggerRef: RefObject<HTMLElement | null>;
29
+ contentRef: RefObject<HTMLDivElement | null>;
30
+ };
31
+
32
+ export type ContextMenuProps = {
33
+ children: ReactNode;
34
+ defaultOpen?: boolean;
35
+ open?: boolean;
36
+ onOpenChange?: (open: boolean) => void;
37
+ closeOnEscape?: boolean;
38
+ closeOnOutsideClick?: boolean;
39
+ };
40
+
41
+ export type ContextMenuTriggerProps = {
42
+ children: ReactNode;
43
+ className?: string;
44
+ disabled?: boolean;
45
+ };
46
+
47
+ export type ContextMenuContentProps = ComponentPropsWithRef<"div"> &
48
+ VariantProps<typeof contextMenuContentVariants> & {
49
+ children: ReactNode;
50
+ collisionPadding?: number;
51
+ width?: number;
52
+ };
53
+
54
+ export type ContextMenuItemProps = HTMLAttributes<HTMLDivElement> &
55
+ VariantProps<typeof contextMenuItemVariants> & {
56
+ children: ReactNode;
57
+ closeOnSelect?: boolean;
58
+ disabled?: boolean;
59
+ inset?: boolean;
60
+ leftIcon?: ReactNode;
61
+ onSelect?: () => void;
62
+ rightIcon?: ReactNode;
63
+ };
64
+
65
+ export type ContextMenuLabelProps = HTMLAttributes<HTMLParagraphElement> & {
66
+ children: ReactNode;
67
+ inset?: boolean;
68
+ };
69
+
70
+ export type ContextMenuSeparatorProps = HTMLAttributes<HTMLDivElement>;
71
+
72
+ export type ContextMenuSubContextType = {
73
+ open: boolean;
74
+ setOpen: (open: boolean) => void;
75
+ };
76
+
77
+ export type ContextMenuSubProps = {
78
+ children: ReactNode;
79
+ defaultOpen?: boolean;
80
+ };
81
+
82
+ export type ContextMenuSubTriggerProps = HTMLAttributes<HTMLDivElement> &
83
+ VariantProps<typeof contextMenuItemVariants> & {
84
+ children: ReactNode;
85
+ disabled?: boolean;
86
+ inset?: boolean;
87
+ rightIcon?: ReactNode;
88
+ };
89
+
90
+ export type ContextMenuSubContentProps = ComponentPropsWithRef<"div"> &
91
+ VariantProps<typeof contextMenuContentVariants> & {
92
+ children: ReactNode;
93
+ };
94
+
95
+ export type GetSafePositionProps = {
96
+ position: ContextMenuPosition | null;
97
+ width: number;
98
+ height: number;
99
+ collisionPadding: number;
100
+ };
101
+
102
+ export type ReactChildSoleCandidate = ReactElement<{
103
+ className?: string;
104
+ ref?: Ref<HTMLElement>;
105
+ onContextMenu?: (event: MouseEvent<HTMLElement>) => void;
106
+ tabIndex?: number;
107
+ "aria-controls"?: string;
108
+ "aria-expanded"?: boolean;
109
+ "aria-haspopup"?: string;
110
+ }>;
@@ -0,0 +1,26 @@
1
+ import { cva } from "class-variance-authority";
2
+
3
+ import {
4
+ zuiContextMenuContentBase,
5
+ zuiContextMenuItemBase,
6
+ zuiContextMenuItemVariants,
7
+ zuiContextMenuSpacing,
8
+ } from "../../design-system/context-menu";
9
+
10
+ export const contextMenuContentVariants = cva(zuiContextMenuContentBase, {
11
+ variants: {
12
+ spacing: zuiContextMenuSpacing,
13
+ },
14
+ defaultVariants: {
15
+ spacing: "default",
16
+ },
17
+ });
18
+
19
+ export const contextMenuItemVariants = cva(zuiContextMenuItemBase, {
20
+ variants: {
21
+ variant: zuiContextMenuItemVariants,
22
+ },
23
+ defaultVariants: {
24
+ variant: "default",
25
+ },
26
+ });
@@ -1,7 +1,5 @@
1
1
  "use client";
2
2
 
3
- import { forwardRef } from "react";
4
-
5
3
  import { cn } from "../../lib/utils";
6
4
 
7
5
  import type { ScrollAreaProps } from "./types";