@stasho/ds 0.1.0 → 0.2.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/package.json +1 -2
- package/src/components/alert/alert.tsx +14 -14
- package/src/components/badge/badge.tsx +15 -29
- package/src/components/breadcrumb/breadcrumb.tsx +4 -4
- package/src/components/button/button.tsx +203 -55
- package/src/components/card/card.tsx +2 -3
- package/src/components/checkbox/checkbox.tsx +21 -23
- package/src/components/combobox/combobox.tsx +20 -13
- package/src/components/copyable-text/copyable-text.tsx +3 -3
- package/src/components/dialog/dialog.tsx +3 -4
- package/src/components/form-field/form-field.tsx +2 -2
- package/src/components/input/input.tsx +13 -7
- package/src/components/multi-select/multi-select.tsx +26 -18
- package/src/components/pagination/pagination.tsx +11 -13
- package/src/components/progress-bar/progress-bar.tsx +6 -2
- package/src/components/radio-group/radio-group.tsx +15 -10
- package/src/components/select/select.tsx +19 -12
- package/src/components/slider/slider.tsx +25 -19
- package/src/components/stepper/stepper.tsx +20 -16
- package/src/components/switch/switch.tsx +23 -16
- package/src/components/table/table.tsx +3 -3
- package/src/components/tabs/tabs.tsx +24 -33
- package/src/components/textarea/textarea.tsx +13 -7
- package/src/components/tooltip/tooltip.tsx +2 -2
- package/src/components/ui/skeleton.tsx +1 -1
- package/src/styles/tokens.css +202 -283
- package/src/components/ui/spinner.tsx +0 -27
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stasho/ds",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "stasho design system",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -41,7 +41,6 @@
|
|
|
41
41
|
"./slider": "./src/components/slider/slider.tsx",
|
|
42
42
|
"./radio-group": "./src/components/radio-group/radio-group.tsx",
|
|
43
43
|
"./ui/skeleton": "./src/components/ui/skeleton.tsx",
|
|
44
|
-
"./ui/spinner": "./src/components/ui/spinner.tsx",
|
|
45
44
|
"./multi-select": "./src/components/multi-select/multi-select.tsx",
|
|
46
45
|
"./pagination": "./src/components/pagination/pagination.tsx",
|
|
47
46
|
"./copyable-text": "./src/components/copyable-text/copyable-text.tsx",
|
|
@@ -30,7 +30,7 @@ const VARIANT_BG_CLASS: Record<AlertVariant, string> = {
|
|
|
30
30
|
|
|
31
31
|
const alertVariants = cva(
|
|
32
32
|
[
|
|
33
|
-
"relative overflow-hidden rounded-
|
|
33
|
+
"relative overflow-hidden rounded-none border",
|
|
34
34
|
"px-3 py-2",
|
|
35
35
|
"transition-all duration-200",
|
|
36
36
|
"motion-reduce:transition-none",
|
|
@@ -38,10 +38,10 @@ const alertVariants = cva(
|
|
|
38
38
|
{
|
|
39
39
|
variants: {
|
|
40
40
|
variant: {
|
|
41
|
-
warning: "border-warning
|
|
42
|
-
error: "border-error
|
|
43
|
-
info: "border-
|
|
44
|
-
success: "border-success
|
|
41
|
+
warning: "border-warning",
|
|
42
|
+
error: "border-error",
|
|
43
|
+
info: "border-accent",
|
|
44
|
+
success: "border-success",
|
|
45
45
|
},
|
|
46
46
|
},
|
|
47
47
|
defaultVariants: {
|
|
@@ -51,14 +51,14 @@ const alertVariants = cva(
|
|
|
51
51
|
);
|
|
52
52
|
|
|
53
53
|
const labelVariants = cva(
|
|
54
|
-
"font-
|
|
54
|
+
"font-mono uppercase tracking-wider text-[11px] leading-normal pb-1",
|
|
55
55
|
{
|
|
56
56
|
variants: {
|
|
57
57
|
variant: {
|
|
58
|
-
warning: "text-warning-
|
|
59
|
-
error: "text-error-
|
|
60
|
-
info: "text-
|
|
61
|
-
success: "text-success-
|
|
58
|
+
warning: "text-warning-500 dark:text-warning",
|
|
59
|
+
error: "text-error-500 dark:text-error",
|
|
60
|
+
info: "text-accent-500 dark:text-accent",
|
|
61
|
+
success: "text-success-500 dark:text-success",
|
|
62
62
|
},
|
|
63
63
|
},
|
|
64
64
|
},
|
|
@@ -67,10 +67,10 @@ const labelVariants = cva(
|
|
|
67
67
|
const progressVariants = cva("absolute bottom-0 left-0 h-0.5", {
|
|
68
68
|
variants: {
|
|
69
69
|
variant: {
|
|
70
|
-
warning: "bg-warning
|
|
71
|
-
error: "bg-error
|
|
72
|
-
info: "bg-
|
|
73
|
-
success: "bg-success
|
|
70
|
+
warning: "bg-warning",
|
|
71
|
+
error: "bg-error",
|
|
72
|
+
info: "bg-accent",
|
|
73
|
+
success: "bg-success",
|
|
74
74
|
},
|
|
75
75
|
},
|
|
76
76
|
});
|
|
@@ -5,7 +5,7 @@ import { cn } from "@ac/lib/cn";
|
|
|
5
5
|
const badgeVariants = cva(
|
|
6
6
|
[
|
|
7
7
|
"inline-flex items-center justify-center gap-1.5",
|
|
8
|
-
"rounded-
|
|
8
|
+
"rounded-[2px] font-mono uppercase tracking-wider",
|
|
9
9
|
"whitespace-nowrap select-none",
|
|
10
10
|
].join(" "),
|
|
11
11
|
{
|
|
@@ -30,70 +30,56 @@ const badgeVariants = cva(
|
|
|
30
30
|
{
|
|
31
31
|
fill: "solid",
|
|
32
32
|
variant: "default",
|
|
33
|
-
className: "
|
|
33
|
+
className: "bg-muted text-foreground",
|
|
34
34
|
},
|
|
35
35
|
{
|
|
36
36
|
fill: "solid",
|
|
37
37
|
variant: "success",
|
|
38
|
-
className: "
|
|
38
|
+
className: "bg-success text-neutral-950",
|
|
39
39
|
},
|
|
40
40
|
{
|
|
41
41
|
fill: "solid",
|
|
42
42
|
variant: "warning",
|
|
43
|
-
className: "
|
|
43
|
+
className: "bg-warning text-neutral-950",
|
|
44
44
|
},
|
|
45
45
|
{
|
|
46
46
|
fill: "solid",
|
|
47
47
|
variant: "error",
|
|
48
|
-
className: "
|
|
48
|
+
className: "bg-error text-neutral-950",
|
|
49
49
|
},
|
|
50
50
|
{
|
|
51
51
|
fill: "solid",
|
|
52
52
|
variant: "info",
|
|
53
|
-
className:
|
|
54
|
-
"bg-neutral-100 text-neutral-700",
|
|
55
|
-
"dark:bg-neutral-800 dark:text-neutral-200",
|
|
56
|
-
].join(" "),
|
|
53
|
+
className: "bg-accent text-neutral-950",
|
|
57
54
|
},
|
|
58
55
|
{
|
|
59
56
|
fill: "outline",
|
|
60
57
|
variant: "default",
|
|
61
|
-
className:
|
|
62
|
-
"border-primary-300 bg-primary-100 text-neutral-950",
|
|
63
|
-
"dark:bg-primary-900/20 dark:text-neutral-200",
|
|
64
|
-
].join(" "),
|
|
58
|
+
className: "bg-transparent border-edge text-foreground/70",
|
|
65
59
|
},
|
|
66
60
|
{
|
|
67
61
|
fill: "outline",
|
|
68
62
|
variant: "success",
|
|
69
|
-
className:
|
|
70
|
-
"border-success
|
|
71
|
-
"dark:bg-success-900/20 dark:text-neutral-200",
|
|
72
|
-
].join(" "),
|
|
63
|
+
className:
|
|
64
|
+
"bg-success/15 border-success/40 text-success-500 dark:text-success",
|
|
73
65
|
},
|
|
74
66
|
{
|
|
75
67
|
fill: "outline",
|
|
76
68
|
variant: "warning",
|
|
77
|
-
className:
|
|
78
|
-
"border-warning
|
|
79
|
-
"dark:bg-warning-900/20 dark:text-neutral-200",
|
|
80
|
-
].join(" "),
|
|
69
|
+
className:
|
|
70
|
+
"bg-warning/15 border-warning/40 text-warning-500 dark:text-warning",
|
|
81
71
|
},
|
|
82
72
|
{
|
|
83
73
|
fill: "outline",
|
|
84
74
|
variant: "error",
|
|
85
|
-
className:
|
|
86
|
-
"border-error
|
|
87
|
-
"dark:bg-error-900/20 dark:text-neutral-200",
|
|
88
|
-
].join(" "),
|
|
75
|
+
className:
|
|
76
|
+
"bg-error/15 border-error/40 text-error-500 dark:text-error",
|
|
89
77
|
},
|
|
90
78
|
{
|
|
91
79
|
fill: "outline",
|
|
92
80
|
variant: "info",
|
|
93
|
-
className:
|
|
94
|
-
"border-
|
|
95
|
-
"dark:border-neutral-600 dark:bg-neutral-800/50 dark:text-neutral-300",
|
|
96
|
-
].join(" "),
|
|
81
|
+
className:
|
|
82
|
+
"bg-accent/15 border-accent/40 text-accent-500 dark:text-accent",
|
|
97
83
|
},
|
|
98
84
|
],
|
|
99
85
|
defaultVariants: {
|
|
@@ -27,7 +27,7 @@ const BreadcrumbList = forwardRef<
|
|
|
27
27
|
ref={ref}
|
|
28
28
|
className={cn(
|
|
29
29
|
"flex flex-wrap items-center gap-1",
|
|
30
|
-
"font-
|
|
30
|
+
"font-sans font-medium text-sm",
|
|
31
31
|
className,
|
|
32
32
|
)}
|
|
33
33
|
{...rest}
|
|
@@ -67,7 +67,7 @@ const BreadcrumbLink = forwardRef<HTMLAnchorElement, BreadcrumbLinkProps>(
|
|
|
67
67
|
className={cn(
|
|
68
68
|
"text-foreground",
|
|
69
69
|
"transition-colors duration-150",
|
|
70
|
-
"hover:text-
|
|
70
|
+
"hover:text-accent-500 dark:hover:text-accent",
|
|
71
71
|
"motion-reduce:transition-none",
|
|
72
72
|
className,
|
|
73
73
|
)}
|
|
@@ -92,7 +92,7 @@ const BreadcrumbSeparator = forwardRef<
|
|
|
92
92
|
<li
|
|
93
93
|
ref={ref}
|
|
94
94
|
aria-hidden="true"
|
|
95
|
-
className={cn("text-
|
|
95
|
+
className={cn("text-foreground/25", className)}
|
|
96
96
|
{...rest}
|
|
97
97
|
>
|
|
98
98
|
{children ?? "/"}
|
|
@@ -110,7 +110,7 @@ const BreadcrumbPage = forwardRef<
|
|
|
110
110
|
<span
|
|
111
111
|
ref={ref}
|
|
112
112
|
aria-current="page"
|
|
113
|
-
className={cn("text-
|
|
113
|
+
className={cn("text-accent-500 dark:text-accent", className)}
|
|
114
114
|
{...rest}
|
|
115
115
|
/>
|
|
116
116
|
));
|
|
@@ -8,63 +8,112 @@ import {
|
|
|
8
8
|
} from "react";
|
|
9
9
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
10
10
|
import { cn } from "@ac/lib/cn";
|
|
11
|
-
import { Spinner } from "@ac/components/ui/spinner";
|
|
12
11
|
|
|
13
12
|
const buttonVariants = cva(
|
|
14
13
|
[
|
|
15
|
-
"inline-flex items-center
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"focus-visible:
|
|
20
|
-
"disabled:pointer-events-none",
|
|
14
|
+
"inline-flex items-center font-body font-bold leading-none",
|
|
15
|
+
"rounded-none border-0 text-white",
|
|
16
|
+
"transition-[background,box-shadow,transform] duration-150 ease-out",
|
|
17
|
+
"active:translate-y-px",
|
|
18
|
+
"focus-visible:outline-2 focus-visible:outline-accent focus-visible:outline-offset-2",
|
|
19
|
+
"disabled:pointer-events-none disabled:cursor-not-allowed",
|
|
20
|
+
"motion-reduce:transition-none motion-reduce:active:translate-y-0",
|
|
21
21
|
].join(" "),
|
|
22
22
|
{
|
|
23
23
|
variants: {
|
|
24
24
|
variant: {
|
|
25
25
|
primary: [
|
|
26
|
-
|
|
27
|
-
"
|
|
26
|
+
// unified brand-blue chassis (both modes)
|
|
27
|
+
"bg-[linear-gradient(180deg,var(--color-primary-400)_0%,var(--color-primary-500)_100%)]",
|
|
28
|
+
"[box-shadow:inset_0_1px_0_rgba(0,225,250,0.55),inset_0_-1px_0_rgba(0,0,0,0.35)]",
|
|
29
|
+
// hover: chassis static, bevel highlight intensifies, halo appears (color matches chassis-500)
|
|
30
|
+
"hover:[box-shadow:inset_0_1px_0_rgba(0,225,250,0.7),inset_0_-1px_0_rgba(0,0,0,0.35),0_0_40px_rgba(0,64,255,0.35)]",
|
|
31
|
+
"dark:hover:[box-shadow:inset_0_1px_0_rgba(0,225,250,0.7),inset_0_-1px_0_rgba(0,0,0,0.35),0_0_40px_rgba(0,64,255,0.75)]",
|
|
32
|
+
"disabled:bg-muted disabled:bg-none disabled:text-foreground/30",
|
|
33
|
+
"disabled:[box-shadow:inset_0_0_0_1px_rgba(20,15,40,0.06)]",
|
|
28
34
|
].join(" "),
|
|
29
35
|
secondary: [
|
|
30
|
-
|
|
31
|
-
"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
"hover:
|
|
42
|
-
"dark:
|
|
43
|
-
"
|
|
44
|
-
"dark:active:bg-primary-700 dark:active:text-primary-100",
|
|
45
|
-
"disabled:bg-transparent disabled:text-primary-600/50",
|
|
46
|
-
"dark:disabled:text-primary-300/50",
|
|
36
|
+
// light (base): raised light chassis, dark text, hairline edge
|
|
37
|
+
"bg-[linear-gradient(180deg,var(--background)_0%,var(--surface)_100%)] text-foreground",
|
|
38
|
+
"[box-shadow:inset_0_1px_0_rgba(255,255,255,0.9),inset_0_-1px_0_rgba(0,0,0,0.12),inset_0_0_0_1px_rgba(20,15,40,0.10)]",
|
|
39
|
+
// hover: chassis static, dark/neutral halo extends chassis outward
|
|
40
|
+
"hover:[box-shadow:inset_0_1px_0_rgba(255,255,255,0.9),inset_0_-1px_0_rgba(0,0,0,0.12),inset_0_0_0_1px_rgba(20,15,40,0.10),0_0_24px_rgba(20,15,40,0.18)]",
|
|
41
|
+
"disabled:bg-muted disabled:bg-none disabled:text-foreground/30",
|
|
42
|
+
"disabled:[box-shadow:inset_0_0_0_1px_rgba(20,15,40,0.06)]",
|
|
43
|
+
// dark (overrides — current shipped behavior)
|
|
44
|
+
"dark:bg-neutral-900 dark:bg-none dark:text-white",
|
|
45
|
+
"dark:[box-shadow:inset_0_1px_0_rgba(255,255,255,0.06),inset_0_-1px_0_rgba(0,0,0,0.4)]",
|
|
46
|
+
// dark hover: chassis static, white halo extends chassis outward
|
|
47
|
+
"dark:hover:[box-shadow:inset_0_1px_0_rgba(255,255,255,0.06),inset_0_-1px_0_rgba(0,0,0,0.4),0_0_32px_rgba(255,255,255,0.2)]",
|
|
48
|
+
"dark:disabled:bg-neutral-900 dark:disabled:text-white/30",
|
|
49
|
+
"dark:disabled:[box-shadow:inset_0_1px_0_rgba(255,255,255,0.03),inset_0_-1px_0_rgba(0,0,0,0.3)]",
|
|
47
50
|
].join(" "),
|
|
48
51
|
destructive: [
|
|
49
|
-
"bg-error
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
|
|
52
|
+
"bg-error text-error-foreground",
|
|
53
|
+
"[box-shadow:inset_0_1px_0_rgba(255,255,255,0.3),inset_0_-1px_0_rgba(0,0,0,0.25),0_0_24px_rgba(255,61,0,0.5)]",
|
|
54
|
+
"hover:[box-shadow:inset_0_1px_0_rgba(255,255,255,0.4),inset_0_-1px_0_rgba(0,0,0,0.25),0_0_40px_rgba(255,61,0,0.75)]",
|
|
55
|
+
// light (base): flat muted chassis when disabled
|
|
56
|
+
"disabled:bg-muted disabled:text-foreground/30",
|
|
57
|
+
"disabled:[box-shadow:inset_0_0_0_1px_rgba(20,15,40,0.06)]",
|
|
58
|
+
// dark (overrides — current shipped behavior)
|
|
59
|
+
"dark:disabled:bg-neutral-900 dark:disabled:text-white/30",
|
|
60
|
+
"dark:disabled:[box-shadow:inset_0_1px_0_rgba(255,255,255,0.03),inset_0_-1px_0_rgba(0,0,0,0.3)]",
|
|
53
61
|
].join(" "),
|
|
54
62
|
warning: [
|
|
55
|
-
"bg-warning
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
|
|
63
|
+
"bg-warning text-warning-foreground",
|
|
64
|
+
"[box-shadow:inset_0_1px_0_rgba(255,255,255,0.5),inset_0_-1px_0_rgba(0,0,0,0.15),0_0_24px_rgba(255,197,61,0.5)]",
|
|
65
|
+
"hover:[box-shadow:inset_0_1px_0_rgba(255,255,255,0.6),inset_0_-1px_0_rgba(0,0,0,0.15),0_0_40px_rgba(255,197,61,0.75)]",
|
|
66
|
+
// light (base): flat muted chassis when disabled
|
|
67
|
+
"disabled:bg-muted disabled:text-foreground/30",
|
|
68
|
+
"disabled:[box-shadow:inset_0_0_0_1px_rgba(20,15,40,0.06)]",
|
|
69
|
+
// dark (overrides — current shipped behavior)
|
|
70
|
+
"dark:disabled:bg-neutral-900 dark:disabled:text-white/30",
|
|
71
|
+
"dark:disabled:[box-shadow:inset_0_1px_0_rgba(255,255,255,0.03),inset_0_-1px_0_rgba(0,0,0,0.3)]",
|
|
72
|
+
].join(" "),
|
|
73
|
+
success: [
|
|
74
|
+
"bg-success text-success-foreground",
|
|
75
|
+
"[box-shadow:inset_0_1px_0_rgba(255,255,255,0.4),inset_0_-1px_0_rgba(0,0,0,0.2),0_0_24px_rgba(43,213,142,0.5)]",
|
|
76
|
+
"hover:[box-shadow:inset_0_1px_0_rgba(255,255,255,0.5),inset_0_-1px_0_rgba(0,0,0,0.2),0_0_40px_rgba(43,213,142,0.75)]",
|
|
77
|
+
// light (base): flat muted chassis when disabled
|
|
78
|
+
"disabled:bg-muted disabled:text-foreground/30",
|
|
79
|
+
"disabled:[box-shadow:inset_0_0_0_1px_rgba(20,15,40,0.06)]",
|
|
80
|
+
// dark (overrides — current shipped behavior)
|
|
81
|
+
"dark:disabled:bg-neutral-900 dark:disabled:text-white/30",
|
|
82
|
+
"dark:disabled:[box-shadow:inset_0_1px_0_rgba(255,255,255,0.03),inset_0_-1px_0_rgba(0,0,0,0.3)]",
|
|
83
|
+
].join(" "),
|
|
84
|
+
outline: [
|
|
85
|
+
// light (base): primary-blue text + border, flat chassis when disabled
|
|
86
|
+
"bg-transparent text-primary border border-[rgba(0,64,255,0.55)]",
|
|
87
|
+
"hover:border-primary",
|
|
88
|
+
"disabled:text-foreground/30 disabled:border-[rgba(20,15,40,0.15)] disabled:bg-muted",
|
|
89
|
+
// dark (overrides — current shipped behavior preserved)
|
|
90
|
+
"dark:text-accent dark:border-[rgba(0,225,250,0.4)]",
|
|
91
|
+
"dark:hover:border-accent",
|
|
92
|
+
"dark:disabled:text-white/30 dark:disabled:border-white/10 dark:disabled:bg-transparent",
|
|
93
|
+
].join(" "),
|
|
94
|
+
ghost: [
|
|
95
|
+
// light (base): foreground text, surface hover
|
|
96
|
+
"bg-transparent text-foreground/75 font-semibold",
|
|
97
|
+
"hover:bg-surface hover:text-foreground",
|
|
98
|
+
"disabled:text-foreground/30 disabled:bg-transparent",
|
|
99
|
+
// dark (overrides — current shipped behavior)
|
|
100
|
+
"dark:text-white/75",
|
|
101
|
+
"dark:hover:bg-white/[0.04] dark:hover:text-white",
|
|
102
|
+
"dark:disabled:text-white/30 dark:disabled:bg-transparent",
|
|
59
103
|
].join(" "),
|
|
60
104
|
},
|
|
61
105
|
size: {
|
|
62
|
-
xs: "py-
|
|
63
|
-
sm: "py-
|
|
64
|
-
md: "py-
|
|
65
|
-
lg: "py-2.5 px-8 text-lg gap-2",
|
|
106
|
+
xs: "py-[6px] px-3 text-[11px] gap-1.5",
|
|
107
|
+
sm: "py-[7px] px-3.5 text-xs gap-[7px]",
|
|
108
|
+
md: "py-[9px] px-[18px] text-[13px] gap-2",
|
|
66
109
|
},
|
|
67
110
|
},
|
|
111
|
+
compoundVariants: [
|
|
112
|
+
// Outline subtracts 1px from each padding axis to compensate for its 1px border.
|
|
113
|
+
{ variant: "outline", size: "xs", class: "py-[5px] px-[11px]" },
|
|
114
|
+
{ variant: "outline", size: "sm", class: "py-[6px] px-[13px]" },
|
|
115
|
+
{ variant: "outline", size: "md", class: "py-[8px] px-[17px]" },
|
|
116
|
+
],
|
|
68
117
|
defaultVariants: {
|
|
69
118
|
variant: "primary",
|
|
70
119
|
size: "md",
|
|
@@ -72,12 +121,45 @@ const buttonVariants = cva(
|
|
|
72
121
|
},
|
|
73
122
|
);
|
|
74
123
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
124
|
+
type Variant = NonNullable<VariantProps<typeof buttonVariants>["variant"]>;
|
|
125
|
+
type Size = NonNullable<VariantProps<typeof buttonVariants>["size"]>;
|
|
126
|
+
|
|
127
|
+
// LED dimensions per size. text-* sets the LED's currentColor.
|
|
128
|
+
const ledSizeClass: Record<Size, string> = {
|
|
129
|
+
xs: "size-1",
|
|
130
|
+
sm: "size-[5px]",
|
|
131
|
+
md: "size-1.5",
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// Icon dimensions per size (used for both iconLeft wrapper and iconRight wrapper).
|
|
135
|
+
const iconSizeClass: Record<Size, string> = {
|
|
136
|
+
xs: "size-[11px]",
|
|
137
|
+
sm: "size-3",
|
|
138
|
+
md: "size-[13px]",
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// LED color + static glow per variant.
|
|
142
|
+
const ledColorClass: Record<Variant, string> = {
|
|
143
|
+
primary: "bg-accent text-accent [box-shadow:0_0_8px_currentColor]",
|
|
144
|
+
secondary: "bg-accent text-accent [box-shadow:0_0_8px_currentColor]",
|
|
145
|
+
destructive: "bg-white text-white [box-shadow:0_0_8px_currentColor]",
|
|
146
|
+
warning: "bg-warning-foreground text-warning-foreground",
|
|
147
|
+
success: "bg-success-foreground text-success-foreground",
|
|
148
|
+
outline: "bg-primary/35 text-primary dark:bg-accent/50 dark:text-accent",
|
|
149
|
+
// ghost: LED is never rendered for ghost, so this entry is a sentinel.
|
|
150
|
+
ghost: "",
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
// iconLeft glow treatment per variant — applied to the wrapper span.
|
|
154
|
+
const iconGlowClass: Record<Variant, string> = {
|
|
155
|
+
primary: "text-accent [filter:drop-shadow(0_0_4px_var(--accent))]",
|
|
156
|
+
secondary: "text-accent [filter:drop-shadow(0_0_4px_var(--accent))]",
|
|
157
|
+
destructive: "text-white",
|
|
158
|
+
warning: "text-warning-foreground",
|
|
159
|
+
success: "text-success-foreground",
|
|
160
|
+
outline: "text-primary dark:text-accent [filter:drop-shadow(0_0_4px_currentColor)]",
|
|
161
|
+
ghost: "text-foreground/60 dark:text-white/60",
|
|
162
|
+
};
|
|
81
163
|
|
|
82
164
|
type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> &
|
|
83
165
|
VariantProps<typeof buttonVariants> & {
|
|
@@ -103,25 +185,91 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
|
|
103
185
|
},
|
|
104
186
|
ref,
|
|
105
187
|
) => {
|
|
106
|
-
const
|
|
188
|
+
const v: Variant = variant ?? "primary";
|
|
189
|
+
const s: Size = size ?? "md";
|
|
190
|
+
|
|
107
191
|
const classes = cn(
|
|
108
|
-
buttonVariants({ variant, size }),
|
|
109
|
-
loading && "pointer-events-none",
|
|
192
|
+
buttonVariants({ variant: v, size: s }),
|
|
193
|
+
loading && "pointer-events-none cursor-wait",
|
|
110
194
|
className,
|
|
111
195
|
);
|
|
112
196
|
|
|
113
|
-
const
|
|
197
|
+
const leadingSlot = (() => {
|
|
198
|
+
// Loading replaces everything in the leading slot (except on ghost).
|
|
199
|
+
if (loading && v !== "ghost") {
|
|
200
|
+
return (
|
|
201
|
+
<span
|
|
202
|
+
data-led-chase
|
|
203
|
+
aria-hidden="true"
|
|
204
|
+
className="inline-flex shrink-0 gap-[3px]"
|
|
205
|
+
>
|
|
206
|
+
<span
|
|
207
|
+
className={cn(
|
|
208
|
+
"inline-block rounded-full",
|
|
209
|
+
ledSizeClass[s],
|
|
210
|
+
ledColorClass[v],
|
|
211
|
+
"animate-button-chase-a",
|
|
212
|
+
)}
|
|
213
|
+
/>
|
|
214
|
+
<span
|
|
215
|
+
className={cn(
|
|
216
|
+
"inline-block rounded-full",
|
|
217
|
+
ledSizeClass[s],
|
|
218
|
+
ledColorClass[v],
|
|
219
|
+
"animate-button-chase-b",
|
|
220
|
+
)}
|
|
221
|
+
/>
|
|
222
|
+
</span>
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
// Resting state with iconLeft.
|
|
226
|
+
if (iconLeft) {
|
|
227
|
+
return (
|
|
228
|
+
<span
|
|
229
|
+
aria-hidden="true"
|
|
230
|
+
className={cn(
|
|
231
|
+
"inline-flex items-center justify-center shrink-0",
|
|
232
|
+
iconSizeClass[s],
|
|
233
|
+
iconGlowClass[v],
|
|
234
|
+
)}
|
|
235
|
+
>
|
|
236
|
+
{iconLeft}
|
|
237
|
+
</span>
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
// Resting state with static LED (non-ghost variants).
|
|
241
|
+
if (v !== "ghost") {
|
|
242
|
+
return (
|
|
243
|
+
<span
|
|
244
|
+
data-led
|
|
245
|
+
aria-hidden="true"
|
|
246
|
+
className={cn(
|
|
247
|
+
"inline-block rounded-full shrink-0",
|
|
248
|
+
ledSizeClass[s],
|
|
249
|
+
ledColorClass[v],
|
|
250
|
+
)}
|
|
251
|
+
/>
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
return null;
|
|
255
|
+
})();
|
|
114
256
|
|
|
115
257
|
const content = (
|
|
116
258
|
<>
|
|
117
|
-
{
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
) : null}
|
|
122
|
-
<span>{children}</span>
|
|
259
|
+
{leadingSlot}
|
|
260
|
+
<span className="inline-flex items-center leading-none">
|
|
261
|
+
{children}
|
|
262
|
+
</span>
|
|
123
263
|
{!loading && iconRight ? (
|
|
124
|
-
<span
|
|
264
|
+
<span
|
|
265
|
+
aria-hidden="true"
|
|
266
|
+
className={cn(
|
|
267
|
+
"inline-flex items-center justify-center shrink-0",
|
|
268
|
+
iconSizeClass[s],
|
|
269
|
+
)}
|
|
270
|
+
>
|
|
271
|
+
{iconRight}
|
|
272
|
+
</span>
|
|
125
273
|
) : null}
|
|
126
274
|
</>
|
|
127
275
|
);
|
|
@@ -2,11 +2,10 @@ import { forwardRef, type HTMLAttributes, type ReactNode } from "react";
|
|
|
2
2
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
3
3
|
import { cn } from "@ac/lib/cn";
|
|
4
4
|
|
|
5
|
-
const cardVariants = cva("rounded-
|
|
5
|
+
const cardVariants = cva("rounded-lg", {
|
|
6
6
|
variants: {
|
|
7
7
|
variant: {
|
|
8
|
-
default: "bg-surface text-surface-foreground",
|
|
9
|
-
noise: "fx-grain-lg text-surface-foreground",
|
|
8
|
+
default: "bg-surface text-surface-foreground border border-edge",
|
|
10
9
|
ghost: "bg-transparent",
|
|
11
10
|
},
|
|
12
11
|
padding: {
|
|
@@ -1,26 +1,34 @@
|
|
|
1
1
|
import { forwardRef, type ComponentPropsWithoutRef } from "react";
|
|
2
2
|
import { Checkbox as CheckboxPrimitive } from "radix-ui";
|
|
3
|
+
import { Check } from "@phosphor-icons/react";
|
|
3
4
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
4
5
|
import { cn } from "@ac/lib/cn";
|
|
5
6
|
|
|
6
7
|
const checkboxVariants = cva(
|
|
7
8
|
[
|
|
8
|
-
"peer shrink-0
|
|
9
|
-
"
|
|
9
|
+
"peer shrink-0",
|
|
10
|
+
"bg-background dark:bg-surface",
|
|
11
|
+
"border border-edge",
|
|
10
12
|
"hover:border-edge-hover",
|
|
11
|
-
"focus-visible:outline-none
|
|
12
|
-
"focus-visible:
|
|
13
|
-
"disabled:
|
|
14
|
-
"
|
|
15
|
-
"
|
|
13
|
+
"focus-visible:outline-none",
|
|
14
|
+
"focus-visible:border-accent-700 dark:focus-visible:border-accent",
|
|
15
|
+
"disabled:bg-muted dark:disabled:bg-background",
|
|
16
|
+
"disabled:border-edge/50",
|
|
17
|
+
"disabled:text-foreground/30",
|
|
18
|
+
"disabled:cursor-not-allowed",
|
|
19
|
+
"disabled:data-[state=checked]:text-foreground/30",
|
|
20
|
+
"disabled:data-[state=checked]:bg-muted dark:disabled:data-[state=checked]:bg-background",
|
|
21
|
+
"disabled:data-[state=checked]:border-edge/50",
|
|
22
|
+
"data-[state=checked]:bg-accent data-[state=checked]:border-accent",
|
|
23
|
+
"data-[state=checked]:text-neutral-950",
|
|
16
24
|
"transition-colors",
|
|
17
25
|
].join(" "),
|
|
18
26
|
{
|
|
19
27
|
variants: {
|
|
20
28
|
size: {
|
|
21
|
-
xs: "size-
|
|
22
|
-
sm: "size-
|
|
23
|
-
md: "size-
|
|
29
|
+
xs: "size-3.5 rounded-none",
|
|
30
|
+
sm: "size-4 rounded-none",
|
|
31
|
+
md: "size-5 rounded-none",
|
|
24
32
|
},
|
|
25
33
|
},
|
|
26
34
|
defaultVariants: {
|
|
@@ -44,7 +52,8 @@ const Checkbox = forwardRef<HTMLButtonElement, CheckboxProps>(
|
|
|
44
52
|
ref={ref}
|
|
45
53
|
className={cn(
|
|
46
54
|
checkboxVariants({ size }),
|
|
47
|
-
error &&
|
|
55
|
+
error &&
|
|
56
|
+
"border-error data-[state=checked]:border-error hover:border-error focus-visible:border-error dark:focus-visible:border-error",
|
|
48
57
|
className,
|
|
49
58
|
)}
|
|
50
59
|
aria-invalid={error || undefined}
|
|
@@ -59,18 +68,7 @@ const Checkbox = forwardRef<HTMLButtonElement, CheckboxProps>(
|
|
|
59
68
|
"transition-[clip-path] duration-200 ease-in-out motion-reduce:transition-none",
|
|
60
69
|
)}
|
|
61
70
|
>
|
|
62
|
-
<
|
|
63
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
64
|
-
viewBox="0 0 24 24"
|
|
65
|
-
fill="none"
|
|
66
|
-
stroke="currentColor"
|
|
67
|
-
strokeWidth={3}
|
|
68
|
-
strokeLinecap="round"
|
|
69
|
-
strokeLinejoin="round"
|
|
70
|
-
className="size-[90%]"
|
|
71
|
-
>
|
|
72
|
-
<polyline points="20 6 9 17 4 12" />
|
|
73
|
-
</svg>
|
|
71
|
+
<Check weight="bold" className="size-[80%]" />
|
|
74
72
|
</CheckboxPrimitive.Indicator>
|
|
75
73
|
</CheckboxPrimitive.Root>
|
|
76
74
|
);
|