@zentauri-ui/zentauri-components 2.2.1 → 2.3.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 (142) hide show
  1. package/README.md +11 -8
  2. package/cli/props.json +437 -0
  3. package/cli/registry.json +9 -0
  4. package/dist/{chunk-NW5BSLR2.js → chunk-AARJLZXP.js} +6 -6
  5. package/dist/{chunk-NW5BSLR2.js.map → chunk-AARJLZXP.js.map} +1 -1
  6. package/dist/chunk-ATE5SCTR.mjs +39 -0
  7. package/dist/chunk-ATE5SCTR.mjs.map +1 -0
  8. package/dist/{chunk-YSQW56JX.mjs → chunk-BFHJF4MV.mjs} +4 -4
  9. package/dist/{chunk-YSQW56JX.mjs.map → chunk-BFHJF4MV.mjs.map} +1 -1
  10. package/dist/chunk-DIAA5VH4.mjs +64 -0
  11. package/dist/chunk-DIAA5VH4.mjs.map +1 -0
  12. package/dist/{chunk-DUH2YLH2.js → chunk-DSX6RUYI.js} +12 -12
  13. package/dist/{chunk-DUH2YLH2.js.map → chunk-DSX6RUYI.js.map} +1 -1
  14. package/dist/chunk-ENKXB2BA.js +19 -0
  15. package/dist/{chunk-YBKNXDZU.js.map → chunk-ENKXB2BA.js.map} +1 -1
  16. package/dist/chunk-EZNR7VLJ.js +65 -0
  17. package/dist/chunk-EZNR7VLJ.js.map +1 -0
  18. package/dist/chunk-H3BJOK22.js +74 -0
  19. package/dist/chunk-H3BJOK22.js.map +1 -0
  20. package/dist/{chunk-45ZHGDT2.mjs → chunk-JKKF5DCF.mjs} +3 -3
  21. package/dist/{chunk-45ZHGDT2.mjs.map → chunk-JKKF5DCF.mjs.map} +1 -1
  22. package/dist/chunk-PQ2XTY3M.js +44 -0
  23. package/dist/chunk-PQ2XTY3M.js.map +1 -0
  24. package/dist/chunk-RDYR4DHG.mjs +62 -0
  25. package/dist/chunk-RDYR4DHG.mjs.map +1 -0
  26. package/dist/chunk-RWF3NVZP.mjs +29 -0
  27. package/dist/chunk-RWF3NVZP.mjs.map +1 -0
  28. package/dist/{chunk-Z4Y5IPR3.mjs → chunk-WZY32L6K.mjs} +3 -3
  29. package/dist/{chunk-Z4Y5IPR3.mjs.map → chunk-WZY32L6K.mjs.map} +1 -1
  30. package/dist/chunk-YRQN3AV4.js +38 -0
  31. package/dist/chunk-YRQN3AV4.js.map +1 -0
  32. package/dist/{chunk-UJZ7JQBQ.js → chunk-YY7G4NV3.js} +25 -6
  33. package/dist/chunk-YY7G4NV3.js.map +1 -0
  34. package/dist/{chunk-5HLEHSPM.mjs → chunk-ZB6C6CJQ.mjs} +25 -6
  35. package/dist/chunk-ZB6C6CJQ.mjs.map +1 -0
  36. package/dist/design-system/facade.js +8 -6
  37. package/dist/design-system/facade.js.map +1 -1
  38. package/dist/design-system/facade.mjs +7 -5
  39. package/dist/design-system/facade.mjs.map +1 -1
  40. package/dist/design-system/hash-generator.d.ts +15 -0
  41. package/dist/design-system/hash-generator.d.ts.map +1 -0
  42. package/dist/design-system/index.d.ts +2 -0
  43. package/dist/design-system/index.d.ts.map +1 -1
  44. package/dist/design-system/secret-reveal.d.ts +57 -0
  45. package/dist/design-system/secret-reveal.d.ts.map +1 -0
  46. package/dist/hooks/index.d.ts +1 -0
  47. package/dist/hooks/index.d.ts.map +1 -1
  48. package/dist/hooks/useHash/index.d.ts +2 -0
  49. package/dist/hooks/useHash/index.d.ts.map +1 -0
  50. package/dist/hooks/useHash/useHash.d.ts +20 -0
  51. package/dist/hooks/useHash/useHash.d.ts.map +1 -0
  52. package/dist/hooks/useHash.js +18 -0
  53. package/dist/hooks/useHash.js.map +1 -0
  54. package/dist/hooks/useHash.mjs +5 -0
  55. package/dist/hooks/useHash.mjs.map +1 -0
  56. package/dist/ui/buttons/animated.js +10 -8
  57. package/dist/ui/buttons/animated.js.map +1 -1
  58. package/dist/ui/buttons/animated.mjs +8 -6
  59. package/dist/ui/buttons/animated.mjs.map +1 -1
  60. package/dist/ui/buttons.js +11 -9
  61. package/dist/ui/buttons.mjs +9 -7
  62. package/dist/ui/data-table.js +21 -19
  63. package/dist/ui/data-table.js.map +1 -1
  64. package/dist/ui/data-table.mjs +11 -9
  65. package/dist/ui/data-table.mjs.map +1 -1
  66. package/dist/ui/dynamic-stepper.js +20 -18
  67. package/dist/ui/dynamic-stepper.js.map +1 -1
  68. package/dist/ui/dynamic-stepper.mjs +9 -7
  69. package/dist/ui/dynamic-stepper.mjs.map +1 -1
  70. package/dist/ui/hash-generator/hash-generator-base.d.ts +6 -0
  71. package/dist/ui/hash-generator/hash-generator-base.d.ts.map +1 -0
  72. package/dist/ui/hash-generator/hash-generator.d.ts +2 -0
  73. package/dist/ui/hash-generator/hash-generator.d.ts.map +1 -0
  74. package/dist/ui/hash-generator/index.d.ts +5 -0
  75. package/dist/ui/hash-generator/index.d.ts.map +1 -0
  76. package/dist/ui/hash-generator/types.d.ts +17 -0
  77. package/dist/ui/hash-generator/types.d.ts.map +1 -0
  78. package/dist/ui/hash-generator/variants.d.ts +10 -0
  79. package/dist/ui/hash-generator/variants.d.ts.map +1 -0
  80. package/dist/ui/hash-generator.js +126 -0
  81. package/dist/ui/hash-generator.js.map +1 -0
  82. package/dist/ui/hash-generator.mjs +117 -0
  83. package/dist/ui/hash-generator.mjs.map +1 -0
  84. package/dist/ui/pagination.js +12 -10
  85. package/dist/ui/pagination.mjs +9 -7
  86. package/dist/ui/secret-reveal/animated/animations.d.ts +8 -0
  87. package/dist/ui/secret-reveal/animated/animations.d.ts.map +1 -0
  88. package/dist/ui/secret-reveal/animated/index.d.ts +4 -0
  89. package/dist/ui/secret-reveal/animated/index.d.ts.map +1 -0
  90. package/dist/ui/secret-reveal/animated/secret-reveal-animated.d.ts +6 -0
  91. package/dist/ui/secret-reveal/animated/secret-reveal-animated.d.ts.map +1 -0
  92. package/dist/ui/secret-reveal/animated/types.d.ts +9 -0
  93. package/dist/ui/secret-reveal/animated/types.d.ts.map +1 -0
  94. package/dist/ui/secret-reveal/animated.js +194 -0
  95. package/dist/ui/secret-reveal/animated.js.map +1 -0
  96. package/dist/ui/secret-reveal/animated.mjs +191 -0
  97. package/dist/ui/secret-reveal/animated.mjs.map +1 -0
  98. package/dist/ui/secret-reveal/index.d.ts +4 -0
  99. package/dist/ui/secret-reveal/index.d.ts.map +1 -0
  100. package/dist/ui/secret-reveal/secret-reveal-base.d.ts +6 -0
  101. package/dist/ui/secret-reveal/secret-reveal-base.d.ts.map +1 -0
  102. package/dist/ui/secret-reveal/secret-reveal.d.ts +2 -0
  103. package/dist/ui/secret-reveal/secret-reveal.d.ts.map +1 -0
  104. package/dist/ui/secret-reveal/types.d.ts +15 -0
  105. package/dist/ui/secret-reveal/types.d.ts.map +1 -0
  106. package/dist/ui/secret-reveal/variants.d.ts +15 -0
  107. package/dist/ui/secret-reveal/variants.d.ts.map +1 -0
  108. package/dist/ui/secret-reveal.js +136 -0
  109. package/dist/ui/secret-reveal.js.map +1 -0
  110. package/dist/ui/secret-reveal.mjs +119 -0
  111. package/dist/ui/secret-reveal.mjs.map +1 -0
  112. package/dist/ui/split-button.js +22 -20
  113. package/dist/ui/split-button.js.map +1 -1
  114. package/dist/ui/split-button.mjs +9 -7
  115. package/dist/ui/split-button.mjs.map +1 -1
  116. package/package.json +1 -1
  117. package/src/design-system/hash-generator.ts +34 -0
  118. package/src/design-system/index.ts +2 -0
  119. package/src/design-system/secret-reveal.ts +75 -0
  120. package/src/hooks/index.ts +6 -0
  121. package/src/hooks/useHash/index.ts +6 -0
  122. package/src/hooks/useHash/useHash.test.ts +77 -0
  123. package/src/hooks/useHash/useHash.ts +89 -0
  124. package/src/ui/hash-generator/hash-generator-base.tsx +106 -0
  125. package/src/ui/hash-generator/hash-generator.test.tsx +73 -0
  126. package/src/ui/hash-generator/hash-generator.tsx +1 -0
  127. package/src/ui/hash-generator/index.ts +18 -0
  128. package/src/ui/hash-generator/types.ts +29 -0
  129. package/src/ui/hash-generator/variants.ts +31 -0
  130. package/src/ui/secret-reveal/animated/animations.ts +74 -0
  131. package/src/ui/secret-reveal/animated/index.ts +5 -0
  132. package/src/ui/secret-reveal/animated/secret-reveal-animated.tsx +132 -0
  133. package/src/ui/secret-reveal/animated/types.ts +11 -0
  134. package/src/ui/secret-reveal/index.ts +14 -0
  135. package/src/ui/secret-reveal/secret-reveal-base.tsx +116 -0
  136. package/src/ui/secret-reveal/secret-reveal.test.tsx +75 -0
  137. package/src/ui/secret-reveal/secret-reveal.tsx +2 -0
  138. package/src/ui/secret-reveal/types.ts +21 -0
  139. package/src/ui/secret-reveal/variants.ts +49 -0
  140. package/dist/chunk-5HLEHSPM.mjs.map +0 -1
  141. package/dist/chunk-UJZ7JQBQ.js.map +0 -1
  142. package/dist/chunk-YBKNXDZU.js +0 -19
