@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,44 @@
1
+ import {
2
+ zuiDropdownItemBase,
3
+ zuiDropdownItemVariants,
4
+ zuiDropdownSpacing,
5
+ } from "./dropdown";
6
+
7
+ export const zuiContextMenuContentBase =
8
+ "min-w-[220px] rounded-lg border border-[color:var(--zui-dropdown-content-border,oklch(20.8%_0.042_265.755_/_0.1))] bg-[var(--zui-dropdown-content-bg,oklch(96.8%_0.007_247.896))] p-2 text-[color:var(--zui-dropdown-content-fg,oklch(20.8%_0.042_265.755))] shadow-lg outline-none dark:border-[color:var(--zui-dropdown-content-border-dark,#ffffff1a)] dark:bg-[var(--zui-dropdown-content-bg-dark,oklch(20.8%_0.042_265.755))] dark:text-[color:var(--zui-dropdown-content-fg-dark,oklch(96.8%_0.007_247.896))]";
9
+
10
+ export const zuiContextMenuItemBase = zuiDropdownItemBase;
11
+
12
+ export const zuiContextMenuItemVariants = {
13
+ ...zuiDropdownItemVariants,
14
+ ghost: `${zuiDropdownItemVariants.ghost} dark:bg-[var(--zui-dropdown-item-ghost-bg-dark,transparent)]`,
15
+ sky: `${zuiDropdownItemVariants.sky} dark:bg-[var(--zui-dropdown-item-sky-bg-dark,oklch(29.3%_0.066_243.157))] dark:text-[color:var(--zui-dropdown-item-sky-fg-dark,oklch(90.1%_0.058_230.902))] dark:hover:text-[color:var(--zui-dropdown-item-sky-fg-hover-dark,oklch(90.1%_0.058_230.902))]`,
16
+ rose: `${zuiDropdownItemVariants.rose} dark:bg-[var(--zui-dropdown-item-rose-bg-dark,oklch(27.1%_0.105_12.094))] dark:text-[color:var(--zui-dropdown-item-rose-fg-dark,oklch(89.2%_0.058_10.001))] dark:hover:text-[color:var(--zui-dropdown-item-rose-fg-hover-dark,oklch(89.2%_0.058_10.001))]`,
17
+ purple: `${zuiDropdownItemVariants.purple} dark:bg-[var(--zui-dropdown-item-purple-bg-dark,oklch(29.1%_0.149_302.717))] dark:text-[color:var(--zui-dropdown-item-purple-fg-dark,oklch(90.2%_0.063_306.703))] dark:hover:text-[color:var(--zui-dropdown-item-purple-fg-hover-dark,oklch(90.2%_0.063_306.703))]`,
18
+ pink: `${zuiDropdownItemVariants.pink} dark:bg-[var(--zui-dropdown-item-pink-bg-dark,oklch(28.4%_0.109_3.907))] dark:text-[color:var(--zui-dropdown-item-pink-fg-dark,oklch(89.9%_0.061_343.231))] dark:hover:text-[color:var(--zui-dropdown-item-pink-fg-hover-dark,oklch(89.9%_0.061_343.231))]`,
19
+ orange: `${zuiDropdownItemVariants.orange} dark:bg-[var(--zui-dropdown-item-orange-bg-dark,oklch(26.6%_0.079_36.259))] dark:text-[color:var(--zui-dropdown-item-orange-fg-dark,oklch(90.1%_0.076_70.697))] dark:hover:text-[color:var(--zui-dropdown-item-orange-fg-hover-dark,oklch(90.1%_0.076_70.697))]`,
20
+ yellow: `${zuiDropdownItemVariants.yellow} dark:bg-[var(--zui-dropdown-item-yellow-bg-dark,oklch(28.6%_0.066_53.813))] dark:text-[color:var(--zui-dropdown-item-yellow-fg-dark,oklch(94.5%_0.129_101.54))] dark:hover:text-[color:var(--zui-dropdown-item-yellow-fg-hover-dark,oklch(94.5%_0.129_101.54))]`,
21
+ teal: `${zuiDropdownItemVariants.teal} dark:bg-[var(--zui-dropdown-item-teal-bg-dark,oklch(27.7%_0.046_192.524))] dark:text-[color:var(--zui-dropdown-item-teal-fg-dark,oklch(91%_0.096_180.426))] dark:hover:text-[color:var(--zui-dropdown-item-teal-fg-hover-dark,oklch(91%_0.096_180.426))]`,
22
+ indigo: `${zuiDropdownItemVariants.indigo} dark:bg-[var(--zui-dropdown-item-indigo-bg-dark,oklch(25.7%_0.09_281.288))] dark:text-[color:var(--zui-dropdown-item-indigo-fg-dark,oklch(87%_0.065_274.039))] dark:hover:text-[color:var(--zui-dropdown-item-indigo-fg-hover-dark,oklch(87%_0.065_274.039))]`,
23
+ emerald: `${zuiDropdownItemVariants.emerald} dark:bg-[var(--zui-dropdown-item-emerald-bg-dark,oklch(26.2%_0.051_172.552))] dark:text-[color:var(--zui-dropdown-item-emerald-fg-dark,oklch(90.5%_0.093_164.15))] dark:hover:text-[color:var(--zui-dropdown-item-emerald-fg-hover-dark,oklch(90.5%_0.093_164.15))]`,
24
+ gray: `${zuiDropdownItemVariants.gray} dark:bg-[var(--zui-dropdown-item-gray-bg-dark,oklch(13%_0.028_261.692))] dark:text-[color:var(--zui-dropdown-item-gray-fg-dark,oklch(92.8%_0.006_264.531))] dark:hover:text-[color:var(--zui-dropdown-item-gray-fg-hover-dark,oklch(92.8%_0.006_264.531))]`,
25
+ amber: `${zuiDropdownItemVariants.amber} dark:bg-[var(--zui-dropdown-item-amber-bg-dark,oklch(27.9%_0.077_45.635))] dark:text-[color:var(--zui-dropdown-item-amber-fg-dark,oklch(92.4%_0.12_95.746))] dark:hover:text-[color:var(--zui-dropdown-item-amber-fg-hover-dark,oklch(92.4%_0.12_95.746))]`,
26
+ violet: `${zuiDropdownItemVariants.violet} dark:bg-[var(--zui-dropdown-item-violet-bg-dark,oklch(28.3%_0.141_291.089))] dark:text-[color:var(--zui-dropdown-item-violet-fg-dark,oklch(89.4%_0.057_293.283))] dark:hover:text-[color:var(--zui-dropdown-item-violet-fg-hover-dark,oklch(89.4%_0.057_293.283))]`,
27
+ "gradient-blue": `${zuiDropdownItemVariants["gradient-blue"]} dark:from-[var(--zui-dropdown-item-gradient-blue-from-dark,oklch(28.2%_0.091_267.935))] dark:to-[var(--zui-dropdown-item-gradient-blue-to-dark,oklch(29.1%_0.149_302.717))]`,
28
+ "gradient-green": `${zuiDropdownItemVariants["gradient-green"]} dark:from-[var(--zui-dropdown-item-gradient-green-from-dark,oklch(26.6%_0.065_152.934))] dark:to-[var(--zui-dropdown-item-gradient-green-to-dark,oklch(27.4%_0.072_132.109))]`,
29
+ "gradient-red": `${zuiDropdownItemVariants["gradient-red"]} dark:from-[var(--zui-dropdown-item-gradient-red-from-dark,oklch(25.8%_0.092_26.042))] dark:to-[var(--zui-dropdown-item-gradient-red-to-dark,oklch(28.4%_0.109_3.907))]`,
30
+ "gradient-yellow": `${zuiDropdownItemVariants["gradient-yellow"]} dark:from-[var(--zui-dropdown-item-gradient-yellow-from-dark,oklch(28.6%_0.066_53.813))] dark:to-[var(--zui-dropdown-item-gradient-yellow-to-dark,oklch(26.6%_0.079_36.259))]`,
31
+ "gradient-purple": `${zuiDropdownItemVariants["gradient-purple"]} dark:from-[var(--zui-dropdown-item-gradient-purple-from-dark,oklch(29.1%_0.149_302.717))] dark:to-[var(--zui-dropdown-item-gradient-purple-to-dark,oklch(28.4%_0.109_3.907))]`,
32
+ "gradient-teal": `${zuiDropdownItemVariants["gradient-teal"]} dark:from-[var(--zui-dropdown-item-gradient-teal-from-dark,oklch(27.7%_0.046_192.524))] dark:to-[var(--zui-dropdown-item-gradient-teal-to-dark,oklch(30.2%_0.056_229.695))]`,
33
+ "gradient-indigo": `${zuiDropdownItemVariants["gradient-indigo"]} dark:from-[var(--zui-dropdown-item-gradient-indigo-from-dark,oklch(25.7%_0.09_281.288))] dark:to-[var(--zui-dropdown-item-gradient-indigo-to-dark,oklch(29.1%_0.149_302.717))]`,
34
+ "gradient-pink": `${zuiDropdownItemVariants["gradient-pink"]} dark:from-[var(--zui-dropdown-item-gradient-pink-from-dark,oklch(28.4%_0.109_3.907))] dark:to-[var(--zui-dropdown-item-gradient-pink-to-dark,oklch(27.1%_0.105_12.094))]`,
35
+ "gradient-orange": `${zuiDropdownItemVariants["gradient-orange"]} dark:from-[var(--zui-dropdown-item-gradient-orange-from-dark,oklch(26.6%_0.079_36.259))] dark:to-[var(--zui-dropdown-item-gradient-orange-to-dark,oklch(25.8%_0.092_26.042))]`,
36
+ } as const;
37
+
38
+ export const zuiContextMenuSpacing = zuiDropdownSpacing;
39
+
40
+ export const zuiContextMenuLabelBase =
41
+ "px-3 py-2 text-xs font-semibold uppercase tracking-[0.18em] text-[color:var(--zui-dropdown-label-fg,oklch(55.1%_0.027_264.364))] dark:text-[color:var(--zui-dropdown-label-fg-dark,oklch(70.7%_0.022_261.325))]";
42
+
43
+ export const zuiContextMenuSeparatorBase =
44
+ "my-1 h-px bg-[var(--zui-dropdown-separator-bg,oklch(20.8%_0.042_265.755_/_0.12))] dark:bg-[var(--zui-dropdown-separator-bg-dark,#ffffff1a)]";
@@ -7,6 +7,7 @@ export * from "./button";
7
7
  export * from "./card";
