@hilum/ui 3.1.2 → 3.2.1

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.
Files changed (61) hide show
  1. package/dist/{chunk-5JX2YKJM.js → chunk-MAHPAP65.js} +65 -11
  2. package/dist/chunk-MAHPAP65.js.map +1 -0
  3. package/dist/icons.d.ts +1 -1
  4. package/dist/icons.js +1 -1
  5. package/dist/index.js +224 -150
  6. package/dist/index.js.map +1 -1
  7. package/dist/tokens.css +10 -0
  8. package/dist/tokens.d.ts +9 -0
  9. package/dist/tokens.js +1 -1
  10. package/package.json +1 -1
  11. package/src/components/account-menu.tsx +3 -10
  12. package/src/components/action-panel.tsx +10 -7
  13. package/src/components/alert-dialog.tsx +10 -6
  14. package/src/components/alert.tsx +6 -2
  15. package/src/components/avatar-stack.tsx +6 -1
  16. package/src/components/avatar.tsx +4 -1
  17. package/src/components/breadcrumb.tsx +6 -1
  18. package/src/components/button-group.tsx +6 -5
  19. package/src/components/button.tsx +9 -7
  20. package/src/components/calendar.tsx +6 -5
  21. package/src/components/card-heading.tsx +4 -2
  22. package/src/components/card.tsx +2 -2
  23. package/src/components/carousel.tsx +2 -2
  24. package/src/components/checkbox.tsx +2 -1
  25. package/src/components/color-picker.tsx +4 -4
  26. package/src/components/combobox.tsx +17 -7
  27. package/src/components/command-palette.tsx +4 -2
  28. package/src/components/command.tsx +4 -2
  29. package/src/components/context-menu.tsx +4 -4
  30. package/src/components/data-table.tsx +7 -4
  31. package/src/components/description-list.tsx +4 -2
  32. package/src/components/dialog.tsx +7 -3
  33. package/src/components/dropdown-menu.tsx +4 -4
  34. package/src/components/empty-state.tsx +4 -2
  35. package/src/components/field.tsx +11 -3
  36. package/src/components/grid-list.tsx +3 -3
  37. package/src/components/input-group.tsx +1 -1
  38. package/src/components/input-number.tsx +4 -1
  39. package/src/components/input-otp.tsx +1 -1
  40. package/src/components/input.tsx +1 -1
  41. package/src/components/menubar.tsx +7 -11
  42. package/src/components/native-select.tsx +1 -1
  43. package/src/components/navigation-menu.tsx +3 -3
  44. package/src/components/notification.tsx +6 -4
  45. package/src/components/page-heading.tsx +4 -2
  46. package/src/components/pagination.tsx +2 -2
  47. package/src/components/progress.tsx +1 -1
  48. package/src/components/radio-card.tsx +7 -6
  49. package/src/components/radio-group.tsx +2 -1
  50. package/src/components/section-heading.tsx +4 -2
  51. package/src/components/select.tsx +2 -2
  52. package/src/components/sheet.tsx +8 -4
  53. package/src/components/sidebar.tsx +8 -8
  54. package/src/components/slider.tsx +1 -1
  55. package/src/components/stat-card.tsx +2 -2
  56. package/src/components/steps.tsx +13 -11
  57. package/src/components/switch.tsx +4 -4
  58. package/src/components/toggle.tsx +5 -5
  59. package/src/icons.ts +4 -0
  60. package/src/tokens/tokens.ts +65 -10
  61. package/dist/chunk-5JX2YKJM.js.map +0 -1
package/dist/tokens.css CHANGED
@@ -205,6 +205,7 @@
205
205
  font-size: 3rem;
206
206
  font-weight: 400;
207
207
  line-height: 1.15;
208
+ text-wrap: balance;
208
209
  }
209
210
 
210
211
  @utility display {
@@ -212,6 +213,7 @@
212
213
  font-size: 2.25rem;
213
214
  font-weight: 400;
214
215
  line-height: 1.15;
216
+ text-wrap: balance;
215
217
  }
216
218
 
217
219
  @utility heading-xl {
@@ -219,6 +221,7 @@
219
221
  font-size: 1.875rem;
220
222
  font-weight: 400;
221
223
  line-height: 1.2;
224
+ text-wrap: balance;
222
225
  }
223
226
 
