@zentauri-ui/zentauri-components 1.7.5 → 1.7.7

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 (124) hide show
  1. package/README.md +11 -6
  2. package/cli/registry.json +3 -0
  3. package/dist/chunk-DEZRB6DS.mjs +83 -0
  4. package/dist/chunk-DEZRB6DS.mjs.map +1 -0
  5. package/dist/chunk-GRJFGIZC.mjs +417 -0
  6. package/dist/chunk-GRJFGIZC.mjs.map +1 -0
  7. package/dist/chunk-QHEHBC6M.js +421 -0
  8. package/dist/chunk-QHEHBC6M.js.map +1 -0
  9. package/dist/chunk-V5JTDRV5.mjs +278 -0
  10. package/dist/chunk-V5JTDRV5.mjs.map +1 -0
  11. package/dist/chunk-Z4KHAD6Y.js +295 -0
  12. package/dist/chunk-Z4KHAD6Y.js.map +1 -0
  13. package/dist/chunk-ZX2IBIZT.js +92 -0
  14. package/dist/chunk-ZX2IBIZT.js.map +1 -0
  15. package/dist/design-system/context-menu.d.ts +41 -0
  16. package/dist/design-system/context-menu.d.ts.map +1 -0
  17. package/dist/design-system/index.d.ts +3 -0
  18. package/dist/design-system/index.d.ts.map +1 -1
  19. package/dist/design-system/timeline.d.ts +56 -0
  20. package/dist/design-system/timeline.d.ts.map +1 -0
  21. package/dist/design-system/tree-view.d.ts +66 -0
  22. package/dist/design-system/tree-view.d.ts.map +1 -0
  23. package/dist/ui/context-menu/context-menu.d.ts +11 -0
  24. package/dist/ui/context-menu/context-menu.d.ts.map +1 -0
  25. package/dist/ui/context-menu/index.d.ts +4 -0
  26. package/dist/ui/context-menu/index.d.ts.map +1 -0
  27. package/dist/ui/context-menu/types.d.ts +81 -0
  28. package/dist/ui/context-menu/types.d.ts.map +1 -0
  29. package/dist/ui/context-menu/variants.d.ts +7 -0
  30. package/dist/ui/context-menu/variants.d.ts.map +1 -0
  31. package/dist/ui/context-menu.js +500 -0
  32. package/dist/ui/context-menu.js.map +1 -0
  33. package/dist/ui/context-menu.mjs +488 -0
  34. package/dist/ui/context-menu.mjs.map +1 -0
  35. package/dist/ui/dropdown.js +9 -89
  36. package/dist/ui/dropdown.js.map +1 -1
  37. package/dist/ui/dropdown.mjs +1 -81
  38. package/dist/ui/dropdown.mjs.map +1 -1
  39. package/dist/ui/scroll-area/scroll-area.d.ts.map +1 -1
  40. package/dist/ui/scroll-area.js.map +1 -1
  41. package/dist/ui/scroll-area.mjs.map +1 -1
  42. package/dist/ui/timeline/animated/animations.d.ts +8 -0
  43. package/dist/ui/timeline/animated/animations.d.ts.map +1 -0
  44. package/dist/ui/timeline/animated/index.d.ts +6 -0
  45. package/dist/ui/timeline/animated/index.d.ts.map +1 -0
  46. package/dist/ui/timeline/animated/timeline-item-animated.d.ts +8 -0
  47. package/dist/ui/timeline/animated/timeline-item-animated.d.ts.map +1 -0
  48. package/dist/ui/timeline/animated/types.d.ts +12 -0
  49. package/dist/ui/timeline/animated/types.d.ts.map +1 -0
  50. package/dist/ui/timeline/animated.js +94 -0
  51. package/dist/ui/timeline/animated.js.map +1 -0
  52. package/dist/ui/timeline/animated.mjs +71 -0
  53. package/dist/ui/timeline/animated.mjs.map +1 -0
  54. package/dist/ui/timeline/index.d.ts +4 -0
  55. package/dist/ui/timeline/index.d.ts.map +1 -0
  56. package/dist/ui/timeline/timeline-base.d.ts +37 -0
  57. package/dist/ui/timeline/timeline-base.d.ts.map +1 -0
  58. package/dist/ui/timeline/timeline.d.ts +8 -0
  59. package/dist/ui/timeline/timeline.d.ts.map +1 -0
  60. package/dist/ui/timeline/types.d.ts +38 -0
  61. package/dist/ui/timeline/types.d.ts.map +1 -0
  62. package/dist/ui/timeline/variants.d.ts +19 -0
  63. package/dist/ui/timeline/variants.d.ts.map +1 -0
  64. package/dist/ui/timeline.js +63 -0
  65. package/dist/ui/timeline.js.map +1 -0
  66. package/dist/ui/timeline.mjs +14 -0
  67. package/dist/ui/timeline.mjs.map +1 -0
  68. package/dist/ui/tree-view/animated/animations.d.ts +6 -0
  69. package/dist/ui/tree-view/animated/animations.d.ts.map +1 -0
  70. package/dist/ui/tree-view/animated/index.d.ts +5 -0
  71. package/dist/ui/tree-view/animated/index.d.ts.map +1 -0
  72. package/dist/ui/tree-view/animated/tree-view-animated.d.ts +6 -0
  73. package/dist/ui/tree-view/animated/tree-view-animated.d.ts.map +1 -0
  74. package/dist/ui/tree-view/animated/types.d.ts +6 -0
  75. package/dist/ui/tree-view/animated/types.d.ts.map +1 -0
  76. package/dist/ui/tree-view/animated.js +53 -0
  77. package/dist/ui/tree-view/animated.js.map +1 -0
  78. package/dist/ui/tree-view/animated.mjs +50 -0
  79. package/dist/ui/tree-view/animated.mjs.map +1 -0
  80. package/dist/ui/tree-view/index.d.ts +5 -0
  81. package/dist/ui/tree-view/index.d.ts.map +1 -0
  82. package/dist/ui/tree-view/tree-view-base.d.ts +15 -0
  83. package/dist/ui/tree-view/tree-view-base.d.ts.map +1 -0
  84. package/dist/ui/tree-view/tree-view.d.ts +6 -0
  85. package/dist/ui/tree-view/tree-view.d.ts.map +1 -0
  86. package/dist/ui/tree-view/types.d.ts +61 -0
  87. package/dist/ui/tree-view/types.d.ts.map +1 -0
  88. package/dist/ui/tree-view/variants.d.ts +9 -0
  89. package/dist/ui/tree-view/variants.d.ts.map +1 -0
  90. package/dist/ui/tree-view.js +27 -0
  91. package/dist/ui/tree-view.js.map +1 -0
  92. package/dist/ui/tree-view.mjs +14 -0
  93. package/dist/ui/tree-view.mjs.map +1 -0
  94. package/package.json +1 -1
  95. package/src/design-system/context-menu.ts +44 -0
  96. package/src/design-system/index.ts +3 -0
  97. package/src/design-system/timeline.ts +87 -0
  98. package/src/design-system/tree-view.ts +113 -0
  99. package/src/ui/context-menu/context-menu.test.tsx +176 -0
  100. package/src/ui/context-menu/context-menu.tsx +536 -0
  101. package/src/ui/context-menu/index.ts +29 -0
  102. package/src/ui/context-menu/types.ts +110 -0
  103. package/src/ui/context-menu/variants.ts +26 -0
  104. package/src/ui/scroll-area/scroll-area.tsx +0 -2
  105. package/src/ui/timeline/animated/animations.ts +16 -0
  106. package/src/ui/timeline/animated/index.ts +22 -0
  107. package/src/ui/timeline/animated/timeline-item-animated.tsx +76 -0
  108. package/src/ui/timeline/animated/types.ts +21 -0
  109. package/src/ui/timeline/index.ts +30 -0
  110. package/src/ui/timeline/timeline-base.tsx +232 -0
  111. package/src/ui/timeline/timeline.test.tsx +262 -0
  112. package/src/ui/timeline/timeline.tsx +24 -0
  113. package/src/ui/timeline/types.ts +61 -0
  114. package/src/ui/timeline/variants.ts +60 -0
  115. package/src/ui/tree-view/animated/animations.ts +13 -0
  116. package/src/ui/tree-view/animated/index.ts +6 -0
  117. package/src/ui/tree-view/animated/tree-view-animated.tsx +52 -0
  118. package/src/ui/tree-view/animated/types.ts +6 -0
  119. package/src/ui/tree-view/index.ts +13 -0
  120. package/src/ui/tree-view/tree-view-base.tsx +496 -0
  121. package/src/ui/tree-view/tree-view.test.tsx +136 -0
  122. package/src/ui/tree-view/tree-view.tsx +9 -0
  123. package/src/ui/tree-view/types.ts +68 -0
  124. package/src/ui/tree-view/variants.ts +32 -0