@@ -8,6 +8,7 @@ export * from "./breadcrumb";
8
8
  export * from "./button";
9
9
  export * from "./card";
10
10
  export * from "./code-diff";
11
+ export * from "./hash-generator";
11
12
  export * from "./checkbox";
12
13
  export * from "./combobox";
13
14
  export * from "./command";
@@ -32,6 +33,7 @@ export * from "./progress";
32
33
  export * from "./rating";
33
34
  export * from "./radio-group";
34
35
  export * from "./scroll-area";
36
+ export * from "./secret-reveal";
35
37
  export * from "./select";
36
38
  export * from "./skeleton";
37
39
  export * from "./split-button";
@@ -0,0 +1,75 @@
1
+ export const zuiSecretRevealContainerBase =
2
+ "inline-flex items-center gap-2 rounded-xl border px-3 py-2";
3
+
4
+ export const zuiSecretRevealLabelBase = "font-medium";
5
+
6
+ export const zuiSecretRevealValueBase = "font-mono tracking-wider select-all";
7
+
8
+ export const zuiSecretRevealToggleBase =
9
+ "inline-flex items-center justify-center rounded-lg transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-sky-500";
10
+
11
+ const zuiSecretRevealFg =
12
+ "text-[color:var(--zui-secret-reveal-fg,var(--zui-fg,oklch(20.8%_0.042_265.755)))] dark:text-[color:var(--zui-secret-reveal-fg-dark,var(--zui-fg-dark,oklch(98.4%_0.003_247.858)))]";
13
+
14
+ const zuiSecretRevealInvertedFg =
15
+ "text-[color:var(--zui-secret-reveal-fg,var(--zui-fg-dark,oklch(98.4%_0.003_247.858)))] dark:text-[color:var(--zui-secret-reveal-fg-dark,var(--zui-fg,oklch(20.8%_0.042_265.755)))]";
16
+
17
+ const zuiSecretRevealGradientFg =
18
+ "text-[color:var(--zui-secret-reveal-fg,var(--zui-brand-fg,oklch(96.8%_0.007_247.896)))] dark:text-[color:var(--zui-secret-reveal-fg-dark,var(--zui-brand-fg-dark,oklch(98.4%_0.003_247.858)))]";
19
+
20
+ export const zuiSecretRevealAppearances = {
21
+ default: `border-[var(--zui-secret-reveal-default-border,var(--zui-border,oklch(87.5%_0.01_258.338)))] dark:border-[var(--zui-secret-reveal-default-border-dark,var(--zui-border-dark,oklch(27.9%_0.041_260.031)))] bg-[var(--zui-secret-reveal-default-bg,var(--zui-surface,oklch(96.8%_0.003_264.542)))] dark:bg-[var(--zui-secret-reveal-default-bg-dark,var(--zui-surface-dark,oklch(21.6%_0.036_260.031)))] ${zuiSecretRevealFg}`,
22
+ subtle: `border-transparent bg-[var(--zui-secret-reveal-subtle-bg,var(--zui-surface-muted,oklch(92.9%_0.013_255.508)))] dark:bg-[var(--zui-secret-reveal-subtle-bg-dark,var(--zui-surface-muted-dark,oklch(27.9%_0.041_260.031)))] ${zuiSecretRevealFg}`,
23
+ muted: `border-transparent bg-[var(--zui-secret-reveal-muted-bg,var(--zui-fg-muted,oklch(44.6%_0.043_257.281)))] dark:bg-[var(--zui-secret-reveal-muted-bg-dark,var(--zui-fg-muted-dark,oklch(86.9%_0.022_252.894)))] ${zuiSecretRevealInvertedFg}`,
24
+ primary: `border-[var(--zui-secret-reveal-primary-border,var(--zui-brand,oklch(20.8%_0.042_265.755)))] dark:border-[var(--zui-secret-reveal-primary-border-dark,var(--zui-brand-dark,oklch(98.4%_0.003_247.858)))] bg-[var(--zui-secret-reveal-primary-bg,var(--zui-brand,oklch(20.8%_0.042_265.755)))] dark:bg-[var(--zui-secret-reveal-primary-bg-dark,var(--zui-brand-dark,oklch(98.4%_0.003_247.858)))] ${zuiSecretRevealInvertedFg}`,
25
+ blue: `border-[var(--zui-secret-reveal-blue-border,var(--zui-color-blue,#2563eb))] dark:border-[var(--zui-secret-reveal-blue-border-dark,var(--zui-color-blue-dark,#3b82f6))] bg-[var(--zui-secret-reveal-blue-bg,oklch(93.5%_0.055_262.881))] dark:bg-[var(--zui-secret-reveal-blue-bg-dark,oklch(30.6%_0.126_262.881))] ${zuiSecretRevealFg}`,
26
+ cyan: `border-[var(--zui-secret-reveal-cyan-border,var(--zui-color-cyan,#0891b2))] dark:border-[var(--zui-secret-reveal-cyan-border-dark,var(--zui-color-cyan-dark,#22d3ee))] bg-[var(--zui-secret-reveal-cyan-bg,oklch(95%_0.025_236.42))] dark:bg-[var(--zui-secret-reveal-cyan-bg-dark,oklch(31.1%_0.085_231.74))] ${zuiSecretRevealFg}`,
27
+ green: `border-[var(--zui-secret-reveal-green-border,var(--zui-color-green,#16a34a))] dark:border-[var(--zui-secret-reveal-green-border-dark,var(--zui-color-green-dark,#22c55e))] bg-[var(--zui-secret-reveal-green-bg,oklch(94.2%_0.053_146.17))] dark:bg-[var(--zui-secret-reveal-green-bg-dark,oklch(30.8%_0.085_149.21))] ${zuiSecretRevealFg}`,
28
+ lime: `border-[var(--zui-secret-reveal-lime-border,var(--zui-color-lime,#65a30d))] dark:border-[var(--zui-secret-reveal-lime-border-dark,var(--zui-color-lime-dark,#a3e635))] bg-[var(--zui-secret-reveal-lime-bg,oklch(93.9%_0.077_125.02))] dark:bg-[var(--zui-secret-reveal-lime-bg-dark,oklch(33.1%_0.098_131.68))] ${zuiSecretRevealFg}`,
29
+ emerald: `border-[var(--zui-secret-reveal-emerald-border,var(--zui-color-emerald,oklch(69.6%_0.17_162.48)))] dark:border-[var(--zui-secret-reveal-emerald-border-dark,var(--zui-color-emerald-dark,oklch(43.2%_0.095_166.913)))] bg-[var(--zui-secret-reveal-emerald-bg,oklch(93.5%_0.062_163.17))] dark:bg-[var(--zui-secret-reveal-emerald-bg-dark,oklch(25.4%_0.065_166.91))] ${zuiSecretRevealFg}`,
30
+ indigo: `border-[var(--zui-secret-reveal-indigo-border,var(--zui-color-indigo,oklch(39.8%_0.195_277.366)))] dark:border-[var(--zui-secret-reveal-indigo-border-dark,var(--zui-color-indigo-dark,oklch(51.1%_0.262_276.966)))] bg-[var(--zui-secret-reveal-indigo-bg,oklch(92.8%_0.067_276.37))] dark:bg-[var(--zui-secret-reveal-indigo-bg-dark,oklch(27.5%_0.153_276.97))] ${zuiSecretRevealFg}`,
31
+ purple: `border-[var(--zui-secret-reveal-purple-border,var(--zui-color-purple,oklch(43.8%_0.218_303.724)))] dark:border-[var(--zui-secret-reveal-purple-border-dark,var(--zui-color-purple-dark,oklch(55.8%_0.288_302.321)))] bg-[var(--zui-secret-reveal-purple-bg,oklch(92.4%_0.075_302.32))] dark:bg-[var(--zui-secret-reveal-purple-bg-dark,oklch(27.8%_0.171_302.32))] ${zuiSecretRevealFg}`,
32
+ pink: `border-[var(--zui-secret-reveal-pink-border,var(--zui-color-pink,oklch(45.9%_0.187_3.815)))] dark:border-[var(--zui-secret-reveal-pink-border-dark,var(--zui-color-pink-dark,oklch(59.2%_0.249_0.584)))] bg-[var(--zui-secret-reveal-pink-bg,oklch(93.5%_0.048_3.82))] dark:bg-[var(--zui-secret-reveal-pink-bg-dark,oklch(29.1%_0.134_0.58))] ${zuiSecretRevealFg}`,
33
+ rose: `border-[var(--zui-secret-reveal-rose-border,var(--zui-color-rose,oklch(64.5%_0.246_16.439)))] dark:border-[var(--zui-secret-reveal-rose-border-dark,var(--zui-color-rose-dark,oklch(51.4%_0.222_16.935)))] bg-[var(--zui-secret-reveal-rose-bg,oklch(93.2%_0.065_16.44))] dark:bg-[var(--zui-secret-reveal-rose-bg-dark,oklch(30.2%_0.157_16.94))] ${zuiSecretRevealFg}`,
34
+ sky: `border-[var(--zui-secret-reveal-sky-border,var(--zui-color-sky,oklch(68.5%_0.169_237.323)))] dark:border-[var(--zui-secret-reveal-sky-border-dark,var(--zui-color-sky-dark,oklch(50%_0.134_242.749)))] bg-[var(--zui-secret-reveal-sky-bg,oklch(94.5%_0.041_237.32))] dark:bg-[var(--zui-secret-reveal-sky-bg-dark,oklch(29.4%_0.108_242.75))] ${zuiSecretRevealFg}`,
35
+ teal: `border-[var(--zui-secret-reveal-teal-border,var(--zui-color-teal,oklch(70.4%_0.14_182.503)))] dark:border-[var(--zui-secret-reveal-teal-border-dark,var(--zui-color-teal-dark,oklch(51.1%_0.096_186.391)))] bg-[var(--zui-secret-reveal-teal-bg,oklch(94.1%_0.046_182.5))] dark:bg-[var(--zui-secret-reveal-teal-bg-dark,oklch(30.2%_0.075_186.4))] ${zuiSecretRevealFg}`,
36
+ yellow: `border-[var(--zui-secret-reveal-yellow-border,var(--zui-color-yellow,oklch(79.5%_0.184_86.047)))] dark:border-[var(--zui-secret-reveal-yellow-border-dark,var(--zui-color-yellow-dark,oklch(47.6%_0.114_61.907)))] bg-[var(--zui-secret-reveal-yellow-bg,oklch(94.1%_0.06_86.05))] dark:bg-[var(--zui-secret-reveal-yellow-bg-dark,oklch(31.5%_0.084_61.91))] ${zuiSecretRevealFg}`,
37
+ orange: `border-[var(--zui-secret-reveal-orange-border,var(--zui-color-orange,oklch(70.5%_0.213_47.604)))] dark:border-[var(--zui-secret-reveal-orange-border-dark,var(--zui-color-orange-dark,oklch(47%_0.157_37.304)))] bg-[var(--zui-secret-reveal-orange-bg,oklch(93.5%_0.076_47.6))] dark:bg-[var(--zui-secret-reveal-orange-bg-dark,oklch(30.1%_0.129_37.3))] ${zuiSecretRevealFg}`,
38
+ red: `border-[var(--zui-secret-reveal-red-border,var(--zui-color-red,#dc2626))] dark:border-[var(--zui-secret-reveal-red-border-dark,var(--zui-color-red-dark,#ef4444))] bg-[var(--zui-secret-reveal-red-bg,oklch(93.9%_0.053_19.85))] dark:bg-[var(--zui-secret-reveal-red-bg-dark,oklch(32.1%_0.111_19.85))] ${zuiSecretRevealFg}`,
39
+ slate: `border-[var(--zui-secret-reveal-slate-border,var(--zui-color-slate,#475569))] dark:border-[var(--zui-secret-reveal-slate-border-dark,var(--zui-color-slate-dark,#64748b))] bg-[var(--zui-secret-reveal-slate-bg,oklch(92.8%_0.011_262.88))] dark:bg-[var(--zui-secret-reveal-slate-bg-dark,oklch(29.6%_0.036_262.88))] ${zuiSecretRevealFg}`,
40
+ gray: `border-[var(--zui-secret-reveal-gray-border,var(--zui-color-gray,oklch(55.1%_0.027_264.364)))] dark:border-[var(--zui-secret-reveal-gray-border-dark,var(--zui-color-gray-dark,oklch(55.1%_0.027_264.364)))] bg-[var(--zui-secret-reveal-gray-bg,oklch(92.8%_0.007_264.36))] dark:bg-[var(--zui-secret-reveal-gray-bg-dark,oklch(29.4%_0.018_264.36))] ${zuiSecretRevealFg}`,
41
+ zinc: `border-[var(--zui-secret-reveal-zinc-border,var(--zui-color-zinc,#52525b))] dark:border-[var(--zui-secret-reveal-zinc-border-dark,var(--zui-color-zinc-dark,#71717a))] bg-[var(--zui-secret-reveal-zinc-bg,oklch(92.9%_0.004_262.88))] dark:bg-[var(--zui-secret-reveal-zinc-bg-dark,oklch(29.4%_0.014_262.88))] ${zuiSecretRevealFg}`,
42
+ "gradient-blue": `border-transparent bg-linear-to-r from-[var(--zui-secret-reveal-gradient-blue-from,var(--zui-color-blue,oklch(42.4%_0.199_265.638)))] dark:from-[var(--zui-secret-reveal-gradient-blue-from-dark,var(--zui-color-blue-dark,oklch(54.6%_0.245_262.881)))] to-[var(--zui-secret-reveal-gradient-blue-to,var(--zui-color-purple,oklch(43.8%_0.218_303.724)))] dark:to-[var(--zui-secret-reveal-gradient-blue-to-dark,var(--zui-color-purple-dark,oklch(55.8%_0.288_302.321)))] ${zuiSecretRevealGradientFg}`,
43
+ "gradient-green": `border-transparent bg-linear-to-r from-[var(--zui-secret-reveal-gradient-green-from,var(--zui-color-green,oklch(44.8%_0.119_151.328)))] dark:from-[var(--zui-secret-reveal-gradient-green-from-dark,var(--zui-color-green-dark,oklch(62.7%_0.194_149.214)))] to-[var(--zui-secret-reveal-gradient-green-to,var(--zui-color-lime,oklch(45.3%_0.124_130.933)))] dark:to-[var(--zui-secret-reveal-gradient-green-to-dark,var(--zui-color-lime-dark,oklch(64.8%_0.2_131.684)))] ${zuiSecretRevealGradientFg}`,
44
+ "gradient-red": `border-transparent bg-linear-to-r from-[var(--zui-secret-reveal-gradient-red-from,var(--zui-color-red,oklch(44.4%_0.177_26.899)))] dark:from-[var(--zui-secret-reveal-gradient-red-from-dark,var(--zui-color-red-dark,oklch(57.7%_0.245_27.325)))] to-[var(--zui-secret-reveal-gradient-red-to,var(--zui-color-pink,oklch(45.9%_0.187_3.815)))] dark:to-[var(--zui-secret-reveal-gradient-red-to-dark,var(--zui-color-pink-dark,oklch(59.2%_0.249_0.584)))] ${zuiSecretRevealGradientFg}`,
45
+ "gradient-yellow": `border-transparent bg-linear-to-r from-[var(--zui-secret-reveal-gradient-yellow-from,var(--zui-color-yellow,oklch(47.6%_0.114_61.907)))] dark:from-[var(--zui-secret-reveal-gradient-yellow-from-dark,var(--zui-color-yellow-dark,oklch(68.1%_0.162_75.834)))] to-[var(--zui-secret-reveal-gradient-yellow-to,var(--zui-color-orange,oklch(47%_0.157_37.304)))] dark:to-[var(--zui-secret-reveal-gradient-yellow-to-dark,var(--zui-color-orange-dark,oklch(64.6%_0.222_41.116)))] ${zuiSecretRevealGradientFg}`,
46
+ "gradient-purple": `border-transparent bg-linear-to-r from-[var(--zui-secret-reveal-gradient-purple-from,var(--zui-color-purple,oklch(43.8%_0.218_303.724)))] dark:from-[var(--zui-secret-reveal-gradient-purple-from-dark,var(--zui-color-purple-dark,oklch(55.8%_0.288_302.321)))] to-[var(--zui-secret-reveal-gradient-purple-to,var(--zui-color-pink,oklch(45.9%_0.187_3.815)))] dark:to-[var(--zui-secret-reveal-gradient-purple-to-dark,var(--zui-color-pink-dark,oklch(59.2%_0.249_0.584)))] ${zuiSecretRevealGradientFg}`,
47
+ "gradient-teal": `border-transparent bg-linear-to-r from-[var(--zui-secret-reveal-gradient-teal-from,var(--zui-color-teal,oklch(43.7%_0.078_188.216)))] dark:from-[var(--zui-secret-reveal-gradient-teal-from-dark,var(--zui-color-teal-dark,oklch(60%_0.118_184.704)))] to-[var(--zui-secret-reveal-gradient-teal-to,var(--zui-color-cyan,oklch(45%_0.085_224.283)))] dark:to-[var(--zui-secret-reveal-gradient-teal-to-dark,var(--zui-color-cyan-dark,oklch(60.9%_0.126_221.723)))] ${zuiSecretRevealGradientFg}`,
48
+ "gradient-indigo": `border-transparent bg-linear-to-r from-[var(--zui-secret-reveal-gradient-indigo-from,var(--zui-color-indigo,oklch(39.8%_0.195_277.366)))] dark:from-[var(--zui-secret-reveal-gradient-indigo-from-dark,var(--zui-color-indigo-dark,oklch(51.1%_0.262_276.966)))] to-[var(--zui-secret-reveal-gradient-indigo-to,var(--zui-color-purple,oklch(43.8%_0.218_303.724)))] dark:to-[var(--zui-secret-reveal-gradient-indigo-to-dark,var(--zui-color-purple-dark,oklch(55.8%_0.288_302.321)))] ${zuiSecretRevealGradientFg}`,
49
+ "gradient-pink": `border-transparent bg-linear-to-r from-[var(--zui-secret-reveal-gradient-pink-from,var(--zui-color-pink,oklch(45.9%_0.187_3.815)))] dark:from-[var(--zui-secret-reveal-gradient-pink-from-dark,var(--zui-color-pink-dark,oklch(59.2%_0.249_0.584)))] to-[var(--zui-secret-reveal-gradient-pink-to,var(--zui-color-rose,oklch(45.5%_0.188_13.697)))] dark:to-[var(--zui-secret-reveal-gradient-pink-to-dark,var(--zui-color-rose-dark,oklch(58.6%_0.253_17.585)))] ${zuiSecretRevealGradientFg}`,
50
+ "gradient-orange": `border-transparent bg-linear-to-r from-[var(--zui-secret-reveal-gradient-orange-from,var(--zui-color-orange,oklch(47%_0.157_37.304)))] dark:from-[var(--zui-secret-reveal-gradient-orange-from-dark,var(--zui-color-orange-dark,oklch(64.6%_0.222_41.116)))] to-[var(--zui-secret-reveal-gradient-orange-to,var(--zui-color-red,oklch(44.4%_0.177_26.899)))] dark:to-[var(--zui-secret-reveal-gradient-orange-to-dark,var(--zui-color-red-dark,oklch(57.7%_0.245_27.325)))] ${zuiSecretRevealGradientFg}`,
51
+ } as const;
52
+
53
+ export const zuiSecretRevealSizes = {
54
+ sm: "gap-1.5 px-2 py-1.5 text-xs",
55
+ md: "gap-2 px-3 py-2 text-sm",
56
+ lg: "gap-2.5 px-4 py-2.5 text-base",
57
+ } as const;
58
+
59
+ export const zuiSecretRevealLabelSizes = {
60
+ sm: "text-xs",
61
+ md: "text-sm",
62
+ lg: "text-base",
63
+ } as const;
64
+
65
+ export const zuiSecretRevealValueSizes = {
66
+ sm: "text-xs",
67
+ md: "text-sm",
68
+ lg: "text-base",
69
+ } as const;
70
+
71
+ export const zuiSecretRevealToggleSizes = {
72
+ sm: "size-6 [&_svg]:size-3.5",
73
+ md: "size-7 [&_svg]:size-4",
74
+ lg: "size-8 [&_svg]:size-5",
75
+ } as const;
@@ -53,6 +53,12 @@ export {
53
53
  type UseDocumentTitleParams,
54
54
  } from "./useDocumentTitle";
