@zentauri-ui/zentauri-components 1.7.9 → 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 CHANGED
@@ -15,12 +15,12 @@ Published artifacts live under `dist/`. Imports use **per-entry subpaths**: `@ze
15
15
 
16
16
  | Metric | Result |
17
17
  | ---------- | ---------------- |
18
- | Test files | 65 passed (65) |
19
- | Tests | 429 passed (429) |
18
+ | Test files | 66 passed (66) |
19
+ | Tests | 438 passed (438) |
20
20
 
21
21
  | Area | Test files | Tests |
22
22
  | --------------------------- | ---------- | ----- |
23
- | Components and UI utilities | 37 | 335 |
23
+ | Components and UI utilities | 38 | 344 |
24
24
  | React hooks | 26 | 85 |
25
25
  | CLI and import rewriting | 2 | 9 |
26
26
 
@@ -56,6 +56,7 @@ Published artifacts live under `dist/`. Imports use **per-entry subpaths**: `@ze
56
56
  | `src/ui/tabs/tabs.test.tsx` | 3 |
57
57
  | `src/ui/stepper/stepper.test.tsx` | 12 |
58
58
  | `src/ui/timeline/timeline.test.tsx` | 14 |
59
+ | `src/ui/animated-number/animated-number.test.tsx` | 9 |
59
60
  | `src/ui/toggle/toggle.test.tsx` | 5 |
60
61
  | `src/ui/slider/slider.test.tsx` | 9 |
61
62
  | `src/ui/typography/typography.test.tsx` | 7 |
@@ -671,7 +672,7 @@ From this package directory in the monorepo:
671
672
 
672
673
  - `pnpm build` (or `npm run build`) — production bundle via `tsup` (Rollup treeshake + `scripts/prepend-use-client.mjs` via `onSuccess` so each UI entry under `dist/ui/`, the chart entry under `dist/charts/`, and `dist/ui/<name>/animated.*` starts with `"use client"` where needed)
673
674
  - `pnpm dev` — `tsup` watch mode (same `onSuccess` hook after each rebuild)
674
- - `pnpm test` / `pnpm test:watch` — **Vitest** and **Testing Library** unit tests // covered 429 test cases in total
675
+ - `pnpm test` / `pnpm test:watch` — **Vitest** and **Testing Library** unit tests // covered 438 test cases in total
675
676
  - **`pnpm run generate:registry`** — runs `scripts/generate-registry.mjs`, which reads **`uiComponentNames`**, **`chartEntryNames`**, and **`hooksEntryNames`** from `tsup.config.ts`, merges in **`spinner`**, applies fixed **`nameAliases`**, and writes **`cli/registry.json`** (`components` + `hooks`). Run this after adding or renaming UI/chart areas or hook entries so the CLI stays in sync (the script prints counts).
676
677
 
677
678
  ## Github Release log