8
8
  export * from "./checkbox";
9
9
  export * from "./command";
10
+ export * from "./context-menu";
10
11
  export * from "./divider";
11
12
  export * from "./drawer";
12
13
  export * from "./dropdown";
@@ -28,6 +29,7 @@ export * from "./spinner";
28
29
  export * from "./stepper";
29
30
  export * from "./table";
30
31
  export * from "./tabs";
32
+ export * from "./timeline";
31
33
  export * from "./toast";
32
34
  export * from "./tokens";
33
35
  export * from "./toggle";
@@ -0,0 +1,87 @@
1
+ export const zuiTimelineBase = "flex w-full flex-col";
2
+
3
+ export const zuiTimelineItemBase = "relative flex gap-4";
4
+
5
+ export const zuiTimelineIndicatorBase =
6
+ "relative z-[1] grid shrink-0 place-items-center rounded-full border font-semibold transition-colors";
7
+
8
+ export const zuiTimelineIndicatorAppearances = {
9
+ default:
10
+ "border-[color:var(--zui-timeline-indicator-default-border,oklch(55.1%_0.027_264.364_/_0.6))] bg-[var(--zui-timeline-indicator-default-bg,oklch(55.1%_0.027_264.364_/_0.2))] text-[color:var(--zui-timeline-indicator-default-fg,oklch(21%_0.034_264.665))] dark:text-[color:var(--zui-timeline-indicator-default-fg-dark,oklch(96.7%_0.003_264.542))] ring-2 ring-[var(--zui-timeline-indicator-default-ring,oklch(70.7%_0.022_261.325_/_0.3))]",
11
+ sky: "border-[color:var(--zui-timeline-indicator-sky-border,oklch(68.5%_0.169_237.323_/_0.6))] bg-[var(--zui-timeline-indicator-sky-bg,oklch(68.5%_0.169_237.323_/_0.2))] text-[color:var(--zui-timeline-indicator-sky-fg,oklch(39.1%_0.09_240.876))] dark:text-[color:var(--zui-timeline-indicator-sky-fg-dark,oklch(95.1%_0.026_236.824))] ring-2 ring-[var(--zui-timeline-indicator-sky-ring,oklch(74.6%_0.16_232.661_/_0.3))]",
12
+ rose: "border-[color:var(--zui-timeline-indicator-rose-border,oklch(64.5%_0.246_16.439_/_0.6))] bg-[var(--zui-timeline-indicator-rose-bg,oklch(64.5%_0.246_16.439_/_0.2))] text-[color:var(--zui-timeline-indicator-rose-fg,oklch(41%_0.159_10.272))] dark:text-[color:var(--zui-timeline-indicator-rose-fg-dark,oklch(94.1%_0.03_12.58))] ring-2 ring-[var(--zui-timeline-indicator-rose-ring,oklch(71.2%_0.194_13.428_/_0.3))]",
13
+ purple:
14
+ "border-[color:var(--zui-timeline-indicator-purple-border,oklch(62.7%_0.265_303.9_/_0.6))] bg-[var(--zui-timeline-indicator-purple-bg,oklch(62.7%_0.265_303.9_/_0.2))] text-[color:var(--zui-timeline-indicator-purple-fg,oklch(38.1%_0.176_304.987))] dark:text-[color:var(--zui-timeline-indicator-purple-fg-dark,oklch(94.6%_0.033_307.174))] ring-2 ring-[var(--zui-timeline-indicator-purple-ring,oklch(71.4%_0.203_305.504_/_0.3))]",
15
+ pink: "border-[color:var(--zui-timeline-indicator-pink-border,oklch(65.6%_0.241_354.308_/_0.6))] bg-[var(--zui-timeline-indicator-pink-bg,oklch(65.6%_0.241_354.308_/_0.2))] text-[color:var(--zui-timeline-indicator-pink-fg,oklch(40.8%_0.153_2.432))] dark:text-[color:var(--zui-timeline-indicator-pink-fg-dark,oklch(94.8%_0.028_342.258))] ring-2 ring-[var(--zui-timeline-indicator-pink-ring,oklch(71.8%_0.202_349.761_/_0.3))]",
16
+ orange:
17
+ "border-[color:var(--zui-timeline-indicator-orange-border,oklch(70.5%_0.213_47.604_/_0.6))] bg-[var(--zui-timeline-indicator-orange-bg,oklch(70.5%_0.213_47.604_/_0.2))] text-[color:var(--zui-timeline-indicator-orange-fg,oklch(40.8%_0.123_38.172))] dark:text-[color:var(--zui-timeline-indicator-orange-fg-dark,oklch(95.4%_0.038_75.164))] ring-2 ring-[var(--zui-timeline-indicator-orange-ring,oklch(75%_0.183_55.934_/_0.3))]",
18
+ yellow:
19
+ "border-[color:var(--zui-timeline-indicator-yellow-border,oklch(79.5%_0.184_86.047_/_0.6))] bg-[var(--zui-timeline-indicator-yellow-bg,oklch(79.5%_0.184_86.047_/_0.2))] text-[color:var(--zui-timeline-indicator-yellow-fg,oklch(42.1%_0.095_57.708))] dark:text-[color:var(--zui-timeline-indicator-yellow-fg-dark,oklch(97.3%_0.071_103.193))] ring-2 ring-[var(--zui-timeline-indicator-yellow-ring,oklch(85.2%_0.199_91.936_/_0.3))]",
20
+ teal: "border-[color:var(--zui-timeline-indicator-teal-border,oklch(70.4%_0.14_182.503_/_0.6))] bg-[var(--zui-timeline-indicator-teal-bg,oklch(70.4%_0.14_182.503_/_0.2))] text-[color:var(--zui-timeline-indicator-teal-fg,oklch(38.6%_0.063_188.416))] dark:text-[color:var(--zui-timeline-indicator-teal-fg-dark,oklch(95.3%_0.051_180.801))] ring-2 ring-[var(--zui-timeline-indicator-teal-ring,oklch(77.7%_0.152_181.912_/_0.3))]",
21
+ indigo:
22
+ "border-[color:var(--zui-timeline-indicator-indigo-border,oklch(58.5%_0.233_277.117_/_0.6))] bg-[var(--zui-timeline-indicator-indigo-bg,oklch(58.5%_0.233_277.117_/_0.2))] text-[color:var(--zui-timeline-indicator-indigo-fg,oklch(35.9%_0.144_278.697))] dark:text-[color:var(--zui-timeline-indicator-indigo-fg-dark,oklch(93%_0.034_272.788))] ring-2 ring-[var(--zui-timeline-indicator-indigo-ring,oklch(67.3%_0.182_276.935_/_0.3))]",
23
+ emerald:
24
+ "border-[color:var(--zui-timeline-indicator-emerald-border,oklch(69.6%_0.17_162.48_/_0.6))] bg-[var(--zui-timeline-indicator-emerald-bg,oklch(69.6%_0.17_162.48_/_0.2))] text-[color:var(--zui-timeline-indicator-emerald-fg,oklch(37.8%_0.077_168.94))] dark:text-[color:var(--zui-timeline-indicator-emerald-fg-dark,oklch(95%_0.052_163.051))] ring-2 ring-[var(--zui-timeline-indicator-emerald-ring,oklch(76.5%_0.177_163.223_/_0.3))]",
25
+ gray: "border-[color:var(--zui-timeline-indicator-gray-border,oklch(55.1%_0.027_264.364_/_0.6))] bg-[var(--zui-timeline-indicator-gray-bg,oklch(55.1%_0.027_264.364_/_0.2))] text-[color:var(--zui-timeline-indicator-gray-fg,oklch(21%_0.034_264.665))] dark:text-[color:var(--zui-timeline-indicator-gray-fg-dark,oklch(96.7%_0.003_264.542))] ring-2 ring-[var(--zui-timeline-indicator-gray-ring,oklch(70.7%_0.022_261.325_/_0.3))]",
26
+ violet:
27
+ "border-[color:var(--zui-timeline-indicator-violet-border,oklch(60.6%_0.25_292.717_/_0.6))] bg-[var(--zui-timeline-indicator-violet-bg,oklch(60.6%_0.25_292.717_/_0.2))] text-[color:var(--zui-timeline-indicator-violet-fg,oklch(38%_0.189_293.745))] dark:text-[color:var(--zui-timeline-indicator-violet-fg-dark,oklch(94.3%_0.029_294.588))] ring-2 ring-[var(--zui-timeline-indicator-violet-ring,oklch(70.2%_0.183_293.541_/_0.3))]",
28
+ "gradient-blue":
29
+ "border-transparent bg-linear-to-br from-[var(--zui-timeline-indicator-gradient-blue-from,oklch(62.3%_0.214_259.815))] to-[var(--zui-timeline-indicator-gradient-blue-to,oklch(54.6%_0.245_262.881))] text-[color:var(--zui-timeline-indicator-gradient-blue-fg,#ffffff)] ring-2 ring-[var(--zui-timeline-indicator-gradient-blue-ring,oklch(70.7%_0.165_254.624_/_0.3))]",
30
+ "gradient-green":
31
+ "border-transparent bg-linear-to-br from-[var(--zui-timeline-indicator-gradient-green-from,oklch(72.3%_0.219_149.579))] to-[var(--zui-timeline-indicator-gradient-green-to,oklch(62.7%_0.194_149.214))] text-[color:var(--zui-timeline-indicator-gradient-green-fg,#ffffff)] ring-2 ring-[var(--zui-timeline-indicator-gradient-green-ring,oklch(79.2%_0.209_151.711_/_0.3))]",
32
+ "gradient-red":
33
+ "border-transparent bg-linear-to-br from-[var(--zui-timeline-indicator-gradient-red-from,oklch(63.7%_0.237_25.331))] to-[var(--zui-timeline-indicator-gradient-red-to,oklch(57.7%_0.245_27.325))] text-[color:var(--zui-timeline-indicator-gradient-red-fg,#ffffff)] ring-2 ring-[var(--zui-timeline-indicator-gradient-red-ring,oklch(70.4%_0.191_22.216_/_0.3))]",
34
+ "gradient-yellow":
35
+ "border-transparent bg-linear-to-br from-[var(--zui-timeline-indicator-gradient-yellow-from,oklch(85.2%_0.199_91.936))] to-[var(--zui-timeline-indicator-gradient-yellow-to,oklch(79.5%_0.184_86.047))] text-[color:var(--zui-timeline-indicator-gradient-yellow-fg,oklch(42.1%_0.095_57.708))] ring-2 ring-[var(--zui-timeline-indicator-gradient-yellow-ring,oklch(85.2%_0.199_91.936_/_0.3))]",
36
+ "gradient-purple":
37
+ "border-transparent bg-linear-to-br from-[var(--zui-timeline-indicator-gradient-purple-from,oklch(71.4%_0.203_305.504))] to-[var(--zui-timeline-indicator-gradient-purple-to,oklch(62.7%_0.265_303.9))] text-[color:var(--zui-timeline-indicator-gradient-purple-fg,#ffffff)] ring-2 ring-[var(--zui-timeline-indicator-gradient-purple-ring,oklch(71.4%_0.203_305.504_/_0.3))]",
38
+ "gradient-teal":
39
+ "border-transparent bg-linear-to-br from-[var(--zui-timeline-indicator-gradient-teal-from,oklch(77.7%_0.152_181.912))] to-[var(--zui-timeline-indicator-gradient-teal-to,oklch(70.4%_0.14_182.503))] text-[color:var(--zui-timeline-indicator-gradient-teal-fg,#ffffff)] ring-2 ring-[var(--zui-timeline-indicator-gradient-teal-ring,oklch(77.7%_0.152_181.912_/_0.3))]",
40
+ "gradient-indigo":
41
+ "border-transparent bg-linear-to-br from-[var(--zui-timeline-indicator-gradient-indigo-from,oklch(67.3%_0.182_276.935))] to-[var(--zui-timeline-indicator-gradient-indigo-to,oklch(58.5%_0.233_277.117))] text-[color:var(--zui-timeline-indicator-gradient-indigo-fg,#ffffff)] ring-2 ring-[var(--zui-timeline-indicator-gradient-indigo-ring,oklch(67.3%_0.182_276.935_/_0.3))]",
42
+ "gradient-pink":
43
+ "border-transparent bg-linear-to-br from-[var(--zui-timeline-indicator-gradient-pink-from,oklch(71.8%_0.202_349.761))] to-[var(--zui-timeline-indicator-gradient-pink-to,oklch(65.6%_0.241_354.308))] text-[color:var(--zui-timeline-indicator-gradient-pink-fg,#ffffff)] ring-2 ring-[var(--zui-timeline-indicator-gradient-pink-ring,oklch(71.8%_0.202_349.761_/_0.3))]",
44
+ "gradient-orange":
45
+ "border-transparent bg-linear-to-br from-[var(--zui-timeline-indicator-gradient-orange-from,oklch(75%_0.183_55.934))] to-[var(--zui-timeline-indicator-gradient-orange-to,oklch(70.5%_0.213_47.604))] text-[color:var(--zui-timeline-indicator-gradient-orange-fg,#ffffff)] ring-2 ring-[var(--zui-timeline-indicator-gradient-orange-ring,oklch(75%_0.183_55.934_/_0.3))]",
46
+ } as const;
47
+
48
+ export const zuiTimelineIndicatorSizes = {
49
+ sm: "size-5 text-[0.625rem]",
50
+ md: "size-6 text-xs",
51
+ lg: "size-7 text-sm",
52
+ } as const;
53
+
54
+ export const zuiTimelineConnectorBase =
55
+ "pointer-events-none absolute bottom-0 w-px -translate-x-1/2 rounded-full bg-[var(--zui-timeline-connector,#0000001f)] dark:bg-[var(--zui-timeline-connector-dark,#ffffff1f)]";
56
+
57
+ export const zuiTimelineConnectorSizes = {
58
+ sm: "left-2.5 top-6",
59
+ md: "left-3 top-7",
60
+ lg: "left-3.5 top-8",
61
+ } as const;
62
+
63
+ export const zuiTimelineContentBase = "min-w-0 flex-1";
64
+
65
+ export const zuiTimelineContentSizes = {
66
+ sm: "pb-5",
67
+ md: "pb-6",
68
+ lg: "pb-8",
69
+ } as const;
70
+
71
+ export const zuiTimelineTitleBase =
72
+ "font-semibold text-[color:var(--zui-timeline-title-fg,oklch(20.8%_0.042_265.755))] dark:text-[color:var(--zui-timeline-title-fg-dark,#ffffff)]";
73
+
74
+ export const zuiTimelineTitleSizes = {
75
+ sm: "text-sm",
76
+ md: "text-sm",
77
+ lg: "text-base",
78
+ } as const;
79
+
80
+ export const zuiTimelineDescriptionBase =
81
+ "text-[color:var(--zui-timeline-description-fg,oklch(44.6%_0.03_256.802))] dark:text-[color:var(--zui-timeline-description-fg-dark,oklch(70.4%_0.04_256.788))]";
82
+
83
+ export const zuiTimelineDescriptionSizes = {
84
+ sm: "text-xs",
85
+ md: "text-xs",
86
+ lg: "text-sm",
87
+ } as const;
@@ -0,0 +1,176 @@
1
+ import { fireEvent, render, screen, waitFor } from "@testing-library/react";
2
+ import userEvent from "@testing-library/user-event";
3
+ import { describe, expect, it, vi } from "vitest";
4
+
5
+ import {
6
+ ContextMenu,
7
+ ContextMenuContent,
8
+ ContextMenuItem,
9
+ ContextMenuLabel,
10
+ ContextMenuSeparator,
11
+ ContextMenuSub,
12
+ ContextMenuSubContent,
13
+ ContextMenuSubTrigger,
14
+ ContextMenuTrigger,
15
+ } from "./context-menu";
16
+
17
+ function renderContextMenu(onSelect = vi.fn()) {
18
+ render(
19
+ <>
20
+ <ContextMenu>
21
+ <ContextMenuTrigger>
22
+ <div data-testid="surface">Right-click row</div>
23
+ </ContextMenuTrigger>
24
+ <ContextMenuContent>
25
+ <ContextMenuLabel>Row actions</ContextMenuLabel>
26
+ <ContextMenuItem onSelect={onSelect}>Copy</ContextMenuItem>
27
+ <ContextMenuSeparator />
28
+ <ContextMenuSub>
29
+ <ContextMenuSubTrigger>More actions</ContextMenuSubTrigger>
30
+ <ContextMenuSubContent>
31
+ <ContextMenuItem>Archive</ContextMenuItem>
32
+ </ContextMenuSubContent>
33
+ </ContextMenuSub>
34
+ </ContextMenuContent>
35
+ </ContextMenu>
36
+ <button type="button">Outside</button>
37
+ </>,
38
+ );
39
+ }
40
+
41
+ describe("ContextMenu", () => {
42
+ it("should open at the pointer position from a context menu event", () => {
43
+ renderContextMenu();
44
+
45
+ fireEvent.contextMenu(screen.getByTestId("surface"), {
46
+ clientX: 120,
47
+ clientY: 80,
48
+ });
49
+
50
+ const menu = screen.getByRole("menu");
51
+ expect(menu).toBeVisible();
52
+ expect(menu).toHaveStyle({ left: "120px", top: "80px" });
53
+ expect(screen.getByText("Row actions").tagName).toBe("P");
54
+ });
55
+
56
+ it("should clamp using the rendered menu dimensions", async () => {
57
+ vi.spyOn(HTMLElement.prototype, "getBoundingClientRect").mockReturnValue({
58
+ bottom: 0,
59
+ height: 300,
60
+ left: 0,
61
+ right: 0,
62
+ top: 0,
63
+ width: 320,
64
+ x: 0,
65
+ y: 0,
66
+ toJSON: () => ({}),
67
+ });
68
+ Object.defineProperty(window, "innerHeight", {
69
+ configurable: true,
70
+ value: 768,
71
+ });
72
+ Object.defineProperty(window, "innerWidth", {
73
+ configurable: true,
74
+ value: 800,
75
+ });
76
+ renderContextMenu();
77
+
78
+ fireEvent.contextMenu(screen.getByTestId("surface"), {
79
+ clientX: 760,
80
+ clientY: 740,
81
+ });
82
+
83
+ await waitFor(() => {
84
+ expect(screen.getByRole("menu")).toHaveStyle({
85
+ left: "472px",
86
+ top: "460px",
87
+ });
88
+ });
89
+ });
90
+
91
+ it("should invoke item selection and close the menu", async () => {
92
+ const user = userEvent.setup();
93
+ const onSelect = vi.fn();
94
+ renderContextMenu(onSelect);
95
+
96
+ fireEvent.contextMenu(screen.getByTestId("surface"));
97
+ await user.click(screen.getByRole("menuitem", { name: "Copy" }));
98
+
99
+ expect(onSelect).toHaveBeenCalledTimes(1);
100
+ await waitFor(() => {
101
+ expect(screen.queryByRole("menu")).not.toBeInTheDocument();
102
+ });
103
+ });
104
+
105
+ it("should close when clicking outside", async () => {
106
+ const user = userEvent.setup();
107
+ renderContextMenu();
108
+
109
+ fireEvent.contextMenu(screen.getByTestId("surface"));
110
+ expect(screen.getByRole("menu")).toBeInTheDocument();
111
+
112
+ await user.click(screen.getByRole("button", { name: "Outside" }));
113
+ await waitFor(() => {
114
+ expect(screen.queryByRole("menu")).not.toBeInTheDocument();
115
+ });
116
+ });
117
+
118
+ it("should close on Escape and return focus to the trigger", async () => {
119
+ const user = userEvent.setup();
120
+ renderContextMenu();
121
+
122
+ const trigger = screen.getByTestId("surface");
123
+ fireEvent.contextMenu(trigger);
124
+ await user.keyboard("{Escape}");
125
+
126
+ await waitFor(() => {
127
+ expect(screen.queryByRole("menu")).not.toBeInTheDocument();
128
+ });
129
+ expect(trigger).toHaveFocus();
130
+ });
131
+
132
+ it("should support controlled open state", () => {
133
+ const onOpenChange = vi.fn();
134
+ render(
135
+ <ContextMenu open={false} onOpenChange={onOpenChange}>
136
+ <ContextMenuTrigger>
137
+ <div data-testid="surface">Right-click row</div>
138
+ </ContextMenuTrigger>
139
+ <ContextMenuContent>
140
+ <ContextMenuItem>Copy</ContextMenuItem>
141
+ </ContextMenuContent>
142
+ </ContextMenu>,
143
+ );
144
+
145
+ fireEvent.contextMenu(screen.getByTestId("surface"));
146
+
147
+ expect(onOpenChange).toHaveBeenCalledWith(true);
148
+ expect(screen.queryByRole("menu")).not.toBeInTheDocument();
149
+ });
150
+
151
+ it("should keep the menu open when closeOnSelect is false", async () => {
152
+ const user = userEvent.setup();
153
+ render(
154
+ <ContextMenu defaultOpen>
155
+ <ContextMenuTrigger>Right-click row</ContextMenuTrigger>
156
+ <ContextMenuContent>
157
+ <ContextMenuItem closeOnSelect={false}>Pin</ContextMenuItem>
158
+ </ContextMenuContent>
159
+ </ContextMenu>,
160
+ );
161
+
162
+ await user.click(screen.getByRole("menuitem", { name: "Pin" }));
163
+
164
+ expect(screen.getByRole("menu")).toBeInTheDocument();
165
+ });
166
+
167
+ it("should reveal submenu content from the sub trigger", async () => {
168
+ const user = userEvent.setup();
169
+ renderContextMenu();
170
+
171
+ fireEvent.contextMenu(screen.getByTestId("surface"));
172
+ await user.hover(screen.getByRole("menuitem", { name: "More actions" }));
173
+
174
+ expect(screen.getByRole("menuitem", { name: "Archive" })).toBeVisible();
175
+ });
176
+ });