@@ -0,0 +1,113 @@
1
+ export const zuiTreeViewBase =
2
+ "w-full text-[color:var(--zui-tree-view-fg,oklch(20.8%_0.042_265.755))] dark:text-[color:var(--zui-tree-view-fg-dark,oklch(92.9%_0.013_255.508))]";
3
+
4
+ export const zuiTreeViewAppearances = {
5
+ default:
6
+ "rounded-xl border border-[color:var(--zui-tree-view-default-border,#0000001a)] dark:border-[color:var(--zui-tree-view-default-border-dark,#ffffff1a)] p-2",
7
+ outline:
8
+ "rounded-xl border border-[color:var(--zui-tree-view-outline-border,#00000026)] dark:border-[color:var(--zui-tree-view-outline-border-dark,#ffffff26)] p-2",
9
+ ghost: "p-1",
10
+ card: "rounded-xl border border-[color:var(--zui-tree-view-card-border,#0000001a)] dark:border-[color:var(--zui-tree-view-card-border-dark,#ffffff1a)] bg-[var(--zui-tree-view-card-bg,#0000000d)] dark:bg-[var(--zui-tree-view-card-bg-dark,#00000099)] p-3",
11
+ separated:
12
+ "rounded-xl border border-[color:var(--zui-tree-view-separated-border,#0000001a)] dark:border-[color:var(--zui-tree-view-separated-border-dark,#ffffff1a)] bg-[var(--zui-tree-view-separated-bg,oklch(98.4%_0.003_247.858_/_0.4))] dark:bg-[var(--zui-tree-view-separated-bg-dark,oklch(12.9%_0.042_264.695_/_0.4))] p-3",
13
+ sky: "rounded-xl border border-[color:var(--zui-tree-view-sky-border,oklch(44.3%_0.11_240.79))] dark:border-[color:var(--zui-tree-view-sky-border-dark,oklch(58.8%_0.158_241.966))] p-2",
14
+ rose: "rounded-xl border border-[color:var(--zui-tree-view-rose-border,oklch(45.5%_0.188_13.697))] dark:border-[color:var(--zui-tree-view-rose-border-dark,oklch(58.6%_0.253_17.585))] p-2",
15
+ purple:
16
+ "rounded-xl border border-[color:var(--zui-tree-view-purple-border,oklch(43.8%_0.218_303.724))] dark:border-[color:var(--zui-tree-view-purple-border-dark,oklch(55.8%_0.288_302.321))] p-2",
17
+ pink: "rounded-xl border border-[color:var(--zui-tree-view-pink-border,oklch(45.9%_0.187_3.815))] dark:border-[color:var(--zui-tree-view-pink-border-dark,oklch(59.2%_0.249_0.584))] p-2",
18
+ orange:
19
+ "rounded-xl border border-[color:var(--zui-tree-view-orange-border,oklch(47%_0.157_37.304))] dark:border-[color:var(--zui-tree-view-orange-border-dark,oklch(64.6%_0.222_41.116))] p-2",
20
+ yellow:
21
+ "rounded-xl border border-[color:var(--zui-tree-view-yellow-border,oklch(47.6%_0.114_61.907))] dark:border-[color:var(--zui-tree-view-yellow-border-dark,oklch(68.1%_0.162_75.834))] p-2",
22
+ teal: "rounded-xl border border-[color:var(--zui-tree-view-teal-border,oklch(43.7%_0.078_188.216))] dark:border-[color:var(--zui-tree-view-teal-border-dark,oklch(60%_0.118_184.704))] p-2",
23
+ indigo:
24
+ "rounded-xl border border-[color:var(--zui-tree-view-indigo-border,oklch(39.8%_0.195_277.366))] dark:border-[color:var(--zui-tree-view-indigo-border-dark,oklch(51.1%_0.262_276.966))] p-2",
25
+ emerald:
26
+ "rounded-xl border border-[color:var(--zui-tree-view-emerald-border,oklch(43.2%_0.095_166.913))] dark:border-[color:var(--zui-tree-view-emerald-border-dark,oklch(59.6%_0.145_163.225))] p-2",
27
+ "gradient-blue":
28
+ "rounded-xl border border-[color:var(--zui-tree-view-gradient-blue-border,oklch(42.4%_0.199_265.638))] dark:border-[color:var(--zui-tree-view-gradient-blue-border-dark,oklch(54.6%_0.245_262.881))] p-2",
29
+ "gradient-green":
30
+ "rounded-xl border border-[color:var(--zui-tree-view-gradient-green-border,oklch(44.8%_0.119_151.328))] dark:border-[color:var(--zui-tree-view-gradient-green-border-dark,oklch(62.7%_0.194_149.214))] p-2",
31
+ "gradient-red":
32
+ "rounded-xl border border-[color:var(--zui-tree-view-gradient-red-border,oklch(44.4%_0.177_26.899))] dark:border-[color:var(--zui-tree-view-gradient-red-border-dark,oklch(57.7%_0.245_27.325))] p-2",
33
+ "gradient-yellow":
34
+ "rounded-xl border border-[color:var(--zui-tree-view-gradient-yellow-border,oklch(47.6%_0.114_61.907))] dark:border-[color:var(--zui-tree-view-gradient-yellow-border-dark,oklch(68.1%_0.162_75.834))] p-2",
35
+ "gradient-purple":
36
+ "rounded-xl border border-[color:var(--zui-tree-view-gradient-purple-border,oklch(43.8%_0.218_303.724))] dark:border-[color:var(--zui-tree-view-gradient-purple-border-dark,oklch(55.8%_0.288_302.321))] p-2",
37
+ "gradient-teal":
38
+ "rounded-xl border border-[color:var(--zui-tree-view-gradient-teal-border,oklch(43.7%_0.078_188.216))] dark:border-[color:var(--zui-tree-view-gradient-teal-border-dark,oklch(60%_0.118_184.704))] p-2",
39
+ "gradient-indigo":
40
+ "rounded-xl border border-[color:var(--zui-tree-view-gradient-indigo-border,oklch(39.8%_0.195_277.366))] dark:border-[color:var(--zui-tree-view-gradient-indigo-border-dark,oklch(51.1%_0.262_276.966))] p-2",
41
+ "gradient-pink":
42
+ "rounded-xl border border-[color:var(--zui-tree-view-gradient-pink-border,oklch(45.9%_0.187_3.815))] dark:border-[color:var(--zui-tree-view-gradient-pink-border-dark,oklch(59.2%_0.249_0.584))] p-2",
43
+ "gradient-orange":
44
+ "rounded-xl border border-[color:var(--zui-tree-view-gradient-orange-border,oklch(47%_0.157_37.304))] dark:border-[color:var(--zui-tree-view-gradient-orange-border-dark,oklch(64.6%_0.222_41.116))] p-2",
45
+ } as const;
46
+
47
+ export const zuiTreeViewSizes = {
48
+ sm: "text-xs",
49
+ md: "text-sm",
50
+ lg: "text-base",
51
+ } as const;
52
+
53
+ export const zuiTreeViewItemBase =
54
+ "relative flex w-full items-center gap-2 rounded-lg pr-2 text-left font-medium outline-none transition select-none cursor-pointer hover:bg-[var(--zui-tree-view-item-hover,#0000000d)] dark:hover:bg-[var(--zui-tree-view-item-hover-dark,#ffffff0d)] focus-visible:ring-2 focus-visible:ring-[var(--zui-tree-view-ring-focus,#0000004d)] dark:focus-visible:ring-[var(--zui-tree-view-ring-focus-dark,#ffffff4d)] data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50";
55
+
56
+ export const zuiTreeViewItemSizes = {
57
+ sm: "py-1 text-xs",
58
+ md: "py-1.5 text-sm",
59
+ lg: "py-2 text-base",
60
+ } as const;
61
+
62
+ export const zuiTreeViewItemAppearances = {
63
+ default:
64
+ "data-[selected=true]:bg-[var(--zui-tree-view-selected,#0000000f)] dark:data-[selected=true]:bg-[var(--zui-tree-view-selected-dark,#ffffff14)] data-[selected=true]:text-[color:var(--zui-tree-view-selected-fg,oklch(20.8%_0.042_265.755))] dark:data-[selected=true]:text-[color:var(--zui-tree-view-selected-fg-dark,#ffffff)]",
65
+ outline:
66
+ "data-[selected=true]:bg-[var(--zui-tree-view-selected,#0000000f)] dark:data-[selected=true]:bg-[var(--zui-tree-view-selected-dark,#ffffff14)] data-[selected=true]:text-[color:var(--zui-tree-view-selected-fg,oklch(20.8%_0.042_265.755))] dark:data-[selected=true]:text-[color:var(--zui-tree-view-selected-fg-dark,#ffffff)]",
67
+ ghost:
68
+ "data-[selected=true]:bg-[var(--zui-tree-view-selected,#0000000f)] dark:data-[selected=true]:bg-[var(--zui-tree-view-selected-dark,#ffffff14)] data-[selected=true]:text-[color:var(--zui-tree-view-selected-fg,oklch(20.8%_0.042_265.755))] dark:data-[selected=true]:text-[color:var(--zui-tree-view-selected-fg-dark,#ffffff)]",
69
+ card: "data-[selected=true]:bg-[var(--zui-tree-view-selected,#00000014)] dark:data-[selected=true]:bg-[var(--zui-tree-view-selected-dark,#ffffff1f)] data-[selected=true]:text-[color:var(--zui-tree-view-selected-fg,oklch(20.8%_0.042_265.755))] dark:data-[selected=true]:text-[color:var(--zui-tree-view-selected-fg-dark,#ffffff)]",
70
+ separated:
71
+ "data-[selected=true]:bg-[var(--zui-tree-view-selected,#00000014)] dark:data-[selected=true]:bg-[var(--zui-tree-view-selected-dark,#ffffff1f)] data-[selected=true]:text-[color:var(--zui-tree-view-selected-fg,oklch(20.8%_0.042_265.755))] dark:data-[selected=true]:text-[color:var(--zui-tree-view-selected-fg-dark,#ffffff)]",
72
+ sky: "data-[selected=true]:bg-[var(--zui-tree-view-sky-selected,oklch(95.1%_0.026_236.824))] dark:data-[selected=true]:bg-[var(--zui-tree-view-sky-selected-dark,oklch(58.8%_0.158_241.966_/_0.16))] data-[selected=true]:text-[color:var(--zui-tree-view-sky-selected-fg,oklch(44.3%_0.11_240.79))] dark:data-[selected=true]:text-[color:var(--zui-tree-view-sky-selected-fg-dark,oklch(82.8%_0.111_230.318))]",
73
+ rose: "data-[selected=true]:bg-[var(--zui-tree-view-rose-selected,oklch(94.1%_0.03_12.58))] dark:data-[selected=true]:bg-[var(--zui-tree-view-rose-selected-dark,oklch(58.6%_0.253_17.585_/_0.16))] data-[selected=true]:text-[color:var(--zui-tree-view-rose-selected-fg,oklch(45.5%_0.188_13.697))] dark:data-[selected=true]:text-[color:var(--zui-tree-view-rose-selected-fg-dark,oklch(81%_0.117_11.638))]",
74
+ purple:
75
+ "data-[selected=true]:bg-[var(--zui-tree-view-purple-selected,oklch(94.6%_0.033_307.174))] dark:data-[selected=true]:bg-[var(--zui-tree-view-purple-selected-dark,oklch(55.8%_0.288_302.321_/_0.16))] data-[selected=true]:text-[color:var(--zui-tree-view-purple-selected-fg,oklch(43.8%_0.218_303.724))] dark:data-[selected=true]:text-[color:var(--zui-tree-view-purple-selected-fg-dark,oklch(82.7%_0.119_306.383))]",
76
+ pink: "data-[selected=true]:bg-[var(--zui-tree-view-pink-selected,oklch(94.8%_0.028_342.258))] dark:data-[selected=true]:bg-[var(--zui-tree-view-pink-selected-dark,oklch(59.2%_0.249_0.584_/_0.16))] data-[selected=true]:text-[color:var(--zui-tree-view-pink-selected-fg,oklch(45.9%_0.187_3.815))] dark:data-[selected=true]:text-[color:var(--zui-tree-view-pink-selected-fg-dark,oklch(82.3%_0.12_346.018))]",
77
+ orange:
78
+ "data-[selected=true]:bg-[var(--zui-tree-view-orange-selected,oklch(95.4%_0.038_75.164))] dark:data-[selected=true]:bg-[var(--zui-tree-view-orange-selected-dark,oklch(64.6%_0.222_41.116_/_0.16))] data-[selected=true]:text-[color:var(--zui-tree-view-orange-selected-fg,oklch(47%_0.157_37.304))] dark:data-[selected=true]:text-[color:var(--zui-tree-view-orange-selected-fg-dark,oklch(83.7%_0.128_66.29))]",
79
+ yellow:
80
+ "data-[selected=true]:bg-[var(--zui-tree-view-yellow-selected,oklch(97.3%_0.071_103.193))] dark:data-[selected=true]:bg-[var(--zui-tree-view-yellow-selected-dark,oklch(68.1%_0.162_75.834_/_0.16))] data-[selected=true]:text-[color:var(--zui-tree-view-yellow-selected-fg,oklch(47.6%_0.114_61.907))] dark:data-[selected=true]:text-[color:var(--zui-tree-view-yellow-selected-fg-dark,oklch(90.5%_0.182_98.111))]",
81
+ teal: "data-[selected=true]:bg-[var(--zui-tree-view-teal-selected,oklch(95.3%_0.051_180.801))] dark:data-[selected=true]:bg-[var(--zui-tree-view-teal-selected-dark,oklch(60%_0.118_184.704_/_0.16))] data-[selected=true]:text-[color:var(--zui-tree-view-teal-selected-fg,oklch(43.7%_0.078_188.216))] dark:data-[selected=true]:text-[color:var(--zui-tree-view-teal-selected-fg-dark,oklch(85.5%_0.138_181.071))]",
82
+ indigo:
83
+ "data-[selected=true]:bg-[var(--zui-tree-view-indigo-selected,oklch(93%_0.034_272.788))] dark:data-[selected=true]:bg-[var(--zui-tree-view-indigo-selected-dark,oklch(51.1%_0.262_276.966_/_0.16))] data-[selected=true]:text-[color:var(--zui-tree-view-indigo-selected-fg,oklch(39.8%_0.195_277.366))] dark:data-[selected=true]:text-[color:var(--zui-tree-view-indigo-selected-fg-dark,oklch(78.5%_0.115_274.713))]",
84
+ emerald:
85
+ "data-[selected=true]:bg-[var(--zui-tree-view-emerald-selected,oklch(95%_0.052_163.051))] dark:data-[selected=true]:bg-[var(--zui-tree-view-emerald-selected-dark,oklch(59.6%_0.145_163.225_/_0.16))] data-[selected=true]:text-[color:var(--zui-tree-view-emerald-selected-fg,oklch(43.2%_0.095_166.913))] dark:data-[selected=true]:text-[color:var(--zui-tree-view-emerald-selected-fg-dark,oklch(84.5%_0.143_164.978))]",
86
+ "gradient-blue":
87
+ "data-[selected=true]:bg-linear-to-r data-[selected=true]:from-[var(--zui-tree-view-gradient-blue-from,oklch(80.9%_0.105_251.813))] data-[selected=true]:to-[var(--zui-tree-view-gradient-blue-to,oklch(82.7%_0.119_306.383))] dark:data-[selected=true]:from-[var(--zui-tree-view-gradient-blue-from-dark,oklch(54.6%_0.245_262.881))] dark:data-[selected=true]:to-[var(--zui-tree-view-gradient-blue-to-dark,oklch(55.8%_0.288_302.321))] data-[selected=true]:text-[color:var(--zui-tree-view-gradient-fg,#ffffff)]",
88
+ "gradient-green":
89
+ "data-[selected=true]:bg-linear-to-r data-[selected=true]:from-[var(--zui-tree-view-gradient-green-from,oklch(87.1%_0.15_154.449))] data-[selected=true]:to-[var(--zui-tree-view-gradient-green-to,oklch(89.7%_0.196_126.665))] dark:data-[selected=true]:from-[var(--zui-tree-view-gradient-green-from-dark,oklch(62.7%_0.194_149.214))] dark:data-[selected=true]:to-[var(--zui-tree-view-gradient-green-to-dark,oklch(64.8%_0.2_131.684))] data-[selected=true]:text-[color:var(--zui-tree-view-gradient-fg,#ffffff)]",
90
+ "gradient-red":
91
+ "data-[selected=true]:bg-linear-to-r data-[selected=true]:from-[var(--zui-tree-view-gradient-red-from,oklch(80.8%_0.114_19.571))] data-[selected=true]:to-[var(--zui-tree-view-gradient-red-to,oklch(82.3%_0.12_346.018))] dark:data-[selected=true]:from-[var(--zui-tree-view-gradient-red-from-dark,oklch(57.7%_0.245_27.325))] dark:data-[selected=true]:to-[var(--zui-tree-view-gradient-red-to-dark,oklch(59.2%_0.249_0.584))] data-[selected=true]:text-[color:var(--zui-tree-view-gradient-fg,#ffffff)]",
92
+ "gradient-yellow":
93
+ "data-[selected=true]:bg-linear-to-r data-[selected=true]:from-[var(--zui-tree-view-gradient-yellow-from,oklch(90.5%_0.182_98.111))] data-[selected=true]:to-[var(--zui-tree-view-gradient-yellow-to,oklch(83.7%_0.128_66.29))] dark:data-[selected=true]:from-[var(--zui-tree-view-gradient-yellow-from-dark,oklch(68.1%_0.162_75.834))] dark:data-[selected=true]:to-[var(--zui-tree-view-gradient-yellow-to-dark,oklch(64.6%_0.222_41.116))] data-[selected=true]:text-[color:var(--zui-tree-view-gradient-fg,#ffffff)]",
94
+ "gradient-purple":
95
+ "data-[selected=true]:bg-linear-to-r data-[selected=true]:from-[var(--zui-tree-view-gradient-purple-from,oklch(82.7%_0.119_306.383))] data-[selected=true]:to-[var(--zui-tree-view-gradient-purple-to,oklch(82.3%_0.12_346.018))] dark:data-[selected=true]:from-[var(--zui-tree-view-gradient-purple-from-dark,oklch(55.8%_0.288_302.321))] dark:data-[selected=true]:to-[var(--zui-tree-view-gradient-purple-to-dark,oklch(59.2%_0.249_0.584))] data-[selected=true]:text-[color:var(--zui-tree-view-gradient-fg,#ffffff)]",
96
+ "gradient-teal":
97
+ "data-[selected=true]:bg-linear-to-r data-[selected=true]:from-[var(--zui-tree-view-gradient-teal-from,oklch(85.5%_0.138_181.071))] data-[selected=true]:to-[var(--zui-tree-view-gradient-teal-to,oklch(86.5%_0.127_207.078))] dark:data-[selected=true]:from-[var(--zui-tree-view-gradient-teal-from-dark,oklch(60%_0.118_184.704))] dark:data-[selected=true]:to-[var(--zui-tree-view-gradient-teal-to-dark,oklch(60.9%_0.126_221.723))] data-[selected=true]:text-[color:var(--zui-tree-view-gradient-fg,#ffffff)]",
98
+ "gradient-indigo":
99
+ "data-[selected=true]:bg-linear-to-r data-[selected=true]:from-[var(--zui-tree-view-gradient-indigo-from,oklch(78.5%_0.115_274.713))] data-[selected=true]:to-[var(--zui-tree-view-gradient-indigo-to,oklch(82.7%_0.119_306.383))] dark:data-[selected=true]:from-[var(--zui-tree-view-gradient-indigo-from-dark,oklch(51.1%_0.262_276.966))] dark:data-[selected=true]:to-[var(--zui-tree-view-gradient-indigo-to-dark,oklch(55.8%_0.288_302.321))] data-[selected=true]:text-[color:var(--zui-tree-view-gradient-fg,#ffffff)]",
100
+ "gradient-pink":
101
+ "data-[selected=true]:bg-linear-to-r data-[selected=true]:from-[var(--zui-tree-view-gradient-pink-from,oklch(82.3%_0.12_346.018))] data-[selected=true]:to-[var(--zui-tree-view-gradient-pink-to,oklch(81%_0.117_11.638))] dark:data-[selected=true]:from-[var(--zui-tree-view-gradient-pink-from-dark,oklch(59.2%_0.249_0.584))] dark:data-[selected=true]:to-[var(--zui-tree-view-gradient-pink-to-dark,oklch(58.6%_0.253_17.585))] data-[selected=true]:text-[color:var(--zui-tree-view-gradient-fg,#ffffff)]",
102
+ "gradient-orange":
103
+ "data-[selected=true]:bg-linear-to-r data-[selected=true]:from-[var(--zui-tree-view-gradient-orange-from,oklch(83.7%_0.128_66.29))] data-[selected=true]:to-[var(--zui-tree-view-gradient-orange-to,oklch(80.8%_0.114_19.571))] dark:data-[selected=true]:from-[var(--zui-tree-view-gradient-orange-from-dark,oklch(64.6%_0.222_41.116))] dark:data-[selected=true]:to-[var(--zui-tree-view-gradient-orange-to-dark,oklch(57.7%_0.245_27.325))] data-[selected=true]:text-[color:var(--zui-tree-view-gradient-fg,#ffffff)]",
104
+ } as const;
105
+
106
+ export const zuiTreeViewChevron =
107
+ "inline-flex h-5 w-5 shrink-0 items-center justify-center rounded text-[color:var(--zui-tree-view-chevron,oklch(55.5%_0.041_257.417))] dark:text-[color:var(--zui-tree-view-chevron-dark,oklch(70.4%_0.04_256.788))] transition-transform duration-200 data-[expanded=true]:rotate-90";
108
+
109
+ export const zuiTreeViewIcon =
110
+ "inline-flex shrink-0 items-center justify-center text-[color:var(--zui-tree-view-icon,oklch(55.5%_0.041_257.417))] dark:text-[color:var(--zui-tree-view-icon-dark,oklch(70.4%_0.04_256.788))]";
111
+
112
+ export const zuiTreeViewGuide =
113
+ "border-l border-[color:var(--zui-tree-view-guide,#0000001a)] dark:border-[color:var(--zui-tree-view-guide-dark,#ffffff1a)]";
@@ -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
+ });