package/cli/registry.json CHANGED
@@ -4,6 +4,7 @@
4
4
  "components": [
5
5
  "accordion",
6
6
  "alert",
7
+ "animated-number",
7
8
  "avatar",
8
9
  "badge",
9
10
  "breadcrumb",
@@ -0,0 +1,32 @@
1
+ export declare const zuiAnimatedNumberBase = "relative flex w-full overflow-hidden [perspective:1000px]";
2
+ export declare const zuiAnimatedNumberAppearance: {
3
+ readonly default: "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))]";
4
+ readonly success: "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))]";
5
+ readonly warning: "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))]";
6
+ readonly error: "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))]";
7
+ readonly 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))]";
8
+ readonly ghost: "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))]";
9
+ readonly purple: "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))]";
10
+ readonly 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))]";
11
+ readonly orange: "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))]";
12
+ readonly yellow: "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))]";
13
+ readonly 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))]";
14
+ readonly indigo: "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))]";
15
+ readonly 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))]";
16
+ readonly violet: "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))]";
17
+ readonly "gradient-blue": "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";
18
+ readonly "gradient-green": "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";
19
+ readonly "gradient-red": "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";
20
+ readonly "gradient-yellow": "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";
21
+ readonly "gradient-purple": "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";
22
+ readonly "gradient-teal": "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";
23
+ readonly "gradient-indigo": "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";
24
+ readonly "gradient-pink": "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";
25
+ readonly "gradient-orange": "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";
26
+ };
27
+ export declare const zuiAnimatedNumberSize: {
28
+ readonly sm: "text-2xl font-semibold tabular-nums";
29
+ readonly md: "text-4xl font-semibold tabular-nums";
30
+ readonly lg: "text-6xl font-bold tabular-nums";
31
+ };
32
+ //# sourceMappingURL=animated-number.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"animated-number.d.ts","sourceRoot":"","sources":["../../src/design-system/animated-number.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,qBAAqB,8DAC2B,CAAC;AAE9D,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;CA2C9B,CAAC;AAEX,eAAO,MAAM,qBAAqB;;;;CAIxB,CAAC"}
@@ -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";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/design-system/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/design-system/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,mBAAmB,CAAC;AAClC,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { AnimatedNumberCounterProps, AnimatedNumberProps } from "./types";
2
+ export declare const AnimatedNumber: ({ number, wrapperClassName, className, ref, appearance, size, type, delayInSecond, transition, initial, whileInView, viewport, ...rest }: AnimatedNumberProps) => import("react/jsx-runtime").JSX.Element;
3
+ export declare const AnimatedNumberCounter: ({ number, className, ref: externalRef, appearance, size, duration, viewport, ...rest }: AnimatedNumberCounterProps) => import("react/jsx-runtime").JSX.Element;
4
+ //# sourceMappingURL=animated-number.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"animated-number.d.ts","sourceRoot":"","sources":["../../../src/ui/animated-number/animated-number.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,0BAA0B,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAQ1E,eAAO,MAAM,cAAc,GAAI,0IAc5B,mBAAmB,4CAsCrB,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,wFASnC,0BAA0B,4CA6C5B,CAAC"}
@@ -0,0 +1,59 @@
1
+ export declare const animationInitialType: {
2
+ up: {
3
+ y: string;
4
+ };
5
+ down: {
6
+ y: string;
7
+ };
8
+ scaleUp: {
9
+ scale: number;
10
+ };
11
+ scaleDown: {
12
+ scale: number;
13
+ };
14
+ rotateX: {
15
+ rotateX: string;
16
+ };
17
+ rotateY: {
18
+ rotateY: string;
19
+ };
20
+ skewX: {
21
+ skewX: number;
22
+ };
23
+ skewY: {
24
+ skewY: number;
25
+ };
26
+ fade: {
27
+ opacity: number;
28
+ };
29
+ };
30
+ export declare const animationFinalType: {
31
+ up: {
32
+ y: number;
33
+ };
34
+ down: {
35
+ y: number;
36
+ };
37
+ scaleUp: {
38
+ scale: number;
39
+ };
40
+ scaleDown: {
41
+ scale: number;
42
+ };
43
+ rotateX: {
44
+ rotateX: string;
45
+ };
46
+ rotateY: {
47
+ rotateY: string;
48
+ };
49
+ skewX: {
50
+ skewX: number;
51
+ };
52
+ skewY: {
53
+ skewY: number;
54
+ };
55
+ fade: {
56
+ opacity: number;
57
+ };
58
+ };
59
+ //# sourceMappingURL=animations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"animations.d.ts","sourceRoot":"","sources":["../../../src/ui/animated-number/animations.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAUhC,CAAC;AACF,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAU9B,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { AnimatedNumber, AnimatedNumberCounter } from "./animated-number";
2
+ export type { AnimatedNumberProps, AnimatedNumberCounterProps } from "./types";
3
+ export { animatedNumberAppearance } from "./variants";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/animated-number/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC1E,YAAY,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAC;AAC/E,OAAO,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,31 @@
1
+ import { VariantProps } from "class-variance-authority";
2
+ import { MotionProps } from "framer-motion";
3
+ import { RefObject } from "react";
4
+ import { animatedNumberAppearance } from "./variants";
5
+ type MotionTransitionWithoutDelay = Omit<NonNullable<MotionProps["transition"]>, "delay"> & {
6
+ delay?: never;
7
+ };
8
+ export type MotionPropsWithoutTransitionDelay = Omit<MotionProps, "transition"> & {
9
+ transition?: MotionTransitionWithoutDelay;
10
+ };
11
+ export type AnimatedNumberProps = MotionPropsWithoutTransitionDelay & {
12
+ number: number;
13
+ wrapperClassName?: string;
14
+ className?: string;
15
+ ref?: RefObject<HTMLDivElement>;
16
+ appearance?: VariantProps<typeof animatedNumberAppearance>["appearance"];
17
+ size?: VariantProps<typeof animatedNumberAppearance>["size"];
18
+ type?: "up" | "down" | "scaleUp" | "scaleDown" | "rotateX" | "rotateY" | "skewX" | "skewY" | "fade";
19
+ delayInSecond?: number;
20
+ transition?: MotionProps["transition"];
21
+ };
22
+ export type AnimatedNumberCounterProps = MotionProps & {
23
+ number: number;
24
+ className?: string;
25
+ ref?: RefObject<HTMLParagraphElement>;
26
+ appearance?: VariantProps<typeof animatedNumberAppearance>["appearance"];
27
+ size?: VariantProps<typeof animatedNumberAppearance>["size"];
28
+ duration?: number;
29
+ };
30
+ export {};
31
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/ui/animated-number/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAClC,OAAO,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAEtD,KAAK,4BAA4B,GAAG,IAAI,CACtC,WAAW,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,EACtC,OAAO,CACR,GAAG;IACF,KAAK,CAAC,EAAE,KAAK,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,iCAAiC,GAAG,IAAI,CAClD,WAAW,EACX,YAAY,CACb,GAAG;IACF,UAAU,CAAC,EAAE,4BAA4B,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,iCAAiC,GAAG;IACpE,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,SAAS,CAAC,cAAc,CAAC,CAAC;IAChC,UAAU,CAAC,EAAE,YAAY,CAAC,OAAO,wBAAwB,CAAC,CAAC,YAAY,CAAC,CAAC;IACzE,IAAI,CAAC,EAAE,YAAY,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAC;IAC7D,IAAI,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;IACpG,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,WAAW,CAAC,YAAY,CAAC,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG,WAAW,GAAG;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,SAAS,CAAC,oBAAoB,CAAC,CAAC;IACtC,UAAU,CAAC,EAAE,YAAY,CAAC,OAAO,wBAAwB,CAAC,CAAC,YAAY,CAAC,CAAC;IACzE,IAAI,CAAC,EAAE,YAAY,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAC;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare const animatedNumberAppearance: (props?: ({
2
+ appearance?: "default" | "violet" | "gray" | "indigo" | "orange" | "pink" | "purple" | "teal" | "yellow" | "gradient-blue" | "gradient-green" | "gradient-red" | "gradient-yellow" | "gradient-purple" | "gradient-teal" | "gradient-indigo" | "gradient-pink" | "gradient-orange" | "ghost" | "error" | "success" | "warning" | "info" | null | undefined;
3
+ size?: "md" | "sm" | "lg" | null | undefined;
4
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
5
+ //# sourceMappingURL=variants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"variants.d.ts","sourceRoot":"","sources":["../../../src/ui/animated-number/variants.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,wBAAwB;;;8EASnC,CAAC"}
@@ -0,0 +1,181 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var chunkZS5756ZC_js = require('../chunk-ZS5756ZC.js');
5
+ var framerMotion = require('framer-motion');
6
+ var classVarianceAuthority = require('class-variance-authority');
7
+ var react = require('react');
8
+ var jsxRuntime = require('react/jsx-runtime');
9
+
10
+ // src/design-system/animated-number.ts
11
+ var zuiAnimatedNumberBase = "relative flex w-full overflow-hidden [perspective:1000px]";
12
+ var zuiAnimatedNumberAppearance = {
13
+ default: "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))]",
14
+ success: "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))]",
15
+ warning: "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))]",
16
+ error: "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))]",
17
+ 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))]",
18
+ ghost: "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))]",
19
+ purple: "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))]",
20
+ 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))]",
21
+ orange: "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))]",
22
+ yellow: "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: "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))]",
25
+ 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))]",
26
+ violet: "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))]",
27
+ "gradient-blue": "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",
28
+ "gradient-green": "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",
29
+ "gradient-red": "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",
30
+ "gradient-yellow": "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",
31
+ "gradient-purple": "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",
32
+ "gradient-teal": "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",
33
+ "gradient-indigo": "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",
34
+ "gradient-pink": "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",
35
+ "gradient-orange": "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"
36
+ };
37
+ var zuiAnimatedNumberSize = {
38
+ sm: "text-2xl font-semibold tabular-nums",
39
+ md: "text-4xl font-semibold tabular-nums",
40
+ lg: "text-6xl font-bold tabular-nums"
41
+ };
42
+
43
+ // src/ui/animated-number/variants.ts
44
+ var animatedNumberAppearance = classVarianceAuthority.cva("inline-flex", {
45
+ variants: {
46
+ appearance: zuiAnimatedNumberAppearance,
47
+ size: zuiAnimatedNumberSize
48
+ },
49
+ defaultVariants: {
50
+ appearance: "default",
51
+ size: "md"
52
+ }
53
+ });
54
+
55
+ // src/ui/animated-number/animations.ts
56
+ var animationInitialType = {
57
+ up: { y: "-100%" },
58
+ down: { y: "100%" },
59
+ scaleUp: { scale: 0 },
60
+ scaleDown: { scale: 1.25 },
61
+ rotateX: { rotateX: "0" },
62
+ rotateY: { rotateY: "0" },
63
+ skewX: { skewX: 20 },
64
+ skewY: { skewY: 20 },
65
+ fade: { opacity: 0 }
66
+ };
67
+ var animationFinalType = {
68
+ up: { y: 0 },
69
+ down: { y: 0 },
70
+ scaleUp: { scale: 1 },
71
+ scaleDown: { scale: 1 },
72
+ rotateX: { rotateX: "360deg" },
73
+ rotateY: { rotateY: "360deg" },
74
+ skewX: { skewX: 0 },
75
+ skewY: { skewY: 0 },
76
+ fade: { opacity: 1 }
77
+ };
78
+ var DEFAULT_VIEWPORT = { once: true, amount: 0.2 };
79
+ var AnimatedNumber = ({
80
+ number,
81
+ wrapperClassName,
82
+ className,
83
+ ref,
84
+ appearance,
85
+ size,
86
+ type = "up",
87
+ delayInSecond = 0.1,
88
+ transition,
89
+ initial,
90
+ whileInView,
91
+ viewport,
92
+ ...rest
93
+ }) => {
94
+ const numbersList = [...number.toString()];
95
+ const reducedMotion = framerMotion.useReducedMotion();
96
+ const motionless = Boolean(reducedMotion);
97
+ const digitVariants = {
98
+ hidden: animationInitialType[type],
99
+ visible: animationFinalType[type]
100
+ };
101
+ return /* @__PURE__ */ jsxRuntime.jsx(
102
+ framerMotion.motion.div,
103
+ {
104
+ ref,
105
+ initial: motionless ? false : "hidden",
106
+ whileInView: motionless ? void 0 : "visible",
107
+ viewport: viewport ?? DEFAULT_VIEWPORT,
108
+ transition: {
109
+ staggerChildren: delayInSecond
110
+ },
111
+ className: chunkZS5756ZC_js.cn(wrapperClassName, zuiAnimatedNumberBase),
112
+ children: numbersList.map((digit, index) => /* @__PURE__ */ jsxRuntime.jsx(
113
+ framerMotion.motion.span,
114
+ {
115
+ className: chunkZS5756ZC_js.cn(
116
+ "inline-block",
117
+ animatedNumberAppearance({ appearance, size }),
118
+ className
119
+ ),
120
+ variants: digitVariants,
121
+ transition,
122
+ ...rest,
123
+ children: digit
124
+ },
125
+ index + "-" + digit
126
+ ))
127
+ }
128
+ );
129
+ };
130
+ var AnimatedNumberCounter = ({
131
+ number,
132
+ className,
133
+ ref: externalRef,
134
+ appearance,
135
+ size,
136
+ duration = 2,
137
+ viewport,
138
+ ...rest
139
+ }) => {
140
+ const [currentNumber, setCurrentNumber] = react.useState(0);
141
+ const reducedMotion = framerMotion.useReducedMotion();
142
+ const internalRef = react.useRef(null);
143
+ const isInView = framerMotion.useInView(internalRef, {
144
+ once: false,
145
+ amount: 0.2,
146
+ ...viewport
147
+ });
148
+ react.useEffect(() => {
149
+ if (!isInView) return;
150
+ if (reducedMotion) {
151
+ setCurrentNumber(number);
152
+ return;
153
+ }
154
+ const controls = framerMotion.animate(currentNumber, number, {
155
+ duration,
156
+ ease: "circOut",
157
+ onUpdate: (latest) => setCurrentNumber(Math.round(latest))
158
+ });
159
+ return () => controls.stop();
160
+ }, [isInView, number, duration, reducedMotion]);
161
+ return /* @__PURE__ */ jsxRuntime.jsx(
162
+ framerMotion.motion.p,
163
+ {
164
+ className: chunkZS5756ZC_js.cn(animatedNumberAppearance({ appearance, size }), className),
165
+ ref: (node) => {
166
+ internalRef.current = node;
167
+ if (externalRef) {
168
+ externalRef.current = node;
169
+ }
170
+ },
171
+ ...rest,
172
+ children: currentNumber
173
+ }
174
+ );
175
+ };
176
+
177
+ exports.AnimatedNumber = AnimatedNumber;
178
+ exports.AnimatedNumberCounter = AnimatedNumberCounter;
179
+ exports.animatedNumberAppearance = animatedNumberAppearance;
180
+ //# sourceMappingURL=animated-number.js.map
181
+ //# sourceMappingURL=animated-number.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/design-system/animated-number.ts","../../src/ui/animated-number/variants.ts","../../src/ui/animated-number/animations.ts","../../src/ui/animated-number/animated-number.tsx"],"names":["cva","useReducedMotion","jsx","motion","cn","useState","useRef","useInView","useEffect","animate"],"mappings":"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","file":"animated-number.js","sourcesContent":["export const zuiAnimatedNumberBase =\n \"relative flex w-full overflow-hidden [perspective:1000px]\";\n\nexport const zuiAnimatedNumberAppearance = {\n default:\n \"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))]\",\n success:\n \"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))]\",\n warning:\n \"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))]\",\n error:\n \"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))]\",\n 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))]\",\n ghost:\n \"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))]\",\n purple:\n \"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))]\",\n 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))]\",\n orange:\n \"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))]\",\n yellow:\n \"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))]\",\n 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))]\",\n indigo:\n \"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))]\",\n 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))]\",\n violet:\n \"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))]\",\n \"gradient-blue\":\n \"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\",\n \"gradient-green\":\n \"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\",\n \"gradient-red\":\n \"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\",\n \"gradient-yellow\":\n \"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\",\n \"gradient-purple\":\n \"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\",\n \"gradient-teal\":\n \"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\",\n \"gradient-indigo\":\n \"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\",\n \"gradient-pink\":\n \"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\",\n \"gradient-orange\":\n \"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\",\n} as const;\n\nexport const zuiAnimatedNumberSize = {\n sm: \"text-2xl font-semibold tabular-nums\",\n md: \"text-4xl font-semibold tabular-nums\",\n lg: \"text-6xl font-bold tabular-nums\",\n} as const;\n","import { cva } from \"class-variance-authority\";\n\nimport { zuiAnimatedNumberAppearance, zuiAnimatedNumberSize } from \"../../design-system/animated-number\";\n\nexport const animatedNumberAppearance = cva(\"inline-flex\",{\n variants: {\n appearance: zuiAnimatedNumberAppearance,\n size: zuiAnimatedNumberSize\n },\n defaultVariants: {\n appearance: \"default\",\n size: \"md\",\n },\n});","export const animationInitialType = {\n up: { y: \"-100%\" },\n down: { y: \"100%\" },\n scaleUp: { scale: 0 },\n scaleDown: { scale: 1.25 },\n rotateX: { rotateX: \"0\" },\n rotateY: { rotateY: \"0\" },\n skewX: { skewX: 20 },\n skewY: { skewY: 20 },\n fade: { opacity: 0 },\n};\nexport const animationFinalType = {\n up: { y: 0 },\n down: { y: 0 },\n scaleUp: { scale: 1 },\n scaleDown: { scale: 1 },\n rotateX: { rotateX: \"360deg\" },\n rotateY: { rotateY: \"360deg\" },\n skewX: { skewX: 0 },\n skewY: { skewY: 0 },\n fade: { opacity: 1 },\n};\n","\"use client\";\nimport { animate, motion, useInView, useReducedMotion, type UseInViewOptions } from \"framer-motion\";\nimport { animatedNumberAppearance } from \"./variants\";\nimport { AnimatedNumberCounterProps, AnimatedNumberProps } from \"./types\";\nimport { cn } from \"../../lib/utils\";\nimport { zuiAnimatedNumberBase } from \"../../design-system/animated-number\";\nimport { animationFinalType, animationInitialType } from \"./animations\";\nimport { useEffect, useRef, useState } from \"react\";\n\nconst DEFAULT_VIEWPORT = { once: true, amount: 0.2 } as const;\n\nexport const AnimatedNumber = ({\n number,\n wrapperClassName,\n className,\n ref,\n appearance,\n size,\n type = \"up\",\n delayInSecond = 0.1,\n transition,\n initial,\n whileInView,\n viewport,\n ...rest\n}: AnimatedNumberProps) => {\n const numbersList = [...number.toString()];\n const reducedMotion = useReducedMotion();\n const motionless = Boolean(reducedMotion);\n\n const digitVariants = {\n hidden: animationInitialType[type],\n visible: animationFinalType[type],\n };\n\n return (\n <motion.div\n ref={ref}\n initial={motionless ? false : \"hidden\"}\n whileInView={motionless ? undefined : \"visible\"}\n viewport={viewport ?? DEFAULT_VIEWPORT}\n transition={{\n staggerChildren: delayInSecond,\n }}\n className={cn(wrapperClassName, zuiAnimatedNumberBase)}\n >\n {numbersList.map((digit, index) => (\n <motion.span\n key={index + \"-\" + digit}\n className={cn(\n \"inline-block\",\n animatedNumberAppearance({ appearance, size }),\n className,\n )}\n variants={digitVariants}\n transition={transition}\n {...rest}\n >\n {digit}\n </motion.span>\n ))}\n </motion.div>\n );\n};\n\nexport const AnimatedNumberCounter = ({\n number,\n className,\n ref: externalRef,\n appearance,\n size,\n duration = 2,\n viewport,\n ...rest\n}: AnimatedNumberCounterProps) => {\n const [currentNumber, setCurrentNumber] = useState(0);\n const reducedMotion = useReducedMotion();\n const internalRef = useRef<HTMLParagraphElement>(null);\n // once: false gives real two-way tracking so isInView flips false when scrolled away,\n // preventing offscreen animations when the number prop changes later.\n const isInView = useInView(internalRef, {\n once: false,\n amount: 0.2,\n ...viewport,\n } as UseInViewOptions);\n\n useEffect(() => {\n if (!isInView) return;\n\n if (reducedMotion) {\n setCurrentNumber(number);\n return;\n }\n\n const controls = animate(currentNumber, number, {\n duration,\n ease: \"circOut\",\n onUpdate: (latest) => setCurrentNumber(Math.round(latest)),\n });\n\n return () => controls.stop();\n // currentNumber intentionally omitted — captured value gives smooth from→to on prop changes\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isInView, number, duration, reducedMotion]);\n\n return (\n <motion.p\n className={cn(animatedNumberAppearance({ appearance, size }), className)}\n ref={(node: HTMLParagraphElement) => {\n internalRef.current = node;\n if (externalRef) {\n externalRef.current = node;\n }\n }}\n {...rest}\n >\n {currentNumber}\n </motion.p>\n );\n};\n"]}
@@ -0,0 +1,177 @@
1
+ "use client";
2
+ import { cn } from '../chunk-4D54YOL6.mjs';
3
+ import { useReducedMotion, motion, useInView, animate } from 'framer-motion';
4
+ import { cva } from 'class-variance-authority';
5
+ import { useState, useRef, useEffect } from 'react';
6
+ import { jsx } from 'react/jsx-runtime';
7
+
8
+ // src/design-system/animated-number.ts
9
+ var zuiAnimatedNumberBase = "relative flex w-full overflow-hidden [perspective:1000px]";
10
+ var zuiAnimatedNumberAppearance = {
11
+ default: "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))]",
12
+ success: "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))]",
13
+ warning: "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))]",
14
+ error: "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))]",
15
+ 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))]",
16
+ ghost: "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))]",
17
+ purple: "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: "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))]",
20
+ yellow: "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))]",
21
+ 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))]",
22
+ indigo: "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))]",
23
+ 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))]",
24
+ violet: "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))]",
25
+ "gradient-blue": "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",
26
+ "gradient-green": "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",
27
+ "gradient-red": "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",
28
+ "gradient-yellow": "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",
29
+ "gradient-purple": "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",
30
+ "gradient-teal": "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",
31
+ "gradient-indigo": "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",
32
+ "gradient-pink": "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",
33
+ "gradient-orange": "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"
34
+ };
35
+ var zuiAnimatedNumberSize = {
36
+ sm: "text-2xl font-semibold tabular-nums",
37
+ md: "text-4xl font-semibold tabular-nums",
38
+ lg: "text-6xl font-bold tabular-nums"
39
+ };
40
+
41
+ // src/ui/animated-number/variants.ts
42
+ var animatedNumberAppearance = cva("inline-flex", {
43
+ variants: {
44
+ appearance: zuiAnimatedNumberAppearance,
45
+ size: zuiAnimatedNumberSize
46
+ },
47
+ defaultVariants: {
48
+ appearance: "default",
49
+ size: "md"
50
+ }
51
+ });
52
+
53
+ // src/ui/animated-number/animations.ts
54
+ var animationInitialType = {
55
+ up: { y: "-100%" },
56
+ down: { y: "100%" },
57
+ scaleUp: { scale: 0 },
58
+ scaleDown: { scale: 1.25 },
59
+ rotateX: { rotateX: "0" },
60
+ rotateY: { rotateY: "0" },
61
+ skewX: { skewX: 20 },
62
+ skewY: { skewY: 20 },
63
+ fade: { opacity: 0 }
64
+ };
65
+ var animationFinalType = {
66
+ up: { y: 0 },
67
+ down: { y: 0 },
68
+ scaleUp: { scale: 1 },
69
+ scaleDown: { scale: 1 },
70
+ rotateX: { rotateX: "360deg" },
71
+ rotateY: { rotateY: "360deg" },
72
+ skewX: { skewX: 0 },
73
+ skewY: { skewY: 0 },
74
+ fade: { opacity: 1 }
75
+ };
76
+ var DEFAULT_VIEWPORT = { once: true, amount: 0.2 };
77
+ var AnimatedNumber = ({
78
+ number,
79
+ wrapperClassName,
80
+ className,
81
+ ref,
82
+ appearance,
83
+ size,
84
+ type = "up",
85
+ delayInSecond = 0.1,
86
+ transition,
87
+ initial,
88
+ whileInView,
89
+ viewport,
90
+ ...rest
91
+ }) => {
92
+ const numbersList = [...number.toString()];
93
+ const reducedMotion = useReducedMotion();
94
+ const motionless = Boolean(reducedMotion);
95
+ const digitVariants = {
96
+ hidden: animationInitialType[type],
97
+ visible: animationFinalType[type]
98
+ };
99
+ return /* @__PURE__ */ jsx(
100
+ motion.div,
101
+ {
102
+ ref,
103
+ initial: motionless ? false : "hidden",
104
+ whileInView: motionless ? void 0 : "visible",
105
+ viewport: viewport ?? DEFAULT_VIEWPORT,
106
+ transition: {
107
+ staggerChildren: delayInSecond
108
+ },
109
+ className: cn(wrapperClassName, zuiAnimatedNumberBase),
110
+ children: numbersList.map((digit, index) => /* @__PURE__ */ jsx(
111
+ motion.span,
112
+ {
113
+ className: cn(
114
+ "inline-block",
115
+ animatedNumberAppearance({ appearance, size }),
116
+ className
117
+ ),
118
+ variants: digitVariants,
119
+ transition,
120
+ ...rest,
121
+ children: digit
122
+ },
123
+ index + "-" + digit
124
+ ))
125
+ }
126
+ );
127
+ };
128
+ var AnimatedNumberCounter = ({
129
+ number,
130
+ className,
131
+ ref: externalRef,
132
+ appearance,
133
+ size,
134
+ duration = 2,
135
+ viewport,
136
+ ...rest
137
+ }) => {
138
+ const [currentNumber, setCurrentNumber] = useState(0);
139
+ const reducedMotion = useReducedMotion();
140
+ const internalRef = useRef(null);
141
+ const isInView = useInView(internalRef, {
142
+ once: false,
143
+ amount: 0.2,
144
+ ...viewport
145
+ });
146
+ useEffect(() => {
147
+ if (!isInView) return;
148
+ if (reducedMotion) {
149
+ setCurrentNumber(number);
150
+ return;
151
+ }
152
+ const controls = animate(currentNumber, number, {
153
+ duration,
154
+ ease: "circOut",
155
+ onUpdate: (latest) => setCurrentNumber(Math.round(latest))
156
+ });
157
+ return () => controls.stop();
158
+ }, [isInView, number, duration, reducedMotion]);
159
+ return /* @__PURE__ */ jsx(
160
+ motion.p,
161
+ {
162
+ className: cn(animatedNumberAppearance({ appearance, size }), className),
163
+ ref: (node) => {
164
+ internalRef.current = node;
165
+ if (externalRef) {
166
+ externalRef.current = node;
167
+ }
168
+ },
169
+ ...rest,
170
+ children: currentNumber
171
+ }
172
+ );
173
+ };
174
+
175
+ export { AnimatedNumber, AnimatedNumberCounter, animatedNumberAppearance };
176
+ //# sourceMappingURL=animated-number.mjs.map
177
+ //# sourceMappingURL=animated-number.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/design-system/animated-number.ts","../../src/ui/animated-number/variants.ts","../../src/ui/animated-number/animations.ts","../../src/ui/animated-number/animated-number.tsx"],"names":[],"mappings":"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","file":"animated-number.mjs","sourcesContent":["export const zuiAnimatedNumberBase =\n \"relative flex w-full overflow-hidden [perspective:1000px]\";\n\nexport const zuiAnimatedNumberAppearance = {\n default:\n \"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))]\",\n success:\n \"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))]\",\n warning:\n \"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))]\",\n error:\n \"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))]\",\n 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))]\",\n ghost:\n \"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))]\",\n purple:\n \"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))]\",\n 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))]\",\n orange:\n \"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))]\",\n yellow:\n \"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))]\",\n 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))]\",\n indigo:\n \"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))]\",\n 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))]\",\n violet:\n \"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))]\",\n \"gradient-blue\":\n \"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\",\n \"gradient-green\":\n \"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\",\n \"gradient-red\":\n \"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\",\n \"gradient-yellow\":\n \"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\",\n \"gradient-purple\":\n \"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\",\n \"gradient-teal\":\n \"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\",\n \"gradient-indigo\":\n \"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\",\n \"gradient-pink\":\n \"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\",\n \"gradient-orange\":\n \"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\",\n} as const;\n\nexport const zuiAnimatedNumberSize = {\n sm: \"text-2xl font-semibold tabular-nums\",\n md: \"text-4xl font-semibold tabular-nums\",\n lg: \"text-6xl font-bold tabular-nums\",\n} as const;\n","import { cva } from \"class-variance-authority\";\n\nimport { zuiAnimatedNumberAppearance, zuiAnimatedNumberSize } from \"../../design-system/animated-number\";\n\nexport const animatedNumberAppearance = cva(\"inline-flex\",{\n variants: {\n appearance: zuiAnimatedNumberAppearance,\n size: zuiAnimatedNumberSize\n },\n defaultVariants: {\n appearance: \"default\",\n size: \"md\",\n },\n});","export const animationInitialType = {\n up: { y: \"-100%\" },\n down: { y: \"100%\" },\n scaleUp: { scale: 0 },\n scaleDown: { scale: 1.25 },\n rotateX: { rotateX: \"0\" },\n rotateY: { rotateY: \"0\" },\n skewX: { skewX: 20 },\n skewY: { skewY: 20 },\n fade: { opacity: 0 },\n};\nexport const animationFinalType = {\n up: { y: 0 },\n down: { y: 0 },\n scaleUp: { scale: 1 },\n scaleDown: { scale: 1 },\n rotateX: { rotateX: \"360deg\" },\n rotateY: { rotateY: \"360deg\" },\n skewX: { skewX: 0 },\n skewY: { skewY: 0 },\n fade: { opacity: 1 },\n};\n","\"use client\";\nimport { animate, motion, useInView, useReducedMotion, type UseInViewOptions } from \"framer-motion\";\nimport { animatedNumberAppearance } from \"./variants\";\nimport { AnimatedNumberCounterProps, AnimatedNumberProps } from \"./types\";\nimport { cn } from \"../../lib/utils\";\nimport { zuiAnimatedNumberBase } from \"../../design-system/animated-number\";\nimport { animationFinalType, animationInitialType } from \"./animations\";\nimport { useEffect, useRef, useState } from \"react\";\n\nconst DEFAULT_VIEWPORT = { once: true, amount: 0.2 } as const;\n\nexport const AnimatedNumber = ({\n number,\n wrapperClassName,\n className,\n ref,\n appearance,\n size,\n type = \"up\",\n delayInSecond = 0.1,\n transition,\n initial,\n whileInView,\n viewport,\n ...rest\n}: AnimatedNumberProps) => {\n const numbersList = [...number.toString()];\n const reducedMotion = useReducedMotion();\n const motionless = Boolean(reducedMotion);\n\n const digitVariants = {\n hidden: animationInitialType[type],\n visible: animationFinalType[type],\n };\n\n return (\n <motion.div\n ref={ref}\n initial={motionless ? false : \"hidden\"}\n whileInView={motionless ? undefined : \"visible\"}\n viewport={viewport ?? DEFAULT_VIEWPORT}\n transition={{\n staggerChildren: delayInSecond,\n }}\n className={cn(wrapperClassName, zuiAnimatedNumberBase)}\n >\n {numbersList.map((digit, index) => (\n <motion.span\n key={index + \"-\" + digit}\n className={cn(\n \"inline-block\",\n animatedNumberAppearance({ appearance, size }),\n className,\n )}\n variants={digitVariants}\n transition={transition}\n {...rest}\n >\n {digit}\n </motion.span>\n ))}\n </motion.div>\n );\n};\n\nexport const AnimatedNumberCounter = ({\n number,\n className,\n ref: externalRef,\n appearance,\n size,\n duration = 2,\n viewport,\n ...rest\n}: AnimatedNumberCounterProps) => {\n const [currentNumber, setCurrentNumber] = useState(0);\n const reducedMotion = useReducedMotion();\n const internalRef = useRef<HTMLParagraphElement>(null);\n // once: false gives real two-way tracking so isInView flips false when scrolled away,\n // preventing offscreen animations when the number prop changes later.\n const isInView = useInView(internalRef, {\n once: false,\n amount: 0.2,\n ...viewport,\n } as UseInViewOptions);\n\n useEffect(() => {\n if (!isInView) return;\n\n if (reducedMotion) {\n setCurrentNumber(number);\n return;\n }\n\n const controls = animate(currentNumber, number, {\n duration,\n ease: \"circOut\",\n onUpdate: (latest) => setCurrentNumber(Math.round(latest)),\n });\n\n return () => controls.stop();\n // currentNumber intentionally omitted — captured value gives smooth from→to on prop changes\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isInView, number, duration, reducedMotion]);\n\n return (\n <motion.p\n className={cn(animatedNumberAppearance({ appearance, size }), className)}\n ref={(node: HTMLParagraphElement) => {\n internalRef.current = node;\n if (externalRef) {\n externalRef.current = node;\n }\n }}\n {...rest}\n >\n {currentNumber}\n </motion.p>\n );\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zentauri-ui/zentauri-components",
3
- "version": "1.7.9",
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";
@@ -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,4 @@
1
+ "use client";
2
+ export { AnimatedNumber, AnimatedNumberCounter } from "./animated-number";
3
+ export type { AnimatedNumberProps, AnimatedNumberCounterProps } from "./types";
4
+ export { animatedNumberAppearance } from "./variants";
@@ -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
+ });