@zentauri-ui/zentauri-components 1.7.8 → 1.8.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 +7 -4
- package/cli/registry.json +2 -0
- package/dist/design-system/animated-number.d.ts +32 -0
- package/dist/design-system/animated-number.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/marquee.d.ts +40 -0
- package/dist/design-system/marquee.d.ts.map +1 -0
- package/dist/ui/animated-number/animated-number.d.ts +4 -0
- package/dist/ui/animated-number/animated-number.d.ts.map +1 -0
- package/dist/ui/animated-number/animations.d.ts +59 -0
- package/dist/ui/animated-number/animations.d.ts.map +1 -0
- package/dist/ui/animated-number/index.d.ts +4 -0
- package/dist/ui/animated-number/index.d.ts.map +1 -0
- package/dist/ui/animated-number/types.d.ts +31 -0
- package/dist/ui/animated-number/types.d.ts.map +1 -0
- package/dist/ui/animated-number/variants.d.ts +5 -0
- package/dist/ui/animated-number/variants.d.ts.map +1 -0
- package/dist/ui/animated-number.js +181 -0
- package/dist/ui/animated-number.js.map +1 -0
- package/dist/ui/animated-number.mjs +177 -0
- package/dist/ui/animated-number.mjs.map +1 -0
- package/dist/ui/marquee/index.d.ts +4 -0
- package/dist/ui/marquee/index.d.ts.map +1 -0
- package/dist/ui/marquee/marquee.d.ts +6 -0
- package/dist/ui/marquee/marquee.d.ts.map +1 -0
- package/dist/ui/marquee/types.d.ts +15 -0
- package/dist/ui/marquee/types.d.ts.map +1 -0
- package/dist/ui/marquee/variants.d.ts +7 -0
- package/dist/ui/marquee/variants.d.ts.map +1 -0
- package/dist/ui/marquee.js +171 -0
- package/dist/ui/marquee.js.map +1 -0
- package/dist/ui/marquee.mjs +168 -0
- package/dist/ui/marquee.mjs.map +1 -0
- package/package.json +1 -1
- package/src/design-system/animated-number.ts +53 -0
- package/src/design-system/index.ts +2 -0
- package/src/design-system/marquee.ts +62 -0
- package/src/ui/animated-number/animated-number.test.tsx +64 -0
- package/src/ui/animated-number/animated-number.tsx +120 -0
- package/src/ui/animated-number/animations.ts +22 -0
- package/src/ui/animated-number/index.ts +4 -0
- package/src/ui/animated-number/types.ts +39 -0
- package/src/ui/animated-number/variants.ts +14 -0
- package/src/ui/marquee/index.ts +9 -0
- package/src/ui/marquee/marquee.test.tsx +138 -0
- package/src/ui/marquee/marquee.tsx +114 -0
- package/src/ui/marquee/types.ts +19 -0
- package/src/ui/marquee/variants.ts +24 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from '../chunk-4D54YOL6.mjs';
|
|
3
|
+
import { cva } from 'class-variance-authority';
|
|
4
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
// src/design-system/marquee.ts
|
|
7
|
+
var zuiMarqueeBase = "group/marquee relative isolate flex min-w-0 overflow-hidden rounded-xl border border-transparent bg-[var(--zui-marquee-bg,transparent)] text-[color:var(--zui-marquee-fg,inherit)] [--zui-marquee-gap:1rem]";
|
|
8
|
+
var zuiMarqueeAppearances = {
|
|
9
|
+
default: "[--zui-marquee-bg:transparent] [--zui-marquee-fg:oklch(20.8%_0.042_265.755)] dark:[--zui-marquee-fg:#ffffff]",
|
|
10
|
+
outline: "border-[color:var(--zui-marquee-outline-border,oklch(86.9%_0.022_252.894))] [--zui-marquee-bg:#ffffff] [--zui-marquee-fg:oklch(20.8%_0.042_265.755)] dark:border-[color:var(--zui-marquee-outline-border-dark,oklch(37.2%_0.044_257.287))] dark:[--zui-marquee-bg:oklch(20.8%_0.042_265.755)] dark:[--zui-marquee-fg:#ffffff]",
|
|
11
|
+
ghost: "[--zui-marquee-bg:transparent] [--zui-marquee-fg:oklch(27.9%_0.041_260.031)] dark:[--zui-marquee-fg:oklch(96.8%_0.007_247.896)]",
|
|
12
|
+
card: "border-[color:var(--zui-marquee-card-border,oklch(92.9%_0.013_255.508))] bg-[var(--zui-marquee-card-bg,#ffffff)] shadow-sm shadow-slate-950/5 [--zui-marquee-fg:oklch(20.8%_0.042_265.755)] dark:border-[color:var(--zui-marquee-card-border-dark,oklch(37.2%_0.044_257.287))] dark:bg-[var(--zui-marquee-card-bg-dark,oklch(20.8%_0.042_265.755_/_0.9))] dark:shadow-black/20 dark:[--zui-marquee-fg:#ffffff]",
|
|
13
|
+
separated: "border-y border-x-0 rounded-none border-[color:var(--zui-marquee-separated-border,oklch(86.9%_0.022_252.894))] [--zui-marquee-bg:transparent] [--zui-marquee-fg:oklch(20.8%_0.042_265.755)] dark:border-[color:var(--zui-marquee-separated-border-dark,oklch(37.2%_0.044_257.287))] dark:[--zui-marquee-fg:#ffffff]",
|
|
14
|
+
sky: "border-[color:var(--zui-marquee-sky-border,oklch(62.3%_0.214_259.815_/_0.28))] [--zui-marquee-bg:oklch(97.7%_0.013_236.62)] [--zui-marquee-fg:oklch(39.1%_0.09_240.876)] dark:border-[color:var(--zui-marquee-sky-border-dark,oklch(70.7%_0.165_254.624_/_0.3))] dark:[--zui-marquee-bg:oklch(39.1%_0.09_240.876_/_0.28)] dark:[--zui-marquee-fg:oklch(95.1%_0.026_236.824)]",
|
|
15
|
+
rose: "border-[color:var(--zui-marquee-rose-border,oklch(58.6%_0.253_17.585_/_0.24))] [--zui-marquee-bg:oklch(96.9%_0.015_12.422)] [--zui-marquee-fg:oklch(41%_0.159_10.272)] dark:border-[color:var(--zui-marquee-rose-border-dark,oklch(71.2%_0.194_13.428_/_0.3))] dark:[--zui-marquee-bg:oklch(41%_0.159_10.272_/_0.28)] dark:[--zui-marquee-fg:oklch(94.1%_0.03_12.58)]",
|
|
16
|
+
purple: "border-[color:var(--zui-marquee-purple-border,oklch(62.7%_0.265_303.9_/_0.24))] [--zui-marquee-bg:oklch(97.7%_0.014_308.299)] [--zui-marquee-fg:oklch(38.1%_0.176_304.987)] dark:border-[color:var(--zui-marquee-purple-border-dark,oklch(71.4%_0.203_305.504_/_0.3))] dark:[--zui-marquee-bg:oklch(38.1%_0.176_304.987_/_0.28)] dark:[--zui-marquee-fg:oklch(94.6%_0.033_307.174)]",
|
|
17
|
+
pink: "border-[color:var(--zui-marquee-pink-border,oklch(65.6%_0.241_354.308_/_0.24))] [--zui-marquee-bg:oklch(97.1%_0.014_343.198)] [--zui-marquee-fg:oklch(40.8%_0.153_2.432)] dark:border-[color:var(--zui-marquee-pink-border-dark,oklch(71.8%_0.202_349.761_/_0.3))] dark:[--zui-marquee-bg:oklch(40.8%_0.153_2.432_/_0.28)] dark:[--zui-marquee-fg:oklch(94.8%_0.028_342.258)]",
|
|
18
|
+
orange: "border-[color:var(--zui-marquee-orange-border,oklch(70.5%_0.213_47.604_/_0.26))] [--zui-marquee-bg:oklch(98%_0.016_73.684)] [--zui-marquee-fg:oklch(40.8%_0.123_38.172)] dark:border-[color:var(--zui-marquee-orange-border-dark,oklch(75%_0.183_55.934_/_0.32))] dark:[--zui-marquee-bg:oklch(40.8%_0.123_38.172_/_0.28)] dark:[--zui-marquee-fg:oklch(95.4%_0.038_75.164)]",
|
|
19
|
+
yellow: "border-[color:var(--zui-marquee-yellow-border,oklch(79.5%_0.184_86.047_/_0.3))] [--zui-marquee-bg:oklch(98.7%_0.026_102.212)] [--zui-marquee-fg:oklch(42.1%_0.095_57.708)] dark:border-[color:var(--zui-marquee-yellow-border-dark,oklch(85.2%_0.199_91.936_/_0.32))] dark:[--zui-marquee-bg:oklch(42.1%_0.095_57.708_/_0.28)] dark:[--zui-marquee-fg:oklch(97.3%_0.071_103.193)]",
|
|
20
|
+
teal: "border-[color:var(--zui-marquee-teal-border,oklch(70.4%_0.14_182.503_/_0.28))] [--zui-marquee-bg:oklch(98.4%_0.014_180.72)] [--zui-marquee-fg:oklch(38.6%_0.063_188.416)] dark:border-[color:var(--zui-marquee-teal-border-dark,oklch(77.7%_0.152_181.912_/_0.32))] dark:[--zui-marquee-bg:oklch(38.6%_0.063_188.416_/_0.28)] dark:[--zui-marquee-fg:oklch(95.3%_0.051_180.801)]",
|
|
21
|
+
indigo: "border-[color:var(--zui-marquee-indigo-border,oklch(58.5%_0.233_277.117_/_0.24))] [--zui-marquee-bg:oklch(96.2%_0.018_272.314)] [--zui-marquee-fg:oklch(35.9%_0.144_278.697)] dark:border-[color:var(--zui-marquee-indigo-border-dark,oklch(67.3%_0.182_276.935_/_0.32))] dark:[--zui-marquee-bg:oklch(35.9%_0.144_278.697_/_0.28)] dark:[--zui-marquee-fg:oklch(93%_0.034_272.788)]",
|
|
22
|
+
emerald: "border-[color:var(--zui-marquee-emerald-border,oklch(69.6%_0.17_162.48_/_0.28))] [--zui-marquee-bg:oklch(97.9%_0.021_166.113)] [--zui-marquee-fg:oklch(37.8%_0.077_168.94)] dark:border-[color:var(--zui-marquee-emerald-border-dark,oklch(76.5%_0.177_163.223_/_0.32))] dark:[--zui-marquee-bg:oklch(37.8%_0.077_168.94_/_0.28)] dark:[--zui-marquee-fg:oklch(95%_0.052_163.051)]",
|
|
23
|
+
"gradient-blue": "border-transparent bg-linear-to-r from-[var(--zui-marquee-gradient-blue-from,oklch(62.3%_0.214_259.815))] to-[var(--zui-marquee-gradient-blue-to,oklch(54.6%_0.245_262.881))] [--zui-marquee-fg:#ffffff]",
|
|
24
|
+
"gradient-green": "border-transparent bg-linear-to-r from-[var(--zui-marquee-gradient-green-from,oklch(72.3%_0.219_149.579))] to-[var(--zui-marquee-gradient-green-to,oklch(62.7%_0.194_149.214))] [--zui-marquee-fg:#ffffff]",
|
|
25
|
+
"gradient-red": "border-transparent bg-linear-to-r from-[var(--zui-marquee-gradient-red-from,oklch(63.7%_0.237_25.331))] to-[var(--zui-marquee-gradient-red-to,oklch(57.7%_0.245_27.325))] [--zui-marquee-fg:#ffffff]",
|
|
26
|
+
"gradient-yellow": "border-transparent bg-linear-to-r from-[var(--zui-marquee-gradient-yellow-from,oklch(85.2%_0.199_91.936))] to-[var(--zui-marquee-gradient-yellow-to,oklch(79.5%_0.184_86.047))] [--zui-marquee-fg:oklch(27.9%_0.077_45.635)]",
|
|
27
|
+
"gradient-purple": "border-transparent bg-linear-to-r from-[var(--zui-marquee-gradient-purple-from,oklch(71.4%_0.203_305.504))] to-[var(--zui-marquee-gradient-purple-to,oklch(62.7%_0.265_303.9))] [--zui-marquee-fg:#ffffff]",
|
|
28
|
+
"gradient-teal": "border-transparent bg-linear-to-r from-[var(--zui-marquee-gradient-teal-from,oklch(77.7%_0.152_181.912))] to-[var(--zui-marquee-gradient-teal-to,oklch(70.4%_0.14_182.503))] [--zui-marquee-fg:#ffffff]",
|
|
29
|
+
"gradient-indigo": "border-transparent bg-linear-to-r from-[var(--zui-marquee-gradient-indigo-from,oklch(67.3%_0.182_276.935))] to-[var(--zui-marquee-gradient-indigo-to,oklch(58.5%_0.233_277.117))] [--zui-marquee-fg:#ffffff]",
|
|
30
|
+
"gradient-pink": "border-transparent bg-linear-to-r from-[var(--zui-marquee-gradient-pink-from,oklch(71.8%_0.202_349.761))] to-[var(--zui-marquee-gradient-pink-to,oklch(65.6%_0.241_354.308))] [--zui-marquee-fg:#ffffff]",
|
|
31
|
+
"gradient-orange": "border-transparent bg-linear-to-r from-[var(--zui-marquee-gradient-orange-from,oklch(75%_0.183_55.934))] to-[var(--zui-marquee-gradient-orange-to,oklch(70.5%_0.213_47.604))] [--zui-marquee-fg:#ffffff]"
|
|
32
|
+
};
|
|
33
|
+
var zuiMarqueeOrientations = {
|
|
34
|
+
horizontal: "w-full flex-row",
|
|
35
|
+
vertical: "h-64 flex-col"
|
|
36
|
+
};
|
|
37
|
+
var zuiMarqueeSizes = {
|
|
38
|
+
sm: "p-2 text-xs",
|
|
39
|
+
md: "p-3 text-sm",
|
|
40
|
+
lg: "p-4 text-base"
|
|
41
|
+
};
|
|
42
|
+
var zuiMarqueeFade = {
|
|
43
|
+
false: "",
|
|
44
|
+
true: "[mask-image:linear-gradient(to_right,transparent,black_12%,black_88%,transparent)] data-[orientation=vertical]:[mask-image:linear-gradient(to_bottom,transparent,black_12%,black_88%,transparent)]"
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// src/ui/marquee/variants.ts
|
|
48
|
+
var marqueeVariants = cva(zuiMarqueeBase, {
|
|
49
|
+
variants: {
|
|
50
|
+
appearance: zuiMarqueeAppearances,
|
|
51
|
+
fade: zuiMarqueeFade,
|
|
52
|
+
orientation: zuiMarqueeOrientations,
|
|
53
|
+
size: zuiMarqueeSizes
|
|
54
|
+
},
|
|
55
|
+
defaultVariants: {
|
|
56
|
+
appearance: "default",
|
|
57
|
+
fade: true,
|
|
58
|
+
orientation: "horizontal",
|
|
59
|
+
size: "md"
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
var marqueeKeyframes = `@keyframes zui-marquee-x{from{transform:translate3d(0,0,0)}to{transform:translate3d(calc(-50% - var(--zui-marquee-gap)/2),0,0)}}@keyframes zui-marquee-y{from{transform:translate3d(0,0,0)}to{transform:translate3d(0,calc(-50% - var(--zui-marquee-gap)/2),0)}}`;
|
|
63
|
+
function toCssLength(value) {
|
|
64
|
+
if (value === void 0) {
|
|
65
|
+
return void 0;
|
|
66
|
+
}
|
|
67
|
+
return typeof value === "number" ? `${value}px` : value;
|
|
68
|
+
}
|
|
69
|
+
function Marquee(props) {
|
|
70
|
+
const {
|
|
71
|
+
appearance,
|
|
72
|
+
children,
|
|
73
|
+
className,
|
|
74
|
+
direction,
|
|
75
|
+
fade,
|
|
76
|
+
gap,
|
|
77
|
+
itemClassName,
|
|
78
|
+
orientation,
|
|
79
|
+
pauseOnHover = false,
|
|
80
|
+
ref,
|
|
81
|
+
size,
|
|
82
|
+
speed = 30,
|
|
83
|
+
style,
|
|
84
|
+
trackClassName,
|
|
85
|
+
...rest
|
|
86
|
+
} = props;
|
|
87
|
+
const resolvedOrientation = orientation ?? (direction === "up" || direction === "down" ? "vertical" : "horizontal");
|
|
88
|
+
const resolvedDirection = direction ?? (resolvedOrientation === "vertical" ? "up" : "left");
|
|
89
|
+
const isReverse = resolvedDirection === "right" || resolvedDirection === "down";
|
|
90
|
+
const animationName = resolvedOrientation === "vertical" ? "zui-marquee-y" : "zui-marquee-x";
|
|
91
|
+
const marqueeStyle = {
|
|
92
|
+
...gap !== void 0 ? { "--zui-marquee-gap": toCssLength(gap) } : null,
|
|
93
|
+
...style
|
|
94
|
+
};
|
|
95
|
+
return /* @__PURE__ */ jsxs(
|
|
96
|
+
"div",
|
|
97
|
+
{
|
|
98
|
+
ref,
|
|
99
|
+
"data-direction": resolvedDirection,
|
|
100
|
+
"data-orientation": resolvedOrientation,
|
|
101
|
+
"data-slot": "marquee",
|
|
102
|
+
className: cn(
|
|
103
|
+
marqueeVariants({
|
|
104
|
+
appearance,
|
|
105
|
+
fade,
|
|
106
|
+
orientation: resolvedOrientation,
|
|
107
|
+
size
|
|
108
|
+
}),
|
|
109
|
+
className
|
|
110
|
+
),
|
|
111
|
+
style: marqueeStyle,
|
|
112
|
+
...rest,
|
|
113
|
+
children: [
|
|
114
|
+
/* @__PURE__ */ jsx("style", { children: marqueeKeyframes }),
|
|
115
|
+
/* @__PURE__ */ jsxs(
|
|
116
|
+
"div",
|
|
117
|
+
{
|
|
118
|
+
"data-slot": "marquee-track",
|
|
119
|
+
className: cn(
|
|
120
|
+
"flex shrink-0 gap-[var(--zui-marquee-gap)] will-change-transform [animation-iteration-count:infinite] [animation-timing-function:linear] motion-reduce:[animation-play-state:paused]",
|
|
121
|
+
resolvedOrientation === "vertical" ? "flex-col" : "w-max flex-row",
|
|
122
|
+
pauseOnHover && "group-hover/marquee:[animation-play-state:paused]",
|
|
123
|
+
isReverse && "[animation-direction:reverse]",
|
|
124
|
+
trackClassName
|
|
125
|
+
),
|
|
126
|
+
style: {
|
|
127
|
+
animationDuration: `${speed}s`,
|
|
128
|
+
animationName
|
|
129
|
+
},
|
|
130
|
+
children: [
|
|
131
|
+
/* @__PURE__ */ jsx(
|
|
132
|
+
"div",
|
|
133
|
+
{
|
|
134
|
+
"data-slot": "marquee-item-group",
|
|
135
|
+
className: cn(
|
|
136
|
+
"flex shrink-0 items-center justify-around gap-[var(--zui-marquee-gap)]",
|
|
137
|
+
resolvedOrientation === "vertical" ? "flex-col" : "flex-row",
|
|
138
|
+
itemClassName
|
|
139
|
+
),
|
|
140
|
+
children
|
|
141
|
+
}
|
|
142
|
+
),
|
|
143
|
+
/* @__PURE__ */ jsx(
|
|
144
|
+
"div",
|
|
145
|
+
{
|
|
146
|
+
"aria-hidden": "true",
|
|
147
|
+
inert: true,
|
|
148
|
+
"data-slot": "marquee-item-group",
|
|
149
|
+
className: cn(
|
|
150
|
+
"flex shrink-0 items-center justify-around gap-[var(--zui-marquee-gap)]",
|
|
151
|
+
resolvedOrientation === "vertical" ? "flex-col" : "flex-row",
|
|
152
|
+
itemClassName
|
|
153
|
+
),
|
|
154
|
+
children
|
|
155
|
+
}
|
|
156
|
+
)
|
|
157
|
+
]
|
|
158
|
+
}
|
|
159
|
+
)
|
|
160
|
+
]
|
|
161
|
+
}
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
Marquee.displayName = "Marquee";
|
|
165
|
+
|
|
166
|
+
export { Marquee, marqueeVariants };
|
|
167
|
+
//# sourceMappingURL=marquee.mjs.map
|
|
168
|
+
//# sourceMappingURL=marquee.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/design-system/marquee.ts","../../src/ui/marquee/variants.ts","../../src/ui/marquee/marquee.tsx"],"names":[],"mappings":"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","file":"marquee.mjs","sourcesContent":["export const zuiMarqueeBase =\n \"group/marquee relative isolate flex min-w-0 overflow-hidden rounded-xl border border-transparent bg-[var(--zui-marquee-bg,transparent)] text-[color:var(--zui-marquee-fg,inherit)] [--zui-marquee-gap:1rem]\";\n\nexport const zuiMarqueeAppearances = {\n default:\n \"[--zui-marquee-bg:transparent] [--zui-marquee-fg:oklch(20.8%_0.042_265.755)] dark:[--zui-marquee-fg:#ffffff]\",\n outline:\n \"border-[color:var(--zui-marquee-outline-border,oklch(86.9%_0.022_252.894))] [--zui-marquee-bg:#ffffff] [--zui-marquee-fg:oklch(20.8%_0.042_265.755)] dark:border-[color:var(--zui-marquee-outline-border-dark,oklch(37.2%_0.044_257.287))] dark:[--zui-marquee-bg:oklch(20.8%_0.042_265.755)] dark:[--zui-marquee-fg:#ffffff]\",\n ghost:\n \"[--zui-marquee-bg:transparent] [--zui-marquee-fg:oklch(27.9%_0.041_260.031)] dark:[--zui-marquee-fg:oklch(96.8%_0.007_247.896)]\",\n card: \"border-[color:var(--zui-marquee-card-border,oklch(92.9%_0.013_255.508))] bg-[var(--zui-marquee-card-bg,#ffffff)] shadow-sm shadow-slate-950/5 [--zui-marquee-fg:oklch(20.8%_0.042_265.755)] dark:border-[color:var(--zui-marquee-card-border-dark,oklch(37.2%_0.044_257.287))] dark:bg-[var(--zui-marquee-card-bg-dark,oklch(20.8%_0.042_265.755_/_0.9))] dark:shadow-black/20 dark:[--zui-marquee-fg:#ffffff]\",\n separated:\n \"border-y border-x-0 rounded-none border-[color:var(--zui-marquee-separated-border,oklch(86.9%_0.022_252.894))] [--zui-marquee-bg:transparent] [--zui-marquee-fg:oklch(20.8%_0.042_265.755)] dark:border-[color:var(--zui-marquee-separated-border-dark,oklch(37.2%_0.044_257.287))] dark:[--zui-marquee-fg:#ffffff]\",\n sky: \"border-[color:var(--zui-marquee-sky-border,oklch(62.3%_0.214_259.815_/_0.28))] [--zui-marquee-bg:oklch(97.7%_0.013_236.62)] [--zui-marquee-fg:oklch(39.1%_0.09_240.876)] dark:border-[color:var(--zui-marquee-sky-border-dark,oklch(70.7%_0.165_254.624_/_0.3))] dark:[--zui-marquee-bg:oklch(39.1%_0.09_240.876_/_0.28)] dark:[--zui-marquee-fg:oklch(95.1%_0.026_236.824)]\",\n rose: \"border-[color:var(--zui-marquee-rose-border,oklch(58.6%_0.253_17.585_/_0.24))] [--zui-marquee-bg:oklch(96.9%_0.015_12.422)] [--zui-marquee-fg:oklch(41%_0.159_10.272)] dark:border-[color:var(--zui-marquee-rose-border-dark,oklch(71.2%_0.194_13.428_/_0.3))] dark:[--zui-marquee-bg:oklch(41%_0.159_10.272_/_0.28)] dark:[--zui-marquee-fg:oklch(94.1%_0.03_12.58)]\",\n purple:\n \"border-[color:var(--zui-marquee-purple-border,oklch(62.7%_0.265_303.9_/_0.24))] [--zui-marquee-bg:oklch(97.7%_0.014_308.299)] [--zui-marquee-fg:oklch(38.1%_0.176_304.987)] dark:border-[color:var(--zui-marquee-purple-border-dark,oklch(71.4%_0.203_305.504_/_0.3))] dark:[--zui-marquee-bg:oklch(38.1%_0.176_304.987_/_0.28)] dark:[--zui-marquee-fg:oklch(94.6%_0.033_307.174)]\",\n pink: \"border-[color:var(--zui-marquee-pink-border,oklch(65.6%_0.241_354.308_/_0.24))] [--zui-marquee-bg:oklch(97.1%_0.014_343.198)] [--zui-marquee-fg:oklch(40.8%_0.153_2.432)] dark:border-[color:var(--zui-marquee-pink-border-dark,oklch(71.8%_0.202_349.761_/_0.3))] dark:[--zui-marquee-bg:oklch(40.8%_0.153_2.432_/_0.28)] dark:[--zui-marquee-fg:oklch(94.8%_0.028_342.258)]\",\n orange:\n \"border-[color:var(--zui-marquee-orange-border,oklch(70.5%_0.213_47.604_/_0.26))] [--zui-marquee-bg:oklch(98%_0.016_73.684)] [--zui-marquee-fg:oklch(40.8%_0.123_38.172)] dark:border-[color:var(--zui-marquee-orange-border-dark,oklch(75%_0.183_55.934_/_0.32))] dark:[--zui-marquee-bg:oklch(40.8%_0.123_38.172_/_0.28)] dark:[--zui-marquee-fg:oklch(95.4%_0.038_75.164)]\",\n yellow:\n \"border-[color:var(--zui-marquee-yellow-border,oklch(79.5%_0.184_86.047_/_0.3))] [--zui-marquee-bg:oklch(98.7%_0.026_102.212)] [--zui-marquee-fg:oklch(42.1%_0.095_57.708)] dark:border-[color:var(--zui-marquee-yellow-border-dark,oklch(85.2%_0.199_91.936_/_0.32))] dark:[--zui-marquee-bg:oklch(42.1%_0.095_57.708_/_0.28)] dark:[--zui-marquee-fg:oklch(97.3%_0.071_103.193)]\",\n teal: \"border-[color:var(--zui-marquee-teal-border,oklch(70.4%_0.14_182.503_/_0.28))] [--zui-marquee-bg:oklch(98.4%_0.014_180.72)] [--zui-marquee-fg:oklch(38.6%_0.063_188.416)] dark:border-[color:var(--zui-marquee-teal-border-dark,oklch(77.7%_0.152_181.912_/_0.32))] dark:[--zui-marquee-bg:oklch(38.6%_0.063_188.416_/_0.28)] dark:[--zui-marquee-fg:oklch(95.3%_0.051_180.801)]\",\n indigo:\n \"border-[color:var(--zui-marquee-indigo-border,oklch(58.5%_0.233_277.117_/_0.24))] [--zui-marquee-bg:oklch(96.2%_0.018_272.314)] [--zui-marquee-fg:oklch(35.9%_0.144_278.697)] dark:border-[color:var(--zui-marquee-indigo-border-dark,oklch(67.3%_0.182_276.935_/_0.32))] dark:[--zui-marquee-bg:oklch(35.9%_0.144_278.697_/_0.28)] dark:[--zui-marquee-fg:oklch(93%_0.034_272.788)]\",\n emerald:\n \"border-[color:var(--zui-marquee-emerald-border,oklch(69.6%_0.17_162.48_/_0.28))] [--zui-marquee-bg:oklch(97.9%_0.021_166.113)] [--zui-marquee-fg:oklch(37.8%_0.077_168.94)] dark:border-[color:var(--zui-marquee-emerald-border-dark,oklch(76.5%_0.177_163.223_/_0.32))] dark:[--zui-marquee-bg:oklch(37.8%_0.077_168.94_/_0.28)] dark:[--zui-marquee-fg:oklch(95%_0.052_163.051)]\",\n \"gradient-blue\":\n \"border-transparent bg-linear-to-r from-[var(--zui-marquee-gradient-blue-from,oklch(62.3%_0.214_259.815))] to-[var(--zui-marquee-gradient-blue-to,oklch(54.6%_0.245_262.881))] [--zui-marquee-fg:#ffffff]\",\n \"gradient-green\":\n \"border-transparent bg-linear-to-r from-[var(--zui-marquee-gradient-green-from,oklch(72.3%_0.219_149.579))] to-[var(--zui-marquee-gradient-green-to,oklch(62.7%_0.194_149.214))] [--zui-marquee-fg:#ffffff]\",\n \"gradient-red\":\n \"border-transparent bg-linear-to-r from-[var(--zui-marquee-gradient-red-from,oklch(63.7%_0.237_25.331))] to-[var(--zui-marquee-gradient-red-to,oklch(57.7%_0.245_27.325))] [--zui-marquee-fg:#ffffff]\",\n \"gradient-yellow\":\n \"border-transparent bg-linear-to-r from-[var(--zui-marquee-gradient-yellow-from,oklch(85.2%_0.199_91.936))] to-[var(--zui-marquee-gradient-yellow-to,oklch(79.5%_0.184_86.047))] [--zui-marquee-fg:oklch(27.9%_0.077_45.635)]\",\n \"gradient-purple\":\n \"border-transparent bg-linear-to-r from-[var(--zui-marquee-gradient-purple-from,oklch(71.4%_0.203_305.504))] to-[var(--zui-marquee-gradient-purple-to,oklch(62.7%_0.265_303.9))] [--zui-marquee-fg:#ffffff]\",\n \"gradient-teal\":\n \"border-transparent bg-linear-to-r from-[var(--zui-marquee-gradient-teal-from,oklch(77.7%_0.152_181.912))] to-[var(--zui-marquee-gradient-teal-to,oklch(70.4%_0.14_182.503))] [--zui-marquee-fg:#ffffff]\",\n \"gradient-indigo\":\n \"border-transparent bg-linear-to-r from-[var(--zui-marquee-gradient-indigo-from,oklch(67.3%_0.182_276.935))] to-[var(--zui-marquee-gradient-indigo-to,oklch(58.5%_0.233_277.117))] [--zui-marquee-fg:#ffffff]\",\n \"gradient-pink\":\n \"border-transparent bg-linear-to-r from-[var(--zui-marquee-gradient-pink-from,oklch(71.8%_0.202_349.761))] to-[var(--zui-marquee-gradient-pink-to,oklch(65.6%_0.241_354.308))] [--zui-marquee-fg:#ffffff]\",\n \"gradient-orange\":\n \"border-transparent bg-linear-to-r from-[var(--zui-marquee-gradient-orange-from,oklch(75%_0.183_55.934))] to-[var(--zui-marquee-gradient-orange-to,oklch(70.5%_0.213_47.604))] [--zui-marquee-fg:#ffffff]\",\n} as const;\n\nexport const zuiMarqueeOrientations = {\n horizontal: \"w-full flex-row\",\n vertical: \"h-64 flex-col\",\n} as const;\n\nexport const zuiMarqueeSizes = {\n sm: \"p-2 text-xs\",\n md: \"p-3 text-sm\",\n lg: \"p-4 text-base\",\n} as const;\n\nexport const zuiMarqueeFade = {\n false: \"\",\n true: \"[mask-image:linear-gradient(to_right,transparent,black_12%,black_88%,transparent)] data-[orientation=vertical]:[mask-image:linear-gradient(to_bottom,transparent,black_12%,black_88%,transparent)]\",\n} as const;\n","import { cva } from \"class-variance-authority\";\n\nimport {\n zuiMarqueeAppearances,\n zuiMarqueeBase,\n zuiMarqueeFade,\n zuiMarqueeOrientations,\n zuiMarqueeSizes,\n} from \"../../design-system/marquee\";\n\nexport const marqueeVariants = cva(zuiMarqueeBase, {\n variants: {\n appearance: zuiMarqueeAppearances,\n fade: zuiMarqueeFade,\n orientation: zuiMarqueeOrientations,\n size: zuiMarqueeSizes,\n },\n defaultVariants: {\n appearance: \"default\",\n fade: true,\n orientation: \"horizontal\",\n size: \"md\",\n },\n});\n","\"use client\";\n\nimport type { CSSProperties } from \"react\";\n\nimport { cn } from \"../../lib/utils\";\n\nimport type { MarqueeProps } from \"./types\";\nimport { marqueeVariants } from \"./variants\";\n\nconst marqueeKeyframes = `@keyframes zui-marquee-x{from{transform:translate3d(0,0,0)}to{transform:translate3d(calc(-50% - var(--zui-marquee-gap)/2),0,0)}}@keyframes zui-marquee-y{from{transform:translate3d(0,0,0)}to{transform:translate3d(0,calc(-50% - var(--zui-marquee-gap)/2),0)}}`;\n\nfunction toCssLength(value: number | string | undefined) {\n if (value === undefined) {\n return undefined;\n }\n return typeof value === \"number\" ? `${value}px` : value;\n}\n\nexport function Marquee(props: MarqueeProps) {\n const {\n appearance,\n children,\n className,\n direction,\n fade,\n gap,\n itemClassName,\n orientation,\n pauseOnHover = false,\n ref,\n size,\n speed = 30,\n style,\n trackClassName,\n ...rest\n } = props;\n\n const resolvedOrientation =\n orientation ??\n (direction === \"up\" || direction === \"down\" ? \"vertical\" : \"horizontal\");\n const resolvedDirection =\n direction ?? (resolvedOrientation === \"vertical\" ? \"up\" : \"left\");\n const isReverse =\n resolvedDirection === \"right\" || resolvedDirection === \"down\";\n const animationName =\n resolvedOrientation === \"vertical\" ? \"zui-marquee-y\" : \"zui-marquee-x\";\n const marqueeStyle = {\n ...(gap !== undefined ? { \"--zui-marquee-gap\": toCssLength(gap) } : null),\n ...style,\n } as CSSProperties;\n\n return (\n <div\n ref={ref}\n data-direction={resolvedDirection}\n data-orientation={resolvedOrientation}\n data-slot=\"marquee\"\n className={cn(\n marqueeVariants({\n appearance,\n fade,\n orientation: resolvedOrientation,\n size,\n }),\n className,\n )}\n style={marqueeStyle}\n {...rest}\n >\n <style>{marqueeKeyframes}</style>\n <div\n data-slot=\"marquee-track\"\n className={cn(\n \"flex shrink-0 gap-[var(--zui-marquee-gap)] will-change-transform [animation-iteration-count:infinite] [animation-timing-function:linear] motion-reduce:[animation-play-state:paused]\",\n resolvedOrientation === \"vertical\" ? \"flex-col\" : \"w-max flex-row\",\n pauseOnHover && \"group-hover/marquee:[animation-play-state:paused]\",\n isReverse && \"[animation-direction:reverse]\",\n trackClassName,\n )}\n style={\n {\n animationDuration: `${speed}s`,\n animationName,\n } as CSSProperties\n }\n >\n <div\n data-slot=\"marquee-item-group\"\n className={cn(\n \"flex shrink-0 items-center justify-around gap-[var(--zui-marquee-gap)]\",\n resolvedOrientation === \"vertical\" ? \"flex-col\" : \"flex-row\",\n itemClassName,\n )}\n >\n {children}\n </div>\n <div\n aria-hidden=\"true\"\n inert\n data-slot=\"marquee-item-group\"\n className={cn(\n \"flex shrink-0 items-center justify-around gap-[var(--zui-marquee-gap)]\",\n resolvedOrientation === \"vertical\" ? \"flex-col\" : \"flex-row\",\n itemClassName,\n )}\n >\n {children}\n </div>\n </div>\n </div>\n );\n}\n\nMarquee.displayName = \"Marquee\";\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zentauri-ui/zentauri-components",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "React + Tailwind UI kit with charts, ESM/CJS builds, per-entry exports, and a zentauri-components / zentauri-ui CLI to vendor UI or hook source into your app",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export const zuiAnimatedNumberBase =
|
|
2
|
+
"relative flex w-full overflow-hidden [perspective:1000px]";
|
|
3
|
+
|
|
4
|
+
export const zuiAnimatedNumberAppearance = {
|
|
5
|
+
default:
|
|
6
|
+
"text-[color:var(--zui-animated-number-default-fg,oklch(20.8%_0.042_265.755))] dark:text-[color:var(--zui-animated-number-default-fg-dark,oklch(98.4%_0.003_247.858))]",
|
|
7
|
+
success:
|
|
8
|
+
"text-[color:var(--zui-animated-number-success-fg,oklch(62.7%_0.194_149.214))] dark:text-[color:var(--zui-animated-number-success-fg-dark,oklch(79.2%_0.209_151.711))]",
|
|
9
|
+
warning:
|
|
10
|
+
"text-[color:var(--zui-animated-number-warning-fg,oklch(66.6%_0.179_58.318))] dark:text-[color:var(--zui-animated-number-warning-fg-dark,oklch(82.8%_0.189_84.429))]",
|
|
11
|
+
error:
|
|
12
|
+
"text-[color:var(--zui-animated-number-error-fg,oklch(57.7%_0.245_27.325))] dark:text-[color:var(--zui-animated-number-error-fg-dark,oklch(70.4%_0.191_22.216))]",
|
|
13
|
+
info: "text-[color:var(--zui-animated-number-info-fg,oklch(58.8%_0.158_241.966))] dark:text-[color:var(--zui-animated-number-info-fg-dark,oklch(74.6%_0.16_232.661))]",
|
|
14
|
+
ghost:
|
|
15
|
+
"text-[color:var(--zui-animated-number-ghost-fg,oklch(55.4%_0.046_257.417))] dark:text-[color:var(--zui-animated-number-ghost-fg-dark,oklch(70.4%_0.04_256.788))]",
|
|
16
|
+
purple:
|
|
17
|
+
"text-[color:var(--zui-animated-number-purple-fg,oklch(55.8%_0.288_302.321))] dark:text-[color:var(--zui-animated-number-purple-fg-dark,oklch(71.4%_0.203_305.504))]",
|
|
18
|
+
pink: "text-[color:var(--zui-animated-number-pink-fg,oklch(59.2%_0.249_0.584))] dark:text-[color:var(--zui-animated-number-pink-fg-dark,oklch(71.8%_0.202_349.761))]",
|
|
19
|
+
orange:
|
|
20
|
+
"text-[color:var(--zui-animated-number-orange-fg,oklch(64.6%_0.222_41.116))] dark:text-[color:var(--zui-animated-number-orange-fg-dark,oklch(75%_0.183_55.934))]",
|
|
21
|
+
yellow:
|
|
22
|
+
"text-[color:var(--zui-animated-number-yellow-fg,oklch(68.1%_0.162_75.834))] dark:text-[color:var(--zui-animated-number-yellow-fg-dark,oklch(85.2%_0.199_91.936))]",
|
|
23
|
+
teal: "text-[color:var(--zui-animated-number-teal-fg,oklch(60%_0.118_184.704))] dark:text-[color:var(--zui-animated-number-teal-fg-dark,oklch(77.7%_0.152_181.912))]",
|
|
24
|
+
indigo:
|
|
25
|
+
"text-[color:var(--zui-animated-number-indigo-fg,oklch(51.1%_0.262_276.966))] dark:text-[color:var(--zui-animated-number-indigo-fg-dark,oklch(67.3%_0.182_276.935))]",
|
|
26
|
+
gray: "text-[color:var(--zui-animated-number-gray-fg,oklch(44.6%_0.03_256.802))] dark:text-[color:var(--zui-animated-number-gray-fg-dark,oklch(70.7%_0.022_261.325))]",
|
|
27
|
+
violet:
|
|
28
|
+
"text-[color:var(--zui-animated-number-violet-fg,oklch(54.1%_0.281_293.009))] dark:text-[color:var(--zui-animated-number-violet-fg-dark,oklch(70.2%_0.183_293.541))]",
|
|
29
|
+
"gradient-blue":
|
|
30
|
+
"bg-linear-to-r from-[var(--zui-animated-number-gradient-blue-from,oklch(42.4%_0.199_265.638))] dark:from-[var(--zui-animated-number-gradient-blue-from-dark,oklch(54.6%_0.245_262.881))] to-[var(--zui-animated-number-gradient-blue-to,oklch(43.8%_0.218_303.724))] dark:to-[var(--zui-animated-number-gradient-blue-to-dark,oklch(55.8%_0.288_302.321))] bg-clip-text text-transparent",
|
|
31
|
+
"gradient-green":
|
|
32
|
+
"bg-linear-to-r from-[var(--zui-animated-number-gradient-green-from,oklch(44.8%_0.119_151.328))] dark:from-[var(--zui-animated-number-gradient-green-from-dark,oklch(62.7%_0.194_149.214))] to-[var(--zui-animated-number-gradient-green-to,oklch(45.3%_0.124_130.933))] dark:to-[var(--zui-animated-number-gradient-green-to-dark,oklch(64.8%_0.2_131.684))] bg-clip-text text-transparent",
|
|
33
|
+
"gradient-red":
|
|
34
|
+
"bg-linear-to-r from-[var(--zui-animated-number-gradient-red-from,oklch(44.4%_0.177_26.899))] dark:from-[var(--zui-animated-number-gradient-red-from-dark,oklch(57.7%_0.245_27.325))] to-[var(--zui-animated-number-gradient-red-to,oklch(45.9%_0.187_3.815))] dark:to-[var(--zui-animated-number-gradient-red-to-dark,oklch(59.2%_0.249_0.584))] bg-clip-text text-transparent",
|
|
35
|
+
"gradient-yellow":
|
|
36
|
+
"bg-linear-to-r from-[var(--zui-animated-number-gradient-yellow-from,oklch(47.6%_0.114_61.907))] dark:from-[var(--zui-animated-number-gradient-yellow-from-dark,oklch(68.1%_0.162_75.834))] to-[var(--zui-animated-number-gradient-yellow-to,oklch(47%_0.157_37.304))] dark:to-[var(--zui-animated-number-gradient-yellow-to-dark,oklch(64.6%_0.222_41.116))] bg-clip-text text-transparent",
|
|
37
|
+
"gradient-purple":
|
|
38
|
+
"bg-linear-to-r from-[var(--zui-animated-number-gradient-purple-from,oklch(43.8%_0.218_303.724))] dark:from-[var(--zui-animated-number-gradient-purple-from-dark,oklch(55.8%_0.288_302.321))] to-[var(--zui-animated-number-gradient-purple-to,oklch(45.9%_0.187_3.815))] dark:to-[var(--zui-animated-number-gradient-purple-to-dark,oklch(59.2%_0.249_0.584))] bg-clip-text text-transparent",
|
|
39
|
+
"gradient-teal":
|
|
40
|
+
"bg-linear-to-r from-[var(--zui-animated-number-gradient-teal-from,oklch(43.7%_0.078_188.216))] dark:from-[var(--zui-animated-number-gradient-teal-from-dark,oklch(60%_0.118_184.704))] to-[var(--zui-animated-number-gradient-teal-to,oklch(45%_0.085_224.283))] dark:to-[var(--zui-animated-number-gradient-teal-to-dark,oklch(60.9%_0.126_221.723))] bg-clip-text text-transparent",
|
|
41
|
+
"gradient-indigo":
|
|
42
|
+
"bg-linear-to-r from-[var(--zui-animated-number-gradient-indigo-from,oklch(39.8%_0.195_277.366))] dark:from-[var(--zui-animated-number-gradient-indigo-from-dark,oklch(51.1%_0.262_276.966))] to-[var(--zui-animated-number-gradient-indigo-to,oklch(43.8%_0.218_303.724))] dark:to-[var(--zui-animated-number-gradient-indigo-to-dark,oklch(55.8%_0.288_302.321))] bg-clip-text text-transparent",
|
|
43
|
+
"gradient-pink":
|
|
44
|
+
"bg-linear-to-r from-[var(--zui-animated-number-gradient-pink-from,oklch(45.9%_0.187_3.815))] dark:from-[var(--zui-animated-number-gradient-pink-from-dark,oklch(59.2%_0.249_0.584))] to-[var(--zui-animated-number-gradient-pink-to,oklch(45.5%_0.188_13.697))] dark:to-[var(--zui-animated-number-gradient-pink-to-dark,oklch(58.6%_0.253_17.585))] bg-clip-text text-transparent",
|
|
45
|
+
"gradient-orange":
|
|
46
|
+
"bg-linear-to-r from-[var(--zui-animated-number-gradient-orange-from,oklch(47%_0.157_37.304))] dark:from-[var(--zui-animated-number-gradient-orange-from-dark,oklch(64.6%_0.222_41.116))] to-[var(--zui-animated-number-gradient-orange-to,oklch(44.4%_0.177_26.899))] dark:to-[var(--zui-animated-number-gradient-orange-to-dark,oklch(57.7%_0.245_27.325))] bg-clip-text text-transparent",
|
|
47
|
+
} as const;
|
|
48
|
+
|
|
49
|
+
export const zuiAnimatedNumberSize = {
|
|
50
|
+
sm: "text-2xl font-semibold tabular-nums",
|
|
51
|
+
md: "text-4xl font-semibold tabular-nums",
|
|
52
|
+
lg: "text-6xl font-bold tabular-nums",
|
|
53
|
+
} as const;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * from "./accordion";
|
|
2
2
|
export * from "./alert";
|
|
3
|
+
export * from "./animated-number";
|
|
3
4
|
export * from "./avatar";
|
|
4
5
|
export * from "./badge";
|
|
5
6
|
export * from "./breadcrumb";
|
|
@@ -15,6 +16,7 @@ export * from "./dynamic-stepper";
|
|
|
15
16
|
export * from "./empty-state";
|
|
16
17
|
export * from "./file-upload";
|
|
17
18
|
export * from "./inputs";
|
|
19
|
+
export * from "./marquee";
|
|
18
20
|
export * from "./modal";
|
|
19
21
|
export * from "./otp-input";
|
|
20
22
|
export * from "./pagination";
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export const zuiMarqueeBase =
|
|
2
|
+
"group/marquee relative isolate flex min-w-0 overflow-hidden rounded-xl border border-transparent bg-[var(--zui-marquee-bg,transparent)] text-[color:var(--zui-marquee-fg,inherit)] [--zui-marquee-gap:1rem]";
|
|
3
|
+
|
|
4
|
+
export const zuiMarqueeAppearances = {
|
|
5
|
+
default:
|
|
6
|
+
"[--zui-marquee-bg:transparent] [--zui-marquee-fg:oklch(20.8%_0.042_265.755)] dark:[--zui-marquee-fg:#ffffff]",
|
|
7
|
+
outline:
|
|
8
|
+
"border-[color:var(--zui-marquee-outline-border,oklch(86.9%_0.022_252.894))] [--zui-marquee-bg:#ffffff] [--zui-marquee-fg:oklch(20.8%_0.042_265.755)] dark:border-[color:var(--zui-marquee-outline-border-dark,oklch(37.2%_0.044_257.287))] dark:[--zui-marquee-bg:oklch(20.8%_0.042_265.755)] dark:[--zui-marquee-fg:#ffffff]",
|
|
9
|
+
ghost:
|
|
10
|
+
"[--zui-marquee-bg:transparent] [--zui-marquee-fg:oklch(27.9%_0.041_260.031)] dark:[--zui-marquee-fg:oklch(96.8%_0.007_247.896)]",
|
|
11
|
+
card: "border-[color:var(--zui-marquee-card-border,oklch(92.9%_0.013_255.508))] bg-[var(--zui-marquee-card-bg,#ffffff)] shadow-sm shadow-slate-950/5 [--zui-marquee-fg:oklch(20.8%_0.042_265.755)] dark:border-[color:var(--zui-marquee-card-border-dark,oklch(37.2%_0.044_257.287))] dark:bg-[var(--zui-marquee-card-bg-dark,oklch(20.8%_0.042_265.755_/_0.9))] dark:shadow-black/20 dark:[--zui-marquee-fg:#ffffff]",
|
|
12
|
+
separated:
|
|
13
|
+
"border-y border-x-0 rounded-none border-[color:var(--zui-marquee-separated-border,oklch(86.9%_0.022_252.894))] [--zui-marquee-bg:transparent] [--zui-marquee-fg:oklch(20.8%_0.042_265.755)] dark:border-[color:var(--zui-marquee-separated-border-dark,oklch(37.2%_0.044_257.287))] dark:[--zui-marquee-fg:#ffffff]",
|
|
14
|
+
sky: "border-[color:var(--zui-marquee-sky-border,oklch(62.3%_0.214_259.815_/_0.28))] [--zui-marquee-bg:oklch(97.7%_0.013_236.62)] [--zui-marquee-fg:oklch(39.1%_0.09_240.876)] dark:border-[color:var(--zui-marquee-sky-border-dark,oklch(70.7%_0.165_254.624_/_0.3))] dark:[--zui-marquee-bg:oklch(39.1%_0.09_240.876_/_0.28)] dark:[--zui-marquee-fg:oklch(95.1%_0.026_236.824)]",
|
|
15
|
+
rose: "border-[color:var(--zui-marquee-rose-border,oklch(58.6%_0.253_17.585_/_0.24))] [--zui-marquee-bg:oklch(96.9%_0.015_12.422)] [--zui-marquee-fg:oklch(41%_0.159_10.272)] dark:border-[color:var(--zui-marquee-rose-border-dark,oklch(71.2%_0.194_13.428_/_0.3))] dark:[--zui-marquee-bg:oklch(41%_0.159_10.272_/_0.28)] dark:[--zui-marquee-fg:oklch(94.1%_0.03_12.58)]",
|
|
16
|
+
purple:
|
|
17
|
+
"border-[color:var(--zui-marquee-purple-border,oklch(62.7%_0.265_303.9_/_0.24))] [--zui-marquee-bg:oklch(97.7%_0.014_308.299)] [--zui-marquee-fg:oklch(38.1%_0.176_304.987)] dark:border-[color:var(--zui-marquee-purple-border-dark,oklch(71.4%_0.203_305.504_/_0.3))] dark:[--zui-marquee-bg:oklch(38.1%_0.176_304.987_/_0.28)] dark:[--zui-marquee-fg:oklch(94.6%_0.033_307.174)]",
|
|
18
|
+
pink: "border-[color:var(--zui-marquee-pink-border,oklch(65.6%_0.241_354.308_/_0.24))] [--zui-marquee-bg:oklch(97.1%_0.014_343.198)] [--zui-marquee-fg:oklch(40.8%_0.153_2.432)] dark:border-[color:var(--zui-marquee-pink-border-dark,oklch(71.8%_0.202_349.761_/_0.3))] dark:[--zui-marquee-bg:oklch(40.8%_0.153_2.432_/_0.28)] dark:[--zui-marquee-fg:oklch(94.8%_0.028_342.258)]",
|
|
19
|
+
orange:
|
|
20
|
+
"border-[color:var(--zui-marquee-orange-border,oklch(70.5%_0.213_47.604_/_0.26))] [--zui-marquee-bg:oklch(98%_0.016_73.684)] [--zui-marquee-fg:oklch(40.8%_0.123_38.172)] dark:border-[color:var(--zui-marquee-orange-border-dark,oklch(75%_0.183_55.934_/_0.32))] dark:[--zui-marquee-bg:oklch(40.8%_0.123_38.172_/_0.28)] dark:[--zui-marquee-fg:oklch(95.4%_0.038_75.164)]",
|
|
21
|
+
yellow:
|
|
22
|
+
"border-[color:var(--zui-marquee-yellow-border,oklch(79.5%_0.184_86.047_/_0.3))] [--zui-marquee-bg:oklch(98.7%_0.026_102.212)] [--zui-marquee-fg:oklch(42.1%_0.095_57.708)] dark:border-[color:var(--zui-marquee-yellow-border-dark,oklch(85.2%_0.199_91.936_/_0.32))] dark:[--zui-marquee-bg:oklch(42.1%_0.095_57.708_/_0.28)] dark:[--zui-marquee-fg:oklch(97.3%_0.071_103.193)]",
|
|
23
|
+
teal: "border-[color:var(--zui-marquee-teal-border,oklch(70.4%_0.14_182.503_/_0.28))] [--zui-marquee-bg:oklch(98.4%_0.014_180.72)] [--zui-marquee-fg:oklch(38.6%_0.063_188.416)] dark:border-[color:var(--zui-marquee-teal-border-dark,oklch(77.7%_0.152_181.912_/_0.32))] dark:[--zui-marquee-bg:oklch(38.6%_0.063_188.416_/_0.28)] dark:[--zui-marquee-fg:oklch(95.3%_0.051_180.801)]",
|
|
24
|
+
indigo:
|
|
25
|
+
"border-[color:var(--zui-marquee-indigo-border,oklch(58.5%_0.233_277.117_/_0.24))] [--zui-marquee-bg:oklch(96.2%_0.018_272.314)] [--zui-marquee-fg:oklch(35.9%_0.144_278.697)] dark:border-[color:var(--zui-marquee-indigo-border-dark,oklch(67.3%_0.182_276.935_/_0.32))] dark:[--zui-marquee-bg:oklch(35.9%_0.144_278.697_/_0.28)] dark:[--zui-marquee-fg:oklch(93%_0.034_272.788)]",
|
|
26
|
+
emerald:
|
|
27
|
+
"border-[color:var(--zui-marquee-emerald-border,oklch(69.6%_0.17_162.48_/_0.28))] [--zui-marquee-bg:oklch(97.9%_0.021_166.113)] [--zui-marquee-fg:oklch(37.8%_0.077_168.94)] dark:border-[color:var(--zui-marquee-emerald-border-dark,oklch(76.5%_0.177_163.223_/_0.32))] dark:[--zui-marquee-bg:oklch(37.8%_0.077_168.94_/_0.28)] dark:[--zui-marquee-fg:oklch(95%_0.052_163.051)]",
|
|
28
|
+
"gradient-blue":
|
|
29
|
+
"border-transparent bg-linear-to-r from-[var(--zui-marquee-gradient-blue-from,oklch(62.3%_0.214_259.815))] to-[var(--zui-marquee-gradient-blue-to,oklch(54.6%_0.245_262.881))] [--zui-marquee-fg:#ffffff]",
|
|
30
|
+
"gradient-green":
|
|
31
|
+
"border-transparent bg-linear-to-r from-[var(--zui-marquee-gradient-green-from,oklch(72.3%_0.219_149.579))] to-[var(--zui-marquee-gradient-green-to,oklch(62.7%_0.194_149.214))] [--zui-marquee-fg:#ffffff]",
|
|
32
|
+
"gradient-red":
|
|
33
|
+
"border-transparent bg-linear-to-r from-[var(--zui-marquee-gradient-red-from,oklch(63.7%_0.237_25.331))] to-[var(--zui-marquee-gradient-red-to,oklch(57.7%_0.245_27.325))] [--zui-marquee-fg:#ffffff]",
|
|
34
|
+
"gradient-yellow":
|
|
35
|
+
"border-transparent bg-linear-to-r from-[var(--zui-marquee-gradient-yellow-from,oklch(85.2%_0.199_91.936))] to-[var(--zui-marquee-gradient-yellow-to,oklch(79.5%_0.184_86.047))] [--zui-marquee-fg:oklch(27.9%_0.077_45.635)]",
|
|
36
|
+
"gradient-purple":
|
|
37
|
+
"border-transparent bg-linear-to-r from-[var(--zui-marquee-gradient-purple-from,oklch(71.4%_0.203_305.504))] to-[var(--zui-marquee-gradient-purple-to,oklch(62.7%_0.265_303.9))] [--zui-marquee-fg:#ffffff]",
|
|
38
|
+
"gradient-teal":
|
|
39
|
+
"border-transparent bg-linear-to-r from-[var(--zui-marquee-gradient-teal-from,oklch(77.7%_0.152_181.912))] to-[var(--zui-marquee-gradient-teal-to,oklch(70.4%_0.14_182.503))] [--zui-marquee-fg:#ffffff]",
|
|
40
|
+
"gradient-indigo":
|
|
41
|
+
"border-transparent bg-linear-to-r from-[var(--zui-marquee-gradient-indigo-from,oklch(67.3%_0.182_276.935))] to-[var(--zui-marquee-gradient-indigo-to,oklch(58.5%_0.233_277.117))] [--zui-marquee-fg:#ffffff]",
|
|
42
|
+
"gradient-pink":
|
|
43
|
+
"border-transparent bg-linear-to-r from-[var(--zui-marquee-gradient-pink-from,oklch(71.8%_0.202_349.761))] to-[var(--zui-marquee-gradient-pink-to,oklch(65.6%_0.241_354.308))] [--zui-marquee-fg:#ffffff]",
|
|
44
|
+
"gradient-orange":
|
|
45
|
+
"border-transparent bg-linear-to-r from-[var(--zui-marquee-gradient-orange-from,oklch(75%_0.183_55.934))] to-[var(--zui-marquee-gradient-orange-to,oklch(70.5%_0.213_47.604))] [--zui-marquee-fg:#ffffff]",
|
|
46
|
+
} as const;
|
|
47
|
+
|
|
48
|
+
export const zuiMarqueeOrientations = {
|
|
49
|
+
horizontal: "w-full flex-row",
|
|
50
|
+
vertical: "h-64 flex-col",
|
|
51
|
+
} as const;
|
|
52
|
+
|
|
53
|
+
export const zuiMarqueeSizes = {
|
|
54
|
+
sm: "p-2 text-xs",
|
|
55
|
+
md: "p-3 text-sm",
|
|
56
|
+
lg: "p-4 text-base",
|
|
57
|
+
} as const;
|
|
58
|
+
|
|
59
|
+
export const zuiMarqueeFade = {
|
|
60
|
+
false: "",
|
|
61
|
+
true: "[mask-image:linear-gradient(to_right,transparent,black_12%,black_88%,transparent)] data-[orientation=vertical]:[mask-image:linear-gradient(to_bottom,transparent,black_12%,black_88%,transparent)]",
|
|
62
|
+
} as const;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/react";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
|
|
4
|
+
import { AnimatedNumber, AnimatedNumberCounter } from "./animated-number";
|
|
5
|
+
|
|
6
|
+
describe("AnimatedNumber", () => {
|
|
7
|
+
it("renders one span per digit", () => {
|
|
8
|
+
render(<AnimatedNumber number={123} />);
|
|
9
|
+
expect(screen.getByText("1")).toBeInTheDocument();
|
|
10
|
+
expect(screen.getByText("2")).toBeInTheDocument();
|
|
11
|
+
expect(screen.getByText("3")).toBeInTheDocument();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("applies the default appearance token by default", () => {
|
|
15
|
+
render(<AnimatedNumber number={7} />);
|
|
16
|
+
expect(screen.getByText("7").className).toContain(
|
|
17
|
+
"--zui-animated-number-default-fg",
|
|
18
|
+
);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("applies the requested appearance token", () => {
|
|
22
|
+
render(<AnimatedNumber number={5} appearance="success" />);
|
|
23
|
+
expect(screen.getByText("5").className).toContain(
|
|
24
|
+
"--zui-animated-number-success-fg",
|
|
25
|
+
);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("clips a gradient to the text for gradient appearances", () => {
|
|
29
|
+
render(<AnimatedNumber number={9} appearance="gradient-blue" />);
|
|
30
|
+
const span = screen.getByText("9");
|
|
31
|
+
expect(span.className).toContain("bg-clip-text");
|
|
32
|
+
expect(span.className).toContain("text-transparent");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("applies the requested size token", () => {
|
|
36
|
+
render(<AnimatedNumber number={4} size="lg" />);
|
|
37
|
+
expect(screen.getByText("4").className).toMatch(/text-6xl/);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("merges a custom className onto each digit", () => {
|
|
41
|
+
render(<AnimatedNumber number={8} className="custom-digit" />);
|
|
42
|
+
expect(screen.getByText("8").className).toContain("custom-digit");
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe("AnimatedNumberCounter", () => {
|
|
47
|
+
it("renders a paragraph starting from zero", () => {
|
|
48
|
+
render(<AnimatedNumberCounter number={500} />);
|
|
49
|
+
expect(screen.getByText("0").tagName).toBe("P");
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("applies the requested appearance token", () => {
|
|
53
|
+
render(<AnimatedNumberCounter number={500} appearance="orange" />);
|
|
54
|
+
expect(screen.getByText("0").className).toContain(
|
|
55
|
+
"--zui-animated-number-orange-fg",
|
|
56
|
+
);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("defers the count until the element is in view", () => {
|
|
60
|
+
render(<AnimatedNumberCounter number={500} />);
|
|
61
|
+
expect(screen.getByText("0")).toBeInTheDocument();
|
|
62
|
+
expect(screen.queryByText("500")).not.toBeInTheDocument();
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { animate, motion, useInView, useReducedMotion, type UseInViewOptions } from "framer-motion";
|
|
3
|
+
import { animatedNumberAppearance } from "./variants";
|
|
4
|
+
import { AnimatedNumberCounterProps, AnimatedNumberProps } from "./types";
|
|
5
|
+
import { cn } from "../../lib/utils";
|
|
6
|
+
import { zuiAnimatedNumberBase } from "../../design-system/animated-number";
|
|
7
|
+
import { animationFinalType, animationInitialType } from "./animations";
|
|
8
|
+
import { useEffect, useRef, useState } from "react";
|
|
9
|
+
|
|
10
|
+
const DEFAULT_VIEWPORT = { once: true, amount: 0.2 } as const;
|
|
11
|
+
|
|
12
|
+
export const AnimatedNumber = ({
|
|
13
|
+
number,
|
|
14
|
+
wrapperClassName,
|
|
15
|
+
className,
|
|
16
|
+
ref,
|
|
17
|
+
appearance,
|
|
18
|
+
size,
|
|
19
|
+
type = "up",
|
|
20
|
+
delayInSecond = 0.1,
|
|
21
|
+
transition,
|
|
22
|
+
initial,
|
|
23
|
+
whileInView,
|
|
24
|
+
viewport,
|
|
25
|
+
...rest
|
|
26
|
+
}: AnimatedNumberProps) => {
|
|
27
|
+
const numbersList = [...number.toString()];
|
|
28
|
+
const reducedMotion = useReducedMotion();
|
|
29
|
+
const motionless = Boolean(reducedMotion);
|
|
30
|
+
|
|
31
|
+
const digitVariants = {
|
|
32
|
+
hidden: animationInitialType[type],
|
|
33
|
+
visible: animationFinalType[type],
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<motion.div
|
|
38
|
+
ref={ref}
|
|
39
|
+
initial={motionless ? false : "hidden"}
|
|
40
|
+
whileInView={motionless ? undefined : "visible"}
|
|
41
|
+
viewport={viewport ?? DEFAULT_VIEWPORT}
|
|
42
|
+
transition={{
|
|
43
|
+
staggerChildren: delayInSecond,
|
|
44
|
+
}}
|
|
45
|
+
className={cn(wrapperClassName, zuiAnimatedNumberBase)}
|
|
46
|
+
>
|
|
47
|
+
{numbersList.map((digit, index) => (
|
|
48
|
+
<motion.span
|
|
49
|
+
key={index + "-" + digit}
|
|
50
|
+
className={cn(
|
|
51
|
+
"inline-block",
|
|
52
|
+
animatedNumberAppearance({ appearance, size }),
|
|
53
|
+
className,
|
|
54
|
+
)}
|
|
55
|
+
variants={digitVariants}
|
|
56
|
+
transition={transition}
|
|
57
|
+
{...rest}
|
|
58
|
+
>
|
|
59
|
+
{digit}
|
|
60
|
+
</motion.span>
|
|
61
|
+
))}
|
|
62
|
+
</motion.div>
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const AnimatedNumberCounter = ({
|
|
67
|
+
number,
|
|
68
|
+
className,
|
|
69
|
+
ref: externalRef,
|
|
70
|
+
appearance,
|
|
71
|
+
size,
|
|
72
|
+
duration = 2,
|
|
73
|
+
viewport,
|
|
74
|
+
...rest
|
|
75
|
+
}: AnimatedNumberCounterProps) => {
|
|
76
|
+
const [currentNumber, setCurrentNumber] = useState(0);
|
|
77
|
+
const reducedMotion = useReducedMotion();
|
|
78
|
+
const internalRef = useRef<HTMLParagraphElement>(null);
|
|
79
|
+
// once: false gives real two-way tracking so isInView flips false when scrolled away,
|
|
80
|
+
// preventing offscreen animations when the number prop changes later.
|
|
81
|
+
const isInView = useInView(internalRef, {
|
|
82
|
+
once: false,
|
|
83
|
+
amount: 0.2,
|
|
84
|
+
...viewport,
|
|
85
|
+
} as UseInViewOptions);
|
|
86
|
+
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
if (!isInView) return;
|
|
89
|
+
|
|
90
|
+
if (reducedMotion) {
|
|
91
|
+
setCurrentNumber(number);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const controls = animate(currentNumber, number, {
|
|
96
|
+
duration,
|
|
97
|
+
ease: "circOut",
|
|
98
|
+
onUpdate: (latest) => setCurrentNumber(Math.round(latest)),
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
return () => controls.stop();
|
|
102
|
+
// currentNumber intentionally omitted — captured value gives smooth from→to on prop changes
|
|
103
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
104
|
+
}, [isInView, number, duration, reducedMotion]);
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<motion.p
|
|
108
|
+
className={cn(animatedNumberAppearance({ appearance, size }), className)}
|
|
109
|
+
ref={(node: HTMLParagraphElement) => {
|
|
110
|
+
internalRef.current = node;
|
|
111
|
+
if (externalRef) {
|
|
112
|
+
externalRef.current = node;
|
|
113
|
+
}
|
|
114
|
+
}}
|
|
115
|
+
{...rest}
|
|
116
|
+
>
|
|
117
|
+
{currentNumber}
|
|
118
|
+
</motion.p>
|
|
119
|
+
);
|
|
120
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export const animationInitialType = {
|
|
2
|
+
up: { y: "-100%" },
|
|
3
|
+
down: { y: "100%" },
|
|
4
|
+
scaleUp: { scale: 0 },
|
|
5
|
+
scaleDown: { scale: 1.25 },
|
|
6
|
+
rotateX: { rotateX: "0" },
|
|
7
|
+
rotateY: { rotateY: "0" },
|
|
8
|
+
skewX: { skewX: 20 },
|
|
9
|
+
skewY: { skewY: 20 },
|
|
10
|
+
fade: { opacity: 0 },
|
|
11
|
+
};
|
|
12
|
+
export const animationFinalType = {
|
|
13
|
+
up: { y: 0 },
|
|
14
|
+
down: { y: 0 },
|
|
15
|
+
scaleUp: { scale: 1 },
|
|
16
|
+
scaleDown: { scale: 1 },
|
|
17
|
+
rotateX: { rotateX: "360deg" },
|
|
18
|
+
rotateY: { rotateY: "360deg" },
|
|
19
|
+
skewX: { skewX: 0 },
|
|
20
|
+
skewY: { skewY: 0 },
|
|
21
|
+
fade: { opacity: 1 },
|
|
22
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { VariantProps } from "class-variance-authority";
|
|
2
|
+
import { MotionProps } from "framer-motion";
|
|
3
|
+
import { RefObject } from "react";
|
|
4
|
+
import { animatedNumberAppearance } from "./variants";
|
|
5
|
+
|
|
6
|
+
type MotionTransitionWithoutDelay = Omit<
|
|
7
|
+
NonNullable<MotionProps["transition"]>,
|
|
8
|
+
"delay"
|
|
9
|
+
> & {
|
|
10
|
+
delay?: never;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type MotionPropsWithoutTransitionDelay = Omit<
|
|
14
|
+
MotionProps,
|
|
15
|
+
"transition"
|
|
16
|
+
> & {
|
|
17
|
+
transition?: MotionTransitionWithoutDelay;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type AnimatedNumberProps = MotionPropsWithoutTransitionDelay & {
|
|
21
|
+
number: number;
|
|
22
|
+
wrapperClassName?: string;
|
|
23
|
+
className?: string;
|
|
24
|
+
ref?: RefObject<HTMLDivElement>;
|
|
25
|
+
appearance?: VariantProps<typeof animatedNumberAppearance>["appearance"];
|
|
26
|
+
size?: VariantProps<typeof animatedNumberAppearance>["size"];
|
|
27
|
+
type?: "up" | "down" | "scaleUp" | "scaleDown" | "rotateX" | "rotateY" | "skewX" | "skewY" | "fade";
|
|
28
|
+
delayInSecond?: number;
|
|
29
|
+
transition?: MotionProps["transition"];
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export type AnimatedNumberCounterProps = MotionProps & {
|
|
33
|
+
number: number;
|
|
34
|
+
className?: string;
|
|
35
|
+
ref?: RefObject<HTMLParagraphElement>;
|
|
36
|
+
appearance?: VariantProps<typeof animatedNumberAppearance>["appearance"];
|
|
37
|
+
size?: VariantProps<typeof animatedNumberAppearance>["size"];
|
|
38
|
+
duration?: number;
|
|
39
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { cva } from "class-variance-authority";
|
|
2
|
+
|
|
3
|
+
import { zuiAnimatedNumberAppearance, zuiAnimatedNumberSize } from "../../design-system/animated-number";
|
|
4
|
+
|
|
5
|
+
export const animatedNumberAppearance = cva("inline-flex",{
|
|
6
|
+
variants: {
|
|
7
|
+
appearance: zuiAnimatedNumberAppearance,
|
|
8
|
+
size: zuiAnimatedNumberSize
|
|
9
|
+
},
|
|
10
|
+
defaultVariants: {
|
|
11
|
+
appearance: "default",
|
|
12
|
+
size: "md",
|
|
13
|
+
},
|
|
14
|
+
});
|