@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.
- package/README.md +11 -8
- package/cli/props.json +437 -0
- package/cli/registry.json +9 -0
- package/dist/{chunk-NW5BSLR2.js → chunk-AARJLZXP.js} +6 -6
- package/dist/{chunk-NW5BSLR2.js.map → chunk-AARJLZXP.js.map} +1 -1
- package/dist/chunk-ATE5SCTR.mjs +39 -0
- package/dist/chunk-ATE5SCTR.mjs.map +1 -0
- package/dist/{chunk-YSQW56JX.mjs → chunk-BFHJF4MV.mjs} +4 -4
- package/dist/{chunk-YSQW56JX.mjs.map → chunk-BFHJF4MV.mjs.map} +1 -1
- package/dist/chunk-DIAA5VH4.mjs +64 -0
- package/dist/chunk-DIAA5VH4.mjs.map +1 -0
- package/dist/{chunk-DUH2YLH2.js → chunk-DSX6RUYI.js} +12 -12
- package/dist/{chunk-DUH2YLH2.js.map → chunk-DSX6RUYI.js.map} +1 -1
- package/dist/chunk-ENKXB2BA.js +19 -0
- package/dist/{chunk-YBKNXDZU.js.map → chunk-ENKXB2BA.js.map} +1 -1
- package/dist/chunk-EZNR7VLJ.js +65 -0
- package/dist/chunk-EZNR7VLJ.js.map +1 -0
- package/dist/chunk-H3BJOK22.js +74 -0
- package/dist/chunk-H3BJOK22.js.map +1 -0
- package/dist/{chunk-45ZHGDT2.mjs → chunk-JKKF5DCF.mjs} +3 -3
- package/dist/{chunk-45ZHGDT2.mjs.map → chunk-JKKF5DCF.mjs.map} +1 -1
- package/dist/chunk-PQ2XTY3M.js +44 -0
- package/dist/chunk-PQ2XTY3M.js.map +1 -0
- package/dist/chunk-RDYR4DHG.mjs +62 -0
- package/dist/chunk-RDYR4DHG.mjs.map +1 -0
- package/dist/chunk-RWF3NVZP.mjs +29 -0
- package/dist/chunk-RWF3NVZP.mjs.map +1 -0
- package/dist/{chunk-Z4Y5IPR3.mjs → chunk-WZY32L6K.mjs} +3 -3
- package/dist/{chunk-Z4Y5IPR3.mjs.map → chunk-WZY32L6K.mjs.map} +1 -1
- package/dist/chunk-YRQN3AV4.js +38 -0
- package/dist/chunk-YRQN3AV4.js.map +1 -0
- package/dist/{chunk-UJZ7JQBQ.js → chunk-YY7G4NV3.js} +25 -6
- package/dist/chunk-YY7G4NV3.js.map +1 -0
- package/dist/{chunk-5HLEHSPM.mjs → chunk-ZB6C6CJQ.mjs} +25 -6
- package/dist/chunk-ZB6C6CJQ.mjs.map +1 -0
- package/dist/design-system/facade.js +8 -6
- package/dist/design-system/facade.js.map +1 -1
- package/dist/design-system/facade.mjs +7 -5
- package/dist/design-system/facade.mjs.map +1 -1
- package/dist/design-system/hash-generator.d.ts +15 -0
- package/dist/design-system/hash-generator.d.ts.map +1 -0
- package/dist/design-system/index.d.ts +2 -0
- package/dist/design-system/index.d.ts.map +1 -1
- package/dist/design-system/secret-reveal.d.ts +57 -0
- package/dist/design-system/secret-reveal.d.ts.map +1 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/useHash/index.d.ts +2 -0
- package/dist/hooks/useHash/index.d.ts.map +1 -0
- package/dist/hooks/useHash/useHash.d.ts +20 -0
- package/dist/hooks/useHash/useHash.d.ts.map +1 -0
- package/dist/hooks/useHash.js +18 -0
- package/dist/hooks/useHash.js.map +1 -0
- package/dist/hooks/useHash.mjs +5 -0
- package/dist/hooks/useHash.mjs.map +1 -0
- package/dist/ui/buttons/animated.js +10 -8
- package/dist/ui/buttons/animated.js.map +1 -1
- package/dist/ui/buttons/animated.mjs +8 -6
- package/dist/ui/buttons/animated.mjs.map +1 -1
- package/dist/ui/buttons.js +11 -9
- package/dist/ui/buttons.mjs +9 -7
- package/dist/ui/data-table.js +21 -19
- package/dist/ui/data-table.js.map +1 -1
- package/dist/ui/data-table.mjs +11 -9
- package/dist/ui/data-table.mjs.map +1 -1
- package/dist/ui/dynamic-stepper.js +20 -18
- package/dist/ui/dynamic-stepper.js.map +1 -1
- package/dist/ui/dynamic-stepper.mjs +9 -7
- package/dist/ui/dynamic-stepper.mjs.map +1 -1
- package/dist/ui/hash-generator/hash-generator-base.d.ts +6 -0
- package/dist/ui/hash-generator/hash-generator-base.d.ts.map +1 -0
- package/dist/ui/hash-generator/hash-generator.d.ts +2 -0
- package/dist/ui/hash-generator/hash-generator.d.ts.map +1 -0
- package/dist/ui/hash-generator/index.d.ts +5 -0
- package/dist/ui/hash-generator/index.d.ts.map +1 -0
- package/dist/ui/hash-generator/types.d.ts +17 -0
- package/dist/ui/hash-generator/types.d.ts.map +1 -0
- package/dist/ui/hash-generator/variants.d.ts +10 -0
- package/dist/ui/hash-generator/variants.d.ts.map +1 -0
- package/dist/ui/hash-generator.js +126 -0
- package/dist/ui/hash-generator.js.map +1 -0
- package/dist/ui/hash-generator.mjs +117 -0
- package/dist/ui/hash-generator.mjs.map +1 -0
- package/dist/ui/pagination.js +12 -10
- package/dist/ui/pagination.mjs +9 -7
- package/dist/ui/secret-reveal/animated/animations.d.ts +8 -0
- package/dist/ui/secret-reveal/animated/animations.d.ts.map +1 -0
- package/dist/ui/secret-reveal/animated/index.d.ts +4 -0
- package/dist/ui/secret-reveal/animated/index.d.ts.map +1 -0
- package/dist/ui/secret-reveal/animated/secret-reveal-animated.d.ts +6 -0
- package/dist/ui/secret-reveal/animated/secret-reveal-animated.d.ts.map +1 -0
- package/dist/ui/secret-reveal/animated/types.d.ts +9 -0
- package/dist/ui/secret-reveal/animated/types.d.ts.map +1 -0
- package/dist/ui/secret-reveal/animated.js +194 -0
- package/dist/ui/secret-reveal/animated.js.map +1 -0
- package/dist/ui/secret-reveal/animated.mjs +191 -0
- package/dist/ui/secret-reveal/animated.mjs.map +1 -0
- package/dist/ui/secret-reveal/index.d.ts +4 -0
- package/dist/ui/secret-reveal/index.d.ts.map +1 -0
- package/dist/ui/secret-reveal/secret-reveal-base.d.ts +6 -0
- package/dist/ui/secret-reveal/secret-reveal-base.d.ts.map +1 -0
- package/dist/ui/secret-reveal/secret-reveal.d.ts +2 -0
- package/dist/ui/secret-reveal/secret-reveal.d.ts.map +1 -0
- package/dist/ui/secret-reveal/types.d.ts +15 -0
- package/dist/ui/secret-reveal/types.d.ts.map +1 -0
- package/dist/ui/secret-reveal/variants.d.ts +15 -0
- package/dist/ui/secret-reveal/variants.d.ts.map +1 -0
- package/dist/ui/secret-reveal.js +136 -0
- package/dist/ui/secret-reveal.js.map +1 -0
- package/dist/ui/secret-reveal.mjs +119 -0
- package/dist/ui/secret-reveal.mjs.map +1 -0
- package/dist/ui/split-button.js +22 -20
- package/dist/ui/split-button.js.map +1 -1
- package/dist/ui/split-button.mjs +9 -7
- package/dist/ui/split-button.mjs.map +1 -1
- package/package.json +1 -1
- package/src/design-system/hash-generator.ts +34 -0
- package/src/design-system/index.ts +2 -0
- package/src/design-system/secret-reveal.ts +75 -0
- package/src/hooks/index.ts +6 -0
- package/src/hooks/useHash/index.ts +6 -0
- package/src/hooks/useHash/useHash.test.ts +77 -0
- package/src/hooks/useHash/useHash.ts +89 -0
- package/src/ui/hash-generator/hash-generator-base.tsx +106 -0
- package/src/ui/hash-generator/hash-generator.test.tsx +73 -0
- package/src/ui/hash-generator/hash-generator.tsx +1 -0
- package/src/ui/hash-generator/index.ts +18 -0
- package/src/ui/hash-generator/types.ts +29 -0
- package/src/ui/hash-generator/variants.ts +31 -0
- package/src/ui/secret-reveal/animated/animations.ts +74 -0
- package/src/ui/secret-reveal/animated/index.ts +5 -0
- package/src/ui/secret-reveal/animated/secret-reveal-animated.tsx +132 -0
- package/src/ui/secret-reveal/animated/types.ts +11 -0
- package/src/ui/secret-reveal/index.ts +14 -0
- package/src/ui/secret-reveal/secret-reveal-base.tsx +116 -0
- package/src/ui/secret-reveal/secret-reveal.test.tsx +75 -0
- package/src/ui/secret-reveal/secret-reveal.tsx +2 -0
- package/src/ui/secret-reveal/types.ts +21 -0
- package/src/ui/secret-reveal/variants.ts +49 -0
- package/dist/chunk-5HLEHSPM.mjs.map +0 -1
- package/dist/chunk-UJZ7JQBQ.js.map +0 -1
- 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;
|
package/src/hooks/index.ts
CHANGED
|
@@ -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,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
|
+
};
|