224
227
  @utility heading {
@@ -226,6 +229,7 @@
226
229
  font-size: 1.5rem;
227
230
  font-weight: 400;
228
231
  line-height: 1.2;
232
+ text-wrap: balance;
229
233
  }
230
234
 
231
235
  @utility subheading {
@@ -233,6 +237,7 @@
233
237
  font-size: 1.25rem;
234
238
  font-weight: 400;
235
239
  line-height: 1.4;
240
+ text-wrap: balance;
236
241
  }
237
242
 
238
243
  @utility body-lg {
@@ -240,6 +245,7 @@
240
245
  font-size: 1rem;
241
246
  font-weight: 400;
242
247
  line-height: 1.625;
248
+ text-wrap: pretty;
243
249
  }
244
250
 
245
251
  @utility body {
@@ -247,6 +253,7 @@
247
253
  font-size: 0.875rem;
248
254
  font-weight: 400;
249
255
  line-height: 1.625;
256
+ text-wrap: pretty;
250
257
  }
251
258
 
252
259
  @utility body-sm {
@@ -254,6 +261,7 @@
254
261
  font-size: 0.75rem;
255
262
  font-weight: 500;
256
263
  line-height: 1.625;
264
+ text-wrap: pretty;
257
265
  }
258
266
 
259
267
  @utility caption {
@@ -261,6 +269,7 @@
261
269
  font-size: 0.75rem;
262
270
  font-weight: 400;
263
271
  line-height: 1.625;
272
+ text-wrap: pretty;
264
273
  }
265
274
 
266
275
  @utility caption-xs {
@@ -335,6 +344,7 @@
335
344
  border-color: var(--border);
336
345
  }
337
346
 