55
55
  export { useHover } from "./useHover";
56
+ export {
57
+ useHash,
58
+ type HashGeneratorAlgorithm,
59
+ type UseHashResult,
60
+ ALGORITHM_LABELS,
61
+ } from "./useHash";
56
62
  export {
57
63
  useIdleTimeout,
58
64
  type UseIdleTimeoutParams,
@@ -0,0 +1,6 @@
1
+ export {
2
+ useHash,
3
+ type HashGeneratorAlgorithm,
4
+ type UseHashResult,
5
+ ALGORITHM_LABELS,
6
+ } from "./useHash";
@@ -0,0 +1,77 @@
1
+ import { act, renderHook } from "@testing-library/react";
2
+ import { describe, expect, it, vi } from "vitest";
3
+
4
+ import { useHash } from "./useHash";
5
+
6
+ vi.stubGlobal("crypto", {
7
+ subtle: {
8
+ digest: vi.fn().mockResolvedValue(new Uint8Array([1, 2, 3, 4]).buffer),
9
+ },
10
+ });
11
+
12
+ describe("useHash", () => {
13
+ it("should return empty hash for empty input", () => {
14
+ const { result } = renderHook(() => useHash(""));
15
+ expect(result.current.hash).toBe("");
16
+ expect(result.current.isHashing).toBe(false);
17
+ expect(result.current.error).toBeUndefined();
18
+ });
19
+
20
+ it("should compute hash for non-empty input", async () => {
21
+ const { result } = renderHook(() => useHash("hello"));
22
+ await vi.waitFor(() => {
23
+ expect(result.current.hash).toBe("01020304");
24
+ });
25
+ expect(result.current.isHashing).toBe(false);
26
+ expect(result.current.error).toBeUndefined();
27
+ });
28
+
29
+ it("should recompute when algorithm changes", async () => {
30
+ const { result, rerender } = renderHook(
31
+ ({ input, algo }: { input: string; algo: "sha256" | "sha512" }) =>
32
+ useHash(input, algo),
33
+ { initialProps: { input: "hello", algo: "sha256" } },
34
+ );
35
+ await vi.waitFor(() => {
36
+ expect(result.current.hash).toBe("01020304");
37
+ });
38
+ rerender({ input: "hello", algo: "sha512" });
39
+ expect(result.current.isHashing).toBe(true);
40
+ });
41
+
42
+ it("should recompute when input changes", async () => {
43
+ const { result, rerender } = renderHook(
44
+ ({ input }: { input: string }) => useHash(input),
45
+ { initialProps: { input: "hello" } },
46
+ );
47
+ await vi.waitFor(() => {
48
+ expect(result.current.hash).toBe("01020304");
49
+ });
50
+ rerender({ input: "world" });
51
+ expect(result.current.isHashing).toBe(true);
52
+ });
53
+
54
+ it("should call recompute on demand", async () => {
55
+ const { result } = renderHook(() => useHash("hello"));
56
+ await vi.waitFor(() => {
57
+ expect(result.current.hash).toBe("01020304");
58
+ });
59
+ act(() => {
60
+ result.current.recompute();
61
+ });
62
+ expect(result.current.isHashing).toBe(true);
63
+ });
64
+
65
+ it("should clear hash when input becomes empty", async () => {
66
+ const { result, rerender } = renderHook(
67
+ ({ input }: { input: string }) => useHash(input),
68
+ { initialProps: { input: "hello" } },
69
+ );
70
+ await vi.waitFor(() => {
71
+ expect(result.current.hash).toBe("01020304");
72
+ });
73
+ rerender({ input: "" });
74
+ expect(result.current.hash).toBe("");
75
+ expect(result.current.isHashing).toBe(false);
76
+ });
77
+ });
@@ -0,0 +1,89 @@
1
+ "use client";
2
+
3
+ import { useCallback, useEffect, useRef, useState } from "react";
4
+
5
+ export type HashGeneratorAlgorithm = "sha1" | "sha256" | "sha384" | "sha512";
6
+
7
+ export const ALGORITHM_LABELS: Record<HashGeneratorAlgorithm, string> = {
8
+ sha1: "SHA-1",
9
+ sha256: "SHA-256",
10
+ sha384: "SHA-384",
11
+ sha512: "SHA-512",
12
+ };
13
+
14
+ async function computeHash(
15
+ algorithm: HashGeneratorAlgorithm,
16
+ input: string,
17
+ ): Promise<string> {
18
+ if (typeof crypto === "undefined" || !crypto.subtle) {
19
+ throw new Error("Web Crypto API is not supported in this environment.");
20
+ }
21
+ const encoder = new TextEncoder();
22
+ const data = encoder.encode(input);
23
+ const hashBuffer = await crypto.subtle.digest(
24
+ algorithm.toUpperCase().replace("SHA", "SHA-") as AlgorithmIdentifier,
25
+ data,
26
+ );
27
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
28
+ return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
29
+ }
30
+
31
+ export type UseHashResult = {
32
+ hash: string;
33
+ isHashing: boolean;
34
+ error: Error | undefined;
35
+ recompute: () => void;
36
+ };
37
+
38
+ /**
39
+ * Computes a cryptographic hash of `input` using the Web Crypto API.
40
+ *
41
+ * Automatically recomputes whenever `input` or `algorithm` changes.
42
+ * Returns `{ hash, isHashing, error, recompute }` for rendering.
43
+ *
44
+ * @param input - The string to hash.
45
+ * @param algorithm - Hash algorithm (default `"sha256"`).
46
+ * @returns `{ hash, isHashing, error, recompute }`
47
+ */
48
+ export function useHash(
49
+ input: string,
50
+ algorithm: HashGeneratorAlgorithm = "sha256",
51
+ ): UseHashResult {
52
+ const [hash, setHash] = useState("");
53
+ const [isHashing, setIsHashing] = useState(false);
54
+ const [error, setError] = useState<Error | undefined>(undefined);
55
+ const [trigger, setTrigger] = useState(0);
56
+ const nonceRef = useRef(0);
57
+
58
+ useEffect(() => {
59
+ if (!input) {
60
+ setHash("");
61
+ setIsHashing(false);
62
+ setError(undefined);
63
+ return;
64
+ }
65
+ const nonce = ++nonceRef.current;
66
+ setIsHashing(true);
67
+ setError(undefined);
68
+ computeHash(algorithm, input).then(
69
+ (result) => {
70
+ if (nonce === nonceRef.current) {
71
+ setHash(result);
72
+ setIsHashing(false);
73
+ }
74
+ },
75
+ (err) => {
76
+ if (nonce === nonceRef.current) {
77
+ setError(err instanceof Error ? err : new Error(String(err)));
78
+ setIsHashing(false);
79
+ }
80
+ },
81
+ );
82
+ }, [algorithm, input, trigger]);
83
+
84
+ const recompute = useCallback(() => {
85
+ setTrigger((prev) => prev + 1);
86
+ }, []);
87
+
88
+ return { hash, isHashing, error, recompute };
89
+ }
@@ -0,0 +1,106 @@
1
+ "use client";
2
+
3
+ import { useCallback, useEffect, useState } from "react";
4
+
5
+ import { cn } from "../../lib/utils";
6
+ import { useHash } from "../../hooks/useHash";
7
+
8
+ import type { HashGeneratorBaseProps } from "./types";
9
+ import { ALGORITHM_LABELS } from "./types";
10
+ import {
11
+ hashGeneratorHeaderVariants,
12
+ hashGeneratorInputVariants,
13
+ hashGeneratorLabelVariants,
14
+ hashGeneratorOutputTextVariants,
15
+ hashGeneratorOutputVariants,
16
+ hashGeneratorVariants,
17
+ } from "./variants";
18
+
19
+ export function HashGeneratorBase({
20
+ className,
21
+ appearance,
22
+ size,
23
+ algorithm = "sha256",
24
+ value,
25
+ onValueChange,
26
+ readOnly = false,
27
+ showCopyButton = true,
28
+ ref,
29
+ ...rest
30
+ }: HashGeneratorBaseProps) {
31
+ const [internalValue, setInternalValue] = useState("");
32
+ const [copied, setCopied] = useState(false);
33
+
34
+ const inputValue = value ?? internalValue;
35
+ const handleChange = onValueChange ?? setInternalValue;
36
+
37
+ const { hash, error } = useHash(inputValue, algorithm);
38
+
39
+ useEffect(() => {
40
+ if (!copied) return;
41
+ const timeout = setTimeout(() => setCopied(false), 2000);
42
+ return () => clearTimeout(timeout);
43
+ }, [copied]);
44
+
45
+ const handleCopy = useCallback(async () => {
46
+ if (!hash) return;
47
+ try {
48
+ await navigator.clipboard.writeText(hash);
49
+ setCopied(true);
50
+ } catch {
51
+ // Clipboard API not available
52
+ }
53
+ }, [hash]);
54
+
55
+ return (
56
+ <div
57
+ ref={ref}
58
+ data-slot="hash-generator"
59
+ className={cn(hashGeneratorVariants({ appearance, size }), className)}
60
+ {...rest}
61
+ >
62
+ <div className={hashGeneratorHeaderVariants()}>
63
+ <span className={hashGeneratorLabelVariants()}>
64
+ {ALGORITHM_LABELS[algorithm]}
65
+ </span>
66
+ {showCopyButton && hash ? (
67
+ <button
68
+ type="button"
69
+ onClick={handleCopy}
70
+ className="rounded px-2 py-0.5 text-xs font-medium transition-colors text-[color:var(--zui-hash-generator-label-fg,var(--zui-fg-muted,oklch(55.2%_0.046_257.417)))] dark:text-[color:var(--zui-hash-generator-label-fg-dark,var(--zui-fg-muted-dark,oklch(70.8%_0.015_256.243)))] hover:bg-[var(--zui-hash-generator-header-bg,var(--zui-surface-muted,oklch(92.9%_0.013_255.508)))] dark:hover:bg-[var(--zui-hash-generator-header-bg-dark,var(--zui-surface-muted-dark,oklch(27.9%_0.041_260.031)))]"
71
+ >
72
+ {copied ? "Copied!" : "Copy"}
73
+ </button>
74
+ ) : null}
75
+ </div>
76
+ <textarea
77
+ data-slot="hash-generator-input"
78
+ value={inputValue}
79
+ onChange={(e) => handleChange(e.target.value)}
80
+ readOnly={readOnly}
81
+ placeholder="Enter text to hash..."
82
+ rows={3}
83
+ aria-label={`Input text to hash using ${ALGORITHM_LABELS[algorithm]}`}
84
+ className={cn(hashGeneratorInputVariants(), "resize-y min-h-[5rem]")}
85
+ />
86
+ <div className={hashGeneratorOutputVariants()}>
87
+ <span
88
+ role="status"
89
+ data-slot="hash-generator-output"
90
+ className={cn(
91
+ hashGeneratorOutputTextVariants(),
92
+ !hash && !error && "opacity-40",
93
+ )}
94
+ >
95
+ {error ? (
96
+ <span className="text-red-500">{error.message}</span>
97
+ ) : (
98
+ hash || "Hash output"
99
+ )}
100
+ </span>
101
+ </div>
102
+ </div>
103
+ );
104
+ }
105
+
106
+ HashGeneratorBase.displayName = "HashGenerator";
@@ -0,0 +1,73 @@
1
+ import { createRef } from "react";
2
+ import { render, screen } from "@testing-library/react";
3
+ import userEvent from "@testing-library/user-event";
4
+ import { describe, expect, it, vi } from "vitest";
5
+
6
+ import { HashGenerator } from "./hash-generator";
7
+
8
+ // Mock crypto.subtle.digest for jsdom
9
+ vi.stubGlobal("crypto", {
10
+ subtle: {
11
+ digest: vi.fn().mockResolvedValue(new Uint8Array([1, 2, 3, 4]).buffer),
12
+ },
13
+ });
14
+
15
+ describe("HashGenerator", () => {
16
+ it("should expose displayName", () => {
17
+ expect(HashGenerator.displayName).toBe("HashGenerator");
18
+ });
19
+
20
+ it("should stamp data-slot", () => {
21
+ render(<HashGenerator />);
22
+ const root = document.querySelector('[data-slot="hash-generator"]');
23
+ expect(root).toBeTruthy();
24
+ expect(root?.getAttribute("data-slot")).toBe("hash-generator");
25
+ });
26
+
27
+ it("should render algorithm label", () => {
28
+ render(<HashGenerator algorithm="sha256" />);
29
+ expect(screen.getByText("SHA-256")).toBeInTheDocument();
30
+ });
31
+
32
+ it("should render with sha512 algorithm", () => {
33
+ render(<HashGenerator algorithm="sha512" />);
34
+ expect(screen.getByText("SHA-512")).toBeInTheDocument();
35
+ });
36
+
37
+ it("should render textarea for input", () => {
38
+ render(<HashGenerator />);
39
+ expect(
40
+ screen.getByPlaceholderText("Enter text to hash..."),
41
+ ).toBeInTheDocument();
42
+ });
43
+
44
+ it("should display hash output", async () => {
45
+ render(<HashGenerator />);
46
+ const textarea = screen.getByPlaceholderText("Enter text to hash...");
47
+ await userEvent.type(textarea, "hello");
48
+ const output = document.querySelector(
49
+ '[data-slot="hash-generator-output"]',
50
+ );
51
+ expect(output).toBeTruthy();
52
+ });
53
+
54
+ it("should forward ref", () => {
55
+ const ref = createRef<HTMLDivElement>();
56
+ render(<HashGenerator ref={ref} />);
57
+ expect(ref.current?.getAttribute("data-slot")).toBe("hash-generator");
58
+ });
59
+
60
+ it("should accept controlled value via value prop", () => {
61
+ render(<HashGenerator value="test text" readOnly />);
62
+ const textarea = screen.getByPlaceholderText("Enter text to hash...");
63
+ expect(textarea).toHaveValue("test text");
64
+ });
65
+
66
+ it("should call onValueChange when typing", async () => {
67
+ const handleChange = vi.fn();
68
+ render(<HashGenerator onValueChange={handleChange} />);
69
+ const textarea = screen.getByPlaceholderText("Enter text to hash...");
70
+ await userEvent.type(textarea, "a");
71
+ expect(handleChange).toHaveBeenCalledWith("a");
72
+ });
73
+ });
@@ -0,0 +1 @@
1
+ export { HashGeneratorBase as HashGenerator } from "./hash-generator-base";
@@ -0,0 +1,18 @@
1
+ "use client";
2
+
3
+ export { HashGenerator } from "./hash-generator";
4
+ export type {
5
+ HashGeneratorAlgorithm,
6
+ HashGeneratorBaseProps,
7
+ HashGeneratorProps,
8
+ HashGeneratorVariantProps,
9
+ } from "./types";
10
+ export { ALGORITHM_LABELS } from "./types";
11
+ export {
12
+ hashGeneratorHeaderVariants,
13
+ hashGeneratorInputVariants,
14
+ hashGeneratorLabelVariants,
15
+ hashGeneratorOutputTextVariants,
16
+ hashGeneratorOutputVariants,
17
+ hashGeneratorVariants,
18
+ } from "./variants";
@@ -0,0 +1,29 @@
1
+ import type { VariantProps } from "class-variance-authority";
2
+ import type { ComponentPropsWithRef } from "react";
3
+
4
+ import type { hashGeneratorVariants } from "./variants";
5
+
6
+ export type HashGeneratorAlgorithm = "sha1" | "sha256" | "sha384" | "sha512";
7
+
8
+ export type HashGeneratorVariantProps = VariantProps<
9
+ typeof hashGeneratorVariants
10
+ >;
11
+
12
+ export interface HashGeneratorBaseProps extends ComponentPropsWithRef<"div"> {
13
+ algorithm?: HashGeneratorAlgorithm;
14
+ value?: string;
15
+ onValueChange?: (value: string) => void;
16
+ readOnly?: boolean;
17
+ showCopyButton?: boolean;
18
+ appearance?: HashGeneratorVariantProps["appearance"];
19
+ size?: HashGeneratorVariantProps["size"];
20
+ }
21
+
22
+ export type HashGeneratorProps = HashGeneratorBaseProps;
23
+
24
+ export const ALGORITHM_LABELS: Record<HashGeneratorAlgorithm, string> = {
25
+ sha1: "SHA-1",
26
+ sha256: "SHA-256",
27
+ sha384: "SHA-384",
28
+ sha512: "SHA-512",
29
+ } as const;
@@ -0,0 +1,31 @@
1
+ import { cva } from "class-variance-authority";
2
+
3
+ import {
4
+ zuiHashGeneratorAppearances,
5
+ zuiHashGeneratorBase,
6
+ zuiHashGeneratorHeaderBase,
7
+ zuiHashGeneratorInputBase,
8
+ zuiHashGeneratorLabelBase,
9
+ zuiHashGeneratorOutputBase,
10
+ zuiHashGeneratorOutputTextBase,
11
+ zuiHashGeneratorSizes,
12
+ } from "../../design-system/hash-generator";
13
+
14
+ export const hashGeneratorVariants = cva(zuiHashGeneratorBase, {
15
+ variants: {
16
+ appearance: zuiHashGeneratorAppearances,
17
+ size: zuiHashGeneratorSizes,
18
+ },
19
+ defaultVariants: {
20
+ appearance: "default",
21
+ size: "md",
22
+ },
23
+ });
24
+
25
+ export const hashGeneratorHeaderVariants = cva(zuiHashGeneratorHeaderBase);
26
+ export const hashGeneratorLabelVariants = cva(zuiHashGeneratorLabelBase);
27
+ export const hashGeneratorInputVariants = cva(zuiHashGeneratorInputBase);
28
+ export const hashGeneratorOutputVariants = cva(zuiHashGeneratorOutputBase);
29
+ export const hashGeneratorOutputTextVariants = cva(
30
+ zuiHashGeneratorOutputTextBase,
31
+ );
@@ -0,0 +1,74 @@
1
+ import type { Transition, Variants } from "framer-motion";
2
+
3
+ export type SecretRevealAnimation =
4
+ | "none"
5
+ | "fade"
6
+ | "slide-up"
7
+ | "scale"
8
+ | "flip";
9
+
10
+ export type SecretRevealAnimationPresets = Record<
11
+ SecretRevealAnimation,
12
+ {
13
+ transition: Transition;
14
+ variants: Variants;
15
+ }
16
+ >;
17
+
18
+ export const secretRevealAnimationPresets: SecretRevealAnimationPresets = {
19
+ none: {
20
+ transition: { duration: 0 },
21
+ variants: {
22
+ initial: { opacity: 1 },
23
+ animate: { opacity: 1 },
24
+ exit: { opacity: 1 },
25
+ },
26
+ },
27
+ fade: {
28
+ transition: { duration: 0.25, ease: "easeInOut" },
29
+ variants: {
30
+ initial: { opacity: 0 },
31
+ animate: { opacity: 1 },
32
+ exit: { opacity: 0 },
33
+ },
34
+ },
35
+ "slide-up": {
36
+ transition: {
37
+ type: "spring",
38
+ stiffness: 300,
39
+ damping: 25,
40
+ mass: 0.5,
41
+ },
42
+ variants: {
43
+ initial: { opacity: 0, y: 8 },
44
+ animate: { opacity: 1, y: 0 },
45
+ exit: { opacity: 0, y: -8 },
46
+ },
47
+ },
48
+ scale: {
49
+ transition: {
50
+ type: "spring",
51
+ stiffness: 400,
52
+ damping: 20,
53
+ mass: 0.4,
54
+ },
55
+ variants: {
56
+ initial: { opacity: 0, scale: 0.9 },
57
+ animate: { opacity: 1, scale: 1 },
58
+ exit: { opacity: 0, scale: 0.9 },
59
+ },
60
+ },
61
+ flip: {
62
+ transition: {
63
+ type: "spring",
64
+ stiffness: 200,
65
+ damping: 18,
66
+ mass: 0.6,
67
+ },
68
+ variants: {
69
+ initial: { opacity: 0, rotateX: 90 },
70
+ animate: { opacity: 1, rotateX: 0 },
71
+ exit: { opacity: 0, rotateX: -90 },
72
+ },
73
+ },
74
+ };
@@ -0,0 +1,5 @@
1
+ "use client";
2
+
3
+ export { SecretRevealAnimated } from "./secret-reveal-animated";
4
+ export type { SecretRevealAnimation, SecretRevealAnimatedProps } from "./types";
5
+ export { secretRevealAnimationPresets } from "./animations";