@stasho/ds 0.1.1 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stasho/ds",
3
- "version": "0.1.1",
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-sm border",
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-400",
42
- error: "border-error-300",
43
- info: "border-primary-300",
44
- success: "border-success-400",
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-heading font-extrabold italic text-xs uppercase leading-normal pb-1",
54
+ "font-mono uppercase tracking-wider text-[11px] leading-normal pb-1",
55
55
  {
56
56
  variants: {
57
57
  variant: {
58
- warning: "text-warning-600 dark:text-warning-300",
59
- error: "text-error-600 dark:text-error-300",
60
- info: "text-primary-600 dark:text-primary-300",
61
- success: "text-success-600 dark:text-success-300",
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-400",
71
- error: "bg-error-400",
72
- info: "bg-primary-400",
73
- success: "bg-success-400",
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-md font-heading font-extrabold italic uppercase",
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: "gradient-fill-info text-neutral-950",
33
+ className: "bg-muted text-foreground",
34
34
  },
35
35
  {
36
36
  fill: "solid",
37
37
  variant: "success",
38
- className: "gradient-fill-success text-neutral-950",
38
+ className: "bg-success text-neutral-950",
39
39
  },
40
40
  {
41
41
  fill: "solid",
42
42
  variant: "warning",
43
- className: "gradient-fill-warning text-neutral-950",
43
+ className: "bg-warning text-neutral-950",
44
44
  },
45
45
  {
46
46
  fill: "solid",
47
47
  variant: "error",
48
- className: "gradient-fill-error text-neutral-950",
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-400 bg-success-100 text-neutral-950",
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-400 bg-warning-100 text-neutral-950",
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-400 bg-error-100 text-neutral-950",
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-neutral-400 bg-neutral-100/50 text-neutral-700",
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-heading font-extrabold italic uppercase text-xs",
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-primary-600 dark:hover:text-primary-400",
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-primary opacity-40", className)}
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-neutral opacity-40", className)}
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 justify-center",
16
- "font-heading font-bold",
17
- "rounded-full border-3 transition-colors",
18
- "focus-visible:outline-none focus-visible:ring-2",
19
- "focus-visible:ring-primary-400 focus-visible:ring-offset-2",
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
- "gradient-fill-main text-white border-transparent",
27
- "disabled:opacity-50",
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
- "gradient-fill-lime text-neutral-950 border-neutral-950",
31
- "disabled:opacity-50",
32
- ].join(" "),
33
- outline: [
34
- "border-gradient-main text-primary-700",
35
- "hover:text-primary-800",
36
- "active:text-primary-800",
37
- "disabled:opacity-50",
38
- ].join(" "),
39
- text: [
40
- "bg-transparent text-primary-600 dark:text-primary-300 border-transparent",
41
- "hover:bg-primary-100 hover:text-primary-700",
42
- "dark:hover:bg-primary-200/10 dark:hover:text-primary-200",
43
- "active:bg-primary-200 active:text-primary-800",
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-600/20 text-error-700 dark:text-error-300 border-error-600",
50
- "hover:bg-error-600/30 hover:border-error-700",
51
- "active:bg-error-600/40 active:border-error-800",
52
- "disabled:bg-error-600/10 disabled:text-error-700/50 disabled:border-error-600/50",
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-500/20 text-warning-800 dark:text-warning-200 border-warning-500",
56
- "hover:bg-warning-500/30 hover:border-warning-600",
57
- "active:bg-warning-500/40 active:border-warning-700",
58
- "disabled:bg-warning-500/10 disabled:text-warning-800/50 disabled:border-warning-500/50",
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-1 px-4 text-sm gap-1",
63
- sm: "py-1.5 px-5 text-base gap-1.5",
64
- md: "py-2 px-6 text-base gap-2",
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
- const iconSize = {
76
- xs: "size-3.5",
77
- sm: "size-4",
78
- md: "size-4",
79
- lg: "size-5",
80
- } as const;
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 sizeKey = size ?? "md";
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 iconClass = cn("shrink-0", iconSize[sizeKey], "[&>svg]:size-full");
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
- {loading ? (
118
- <Spinner className={cn("shrink-0", iconSize[sizeKey])} />
119
- ) : iconLeft ? (
120
- <span className={iconClass}>{iconLeft}</span>
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 className={iconClass}>{iconRight}</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-md", {
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 bg-surface",
9
- "border-3 border-edge",
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 focus-visible:ring-3",
12
- "focus-visible:ring-primary-500",
13
- "disabled:opacity-50 disabled:pointer-events-none",
14
- "data-[state=checked]:bg-primary data-[state=checked]:border-primary",
15
- "data-[state=checked]:text-primary-foreground",
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-4 rounded",
22
- sm: "size-5 rounded-md",
23
- md: "size-6 rounded-md",
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 && "border-3 border-error-400 hover:border-error-500",
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
- <svg
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
  );