347
+ html,
338
348
  body {
339
349
  background-color: var(--background);
340
350
  color: var(--foreground);
package/dist/tokens.d.ts CHANGED
@@ -132,54 +132,63 @@ declare const tokens: {
132
132
  readonly size: "3rem";
133
133
  readonly weight: 400;
134
134
  readonly lineHeight: "1.15";
135
+ readonly textWrap: "balance";
135
136
  };
136
137
  readonly display: {
137
138
  readonly family: "display";
138
139
  readonly size: "2.25rem";
139
140
  readonly weight: 400;
140
141
  readonly lineHeight: "1.15";
142
+ readonly textWrap: "balance";
141
143
  };
142
144
  readonly "heading-xl": {
143
145
  readonly family: "display";
144
146
  readonly size: "1.875rem";
145
147
  readonly weight: 400;
146
148
  readonly lineHeight: "1.2";
149
+ readonly textWrap: "balance";
147
150
  };
148
151
  readonly heading: {
149
152
  readonly family: "display";
150
153
  readonly size: "1.5rem";
151
154
  readonly weight: 400;
152
155
  readonly lineHeight: "1.2";
156
+ readonly textWrap: "balance";
153
157
  };
154
158
  readonly subheading: {
155
159
  readonly family: "display";
156
160
  readonly size: "1.25rem";
157
161
  readonly weight: 400;
158
162
  readonly lineHeight: "1.4";
163
+ readonly textWrap: "balance";
159
164
  };
160
165
  readonly "body-lg": {
161
166
  readonly family: "sans";
162
167
  readonly size: "1rem";
163
168
  readonly weight: 400;
164
169
  readonly lineHeight: "1.625";
170
+ readonly textWrap: "pretty";
165
171
  };
166
172
  readonly body: {
167
173
  readonly family: "sans";
168
174
  readonly size: "0.875rem";
169
175
  readonly weight: 400;
170
176
  readonly lineHeight: "1.625";
177
+ readonly textWrap: "pretty";
171
178
  };
172
179
  readonly "body-sm": {
173
180
  readonly family: "sans";
174
181
  readonly size: "0.75rem";
175
182
  readonly weight: 500;
176
183
  readonly lineHeight: "1.625";
184
+ readonly textWrap: "pretty";
177
185
  };
178
186
  readonly caption: {
179
187
  readonly family: "sans";
180
188
  readonly size: "0.75rem";
181
189
  readonly weight: 400;
182
190
  readonly lineHeight: "1.625";
191
+ readonly textWrap: "pretty";
183
192
  };
184
193
  readonly "caption-xs": {
185
194
  readonly family: "sans";
package/dist/tokens.js CHANGED
@@ -1,3 +1,3 @@
1
- export { tokens } from './chunk-5JX2YKJM.js';
1
+ export { tokens } from './chunk-MAHPAP65.js';
2
2
  //# sourceMappingURL=tokens.js.map
3
3
  //# sourceMappingURL=tokens.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hilum/ui",
3
- "version": "3.1.2",
3
+ "version": "3.2.1",
4
4
  "private": false,
5
5
  "description": "Hilum UI — design system primitives (Button, Input, Dialog, Combobox, …) + tokens + fonts + icons",
6
6
  "license": "MIT",
@@ -1,11 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  import * as React from "react";
4
- import {
5
- DropdownMenuContent,
6
- DropdownMenuItem,
7
- DropdownMenuSeparator,
8
- } from "./dropdown-menu";
4
+ import { DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator } from "./dropdown-menu";
9
5
  import { Avatar, AvatarFallback, AvatarImage } from "./avatar";
10
6
  import { cn } from "../lib/utils";
11
7
 
@@ -54,14 +50,11 @@ const AccountMenuHeader = React.forwardRef<HTMLDivElement, AccountMenuHeaderProp
54
50
  AccountMenuHeader.displayName = "AccountMenuHeader";
55
51
 
56
52
  const AccountMenuSection = React.forwardRef<HTMLDivElement, React.ComponentProps<"div">>(
57
- ({ className, ...props }, ref) => (
58
- <div ref={ref} className={cn("p-2", className)} {...props} />
59
- ),
53
+ ({ className, ...props }, ref) => <div ref={ref} className={cn("p-2", className)} {...props} />,
60
54
  );
61
55
  AccountMenuSection.displayName = "AccountMenuSection";
62
56
 
63
- interface AccountMenuItemProps
64
- extends React.ComponentPropsWithoutRef<typeof DropdownMenuItem> {
57
+ interface AccountMenuItemProps extends React.ComponentPropsWithoutRef<typeof DropdownMenuItem> {
65
58
  icon?: React.ReactNode;
66
59
  trailing?: React.ReactNode;
67
60
  description?: React.ReactNode;
@@ -48,7 +48,7 @@ function ActionPanel({
48
48
  (link.href ? (
49
49
  <a
50
50
  href={link.href}
51
- className="body font-medium text-muted-foreground hover:text-foreground transition-colors inline-flex items-center gap-1"
51
+ className="inline-flex min-h-10 items-center gap-1 body font-medium text-muted-foreground transition-colors hover:text-foreground"
52
52
  >
53
53
  {link.label} <span aria-hidden>→</span>
54
54
  </a>
@@ -56,7 +56,7 @@ function ActionPanel({
56
56
  <button
57
57
  type="button"
58
58
  onClick={link.onClick}
59
- className="body font-medium text-muted-foreground hover:text-foreground transition-colors inline-flex items-center gap-1"
59
+ className="inline-flex min-h-10 items-center gap-1 body font-medium text-muted-foreground transition-colors hover:text-foreground"
60
60
  >
61
61
  {link.label} <span aria-hidden>→</span>
62
62
  </button>
@@ -80,17 +80,20 @@ function ActionPanel({
80
80
  <div
81
81
  className={cn(
82
82
  "rounded-xl border px-5 py-5",
83
- variant === "muted"
84
- ? "border-border bg-muted"
85
- : "border-border bg-card shadow-natural",
83
+ variant === "muted" ? "border-border bg-muted" : "border-border bg-card shadow-natural",
86
84
  layout === "inline" && "flex items-center justify-between gap-6",
87
85
  className,
88
86
  )}
89
87
  >
90
88
  <div className={cn("min-w-0", layout === "inline" ? "flex-1" : "")}>
91
- <p className="body font-semibold text-foreground">{title}</p>
89
+ <p className="body font-semibold text-foreground text-balance">{title}</p>
92
90
  {description && (
93
- <p className={cn("body text-muted-foreground", layout === "stacked" ? "mt-1" : "")}>
91
+ <p
92
+ className={cn(
93
+ "body text-muted-foreground text-pretty",
94
+ layout === "stacked" ? "mt-1" : "",
95
+ )}
96
+ >
94
97
  {description}
95
98
  </p>
96
99
  )}
@@ -65,7 +65,7 @@ const AlertDialogTitle = React.forwardRef<
65
65
  >(({ className, ...props }, ref) => (
66
66
  <AlertDialog.Title
67
67
  ref={ref}
68
- className={cn("body-lg font-semibold text-foreground", className)}
68
+ className={cn("body-lg font-semibold text-balance text-foreground", className)}
69
69
  {...props}
70
70
  />
71
71
  ));
@@ -75,7 +75,11 @@ const AlertDialogDescription = React.forwardRef<
75
75
  React.ComponentRef<typeof AlertDialog.Description>,
76
76
  React.ComponentPropsWithoutRef<typeof AlertDialog.Description>
77
77
  >(({ className, ...props }, ref) => (
78
- <AlertDialog.Description ref={ref} className={cn("body text-muted-foreground", className)} {...props} />
78
+ <AlertDialog.Description
79
+ ref={ref}
80
+ className={cn("body text-pretty text-muted-foreground", className)}
81
+ {...props}
82
+ />
79
83
  ));
80
84
  AlertDialogDescription.displayName = "AlertDialogDescription";
81
85
 
@@ -86,8 +90,8 @@ const AlertDialogAction = React.forwardRef<
86
90
  <AlertDialog.Action
87
91
  ref={ref}
88
92
  className={cn(
89
- "inline-flex h-9 items-center justify-center rounded-md px-4",
90
- "body font-medium whitespace-nowrap transition-all duration-150",
93
+ "inline-flex h-10 items-center justify-center rounded-md px-4",
94
+ "body font-medium whitespace-nowrap transition-[background-color,box-shadow,color,opacity,scale] duration-150 active:scale-[0.96]",
91
95
  "bg-brand-primary text-background hover:bg-brand-primary/90 active:bg-brand-primary/80",
92
96
  "focus-visible:ring-2 focus-visible:ring-brand-primary/30 focus-visible:ring-offset-1 outline-none",
93
97
  "disabled:pointer-events-none disabled:opacity-50",
@@ -105,8 +109,8 @@ const AlertDialogCancel = React.forwardRef<
105
109
  <AlertDialog.Cancel
106
110
  ref={ref}
107
111
  className={cn(
108
- "inline-flex h-9 items-center justify-center rounded-md px-4",
109
- "body font-medium whitespace-nowrap transition-all duration-150",
112
+ "inline-flex h-10 items-center justify-center rounded-md px-4",
113
+ "body font-medium whitespace-nowrap transition-[background-color,box-shadow,color,opacity,scale] duration-150 active:scale-[0.96]",
110
114
  "bg-card text-muted-foreground shadow-natural hover:bg-muted rounded-xl",
111
115
  "focus-visible:ring-2 focus-visible:ring-brand-primary/30 focus-visible:ring-offset-1 outline-none",
112
116
  "disabled:pointer-events-none disabled:opacity-50",
@@ -29,14 +29,18 @@ Alert.displayName = "Alert";
29
29
 
30
30
  const AlertTitle = React.forwardRef<HTMLParagraphElement, React.ComponentProps<"p">>(
31
31
  ({ className, ...props }, ref) => (
32
- <p ref={ref} className={cn("mb-0.5 body font-semibold leading-tight", className)} {...props} />
32
+ <p
33
+ ref={ref}
34
+ className={cn("mb-0.5 body font-semibold leading-tight text-balance", className)}
35
+ {...props}
36
+ />
33
37
  ),
34
38
  );
35
39
  AlertTitle.displayName = "AlertTitle";
36
40
 
37
41
  const AlertDescription = React.forwardRef<HTMLParagraphElement, React.ComponentProps<"p">>(
38
42
  ({ className, ...props }, ref) => (
39
- <p ref={ref} className={cn("body opacity-90", className)} {...props} />
43
+ <p ref={ref} className={cn("body text-pretty opacity-90", className)} {...props} />
40
44
  ),
41
45
  );
42
46
  AlertDescription.displayName = "AlertDescription";
@@ -38,7 +38,11 @@ function AvatarStack({ avatars, max, size = "md", className }: AvatarStackProps)
38
38
  )}
39
39
  >
40
40
  {avatar.src ? (
41
- <img src={avatar.src} alt={avatar.name} className="size-full object-cover" />
41
+ <img
42
+ src={avatar.src}
43
+ alt={avatar.name}
44
+ className="size-full object-cover outline outline-1 -outline-offset-1 outline-black/10 dark:outline-white/10"
45
+ />
42
46
  ) : (
43
47
  <span
44
48
  className={cn(
@@ -58,6 +62,7 @@ function AvatarStack({ avatars, max, size = "md", className }: AvatarStackProps)
58
62
  "relative inline-flex shrink-0 items-center justify-center rounded-full ring-background bg-muted font-medium text-muted-foreground",
59
63
  s.wrapper,
60
64
  s.text,
65
+ "tabular-nums",
61
66
  )}
62
67
  >
63
68
  +{overflow}
@@ -39,7 +39,10 @@ const AvatarImage = React.forwardRef<
39
39
  >(({ className, ...props }, ref) => (
40
40
  <AvatarPrimitive.Image
41
41
  ref={ref}
42
- className={cn("aspect-square h-full w-full object-cover", className)}
42
+ className={cn(
43
+ "aspect-square h-full w-full object-cover outline outline-1 -outline-offset-1 outline-black/10 dark:outline-white/10",
44
+ className,
45
+ )}
43
46
  {...props}
44
47
  />
45
48
  ));
@@ -46,7 +46,12 @@ const BreadcrumbPage = React.forwardRef<HTMLSpanElement, React.ComponentProps<"s
46
46
  BreadcrumbPage.displayName = "BreadcrumbPage";
47
47
 
48
48
  const BreadcrumbSeparator = ({ children, className, ...props }: React.ComponentProps<"li">) => (
49
- <li role="presentation" aria-hidden="true" className={cn("text-muted-foreground", className)} {...props}>
49
+ <li
50
+ role="presentation"
51
+ aria-hidden="true"
52
+ className={cn("text-muted-foreground", className)}
53
+ {...props}
54
+ >
50
55
  {children ?? <ChevronRight size={14} />}
51
56
  </li>
52
57
  );
@@ -10,7 +10,7 @@ function ButtonGroup({ children, className }: ButtonGroupProps) {
10
10
  return (
11
11
  <div
12
12
  className={cn(
13
- "inline-flex divide-x divide-border overflow-hidden rounded-lg border border-border bg-card shadow-natural",
13
+ "inline-flex items-center gap-0.5 rounded-2xl bg-muted p-1",
14
14
  className,
15
15
  )}
16
16
  >
@@ -28,11 +28,12 @@ function ButtonGroupItem({ active, className, children, ...props }: ButtonGroupI
28
28
  <button
29
29
  type="button"
30
30
  className={cn(
31
- "relative inline-flex items-center gap-1.5 px-3.5 py-2 body font-medium transition-colors",
32
- "focus:z-10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/30 focus-visible:ring-inset",
31
+ "relative inline-flex min-h-10 items-center justify-center gap-1.5 rounded-xl px-3.5 py-2 body font-medium",
32
+ "transition-[background-color,box-shadow,color,opacity,scale] active:scale-[0.96]",
33
+ "focus:z-10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/30",
33
34
  active
34
- ? "bg-foreground text-background"
35
- : "text-muted-foreground hover:bg-muted hover:text-foreground",
35
+ ? "bg-card text-foreground shadow-natural"
36
+ : "text-muted-foreground hover:text-foreground",
36
37
  className,
37
38
  )}
38
39
  {...props}
@@ -7,7 +7,7 @@ const buttonVariants = cva(
7
7
  [
8
8
  "inline-flex shrink-0 items-center justify-center gap-2",
9
9
  "body font-medium whitespace-nowrap",
10
- "transition-all duration-150 outline-none",
10
+ "transition-[background-color,border-color,box-shadow,color,opacity,scale] duration-150 outline-none active:scale-[0.96]",
11
11
  "focus-visible:ring-2 focus-visible:ring-brand-primary/30 focus-visible:ring-offset-1",
12
12
  "disabled:pointer-events-none disabled:opacity-50",
13
13
  "[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
@@ -15,8 +15,10 @@ const buttonVariants = cva(
15
15
  {
16
16
  variants: {
17
17
  variant: {
18
- default: "bg-brand-primary text-background hover:bg-brand-primary/90 active:bg-brand-primary/80",
19
- destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90 active:bg-destructive/80",
18
+ default:
19
+ "bg-brand-primary text-background hover:bg-brand-primary/90 active:bg-brand-primary/80",
20
+ destructive:
21
+ "bg-destructive text-destructive-foreground hover:bg-destructive/90 active:bg-destructive/80",
20
22
  outline: "bg-card text-muted-foreground shadow-natural hover:bg-muted rounded-xl",
21
23
  secondary: "bg-muted text-muted-foreground hover:bg-muted",
22
24
  brand:
@@ -25,14 +27,14 @@ const buttonVariants = cva(
25
27
  link: "text-foreground underline-offset-4 hover:underline",
26
28
  },
27
29
  size: {
28
- default: "h-9 px-4 py-2 rounded-md",
30
+ default: "h-10 px-4 py-2 rounded-md",
29
31
  xs: "h-6 gap-1 px-2 caption rounded-md",
30
32
  sm: "h-8 gap-1.5 px-3 rounded-md",
31
- lg: "h-10 px-6 rounded-md",
32
- icon: "size-9 rounded-md",
33
+ lg: "h-11 px-6 rounded-md",
34
+ icon: "size-10 rounded-md",
33
35
  "icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
34
36
  "icon-sm": "size-8 rounded-md",
35
- "icon-lg": "size-10 rounded-md",
37
+ "icon-lg": "size-11 rounded-md",
36
38
  },
37
39
  },
38
40
  defaultVariants: {
@@ -19,20 +19,20 @@ function Calendar({ className, classNames, showOutsideDays = true, ...props }: C
19
19
  caption_label: "body font-semibold text-foreground",
20
20
  nav: "flex items-center justify-between absolute inset-x-0 top-1",
21
21
  button_previous: cn(
22
- "absolute left-0 h-7 w-7 flex items-center justify-center rounded-md",
22
+ "absolute left-0 flex size-10 items-center justify-center rounded-md",
23
23
  "text-muted-foreground hover:bg-muted hover:text-muted-foreground transition-colors",
24
24
  ),
25
25
  button_next: cn(
26
- "absolute right-0 h-7 w-7 flex items-center justify-center rounded-md",
26
+ "absolute right-0 flex size-10 items-center justify-center rounded-md",
27
27
  "text-muted-foreground hover:bg-muted hover:text-muted-foreground transition-colors",
28
28
  ),
29
29
  month_grid: "w-full border-collapse mt-1",
30
30
  weekdays: "flex",
31
- weekday: "w-9 h-9 flex items-center justify-center label text-muted-foreground font-normal",
31
+ weekday: "flex size-10 items-center justify-center label text-muted-foreground font-normal",
32
32
  week: "flex w-full mt-1",
33
33
  day: "relative p-0 text-center",
34
34
  day_button: cn(
35
- "h-9 w-9 flex items-center justify-center rounded-full body font-normal",
35
+ "flex size-10 items-center justify-center rounded-full body font-normal",
36
36
  "text-foreground hover:bg-muted transition-colors",
37
37
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-primary/30",
38
38
  ),
@@ -41,7 +41,8 @@ function Calendar({ className, classNames, showOutsideDays = true, ...props }: C
41
41
  today: "[&>button]:font-semibold [&>button]:text-brand-primary",
42
42
  outside: "opacity-40 [&>button]:text-muted-foreground",
43
43
  disabled: "opacity-30 [&>button]:cursor-not-allowed",
44
- range_start: "[&>button]:bg-brand-primary [&>button]:text-background [&>button]:rounded-full",
44
+ range_start:
45
+ "[&>button]:bg-brand-primary [&>button]:text-background [&>button]:rounded-full",
45
46
  range_end: "[&>button]:bg-brand-primary [&>button]:text-background [&>button]:rounded-full",
46
47
  range_middle:
47
48
  "[&>button]:bg-brand-primary/15 [&>button]:text-foreground [&>button]:rounded-none",
@@ -28,8 +28,10 @@ function CardHeading({ title, description, actions, children, className }: CardH
28
28
  <div className="flex min-w-0 items-center gap-3">
29
29
  {children}
30
30
  <div className="min-w-0">
31
- <p className="body font-semibold text-foreground truncate">{title}</p>
32
- {description && <p className="caption text-muted-foreground mt-0.5">{description}</p>}
31
+ <p className="body truncate font-semibold text-balance text-foreground">{title}</p>
32
+ {description && (
33
+ <p className="caption mt-0.5 text-pretty text-muted-foreground">{description}</p>
34
+ )}
33
35
  </div>
34
36
  </div>
35
37
 
@@ -54,7 +54,7 @@ const CardTitle = React.forwardRef<HTMLHeadingElement, React.ComponentProps<"h3"
54
54
  <h3
55
55
  ref={ref}
56
56
  data-slot="card-title"
57
- className={cn("subheading text-foreground", className)}
57
+ className={cn("subheading text-balance text-foreground", className)}
58
58
  {...props}
59
59
  />
60
60
  ),
@@ -66,7 +66,7 @@ const CardDescription = React.forwardRef<HTMLParagraphElement, React.ComponentPr
66
66
  <p
67
67
  ref={ref}
68
68
  data-slot="card-description"
69
- className={cn("caption text-muted-foreground", className)}
69
+ className={cn("caption text-pretty text-muted-foreground", className)}
70
70
  {...props}
71
71
  />
72
72
  ),
@@ -167,7 +167,7 @@ function CarouselPrevious({
167
167
  variant={variant}
168
168
  size={size}
169
169
  className={cn(
170
- "absolute h-9 w-9 rounded-full",
170
+ "absolute size-10 rounded-full",
171
171
  orientation === "vertical"
172
172
  ? "-top-12 left-1/2 -translate-x-1/2 rotate-90"
173
173
  : "-left-12 top-1/2 -translate-y-1/2",
@@ -196,7 +196,7 @@ function CarouselNext({
196
196
  variant={variant}
197
197
  size={size}
198
198
  className={cn(
199
- "absolute h-9 w-9 rounded-full",
199
+ "absolute size-10 rounded-full",
200
200
  orientation === "vertical"
201
201
  ? "-bottom-12 left-1/2 -translate-x-1/2 rotate-90"
202
202
  : "-right-12 top-1/2 -translate-y-1/2",
@@ -12,7 +12,8 @@ const CheckboxRoot = React.forwardRef<
12
12
  <Checkbox.Root
13
13
  ref={ref}
14
14
  className={cn(
15
- "peer size-4 shrink-0 rounded border border-border bg-card transition-colors",
15
+ "peer relative size-4 shrink-0 rounded border border-border bg-card transition-colors",
16
+ "after:absolute after:left-1/2 after:top-1/2 after:size-10 after:-translate-x-1/2 after:-translate-y-1/2",
16
17
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-primary/30",
17
18
  "disabled:cursor-not-allowed disabled:opacity-50",
18
19
  "data-[state=checked]:bg-brand-primary data-[state=checked]:border-brand-primary",
@@ -45,7 +45,7 @@ function ColorPicker({
45
45
  disabled={disabled}
46
46
  aria-label={ariaLabel}
47
47
  className={cn(
48
- "inline-flex h-8 w-8 items-center justify-center rounded-md border border-border bg-card",
48
+ "inline-flex size-10 items-center justify-center rounded-md border border-border bg-card",
49
49
  "transition-colors hover:border-border",
50
50
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-primary/20 focus-visible:border-brand-primary",
51
51
  "disabled:cursor-not-allowed disabled:opacity-50",
@@ -84,18 +84,18 @@ function ColorPicker({
84
84
  onKeyDown={(e) => {
85
85
  if (e.key === "Enter") commit((e.target as HTMLInputElement).value);
86
86
  }}
87
- className="flex-1 h-7 rounded-md border border-border bg-card px-2 caption text-foreground focus:outline-none focus:border-brand-primary"
87
+ className="h-10 flex-1 rounded-md border border-border bg-card px-2 caption text-foreground focus:outline-none focus:border-brand-primary"
88
88
  />
89
89
  </div>
90
90
  {presets && presets.length > 0 && (
91
- <div className="mt-3 grid grid-cols-8 gap-1.5">
91
+ <div className="mt-3 grid grid-cols-4 gap-2">
92
92
  {presets.map((p) => (
93
93
  <button
94
94
  key={p}
95
95
  type="button"
96
96
  onClick={() => onChange(p)}
97
97
  aria-label={p}
98
- className="h-5 w-5 rounded-sm border border-black/10 transition-transform hover:scale-110 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-primary/30"
98
+ className="size-10 rounded-md border border-black/10 transition-transform hover:scale-105 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-primary/30"
99
99
  style={{ backgroundColor: p }}
100
100
  />
101
101
  ))}
@@ -84,14 +84,20 @@ function Combobox({
84
84
  }
85
85
  if (e.key === "ArrowDown") {
86
86
  e.preventDefault();
87
- if (!open) { setOpen(true); return; }
87
+ if (!open) {
88
+ setOpen(true);
89
+ return;
90
+ }
88
91
  setActiveIndex((i) => Math.min(i + 1, filtered.length - 1));
89
92
  } else if (e.key === "ArrowUp") {
90
93
  e.preventDefault();
91
94
  setActiveIndex((i) => Math.max(i - 1, 0));
92
95
  } else if (e.key === "Enter") {
93
96
  e.preventDefault();
94
- if (!open) { setOpen(true); return; }
97
+ if (!open) {
98
+ setOpen(true);
99
+ return;
100
+ }
95
101
  const target = activeIndex >= 0 ? filtered[activeIndex] : filtered[0];
96
102
  if (target) selectOption(target);
97
103
  } else if (e.key === "Tab") {
@@ -121,10 +127,12 @@ function Combobox({
121
127
  aria-expanded={open}
122
128
  aria-haspopup="listbox"
123
129
  aria-controls={open ? listboxId : undefined}
124
- aria-activedescendant={open && activeIndex >= 0 ? `${listboxId}-option-${activeIndex}` : undefined}
130
+ aria-activedescendant={
131
+ open && activeIndex >= 0 ? `${listboxId}-option-${activeIndex}` : undefined
132
+ }
125
133
  aria-autocomplete="list"
126
134
  className={cn(
127
- "flex h-9 w-full rounded-lg border border-border bg-card pr-8 body text-foreground",
135
+ "flex h-10 w-full rounded-lg border border-border bg-card pr-10 body text-foreground",
128
136
  "placeholder:text-muted-foreground",
129
137
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/30 focus-visible:border-border",
130
138
  "disabled:cursor-not-allowed disabled:opacity-50",
@@ -150,7 +158,7 @@ function Combobox({
150
158
  type="button"
151
159
  tabIndex={-1}
152
160
  aria-label={open ? "Close" : "Open"}
153
- className="absolute inset-y-0 right-0 flex items-center px-2 text-muted-foreground hover:text-muted-foreground transition-colors"
161
+ className="absolute inset-y-0 right-0 flex w-10 items-center justify-center text-muted-foreground hover:text-muted-foreground transition-colors"
154
162
  onClick={() => {
155
163
  if (open) {
156
164
  closeDropdown();
@@ -181,7 +189,7 @@ function Combobox({
181
189
  role="option"
182
190
  aria-selected={isSelected}
183
191
  className={cn(
184
- "flex cursor-pointer select-none items-center gap-2.5 px-3 py-2 body transition-colors",
192
+ "flex min-h-10 cursor-pointer select-none items-center gap-2.5 px-3 py-2 body transition-colors",
185
193
  isSelected
186
194
  ? "bg-brand-primary text-background"
187
195
  : isActive
@@ -197,7 +205,9 @@ function Combobox({
197
205
  <div
198
206
  className={cn(
199
207
  "flex size-6 shrink-0 items-center justify-center rounded-full caption-xs font-semibold",
200
- isSelected ? "bg-card/20 text-background" : "bg-muted text-muted-foreground",
208
+ isSelected
209
+ ? "bg-card/20 text-background"
210
+ : "bg-muted text-muted-foreground",
201
211
  )}
202
212
  >
203
213
  {option.avatar}
@@ -107,7 +107,7 @@ function CommandPalette({
107
107
  <button
108
108
  key={item.id ?? i}
109
109
  type="button"
110
- className="flex w-full items-center gap-3 px-4 py-2.5 body text-left transition-colors hover:bg-muted focus-visible:bg-muted focus-visible:outline-none"
110
+ className="flex min-h-10 w-full items-center gap-3 px-4 py-2.5 body text-left transition-colors hover:bg-muted focus-visible:bg-muted focus-visible:outline-none"
111
111
  onClick={() => handleSelect(item)}
112
112
  >
113
113
  {item.icon && (
@@ -118,7 +118,9 @@ function CommandPalette({
118
118
  <div className="min-w-0 flex-1">
119
119
  <p className="font-medium text-foreground truncate">{item.label}</p>
120
120
  {item.description && (
121
- <p className="caption text-muted-foreground truncate">{item.description}</p>
121
+ <p className="caption text-muted-foreground truncate">
122
+ {item.description}
123
+ </p>
122
124
  )}
123
125
  </div>
124
126
  <ArrowRight size={13} className="shrink-0 text-muted-foreground" />