@karakuri-ui/react 0.2.3 → 0.2.4
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 +0 -1
- package/dist/components/ui/accordion.d.mts +49 -0
- package/dist/components/ui/accordion.d.ts +49 -0
- package/dist/components/ui/accordion.js +220 -0
- package/dist/components/ui/accordion.js.map +1 -0
- package/dist/components/ui/accordion.mjs +181 -0
- package/dist/components/ui/accordion.mjs.map +1 -0
- package/dist/components/ui/alert.d.mts +47 -0
- package/dist/components/ui/alert.d.ts +47 -0
- package/dist/components/ui/alert.js +223 -0
- package/dist/components/ui/alert.js.map +1 -0
- package/dist/components/ui/alert.mjs +185 -0
- package/dist/components/ui/alert.mjs.map +1 -0
- package/dist/components/ui/avatar.d.mts +232 -0
- package/dist/components/ui/avatar.d.ts +232 -0
- package/dist/components/ui/avatar.js +250 -0
- package/dist/components/ui/avatar.js.map +1 -0
- package/dist/components/ui/avatar.mjs +209 -0
- package/dist/components/ui/avatar.mjs.map +1 -0
- package/dist/components/ui/badge.d.mts +31 -0
- package/dist/components/ui/badge.d.ts +31 -0
- package/dist/components/ui/badge.js +205 -0
- package/dist/components/ui/badge.js.map +1 -0
- package/dist/components/ui/badge.mjs +170 -0
- package/dist/components/ui/badge.mjs.map +1 -0
- package/dist/components/ui/breadcrumb.d.mts +57 -0
- package/dist/components/ui/breadcrumb.d.ts +57 -0
- package/dist/components/ui/breadcrumb.js +209 -0
- package/dist/components/ui/breadcrumb.js.map +1 -0
- package/dist/components/ui/breadcrumb.mjs +168 -0
- package/dist/components/ui/breadcrumb.mjs.map +1 -0
- package/dist/components/ui/button-group.d.mts +22 -0
- package/dist/components/ui/button-group.d.ts +22 -0
- package/dist/components/ui/button-group.js +107 -0
- package/dist/components/ui/button-group.js.map +1 -0
- package/dist/components/ui/button-group.mjs +72 -0
- package/dist/components/ui/button-group.mjs.map +1 -0
- package/dist/components/ui/button.d.mts +31 -0
- package/dist/components/ui/button.d.ts +31 -0
- package/dist/components/ui/button.js +176 -0
- package/dist/components/ui/button.js.map +1 -0
- package/dist/components/ui/button.mjs +141 -0
- package/dist/components/ui/button.mjs.map +1 -0
- package/dist/components/ui/card.d.mts +77 -0
- package/dist/components/ui/card.d.ts +77 -0
- package/dist/components/ui/card.js +370 -0
- package/dist/components/ui/card.js.map +1 -0
- package/dist/components/ui/card.mjs +328 -0
- package/dist/components/ui/card.mjs.map +1 -0
- package/dist/{chart.js → components/ui/chart.js} +29 -39
- package/dist/components/ui/chart.js.map +1 -0
- package/dist/{chart.mjs → components/ui/chart.mjs} +21 -31
- package/dist/components/ui/chart.mjs.map +1 -0
- package/dist/components/ui/checkbox.d.mts +24 -0
- package/dist/components/ui/checkbox.d.ts +24 -0
- package/dist/components/ui/checkbox.js +173 -0
- package/dist/components/ui/checkbox.js.map +1 -0
- package/dist/components/ui/checkbox.mjs +138 -0
- package/dist/components/ui/checkbox.mjs.map +1 -0
- package/dist/components/ui/divider.d.mts +27 -0
- package/dist/components/ui/divider.d.ts +27 -0
- package/dist/components/ui/divider.js +147 -0
- package/dist/components/ui/divider.js.map +1 -0
- package/dist/components/ui/divider.mjs +112 -0
- package/dist/components/ui/divider.mjs.map +1 -0
- package/dist/components/ui/drawer.d.mts +51 -0
- package/dist/components/ui/drawer.d.ts +51 -0
- package/dist/components/ui/drawer.js +225 -0
- package/dist/components/ui/drawer.js.map +1 -0
- package/dist/components/ui/drawer.mjs +178 -0
- package/dist/components/ui/drawer.mjs.map +1 -0
- package/dist/components/ui/dropdown.d.mts +59 -0
- package/dist/components/ui/dropdown.d.ts +59 -0
- package/dist/components/ui/dropdown.js +310 -0
- package/dist/components/ui/dropdown.js.map +1 -0
- package/dist/components/ui/dropdown.mjs +263 -0
- package/dist/components/ui/dropdown.mjs.map +1 -0
- package/dist/components/ui/field.d.mts +33 -0
- package/dist/components/ui/field.d.ts +33 -0
- package/dist/components/ui/field.js +146 -0
- package/dist/components/ui/field.js.map +1 -0
- package/dist/components/ui/field.mjs +108 -0
- package/dist/components/ui/field.mjs.map +1 -0
- package/dist/components/ui/icon-button.d.mts +20 -0
- package/dist/components/ui/icon-button.d.ts +20 -0
- package/dist/components/ui/icon-button.js +147 -0
- package/dist/components/ui/icon-button.js.map +1 -0
- package/dist/components/ui/icon-button.mjs +112 -0
- package/dist/components/ui/icon-button.mjs.map +1 -0
- package/dist/components/ui/index.d.mts +55 -0
- package/dist/components/ui/index.d.ts +55 -0
- package/dist/components/ui/index.js +476 -0
- package/dist/components/ui/index.js.map +1 -0
- package/dist/components/ui/index.mjs +246 -0
- package/dist/components/ui/index.mjs.map +1 -0
- package/dist/components/ui/input.d.mts +20 -0
- package/dist/components/ui/input.d.ts +20 -0
- package/dist/components/ui/input.js +250 -0
- package/dist/components/ui/input.js.map +1 -0
- package/dist/components/ui/input.mjs +215 -0
- package/dist/components/ui/input.mjs.map +1 -0
- package/dist/components/ui/metric-card.d.mts +53 -0
- package/dist/components/ui/metric-card.d.ts +53 -0
- package/dist/components/ui/metric-card.js +258 -0
- package/dist/components/ui/metric-card.js.map +1 -0
- package/dist/components/ui/metric-card.mjs +217 -0
- package/dist/components/ui/metric-card.mjs.map +1 -0
- package/dist/components/ui/modal.d.mts +77 -0
- package/dist/components/ui/modal.d.ts +77 -0
- package/dist/components/ui/modal.js +396 -0
- package/dist/components/ui/modal.js.map +1 -0
- package/dist/components/ui/modal.mjs +338 -0
- package/dist/components/ui/modal.mjs.map +1 -0
- package/dist/components/ui/navigation-menu.d.mts +139 -0
- package/dist/components/ui/navigation-menu.d.ts +139 -0
- package/dist/components/ui/navigation-menu.js +531 -0
- package/dist/components/ui/navigation-menu.js.map +1 -0
- package/dist/components/ui/navigation-menu.mjs +488 -0
- package/dist/components/ui/navigation-menu.mjs.map +1 -0
- package/dist/components/ui/pagination.d.mts +130 -0
- package/dist/components/ui/pagination.d.ts +130 -0
- package/dist/components/ui/pagination.js +495 -0
- package/dist/components/ui/pagination.js.map +1 -0
- package/dist/components/ui/pagination.mjs +449 -0
- package/dist/components/ui/pagination.mjs.map +1 -0
- package/dist/components/ui/popover.d.mts +41 -0
- package/dist/components/ui/popover.d.ts +41 -0
- package/dist/components/ui/popover.js +175 -0
- package/dist/components/ui/popover.js.map +1 -0
- package/dist/components/ui/popover.mjs +133 -0
- package/dist/components/ui/popover.mjs.map +1 -0
- package/dist/components/ui/progress.d.mts +35 -0
- package/dist/components/ui/progress.d.ts +35 -0
- package/dist/components/ui/progress.js +194 -0
- package/dist/components/ui/progress.js.map +1 -0
- package/dist/components/ui/progress.mjs +159 -0
- package/dist/components/ui/progress.mjs.map +1 -0
- package/dist/components/ui/radio-group.d.mts +40 -0
- package/dist/components/ui/radio-group.d.ts +40 -0
- package/dist/components/ui/radio-group.js +177 -0
- package/dist/components/ui/radio-group.js.map +1 -0
- package/dist/components/ui/radio-group.mjs +140 -0
- package/dist/components/ui/radio-group.mjs.map +1 -0
- package/dist/components/ui/segmented.d.mts +30 -0
- package/dist/components/ui/segmented.d.ts +30 -0
- package/dist/components/ui/segmented.js +241 -0
- package/dist/components/ui/segmented.js.map +1 -0
- package/dist/components/ui/segmented.mjs +204 -0
- package/dist/components/ui/segmented.mjs.map +1 -0
- package/dist/components/ui/select.d.mts +31 -0
- package/dist/components/ui/select.d.ts +31 -0
- package/dist/components/ui/select.js +317 -0
- package/dist/components/ui/select.js.map +1 -0
- package/dist/components/ui/select.mjs +276 -0
- package/dist/components/ui/select.mjs.map +1 -0
- package/dist/components/ui/skeleton.d.mts +26 -0
- package/dist/components/ui/skeleton.d.ts +26 -0
- package/dist/components/ui/skeleton.js +144 -0
- package/dist/components/ui/skeleton.js.map +1 -0
- package/dist/components/ui/skeleton.mjs +109 -0
- package/dist/components/ui/skeleton.mjs.map +1 -0
- package/dist/components/ui/slider.d.mts +38 -0
- package/dist/components/ui/slider.d.ts +38 -0
- package/dist/components/ui/slider.js +180 -0
- package/dist/components/ui/slider.js.map +1 -0
- package/dist/components/ui/slider.mjs +145 -0
- package/dist/components/ui/slider.mjs.map +1 -0
- package/dist/components/ui/spinner.d.mts +23 -0
- package/dist/components/ui/spinner.d.ts +23 -0
- package/dist/components/ui/spinner.js +471 -0
- package/dist/components/ui/spinner.js.map +1 -0
- package/dist/components/ui/spinner.mjs +436 -0
- package/dist/components/ui/spinner.mjs.map +1 -0
- package/dist/components/ui/switch.d.mts +22 -0
- package/dist/components/ui/switch.d.ts +22 -0
- package/dist/components/ui/switch.js +173 -0
- package/dist/components/ui/switch.js.map +1 -0
- package/dist/components/ui/switch.mjs +138 -0
- package/dist/components/ui/switch.mjs.map +1 -0
- package/dist/components/ui/table.d.mts +74 -0
- package/dist/components/ui/table.d.ts +74 -0
- package/dist/components/ui/table.js +240 -0
- package/dist/components/ui/table.js.map +1 -0
- package/dist/components/ui/table.mjs +199 -0
- package/dist/components/ui/table.mjs.map +1 -0
- package/dist/components/ui/tabs.d.mts +40 -0
- package/dist/components/ui/tabs.d.ts +40 -0
- package/dist/components/ui/tabs.js +238 -0
- package/dist/components/ui/tabs.js.map +1 -0
- package/dist/components/ui/tabs.mjs +199 -0
- package/dist/components/ui/tabs.mjs.map +1 -0
- package/dist/components/ui/textarea.d.mts +19 -0
- package/dist/components/ui/textarea.d.ts +19 -0
- package/dist/components/ui/textarea.js +181 -0
- package/dist/components/ui/textarea.js.map +1 -0
- package/dist/components/ui/textarea.mjs +146 -0
- package/dist/components/ui/textarea.mjs.map +1 -0
- package/dist/components/ui/toast.d.mts +93 -0
- package/dist/components/ui/toast.d.ts +93 -0
- package/dist/components/ui/toast.js +429 -0
- package/dist/components/ui/toast.js.map +1 -0
- package/dist/components/ui/toast.mjs +393 -0
- package/dist/components/ui/toast.mjs.map +1 -0
- package/dist/components/ui/toggle-group.d.mts +47 -0
- package/dist/components/ui/toggle-group.d.ts +47 -0
- package/dist/components/ui/toggle-group.js +186 -0
- package/dist/components/ui/toggle-group.js.map +1 -0
- package/dist/components/ui/toggle-group.mjs +149 -0
- package/dist/components/ui/toggle-group.mjs.map +1 -0
- package/dist/components/ui/toggle.d.mts +19 -0
- package/dist/components/ui/toggle.d.ts +19 -0
- package/dist/components/ui/toggle.js +194 -0
- package/dist/components/ui/toggle.js.map +1 -0
- package/dist/components/ui/toggle.mjs +159 -0
- package/dist/components/ui/toggle.mjs.map +1 -0
- package/dist/components/ui/tooltip.d.mts +37 -0
- package/dist/components/ui/tooltip.d.ts +37 -0
- package/dist/components/ui/tooltip.js +137 -0
- package/dist/components/ui/tooltip.js.map +1 -0
- package/dist/components/ui/tooltip.mjs +96 -0
- package/dist/components/ui/tooltip.mjs.map +1 -0
- package/dist/lib/utils.d.mts +10 -0
- package/dist/lib/utils.d.ts +10 -0
- package/dist/lib/utils.js +33 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/lib/utils.mjs +9 -0
- package/dist/lib/utils.mjs.map +1 -0
- package/package.json +11 -11
- package/dist/chart.js.map +0 -1
- package/dist/chart.mjs.map +0 -1
- package/dist/index.d.mts +0 -1636
- package/dist/index.d.ts +0 -1636
- package/dist/index.js +0 -7291
- package/dist/index.js.map +0 -1
- package/dist/index.mjs +0 -7048
- package/dist/index.mjs.map +0 -1
- /package/dist/{chart.d.mts → components/ui/chart.d.mts} +0 -0
- /package/dist/{chart.d.ts → components/ui/chart.d.ts} +0 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { cva } from "class-variance-authority";
|
|
4
|
+
import { cn } from "../../lib/utils";
|
|
5
|
+
import { useFieldContext } from "./field";
|
|
6
|
+
const inputVariants = cva(
|
|
7
|
+
[
|
|
8
|
+
"flex w-full bg-background text-foreground placeholder:text-foreground/30",
|
|
9
|
+
"border transition-colors duration-micro outline-transparent",
|
|
10
|
+
"focus:[outline:2px_solid_transparent]",
|
|
11
|
+
"disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-background-muted",
|
|
12
|
+
"file:border-0 file:bg-transparent file:text-sm file:font-semibold"
|
|
13
|
+
].join(" "),
|
|
14
|
+
{
|
|
15
|
+
variants: {
|
|
16
|
+
variant: {
|
|
17
|
+
default: "border-border-form hover:border-border-form-strong",
|
|
18
|
+
filled: "border-transparent bg-background-muted"
|
|
19
|
+
},
|
|
20
|
+
focusRing: {
|
|
21
|
+
true: "",
|
|
22
|
+
false: ""
|
|
23
|
+
},
|
|
24
|
+
size: {
|
|
25
|
+
xs: "h-9 px-3 text-sm",
|
|
26
|
+
// 36px / 12px padding / 13px font (3.0:1)
|
|
27
|
+
sm: "h-10 px-3 text-md",
|
|
28
|
+
// 40px / 12px padding / 14px font (3.3:1)
|
|
29
|
+
default: "h-11 px-4 text-base",
|
|
30
|
+
// 44px / 16px padding / 16px font (2.75:1)
|
|
31
|
+
lg: "h-12 px-4 text-base",
|
|
32
|
+
// 48px / 16px padding / 16px font (3.0:1)
|
|
33
|
+
xl: "h-14 px-4 text-base"
|
|
34
|
+
// 56px / 16px padding / 16px font (3.5:1)
|
|
35
|
+
},
|
|
36
|
+
radius: {
|
|
37
|
+
none: "rounded-none",
|
|
38
|
+
sm: "rounded-sm",
|
|
39
|
+
base: "rounded",
|
|
40
|
+
default: "rounded-md",
|
|
41
|
+
lg: "rounded-lg",
|
|
42
|
+
xl: "rounded-xl",
|
|
43
|
+
"2xl": "rounded-2xl",
|
|
44
|
+
"3xl": "rounded-3xl",
|
|
45
|
+
full: "rounded-full"
|
|
46
|
+
},
|
|
47
|
+
state: {
|
|
48
|
+
default: "",
|
|
49
|
+
error: "border-error hover:border-error focus:border-error shadow-[0_0_0_2px_var(--color-focus-ring-error)]"
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
compoundVariants: [
|
|
53
|
+
// focusRing: true → show custom focus ring
|
|
54
|
+
{ focusRing: true, className: "focus-visible:shadow-[0_0_0_2px_var(--color-focus-ring)]" },
|
|
55
|
+
// focusRing: false → keep same state as hover
|
|
56
|
+
{ variant: "default", focusRing: false, className: "focus:border-border-form-strong" },
|
|
57
|
+
// filled + error
|
|
58
|
+
{
|
|
59
|
+
variant: "filled",
|
|
60
|
+
state: "error",
|
|
61
|
+
className: "border-transparent hover:border-transparent focus:border-transparent bg-[var(--color-error-bg)] hover:bg-[var(--color-error-bg)] focus:bg-[var(--color-error-bg)] shadow-none"
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
defaultVariants: {
|
|
65
|
+
variant: "default",
|
|
66
|
+
size: "default",
|
|
67
|
+
radius: "default",
|
|
68
|
+
state: "default",
|
|
69
|
+
focusRing: false
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
);
|
|
73
|
+
const iconSizeClasses = {
|
|
74
|
+
xs: "icon-xs",
|
|
75
|
+
// 14px
|
|
76
|
+
sm: "icon-xs",
|
|
77
|
+
// 14px
|
|
78
|
+
default: "icon-sm",
|
|
79
|
+
// 16px
|
|
80
|
+
lg: "icon-sm",
|
|
81
|
+
// 16px
|
|
82
|
+
xl: "icon-sm"
|
|
83
|
+
// 16px
|
|
84
|
+
};
|
|
85
|
+
const iconPaddingClasses = {
|
|
86
|
+
xs: { left: "pl-8", right: "pr-8" },
|
|
87
|
+
// 12px + 14px icon + 6px gap = 32px
|
|
88
|
+
sm: { left: "pl-9", right: "pr-9" },
|
|
89
|
+
// 12px + 14px icon + 8px gap = 34px → 36px
|
|
90
|
+
default: { left: "pl-10", right: "pr-10" },
|
|
91
|
+
// 16px + 16px icon + 8px gap = 40px
|
|
92
|
+
lg: { left: "pl-10", right: "pr-10" },
|
|
93
|
+
// 16px + 16px icon + 8px gap = 40px
|
|
94
|
+
xl: { left: "pl-10", right: "pr-10" }
|
|
95
|
+
// 16px + 16px icon + 8px gap = 40px
|
|
96
|
+
};
|
|
97
|
+
const iconPositionClasses = {
|
|
98
|
+
xs: { left: "left-3", right: "right-3" },
|
|
99
|
+
// 12px
|
|
100
|
+
sm: { left: "left-3", right: "right-3" },
|
|
101
|
+
// 12px
|
|
102
|
+
default: { left: "left-4", right: "right-4" },
|
|
103
|
+
// 16px
|
|
104
|
+
lg: { left: "left-4", right: "right-4" },
|
|
105
|
+
// 16px
|
|
106
|
+
xl: { left: "left-4", right: "right-4" }
|
|
107
|
+
// 16px
|
|
108
|
+
};
|
|
109
|
+
const Input = React.forwardRef(
|
|
110
|
+
({ className, variant, size, radius, state, type, leftIcon, rightIcon, error, focusRing, id, onPointerDown, onFocus, onBlur, ...props }, ref) => {
|
|
111
|
+
const fieldContext = useFieldContext();
|
|
112
|
+
const resolvedSize = size || "default";
|
|
113
|
+
const resolvedError = error ?? fieldContext?.error;
|
|
114
|
+
const resolvedState = resolvedError ? "error" : state;
|
|
115
|
+
const inputId = id ?? fieldContext?.id;
|
|
116
|
+
const isDisabled = props.disabled ?? fieldContext?.disabled;
|
|
117
|
+
const pointerRef = React.useRef(false);
|
|
118
|
+
const windowBlurredRef = React.useRef(false);
|
|
119
|
+
const [keyboardFocus, setKeyboardFocus] = React.useState(false);
|
|
120
|
+
React.useEffect(() => {
|
|
121
|
+
const onBlur2 = () => {
|
|
122
|
+
windowBlurredRef.current = true;
|
|
123
|
+
};
|
|
124
|
+
const onFocus2 = () => {
|
|
125
|
+
requestAnimationFrame(() => {
|
|
126
|
+
windowBlurredRef.current = false;
|
|
127
|
+
});
|
|
128
|
+
};
|
|
129
|
+
window.addEventListener("blur", onBlur2);
|
|
130
|
+
window.addEventListener("focus", onFocus2);
|
|
131
|
+
return () => {
|
|
132
|
+
window.removeEventListener("blur", onBlur2);
|
|
133
|
+
window.removeEventListener("focus", onFocus2);
|
|
134
|
+
};
|
|
135
|
+
}, []);
|
|
136
|
+
const handlePointerDown = React.useCallback((e) => {
|
|
137
|
+
pointerRef.current = true;
|
|
138
|
+
onPointerDown?.(e);
|
|
139
|
+
}, [onPointerDown]);
|
|
140
|
+
const handleFocus = React.useCallback((e) => {
|
|
141
|
+
if (!pointerRef.current && !focusRing && !windowBlurredRef.current) {
|
|
142
|
+
setKeyboardFocus(true);
|
|
143
|
+
}
|
|
144
|
+
pointerRef.current = false;
|
|
145
|
+
onFocus?.(e);
|
|
146
|
+
}, [focusRing, onFocus]);
|
|
147
|
+
const handleBlur = React.useCallback((e) => {
|
|
148
|
+
setKeyboardFocus(false);
|
|
149
|
+
pointerRef.current = false;
|
|
150
|
+
onBlur?.(e);
|
|
151
|
+
}, [onBlur]);
|
|
152
|
+
const ariaDescribedBy = fieldContext ? [
|
|
153
|
+
resolvedError ? `${fieldContext.id}-error` : null
|
|
154
|
+
].filter(Boolean).join(" ") || void 0 : void 0;
|
|
155
|
+
const focusHandlers = {
|
|
156
|
+
onPointerDown: handlePointerDown,
|
|
157
|
+
onFocus: handleFocus,
|
|
158
|
+
onBlur: handleBlur
|
|
159
|
+
};
|
|
160
|
+
if (leftIcon || rightIcon) {
|
|
161
|
+
return /* @__PURE__ */ React.createElement("div", { className: "relative w-full" }, leftIcon && /* @__PURE__ */ React.createElement("div", { className: cn(
|
|
162
|
+
"absolute top-1/2 -translate-y-1/2 pointer-events-none text-text-muted z-10",
|
|
163
|
+
iconPositionClasses[resolvedSize].left,
|
|
164
|
+
`[&>svg]:${iconSizeClasses[resolvedSize]}`
|
|
165
|
+
) }, leftIcon), /* @__PURE__ */ React.createElement(
|
|
166
|
+
"input",
|
|
167
|
+
{
|
|
168
|
+
type,
|
|
169
|
+
id: inputId,
|
|
170
|
+
className: cn(
|
|
171
|
+
inputVariants({ variant, size, radius, state: resolvedState, focusRing }),
|
|
172
|
+
keyboardFocus && "shadow-[0_0_0_2px_var(--color-focus-ring)]",
|
|
173
|
+
leftIcon && iconPaddingClasses[resolvedSize].left,
|
|
174
|
+
rightIcon && iconPaddingClasses[resolvedSize].right,
|
|
175
|
+
className
|
|
176
|
+
),
|
|
177
|
+
"aria-invalid": resolvedError || void 0,
|
|
178
|
+
"aria-describedby": ariaDescribedBy,
|
|
179
|
+
disabled: isDisabled,
|
|
180
|
+
ref,
|
|
181
|
+
...focusHandlers,
|
|
182
|
+
...props
|
|
183
|
+
}
|
|
184
|
+
), rightIcon && /* @__PURE__ */ React.createElement("div", { className: cn(
|
|
185
|
+
"absolute top-1/2 -translate-y-1/2 pointer-events-none text-text-muted z-10",
|
|
186
|
+
iconPositionClasses[resolvedSize].right,
|
|
187
|
+
`[&>svg]:${iconSizeClasses[resolvedSize]}`
|
|
188
|
+
) }, rightIcon));
|
|
189
|
+
}
|
|
190
|
+
return /* @__PURE__ */ React.createElement(
|
|
191
|
+
"input",
|
|
192
|
+
{
|
|
193
|
+
type,
|
|
194
|
+
id: inputId,
|
|
195
|
+
className: cn(
|
|
196
|
+
inputVariants({ variant, size, radius, state: resolvedState, focusRing }),
|
|
197
|
+
keyboardFocus && "shadow-[0_0_0_2px_var(--color-focus-ring)]",
|
|
198
|
+
className
|
|
199
|
+
),
|
|
200
|
+
"aria-invalid": resolvedError || void 0,
|
|
201
|
+
"aria-describedby": ariaDescribedBy,
|
|
202
|
+
disabled: isDisabled,
|
|
203
|
+
ref,
|
|
204
|
+
...focusHandlers,
|
|
205
|
+
...props
|
|
206
|
+
}
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
);
|
|
210
|
+
Input.displayName = "Input";
|
|
211
|
+
export {
|
|
212
|
+
Input,
|
|
213
|
+
inputVariants
|
|
214
|
+
};
|
|
215
|
+
//# sourceMappingURL=input.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/ui/input.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '../../lib/utils'\nimport { useFieldContext } from './field'\n\nconst inputVariants = cva(\n [\n 'flex w-full bg-background text-foreground placeholder:text-foreground/30',\n 'border transition-colors duration-micro outline-transparent',\n 'focus:[outline:2px_solid_transparent]',\n 'disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-background-muted',\n 'file:border-0 file:bg-transparent file:text-sm file:font-semibold',\n ].join(' '),\n {\n variants: {\n variant: {\n default: 'border-border-form hover:border-border-form-strong',\n filled: 'border-transparent bg-background-muted',\n },\n focusRing: {\n true: '',\n false: '',\n },\n size: {\n xs: 'h-9 px-3 text-sm', // 36px / 12px padding / 13px font (3.0:1)\n sm: 'h-10 px-3 text-md', // 40px / 12px padding / 14px font (3.3:1)\n default: 'h-11 px-4 text-base', // 44px / 16px padding / 16px font (2.75:1)\n lg: 'h-12 px-4 text-base', // 48px / 16px padding / 16px font (3.0:1)\n xl: 'h-14 px-4 text-base', // 56px / 16px padding / 16px font (3.5:1)\n },\n radius: {\n none: 'rounded-none',\n sm: 'rounded-sm',\n base: 'rounded',\n default: 'rounded-md',\n lg: 'rounded-lg',\n xl: 'rounded-xl',\n '2xl': 'rounded-2xl',\n '3xl': 'rounded-3xl',\n full: 'rounded-full',\n },\n state: {\n default: '',\n error: 'border-error hover:border-error focus:border-error shadow-[0_0_0_2px_var(--color-focus-ring-error)]',\n },\n },\n compoundVariants: [\n // focusRing: true → show custom focus ring\n { focusRing: true, className: 'focus-visible:shadow-[0_0_0_2px_var(--color-focus-ring)]' },\n // focusRing: false → keep same state as hover\n { variant: 'default', focusRing: false, className: 'focus:border-border-form-strong' },\n // filled + error\n {\n variant: 'filled',\n state: 'error',\n className: 'border-transparent hover:border-transparent focus:border-transparent bg-[var(--color-error-bg)] hover:bg-[var(--color-error-bg)] focus:bg-[var(--color-error-bg)] shadow-none',\n },\n ],\n defaultVariants: {\n variant: 'default',\n size: 'default',\n radius: 'default',\n state: 'default',\n focusRing: false,\n },\n }\n)\n\nexport interface InputProps\n extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'>,\n VariantProps<typeof inputVariants> {\n leftIcon?: React.ReactNode\n rightIcon?: React.ReactNode\n error?: boolean\n focusRing?: boolean\n}\n\n// Icon size for input (2-step scale)\n// xs~sm: 14px, default~xl: 16px\nconst iconSizeClasses = {\n xs: 'icon-xs', // 14px\n sm: 'icon-xs', // 14px\n default: 'icon-sm', // 16px\n lg: 'icon-sm', // 16px\n xl: 'icon-sm', // 16px\n}\n\n// Icon padding (padding + icon + gap)\nconst iconPaddingClasses = {\n xs: { left: 'pl-8', right: 'pr-8' }, // 12px + 14px icon + 6px gap = 32px\n sm: { left: 'pl-9', right: 'pr-9' }, // 12px + 14px icon + 8px gap = 34px → 36px\n default: { left: 'pl-10', right: 'pr-10' }, // 16px + 16px icon + 8px gap = 40px\n lg: { left: 'pl-10', right: 'pr-10' }, // 16px + 16px icon + 8px gap = 40px\n xl: { left: 'pl-10', right: 'pr-10' }, // 16px + 16px icon + 8px gap = 40px\n}\n\n// Icon position (matches horizontal padding)\nconst iconPositionClasses = {\n xs: { left: 'left-3', right: 'right-3' }, // 12px\n sm: { left: 'left-3', right: 'right-3' }, // 12px\n default: { left: 'left-4', right: 'right-4' }, // 16px\n lg: { left: 'left-4', right: 'right-4' }, // 16px\n xl: { left: 'left-4', right: 'right-4' }, // 16px\n}\n\nconst Input = React.forwardRef<HTMLInputElement, InputProps>(\n ({ className, variant, size, radius, state, type, leftIcon, rightIcon, error, focusRing, id, onPointerDown, onFocus, onBlur, ...props }, ref) => {\n const fieldContext = useFieldContext()\n const resolvedSize = size || 'default'\n const resolvedError = error ?? fieldContext?.error\n const resolvedState = resolvedError ? 'error' : state\n const inputId = id ?? fieldContext?.id\n const isDisabled = props.disabled ?? fieldContext?.disabled\n\n // Keyboard focus detection (when focusRing: false, auto-show ring on Tab navigation)\n const pointerRef = React.useRef(false)\n const windowBlurredRef = React.useRef(false)\n const [keyboardFocus, setKeyboardFocus] = React.useState(false)\n\n // Track window blur/focus to distinguish Tab navigation from window re-activation\n React.useEffect(() => {\n const onBlur = () => { windowBlurredRef.current = true }\n const onFocus = () => { requestAnimationFrame(() => { windowBlurredRef.current = false }) }\n window.addEventListener('blur', onBlur)\n window.addEventListener('focus', onFocus)\n return () => { window.removeEventListener('blur', onBlur); window.removeEventListener('focus', onFocus) }\n }, [])\n\n const handlePointerDown = React.useCallback((e: React.PointerEvent<HTMLInputElement>) => {\n pointerRef.current = true\n onPointerDown?.(e)\n }, [onPointerDown])\n\n const handleFocus = React.useCallback((e: React.FocusEvent<HTMLInputElement>) => {\n if (!pointerRef.current && !focusRing && !windowBlurredRef.current) {\n setKeyboardFocus(true)\n }\n pointerRef.current = false\n onFocus?.(e)\n }, [focusRing, onFocus])\n\n const handleBlur = React.useCallback((e: React.FocusEvent<HTMLInputElement>) => {\n setKeyboardFocus(false)\n pointerRef.current = false\n onBlur?.(e)\n }, [onBlur])\n\n // Build aria-describedby from context\n const ariaDescribedBy = fieldContext\n ? [\n resolvedError ? `${fieldContext.id}-error` : null,\n ]\n .filter(Boolean)\n .join(' ') || undefined\n : undefined\n\n const focusHandlers = {\n onPointerDown: handlePointerDown,\n onFocus: handleFocus,\n onBlur: handleBlur,\n }\n\n // If icons are present, wrap input in a container\n if (leftIcon || rightIcon) {\n return (\n <div className=\"relative w-full\">\n {leftIcon && (\n <div className={cn(\n 'absolute top-1/2 -translate-y-1/2 pointer-events-none text-text-muted z-10',\n iconPositionClasses[resolvedSize].left,\n `[&>svg]:${iconSizeClasses[resolvedSize]}`\n )}>\n {leftIcon}\n </div>\n )}\n <input\n type={type}\n id={inputId}\n className={cn(\n inputVariants({ variant, size, radius, state: resolvedState, focusRing }),\n keyboardFocus && 'shadow-[0_0_0_2px_var(--color-focus-ring)]',\n leftIcon && iconPaddingClasses[resolvedSize].left,\n rightIcon && iconPaddingClasses[resolvedSize].right,\n className\n )}\n aria-invalid={resolvedError || undefined}\n aria-describedby={ariaDescribedBy}\n disabled={isDisabled}\n ref={ref}\n {...focusHandlers}\n {...props}\n />\n {rightIcon && (\n <div className={cn(\n 'absolute top-1/2 -translate-y-1/2 pointer-events-none text-text-muted z-10',\n iconPositionClasses[resolvedSize].right,\n `[&>svg]:${iconSizeClasses[resolvedSize]}`\n )}>\n {rightIcon}\n </div>\n )}\n </div>\n )\n }\n\n return (\n <input\n type={type}\n id={inputId}\n className={cn(\n inputVariants({ variant, size, radius, state: resolvedState, focusRing }),\n keyboardFocus && 'shadow-[0_0_0_2px_var(--color-focus-ring)]',\n className\n )}\n aria-invalid={resolvedError || undefined}\n aria-describedby={ariaDescribedBy}\n disabled={isDisabled}\n ref={ref}\n {...focusHandlers}\n {...props}\n />\n )\n }\n)\nInput.displayName = 'Input'\n\nexport { Input, inputVariants }\n"],"mappings":"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","names":["onBlur","onFocus"]}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import * as class_variance_authority_types from 'class-variance-authority/types';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { VariantProps } from 'class-variance-authority';
|
|
4
|
+
|
|
5
|
+
declare const metricCardVariants: (props?: ({
|
|
6
|
+
variant?: "default" | "ghost" | "elevated" | null | undefined;
|
|
7
|
+
size?: "default" | "sm" | "lg" | null | undefined;
|
|
8
|
+
radius?: "default" | "sm" | "lg" | "base" | "none" | "xl" | "2xl" | "3xl" | "full" | null | undefined;
|
|
9
|
+
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
10
|
+
type MetricCardVariant = 'default' | 'elevated' | 'ghost';
|
|
11
|
+
type MetricCardSize = 'sm' | 'default' | 'lg';
|
|
12
|
+
type MetricCardRadius = 'none' | 'sm' | 'base' | 'default' | 'lg' | 'xl' | '2xl' | '3xl' | 'full';
|
|
13
|
+
type MetricCardTrendDirection = 'up' | 'down' | 'neutral';
|
|
14
|
+
interface MetricCardProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof metricCardVariants> {
|
|
15
|
+
animated?: boolean;
|
|
16
|
+
}
|
|
17
|
+
interface MetricCardHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
18
|
+
}
|
|
19
|
+
declare const MetricCardHeader: React.ForwardRefExoticComponent<MetricCardHeaderProps & React.RefAttributes<HTMLDivElement>>;
|
|
20
|
+
interface MetricCardTitleProps extends React.HTMLAttributes<HTMLParagraphElement> {
|
|
21
|
+
}
|
|
22
|
+
declare const MetricCardTitle: React.ForwardRefExoticComponent<MetricCardTitleProps & React.RefAttributes<HTMLParagraphElement>>;
|
|
23
|
+
interface MetricCardValueProps extends React.HTMLAttributes<HTMLParagraphElement> {
|
|
24
|
+
}
|
|
25
|
+
declare const MetricCardValue: React.ForwardRefExoticComponent<MetricCardValueProps & React.RefAttributes<HTMLParagraphElement>>;
|
|
26
|
+
interface MetricCardTrendProps extends React.HTMLAttributes<HTMLParagraphElement> {
|
|
27
|
+
direction: MetricCardTrendDirection;
|
|
28
|
+
}
|
|
29
|
+
declare const MetricCardTrend: React.ForwardRefExoticComponent<MetricCardTrendProps & React.RefAttributes<HTMLParagraphElement>>;
|
|
30
|
+
interface MetricCardDescriptionProps extends React.HTMLAttributes<HTMLParagraphElement> {
|
|
31
|
+
}
|
|
32
|
+
declare const MetricCardDescription: React.ForwardRefExoticComponent<MetricCardDescriptionProps & React.RefAttributes<HTMLParagraphElement>>;
|
|
33
|
+
interface MetricCardSymbolProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
34
|
+
}
|
|
35
|
+
declare const MetricCardSymbol: React.ForwardRefExoticComponent<MetricCardSymbolProps & React.RefAttributes<HTMLDivElement>>;
|
|
36
|
+
declare const MetricCard: React.ForwardRefExoticComponent<MetricCardProps & React.RefAttributes<HTMLDivElement>> & {
|
|
37
|
+
Header: React.ForwardRefExoticComponent<MetricCardHeaderProps & React.RefAttributes<HTMLDivElement>>;
|
|
38
|
+
Title: React.ForwardRefExoticComponent<MetricCardTitleProps & React.RefAttributes<HTMLParagraphElement>>;
|
|
39
|
+
Value: React.ForwardRefExoticComponent<MetricCardValueProps & React.RefAttributes<HTMLParagraphElement>>;
|
|
40
|
+
Trend: React.ForwardRefExoticComponent<MetricCardTrendProps & React.RefAttributes<HTMLParagraphElement>>;
|
|
41
|
+
Description: React.ForwardRefExoticComponent<MetricCardDescriptionProps & React.RefAttributes<HTMLParagraphElement>>;
|
|
42
|
+
Symbol: React.ForwardRefExoticComponent<MetricCardSymbolProps & React.RefAttributes<HTMLDivElement>>;
|
|
43
|
+
};
|
|
44
|
+
declare namespace MetricCard {
|
|
45
|
+
type HeaderProps = MetricCardHeaderProps;
|
|
46
|
+
type TitleProps = MetricCardTitleProps;
|
|
47
|
+
type ValueProps = MetricCardValueProps;
|
|
48
|
+
type TrendProps = MetricCardTrendProps;
|
|
49
|
+
type DescriptionProps = MetricCardDescriptionProps;
|
|
50
|
+
type SymbolProps = MetricCardSymbolProps;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export { MetricCard, MetricCardDescription, type MetricCardDescriptionProps, MetricCardHeader, type MetricCardHeaderProps, type MetricCardProps, type MetricCardRadius, type MetricCardSize, MetricCardSymbol, type MetricCardSymbolProps, MetricCardTitle, type MetricCardTitleProps, MetricCardTrend, type MetricCardTrendDirection, type MetricCardTrendProps, MetricCardValue, type MetricCardValueProps, type MetricCardVariant, metricCardVariants };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import * as class_variance_authority_types from 'class-variance-authority/types';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { VariantProps } from 'class-variance-authority';
|
|
4
|
+
|
|
5
|
+
declare const metricCardVariants: (props?: ({
|
|
6
|
+
variant?: "default" | "ghost" | "elevated" | null | undefined;
|
|
7
|
+
size?: "default" | "sm" | "lg" | null | undefined;
|
|
8
|
+
radius?: "default" | "sm" | "lg" | "base" | "none" | "xl" | "2xl" | "3xl" | "full" | null | undefined;
|
|
9
|
+
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
10
|
+
type MetricCardVariant = 'default' | 'elevated' | 'ghost';
|
|
11
|
+
type MetricCardSize = 'sm' | 'default' | 'lg';
|
|
12
|
+
type MetricCardRadius = 'none' | 'sm' | 'base' | 'default' | 'lg' | 'xl' | '2xl' | '3xl' | 'full';
|
|
13
|
+
type MetricCardTrendDirection = 'up' | 'down' | 'neutral';
|
|
14
|
+
interface MetricCardProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof metricCardVariants> {
|
|
15
|
+
animated?: boolean;
|
|
16
|
+
}
|
|
17
|
+
interface MetricCardHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
18
|
+
}
|
|
19
|
+
declare const MetricCardHeader: React.ForwardRefExoticComponent<MetricCardHeaderProps & React.RefAttributes<HTMLDivElement>>;
|
|
20
|
+
interface MetricCardTitleProps extends React.HTMLAttributes<HTMLParagraphElement> {
|
|
21
|
+
}
|
|
22
|
+
declare const MetricCardTitle: React.ForwardRefExoticComponent<MetricCardTitleProps & React.RefAttributes<HTMLParagraphElement>>;
|
|
23
|
+
interface MetricCardValueProps extends React.HTMLAttributes<HTMLParagraphElement> {
|
|
24
|
+
}
|
|
25
|
+
declare const MetricCardValue: React.ForwardRefExoticComponent<MetricCardValueProps & React.RefAttributes<HTMLParagraphElement>>;
|
|
26
|
+
interface MetricCardTrendProps extends React.HTMLAttributes<HTMLParagraphElement> {
|
|
27
|
+
direction: MetricCardTrendDirection;
|
|
28
|
+
}
|
|
29
|
+
declare const MetricCardTrend: React.ForwardRefExoticComponent<MetricCardTrendProps & React.RefAttributes<HTMLParagraphElement>>;
|
|
30
|
+
interface MetricCardDescriptionProps extends React.HTMLAttributes<HTMLParagraphElement> {
|
|
31
|
+
}
|
|
32
|
+
declare const MetricCardDescription: React.ForwardRefExoticComponent<MetricCardDescriptionProps & React.RefAttributes<HTMLParagraphElement>>;
|
|
33
|
+
interface MetricCardSymbolProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
34
|
+
}
|
|
35
|
+
declare const MetricCardSymbol: React.ForwardRefExoticComponent<MetricCardSymbolProps & React.RefAttributes<HTMLDivElement>>;
|
|
36
|
+
declare const MetricCard: React.ForwardRefExoticComponent<MetricCardProps & React.RefAttributes<HTMLDivElement>> & {
|
|
37
|
+
Header: React.ForwardRefExoticComponent<MetricCardHeaderProps & React.RefAttributes<HTMLDivElement>>;
|
|
38
|
+
Title: React.ForwardRefExoticComponent<MetricCardTitleProps & React.RefAttributes<HTMLParagraphElement>>;
|
|
39
|
+
Value: React.ForwardRefExoticComponent<MetricCardValueProps & React.RefAttributes<HTMLParagraphElement>>;
|
|
40
|
+
Trend: React.ForwardRefExoticComponent<MetricCardTrendProps & React.RefAttributes<HTMLParagraphElement>>;
|
|
41
|
+
Description: React.ForwardRefExoticComponent<MetricCardDescriptionProps & React.RefAttributes<HTMLParagraphElement>>;
|
|
42
|
+
Symbol: React.ForwardRefExoticComponent<MetricCardSymbolProps & React.RefAttributes<HTMLDivElement>>;
|
|
43
|
+
};
|
|
44
|
+
declare namespace MetricCard {
|
|
45
|
+
type HeaderProps = MetricCardHeaderProps;
|
|
46
|
+
type TitleProps = MetricCardTitleProps;
|
|
47
|
+
type ValueProps = MetricCardValueProps;
|
|
48
|
+
type TrendProps = MetricCardTrendProps;
|
|
49
|
+
type DescriptionProps = MetricCardDescriptionProps;
|
|
50
|
+
type SymbolProps = MetricCardSymbolProps;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export { MetricCard, MetricCardDescription, type MetricCardDescriptionProps, MetricCardHeader, type MetricCardHeaderProps, type MetricCardProps, type MetricCardRadius, type MetricCardSize, MetricCardSymbol, type MetricCardSymbolProps, MetricCardTitle, type MetricCardTitleProps, MetricCardTrend, type MetricCardTrendDirection, type MetricCardTrendProps, MetricCardValue, type MetricCardValueProps, type MetricCardVariant, metricCardVariants };
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
var metric_card_exports = {};
|
|
31
|
+
__export(metric_card_exports, {
|
|
32
|
+
MetricCard: () => MetricCard,
|
|
33
|
+
MetricCardDescription: () => MetricCardDescription,
|
|
34
|
+
MetricCardHeader: () => MetricCardHeader,
|
|
35
|
+
MetricCardSymbol: () => MetricCardSymbol,
|
|
36
|
+
MetricCardTitle: () => MetricCardTitle,
|
|
37
|
+
MetricCardTrend: () => MetricCardTrend,
|
|
38
|
+
MetricCardValue: () => MetricCardValue,
|
|
39
|
+
metricCardVariants: () => metricCardVariants
|
|
40
|
+
});
|
|
41
|
+
module.exports = __toCommonJS(metric_card_exports);
|
|
42
|
+
var React = __toESM(require("react"));
|
|
43
|
+
var import_class_variance_authority = require("class-variance-authority");
|
|
44
|
+
var import_utils = require("../../lib/utils");
|
|
45
|
+
const metricCardVariants = (0, import_class_variance_authority.cva)(
|
|
46
|
+
"transition-colors",
|
|
47
|
+
{
|
|
48
|
+
variants: {
|
|
49
|
+
variant: {
|
|
50
|
+
default: "bg-background-paper border border-border",
|
|
51
|
+
elevated: "bg-background-paper shadow-md",
|
|
52
|
+
ghost: "bg-transparent"
|
|
53
|
+
},
|
|
54
|
+
size: {
|
|
55
|
+
sm: "p-4",
|
|
56
|
+
default: "p-4 sm:p-5",
|
|
57
|
+
lg: "p-4 sm:p-6"
|
|
58
|
+
},
|
|
59
|
+
radius: {
|
|
60
|
+
none: "rounded-none",
|
|
61
|
+
// 0px
|
|
62
|
+
sm: "rounded-sm",
|
|
63
|
+
// 2px
|
|
64
|
+
base: "rounded",
|
|
65
|
+
// 4px
|
|
66
|
+
default: "rounded-xl",
|
|
67
|
+
// 12px - card default
|
|
68
|
+
lg: "rounded-lg",
|
|
69
|
+
// 8px
|
|
70
|
+
xl: "rounded-xl",
|
|
71
|
+
// 12px
|
|
72
|
+
"2xl": "rounded-2xl",
|
|
73
|
+
// 16px
|
|
74
|
+
"3xl": "rounded-3xl",
|
|
75
|
+
// 24px
|
|
76
|
+
full: "rounded-full"
|
|
77
|
+
// 9999px
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
defaultVariants: { variant: "default", size: "default", radius: "default" }
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
const valueSizes = {
|
|
84
|
+
sm: "text-xl",
|
|
85
|
+
default: "text-2xl",
|
|
86
|
+
lg: "text-3xl"
|
|
87
|
+
};
|
|
88
|
+
const titleSizes = {
|
|
89
|
+
sm: "text-xs",
|
|
90
|
+
default: "text-sm",
|
|
91
|
+
lg: "text-sm"
|
|
92
|
+
};
|
|
93
|
+
const iconWrapperSizes = {
|
|
94
|
+
sm: "[&>svg]:icon-sm",
|
|
95
|
+
default: "[&>svg]:icon-md",
|
|
96
|
+
lg: "[&>svg]:icon-lg"
|
|
97
|
+
};
|
|
98
|
+
const trendConfig = {
|
|
99
|
+
up: { color: "text-text-success", srLabel: "Increased" },
|
|
100
|
+
down: { color: "text-text-error", srLabel: "Decreased" },
|
|
101
|
+
neutral: { color: "text-text-muted", srLabel: "No change" }
|
|
102
|
+
};
|
|
103
|
+
const MetricCardContext = React.createContext({ size: "default", animated: false });
|
|
104
|
+
const MetricCardRoot = React.forwardRef(
|
|
105
|
+
({ className, variant, size, radius, animated = false, children, ...props }, ref) => {
|
|
106
|
+
const resolvedSize = size || "default";
|
|
107
|
+
return /* @__PURE__ */ React.createElement(MetricCardContext.Provider, { value: { size: resolvedSize, animated } }, /* @__PURE__ */ React.createElement(
|
|
108
|
+
"div",
|
|
109
|
+
{
|
|
110
|
+
ref,
|
|
111
|
+
className: (0, import_utils.cn)(metricCardVariants({ variant, size, radius }), className),
|
|
112
|
+
...props
|
|
113
|
+
},
|
|
114
|
+
children
|
|
115
|
+
));
|
|
116
|
+
}
|
|
117
|
+
);
|
|
118
|
+
MetricCardRoot.displayName = "MetricCard";
|
|
119
|
+
const MetricCardHeader = React.forwardRef(
|
|
120
|
+
({ className, ...props }, ref) => /* @__PURE__ */ React.createElement(
|
|
121
|
+
"div",
|
|
122
|
+
{
|
|
123
|
+
ref,
|
|
124
|
+
className: (0, import_utils.cn)("flex items-center justify-between gap-2", className),
|
|
125
|
+
...props
|
|
126
|
+
}
|
|
127
|
+
)
|
|
128
|
+
);
|
|
129
|
+
MetricCardHeader.displayName = "MetricCardHeader";
|
|
130
|
+
const MetricCardTitle = React.forwardRef(
|
|
131
|
+
({ className, ...props }, ref) => {
|
|
132
|
+
const { size } = React.useContext(MetricCardContext);
|
|
133
|
+
return /* @__PURE__ */ React.createElement(
|
|
134
|
+
"p",
|
|
135
|
+
{
|
|
136
|
+
ref,
|
|
137
|
+
className: (0, import_utils.cn)(titleSizes[size], "font-semibold text-text-muted", className),
|
|
138
|
+
...props
|
|
139
|
+
}
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
);
|
|
143
|
+
MetricCardTitle.displayName = "MetricCardTitle";
|
|
144
|
+
const MetricCardValue = React.forwardRef(
|
|
145
|
+
({ className, children, ...props }, ref) => {
|
|
146
|
+
const { size, animated } = React.useContext(MetricCardContext);
|
|
147
|
+
const [display, setDisplay] = React.useState(children);
|
|
148
|
+
React.useEffect(() => {
|
|
149
|
+
if (!animated || typeof children !== "string") {
|
|
150
|
+
setDisplay(children);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const numMatch = children.match(/[\d,.]+/);
|
|
154
|
+
if (!numMatch) {
|
|
155
|
+
setDisplay(children);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
const numStr = numMatch[0].replace(/,/g, "");
|
|
159
|
+
const target = parseFloat(numStr);
|
|
160
|
+
if (isNaN(target)) {
|
|
161
|
+
setDisplay(children);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const prefix = children.slice(0, children.indexOf(numMatch[0]));
|
|
165
|
+
const suffix = children.slice(children.indexOf(numMatch[0]) + numMatch[0].length);
|
|
166
|
+
const steps = 24;
|
|
167
|
+
const duration = 700;
|
|
168
|
+
let step = 0;
|
|
169
|
+
setDisplay(prefix + "0" + suffix);
|
|
170
|
+
const timer = setInterval(() => {
|
|
171
|
+
step++;
|
|
172
|
+
const eased = 1 - Math.pow(1 - step / steps, 3);
|
|
173
|
+
const current = target * eased;
|
|
174
|
+
const formatted = target >= 1e3 ? Math.floor(current).toLocaleString() : current.toFixed(numStr.includes(".") ? 2 : 0);
|
|
175
|
+
setDisplay(prefix + formatted + suffix);
|
|
176
|
+
if (step >= steps) {
|
|
177
|
+
setDisplay(children);
|
|
178
|
+
clearInterval(timer);
|
|
179
|
+
}
|
|
180
|
+
}, duration / steps);
|
|
181
|
+
return () => clearInterval(timer);
|
|
182
|
+
}, [children, animated]);
|
|
183
|
+
return /* @__PURE__ */ React.createElement(
|
|
184
|
+
"p",
|
|
185
|
+
{
|
|
186
|
+
ref,
|
|
187
|
+
className: (0, import_utils.cn)(valueSizes[size], "font-bold text-foreground mt-1", className),
|
|
188
|
+
...props
|
|
189
|
+
},
|
|
190
|
+
display
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
);
|
|
194
|
+
MetricCardValue.displayName = "MetricCardValue";
|
|
195
|
+
const MetricCardTrend = React.forwardRef(
|
|
196
|
+
({ className, direction, children, ...props }, ref) => {
|
|
197
|
+
const config = trendConfig[direction];
|
|
198
|
+
return /* @__PURE__ */ React.createElement(
|
|
199
|
+
"p",
|
|
200
|
+
{
|
|
201
|
+
ref,
|
|
202
|
+
className: (0, import_utils.cn)("flex items-center gap-1 text-sm mt-2", config.color, className),
|
|
203
|
+
...props
|
|
204
|
+
},
|
|
205
|
+
direction === "up" && /* @__PURE__ */ React.createElement("svg", { className: "icon-xs", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2.5, "aria-hidden": "true" }, /* @__PURE__ */ React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.5 15.75l7.5-7.5 7.5 7.5" })),
|
|
206
|
+
direction === "down" && /* @__PURE__ */ React.createElement("svg", { className: "icon-xs", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2.5, "aria-hidden": "true" }, /* @__PURE__ */ React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19.5 8.25l-7.5 7.5-7.5-7.5" })),
|
|
207
|
+
direction === "neutral" && /* @__PURE__ */ React.createElement("svg", { className: "icon-xs", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2.5, "aria-hidden": "true" }, /* @__PURE__ */ React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 12h14" })),
|
|
208
|
+
/* @__PURE__ */ React.createElement("span", { className: "sr-only" }, config.srLabel),
|
|
209
|
+
children
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
);
|
|
213
|
+
MetricCardTrend.displayName = "MetricCardTrend";
|
|
214
|
+
const MetricCardDescription = React.forwardRef(
|
|
215
|
+
({ className, ...props }, ref) => /* @__PURE__ */ React.createElement(
|
|
216
|
+
"p",
|
|
217
|
+
{
|
|
218
|
+
ref,
|
|
219
|
+
className: (0, import_utils.cn)("text-xs text-text-muted mt-1", className),
|
|
220
|
+
...props
|
|
221
|
+
}
|
|
222
|
+
)
|
|
223
|
+
);
|
|
224
|
+
MetricCardDescription.displayName = "MetricCardDescription";
|
|
225
|
+
const MetricCardSymbol = React.forwardRef(
|
|
226
|
+
({ className, ...props }, ref) => {
|
|
227
|
+
const { size } = React.useContext(MetricCardContext);
|
|
228
|
+
return /* @__PURE__ */ React.createElement(
|
|
229
|
+
"div",
|
|
230
|
+
{
|
|
231
|
+
ref,
|
|
232
|
+
className: (0, import_utils.cn)("text-text-muted", iconWrapperSizes[size], className),
|
|
233
|
+
...props
|
|
234
|
+
}
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
);
|
|
238
|
+
MetricCardSymbol.displayName = "MetricCardSymbol";
|
|
239
|
+
const MetricCard = Object.assign(MetricCardRoot, {
|
|
240
|
+
Header: MetricCardHeader,
|
|
241
|
+
Title: MetricCardTitle,
|
|
242
|
+
Value: MetricCardValue,
|
|
243
|
+
Trend: MetricCardTrend,
|
|
244
|
+
Description: MetricCardDescription,
|
|
245
|
+
Symbol: MetricCardSymbol
|
|
246
|
+
});
|
|
247
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
248
|
+
0 && (module.exports = {
|
|
249
|
+
MetricCard,
|
|
250
|
+
MetricCardDescription,
|
|
251
|
+
MetricCardHeader,
|
|
252
|
+
MetricCardSymbol,
|
|
253
|
+
MetricCardTitle,
|
|
254
|
+
MetricCardTrend,
|
|
255
|
+
MetricCardValue,
|
|
256
|
+
metricCardVariants
|
|
257
|
+
});
|
|
258
|
+
//# sourceMappingURL=metric-card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/ui/metric-card.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '../../lib/utils'\n\n// ── CVA Variants ──\n\nconst metricCardVariants = cva(\n 'transition-colors',\n {\n variants: {\n variant: {\n default: 'bg-background-paper border border-border',\n elevated: 'bg-background-paper shadow-md',\n ghost: 'bg-transparent',\n },\n size: {\n sm: 'p-4',\n default: 'p-4 sm:p-5',\n lg: 'p-4 sm:p-6',\n },\n radius: {\n none: 'rounded-none', // 0px\n sm: 'rounded-sm', // 2px\n base: 'rounded', // 4px\n default: 'rounded-xl', // 12px - card default\n lg: 'rounded-lg', // 8px\n xl: 'rounded-xl', // 12px\n '2xl': 'rounded-2xl', // 16px\n '3xl': 'rounded-3xl', // 24px\n full: 'rounded-full', // 9999px\n },\n },\n defaultVariants: { variant: 'default', size: 'default', radius: 'default' },\n }\n)\n\n// ── Size maps ──\n\nconst valueSizes = {\n sm: 'text-xl',\n default: 'text-2xl',\n lg: 'text-3xl',\n} as const\n\nconst titleSizes = {\n sm: 'text-xs',\n default: 'text-sm',\n lg: 'text-sm',\n} as const\n\nconst iconWrapperSizes = {\n sm: '[&>svg]:icon-sm',\n default: '[&>svg]:icon-md',\n lg: '[&>svg]:icon-lg',\n} as const\n\n// ── Trend config ──\n\nconst trendConfig = {\n up: { color: 'text-text-success', srLabel: 'Increased' },\n down: { color: 'text-text-error', srLabel: 'Decreased' },\n neutral: { color: 'text-text-muted', srLabel: 'No change' },\n} as const\n\n// ── Context ──\n\ntype MetricCardContextValue = { size: 'sm' | 'default' | 'lg'; animated: boolean }\nconst MetricCardContext = React.createContext<MetricCardContextValue>({ size: 'default', animated: false })\n\n// ── Types ──\n\nexport type MetricCardVariant = 'default' | 'elevated' | 'ghost'\nexport type MetricCardSize = 'sm' | 'default' | 'lg'\nexport type MetricCardRadius = 'none' | 'sm' | 'base' | 'default' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\nexport type MetricCardTrendDirection = 'up' | 'down' | 'neutral'\n\n// ── MetricCard (root) ──\n\nexport interface MetricCardProps\n extends React.HTMLAttributes<HTMLDivElement>,\n VariantProps<typeof metricCardVariants> {\n animated?: boolean\n}\n\nconst MetricCardRoot = React.forwardRef<HTMLDivElement, MetricCardProps>(\n ({ className, variant, size, radius, animated = false, children, ...props }, ref) => {\n const resolvedSize = (size || 'default') as MetricCardSize\n return (\n <MetricCardContext.Provider value={{ size: resolvedSize, animated }}>\n <div\n ref={ref}\n className={cn(metricCardVariants({ variant, size, radius }), className)}\n {...props}\n >\n {children}\n </div>\n </MetricCardContext.Provider>\n )\n }\n)\nMetricCardRoot.displayName = 'MetricCard'\n\n// ── MetricCardHeader ──\n\nexport interface MetricCardHeaderProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nconst MetricCardHeader = React.forwardRef<HTMLDivElement, MetricCardHeaderProps>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('flex items-center justify-between gap-2', className)}\n {...props}\n />\n )\n)\nMetricCardHeader.displayName = 'MetricCardHeader'\n\n// ── MetricCardTitle ──\n\nexport interface MetricCardTitleProps extends React.HTMLAttributes<HTMLParagraphElement> {}\n\nconst MetricCardTitle = React.forwardRef<HTMLParagraphElement, MetricCardTitleProps>(\n ({ className, ...props }, ref) => {\n const { size } = React.useContext(MetricCardContext)\n return (\n <p\n ref={ref}\n className={cn(titleSizes[size], 'font-semibold text-text-muted', className)}\n {...props}\n />\n )\n }\n)\nMetricCardTitle.displayName = 'MetricCardTitle'\n\n// ── MetricCardValue ──\n\nexport interface MetricCardValueProps extends React.HTMLAttributes<HTMLParagraphElement> {}\n\nconst MetricCardValue = React.forwardRef<HTMLParagraphElement, MetricCardValueProps>(\n ({ className, children, ...props }, ref) => {\n const { size, animated } = React.useContext(MetricCardContext)\n const [display, setDisplay] = React.useState<React.ReactNode>(children)\n\n React.useEffect(() => {\n if (!animated || typeof children !== 'string') { setDisplay(children); return }\n const numMatch = children.match(/[\\d,.]+/)\n if (!numMatch) { setDisplay(children); return }\n const numStr = numMatch[0].replace(/,/g, '')\n const target = parseFloat(numStr)\n if (isNaN(target)) { setDisplay(children); return }\n const prefix = children.slice(0, children.indexOf(numMatch[0]))\n const suffix = children.slice(children.indexOf(numMatch[0]) + numMatch[0].length)\n const steps = 24\n const duration = 700\n let step = 0\n setDisplay(prefix + '0' + suffix)\n const timer = setInterval(() => {\n step++\n const eased = 1 - Math.pow(1 - step / steps, 3)\n const current = target * eased\n const formatted = target >= 1000\n ? Math.floor(current).toLocaleString()\n : current.toFixed(numStr.includes('.') ? 2 : 0)\n setDisplay(prefix + formatted + suffix)\n if (step >= steps) { setDisplay(children); clearInterval(timer) }\n }, duration / steps)\n return () => clearInterval(timer)\n }, [children, animated])\n\n return (\n <p\n ref={ref}\n className={cn(valueSizes[size], 'font-bold text-foreground mt-1', className)}\n {...props}\n >\n {display}\n </p>\n )\n }\n)\nMetricCardValue.displayName = 'MetricCardValue'\n\n// ── MetricCardTrend ──\n\nexport interface MetricCardTrendProps extends React.HTMLAttributes<HTMLParagraphElement> {\n direction: MetricCardTrendDirection\n}\n\nconst MetricCardTrend = React.forwardRef<HTMLParagraphElement, MetricCardTrendProps>(\n ({ className, direction, children, ...props }, ref) => {\n const config = trendConfig[direction]\n return (\n <p\n ref={ref}\n className={cn('flex items-center gap-1 text-sm mt-2', config.color, className)}\n {...props}\n >\n {direction === 'up' && (\n <svg className=\"icon-xs\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2.5} aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M4.5 15.75l7.5-7.5 7.5 7.5\" />\n </svg>\n )}\n {direction === 'down' && (\n <svg className=\"icon-xs\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2.5} aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M19.5 8.25l-7.5 7.5-7.5-7.5\" />\n </svg>\n )}\n {direction === 'neutral' && (\n <svg className=\"icon-xs\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2.5} aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 12h14\" />\n </svg>\n )}\n <span className=\"sr-only\">{config.srLabel}</span>\n {children}\n </p>\n )\n }\n)\nMetricCardTrend.displayName = 'MetricCardTrend'\n\n// ── MetricCardDescription ──\n\nexport interface MetricCardDescriptionProps extends React.HTMLAttributes<HTMLParagraphElement> {}\n\nconst MetricCardDescription = React.forwardRef<HTMLParagraphElement, MetricCardDescriptionProps>(\n ({ className, ...props }, ref) => (\n <p\n ref={ref}\n className={cn('text-xs text-text-muted mt-1', className)}\n {...props}\n />\n )\n)\nMetricCardDescription.displayName = 'MetricCardDescription'\n\n// ── MetricCardSymbol ──\n\nexport interface MetricCardSymbolProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nconst MetricCardSymbol = React.forwardRef<HTMLDivElement, MetricCardSymbolProps>(\n ({ className, ...props }, ref) => {\n const { size } = React.useContext(MetricCardContext)\n return (\n <div\n ref={ref}\n className={cn('text-text-muted', iconWrapperSizes[size], className)}\n {...props}\n />\n )\n }\n)\nMetricCardSymbol.displayName = 'MetricCardSymbol'\n\n// ── Exports ──\n\n// ─── Namespace ──────────────────────────────────────────\nconst MetricCard = Object.assign(MetricCardRoot, {\n Header: MetricCardHeader,\n Title: MetricCardTitle,\n Value: MetricCardValue,\n Trend: MetricCardTrend,\n Description: MetricCardDescription,\n Symbol: MetricCardSymbol,\n})\n\n// eslint-disable-next-line @typescript-eslint/no-namespace\nnamespace MetricCard {\n export type HeaderProps = MetricCardHeaderProps\n export type TitleProps = MetricCardTitleProps\n export type ValueProps = MetricCardValueProps\n export type TrendProps = MetricCardTrendProps\n export type DescriptionProps = MetricCardDescriptionProps\n export type SymbolProps = MetricCardSymbolProps\n}\n\nexport {\n MetricCard,\n MetricCardHeader,\n MetricCardTitle,\n MetricCardValue,\n MetricCardTrend,\n MetricCardDescription,\n MetricCardSymbol,\n metricCardVariants,\n}\n"],"mappings":"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","names":[]}
|