@hilum/ui 1.0.1 → 2.0.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 (82) hide show
  1. package/README.md +2 -2
  2. package/dist/{chunk-ELL3JM3Z.js → chunk-H6JZQWX3.js} +59 -15
  3. package/dist/chunk-H6JZQWX3.js.map +1 -0
  4. package/dist/index.d.ts +350 -290
  5. package/dist/index.js +490 -436
  6. package/dist/index.js.map +1 -1
  7. package/dist/tokens.css +42 -16
  8. package/dist/tokens.d.ts +33 -8
  9. package/dist/tokens.js +1 -1
  10. package/llms.txt +9 -9
  11. package/package.json +1 -1
  12. package/src/components/accordion.tsx +5 -5
  13. package/src/components/action-panel.tsx +8 -6
  14. package/src/components/activity-feed.tsx +7 -5
  15. package/src/components/alert-dialog.tsx +5 -5
  16. package/src/components/alert.tsx +5 -5
  17. package/src/components/avatar-stack.tsx +3 -3
  18. package/src/components/avatar.tsx +4 -4
  19. package/src/components/badge.tsx +7 -7
  20. package/src/components/breadcrumb.tsx +5 -6
  21. package/src/components/button-group.tsx +7 -4
  22. package/src/components/button.tsx +7 -7
  23. package/src/components/calendar.tsx +10 -10
  24. package/src/components/card-heading.tsx +3 -3
  25. package/src/components/card.tsx +4 -4
  26. package/src/components/chart.tsx +10 -10
  27. package/src/components/checkbox.tsx +2 -2
  28. package/src/components/color-input.tsx +7 -5
  29. package/src/components/color-picker.tsx +8 -6
  30. package/src/components/combobox.tsx +66 -31
  31. package/src/components/command-palette.tsx +13 -11
  32. package/src/components/command.tsx +14 -12
  33. package/src/components/context-menu.tsx +16 -16
  34. package/src/components/data-table.tsx +18 -7
  35. package/src/components/date-picker.tsx +2 -2
  36. package/src/components/description-list.tsx +10 -8
  37. package/src/components/dialog.tsx +4 -4
  38. package/src/components/drawer.tsx +5 -5
  39. package/src/components/dropdown-menu.tsx +16 -16
  40. package/src/components/empty-state.tsx +5 -3
  41. package/src/components/field.tsx +4 -4
  42. package/src/components/grid-list.tsx +17 -13
  43. package/src/components/hover-card.tsx +1 -1
  44. package/src/components/input-group.tsx +10 -10
  45. package/src/components/input-number.tsx +7 -7
  46. package/src/components/input-otp.tsx +3 -3
  47. package/src/components/input.tsx +4 -4
  48. package/src/components/kbd.tsx +1 -1
  49. package/src/components/label.tsx +1 -1
  50. package/src/components/media-object.tsx +2 -0
  51. package/src/components/menubar.tsx +21 -21
  52. package/src/components/native-select.tsx +5 -5
  53. package/src/components/navigation-menu.tsx +10 -10
  54. package/src/components/notification.tsx +13 -11
  55. package/src/components/page-heading.tsx +8 -8
  56. package/src/components/pagination.tsx +1 -1
  57. package/src/components/popover.tsx +1 -1
  58. package/src/components/progress.tsx +1 -1
  59. package/src/components/property-row.tsx +3 -1
  60. package/src/components/radio-card.tsx +10 -8
  61. package/src/components/radio-group.tsx +4 -4
  62. package/src/components/resizable.tsx +3 -3
  63. package/src/components/scroll-area.tsx +1 -1
  64. package/src/components/section-heading.tsx +3 -3
  65. package/src/components/select.tsx +13 -13
  66. package/src/components/separator.tsx +1 -1
  67. package/src/components/sheet.tsx +4 -4
  68. package/src/components/sidebar.tsx +20 -20
  69. package/src/components/skeleton.tsx +1 -1
  70. package/src/components/slider.tsx +2 -2
  71. package/src/components/sonner.tsx +9 -8
  72. package/src/components/stacked-list.tsx +5 -5
  73. package/src/components/stat-card.tsx +9 -7
  74. package/src/components/steps.tsx +16 -14
  75. package/src/components/switch.tsx +2 -2
  76. package/src/components/table.tsx +9 -9
  77. package/src/components/tabs.tsx +2 -2
  78. package/src/components/textarea.tsx +4 -4
  79. package/src/components/toggle.tsx +9 -9
  80. package/src/components/tooltip.tsx +1 -1
  81. package/src/tokens/tokens.ts +36 -9
  82. package/dist/chunk-ELL3JM3Z.js.map +0 -1
@@ -16,35 +16,35 @@ function Calendar({ className, classNames, showOutsideDays = true, ...props }: C
16
16
  months: "flex flex-col sm:flex-row gap-4",
17
17
  month: "flex flex-col gap-4",
18
18
  month_caption: "flex justify-center pt-1 relative items-center px-10",
19
- caption_label: "body font-semibold text-ground-900",
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
22
  "absolute left-0 h-7 w-7 flex items-center justify-center rounded-md",
23
- "text-ground-400 hover:bg-ground-100 hover:text-ground-700 transition-colors",
23
+ "text-muted-foreground hover:bg-muted hover:text-muted-foreground transition-colors",
24
24
  ),
25
25
  button_next: cn(
26
26
  "absolute right-0 h-7 w-7 flex items-center justify-center rounded-md",
27
- "text-ground-400 hover:bg-ground-100 hover:text-ground-700 transition-colors",
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-ground-400 font-normal",
31
+ weekday: "w-9 h-9 flex 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
35
  "h-9 w-9 flex items-center justify-center rounded-full body font-normal",
36
- "text-ground-900 hover:bg-ground-100 transition-colors",
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
  ),
39
39
  selected:
40
- "[&>button]:bg-brand-primary [&>button]:text-white [&>button]:hover:bg-brand-primary/90",
40
+ "[&>button]:bg-brand-primary [&>button]:text-background [&>button]:hover:bg-brand-primary/90",
41
41
  today: "[&>button]:font-semibold [&>button]:text-brand-primary",
42
- outside: "opacity-40 [&>button]:text-ground-400",
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-white [&>button]:rounded-full",
45
- range_end: "[&>button]:bg-brand-primary [&>button]:text-white [&>button]:rounded-full",
44
+ range_start: "[&>button]:bg-brand-primary [&>button]:text-background [&>button]:rounded-full",
45
+ range_end: "[&>button]:bg-brand-primary [&>button]:text-background [&>button]:rounded-full",
46
46
  range_middle:
47
- "[&>button]:bg-brand-primary/15 [&>button]:text-ground-900 [&>button]:rounded-none",
47
+ "[&>button]:bg-brand-primary/15 [&>button]:text-foreground [&>button]:rounded-none",
48
48
  hidden: "invisible",
49
49
  ...classNames,
50
50
  }}
@@ -21,15 +21,15 @@ function CardHeading({ title, description, actions, children, className }: CardH
21
21
  return (
22
22
  <div
23
23
  className={cn(
24
- "flex items-start justify-between gap-4 border-b border-ground-100 px-5 py-4",
24
+ "flex items-start justify-between gap-4 border-b border-border px-5 py-4",
25
25
  className,
26
26
  )}
27
27
  >
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-ground-900 truncate">{title}</p>
32
- {description && <p className="caption text-ground-400 mt-0.5">{description}</p>}
31
+ <p className="body font-semibold text-foreground truncate">{title}</p>
32
+ {description && <p className="caption text-muted-foreground mt-0.5">{description}</p>}
33
33
  </div>
34
34
  </div>
35
35
 
@@ -9,8 +9,8 @@ import { cn } from "../lib/utils";
9
9
  const cardVariants = cva("rounded-xl", {
10
10
  variants: {
11
11
  variant: {
12
- default: "bg-white shadow-natural",
13
- muted: "bg-ground-50",
12
+ default: "bg-card shadow-natural",
13
+ muted: "bg-muted",
14
14
  ghost: "bg-transparent",
15
15
  },
16
16
  },
@@ -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-ground-900", className)}
57
+ className={cn("subheading 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-ground-500", className)}
69
+ className={cn("caption text-muted-foreground", className)}
70
70
  {...props}
71
71
  />
72
72
  ),
@@ -6,12 +6,12 @@ import { cn } from "../lib/utils";
6
6
  import { tokens } from "../tokens/tokens";
7
7
 
8
8
  export const CHART_COLORS = {
9
- primary: tokens.brand.primary, // "#C100F1" — vivid purple
10
- secondary: tokens.semantic.light.success, // "#CDEA19" — lime
11
- tertiary: tokens.brand.secondary, // "#FFF5BF" — pale lemon
12
- muted: tokens.ground[400], // "#a8978a"
13
- subtle: tokens.ground[200], // "#e3dcd4"
14
- dark: tokens.ground[900], // "#26181a"
9
+ primary: tokens.semantic.light.primary,
10
+ secondary: tokens.semantic.light.success,
11
+ tertiary: tokens.semantic.light.warning,
12
+ muted: tokens.semantic.light.mutedForeground,
13
+ subtle: tokens.semantic.light.border,
14
+ dark: tokens.semantic.light.foreground,
15
15
  };
16
16
 
17
17
  interface ChartContainerProps {
@@ -39,16 +39,16 @@ interface ChartTooltipProps extends Partial<TooltipContentProps<number, string>>
39
39
  function ChartTooltip({ active, payload, label, labelClassName }: ChartTooltipProps) {
40
40
  if (!active || !payload?.length) return null;
41
41
  return (
42
- <div className="rounded-xl border border-ground-100 bg-white px-3 py-2 shadow-elevated">
43
- {label && <p className={cn("mb-1 label text-ground-400", labelClassName)}>{label}</p>}
42
+ <div className="rounded-xl border border-border bg-card px-3 py-2 shadow-elevated">
43
+ {label && <p className={cn("mb-1 label text-muted-foreground", labelClassName)}>{label}</p>}
44
44
  {payload.map((entry, i) => (
45
45
  <div key={i} className="flex items-center gap-2">
46
46
  <span
47
47
  className="inline-block h-2 w-2 rounded-full"
48
48
  style={{ backgroundColor: entry.color }}
49
49
  />
50
- <span className="caption text-ground-500">{entry.name}:</span>
51
- <span className="caption font-medium text-ground-900">{entry.value}</span>
50
+ <span className="caption text-muted-foreground">{entry.name}:</span>
51
+ <span className="caption font-medium text-foreground">{entry.value}</span>
52
52
  </div>
53
53
  ))}
54
54
  </div>
@@ -12,7 +12,7 @@ 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-ground-300 bg-white transition-colors",
15
+ "peer size-4 shrink-0 rounded border border-border bg-card transition-colors",
16
16
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-primary/30",
17
17
  "disabled:cursor-not-allowed disabled:opacity-50",
18
18
  "data-[state=checked]:bg-brand-primary data-[state=checked]:border-brand-primary",
@@ -21,7 +21,7 @@ const CheckboxRoot = React.forwardRef<
21
21
  )}
22
22
  {...props}
23
23
  >
24
- <Checkbox.Indicator className="flex items-center justify-center text-white">
24
+ <Checkbox.Indicator className="flex items-center justify-center text-background">
25
25
  {props.checked === "indeterminate" ? (
26
26
  <Minus size={11} strokeWidth={3} />
27
27
  ) : (
@@ -42,7 +42,7 @@ function ColorInput({
42
42
  return (
43
43
  <div
44
44
  className={cn(
45
- "inline-flex h-8 items-stretch gap-0 rounded-md border border-ground-200 bg-white overflow-hidden",
45
+ "inline-flex h-8 items-stretch gap-0 rounded-md border border-border bg-card overflow-hidden",
46
46
  "focus-within:ring-2 focus-within:ring-brand-primary/20 focus-within:border-brand-primary",
47
47
  disabled && "opacity-50 pointer-events-none",
48
48
  className,
@@ -65,19 +65,19 @@ function ColorInput({
65
65
  commitHex("#" + (e.target as HTMLInputElement).value.replace(/^#/, ""));
66
66
  }}
67
67
  spellCheck={false}
68
- className="w-[5.5rem] caption text-ground-900 px-2 bg-transparent border-l border-ground-100 focus:outline-none uppercase"
68
+ className="w-[5.5rem] caption text-foreground px-2 bg-transparent border-l border-border focus:outline-none uppercase"
69
69
  />
70
70
  {typeof opacity === "number" && onOpacityChange && (
71
- <div className="relative flex items-center border-l border-ground-100">
71
+ <div className="relative flex items-center border-l border-border">
72
72
  <input
73
73
  type="number"
74
74
  min={0}
75
75
  max={100}
76
76
  value={Math.round(opacity)}
77
77
  onChange={(e) => onOpacityChange(Number(e.target.value))}
78
- className="w-12 caption text-ground-900 px-2 bg-transparent focus:outline-none text-right [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
78
+ className="w-12 caption text-foreground px-2 bg-transparent focus:outline-none text-right [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
79
79
  />
80
- <span aria-hidden className="caption-xs text-ground-400 pr-2">
80
+ <span aria-hidden className="caption-xs text-muted-foreground pr-2">
81
81
  %
82
82
  </span>
83
83
  </div>
@@ -86,5 +86,7 @@ function ColorInput({
86
86
  );
87
87
  }
88
88
 
89
+ ColorInput.displayName = "ColorInput";
90
+
89
91
  export { ColorInput };
90
92
  export type { ColorInputProps };
@@ -45,8 +45,8 @@ 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-ground-200 bg-white",
49
- "transition-colors hover:border-ground-300",
48
+ "inline-flex h-8 w-8 items-center justify-center rounded-md border border-border bg-card",
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",
52
52
  className,
@@ -63,7 +63,7 @@ function ColorPicker({
63
63
  <Popover.Content
64
64
  align="start"
65
65
  sideOffset={6}
66
- className="z-50 w-56 rounded-xl bg-white p-3 shadow-natural outline-none"
66
+ className="z-50 w-56 rounded-xl bg-card p-3 shadow-natural outline-none"
67
67
  >
68
68
  <input
69
69
  type="color"
@@ -72,10 +72,10 @@ function ColorPicker({
72
72
  setHex(e.target.value);
73
73
  onChange(e.target.value);
74
74
  }}
75
- className="h-10 w-full cursor-pointer rounded-md border border-ground-200 bg-white p-0.5"
75
+ className="h-10 w-full cursor-pointer rounded-md border border-border bg-card p-0.5"
76
76
  />
77
77
  <div className="mt-2 flex items-center gap-2">
78
- <span className="caption text-ground-500">Hex</span>
78
+ <span className="caption text-muted-foreground">Hex</span>
79
79
  <input
80
80
  type="text"
81
81
  value={hex}
@@ -84,7 +84,7 @@ 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-ground-200 bg-white px-2 caption text-ground-900 focus:outline-none focus:border-brand-primary"
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"
88
88
  />
89
89
  </div>
90
90
  {presets && presets.length > 0 && (
@@ -107,5 +107,7 @@ function ColorPicker({
107
107
  );
108
108
  }
109
109
 
110
+ ColorPicker.displayName = "ColorPicker";
111
+
110
112
  export { ColorPicker };
111
113
  export type { ColorPickerProps };
@@ -33,8 +33,10 @@ function Combobox({
33
33
  }: ComboboxProps) {
34
34
  const [open, setOpen] = React.useState(false);
35
35
  const [query, setQuery] = React.useState("");
36
+ const [activeIndex, setActiveIndex] = React.useState(-1);
36
37
  const containerRef = React.useRef<HTMLDivElement>(null);
37
38
  const inputRef = React.useRef<HTMLInputElement>(null);
39
+ const listboxId = React.useId();
38
40
 
39
41
  const selectedOption = options.find((o) => o.value === value);
40
42
 
@@ -47,6 +49,11 @@ function Combobox({
47
49
  o.description?.toLowerCase().includes(query.toLowerCase()),
48
50
  );
49
51
 
52
+ // Reset active index when the filtered list changes
53
+ React.useEffect(() => {
54
+ setActiveIndex(-1);
55
+ }, [filtered.length, open]);
56
+
50
57
  // Close on outside click
51
58
  React.useEffect(() => {
52
59
  function onMouseDown(e: MouseEvent) {
@@ -59,25 +66,45 @@ function Combobox({
59
66
  return () => document.removeEventListener("mousedown", onMouseDown);
60
67
  }, []);
61
68
 
62
- // Close on Escape
63
- React.useEffect(() => {
64
- if (!open) return;
65
- function onKey(e: KeyboardEvent) {
66
- if (e.key === "Escape") {
67
- setOpen(false);
68
- setQuery("");
69
- }
69
+ function closeDropdown() {
70
+ setOpen(false);
71
+ setQuery("");
72
+ setActiveIndex(-1);
73
+ }
74
+
75
+ function selectOption(opt: ComboboxOption) {
76
+ onValueChange?.(opt.value);
77
+ closeDropdown();
78
+ }
79
+
80
+ function handleInputKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {
81
+ if (e.key === "Escape") {
82
+ closeDropdown();
83
+ return;
70
84
  }
71
- document.addEventListener("keydown", onKey);
72
- return () => document.removeEventListener("keydown", onKey);
73
- }, [open]);
85
+ if (e.key === "ArrowDown") {
86
+ e.preventDefault();
87
+ if (!open) { setOpen(true); return; }
88
+ setActiveIndex((i) => Math.min(i + 1, filtered.length - 1));
89
+ } else if (e.key === "ArrowUp") {
90
+ e.preventDefault();
91
+ setActiveIndex((i) => Math.max(i - 1, 0));
92
+ } else if (e.key === "Enter") {
93
+ e.preventDefault();
94
+ if (!open) { setOpen(true); return; }
95
+ const target = activeIndex >= 0 ? filtered[activeIndex] : filtered[0];
96
+ if (target) selectOption(target);
97
+ } else if (e.key === "Tab") {
98
+ closeDropdown();
99
+ }
100
+ }
74
101
 
75
102
  return (
76
103
  <div ref={containerRef} className={cn("relative", className)}>
77
104
  {/* Trigger */}
78
105
  <div className="relative flex items-center">
79
106
  {selectedOption?.avatar && !open && (
80
- <div className="pointer-events-none absolute left-2.5 flex size-5 items-center justify-center rounded-full bg-ground-200 caption-xs font-semibold text-ground-700 shrink-0">
107
+ <div className="pointer-events-none absolute left-2.5 flex size-5 items-center justify-center rounded-full bg-muted caption-xs font-semibold text-muted-foreground shrink-0">
81
108
  {selectedOption.avatar}
82
109
  </div>
83
110
  )}
@@ -92,10 +119,14 @@ function Combobox({
92
119
  type="text"
93
120
  role="combobox"
94
121
  aria-expanded={open}
122
+ aria-haspopup="listbox"
123
+ aria-controls={open ? listboxId : undefined}
124
+ aria-activedescendant={open && activeIndex >= 0 ? `${listboxId}-option-${activeIndex}` : undefined}
125
+ aria-autocomplete="list"
95
126
  className={cn(
96
- "flex h-9 w-full rounded-lg border border-ground-200 bg-white pr-8 body text-ground-900",
97
- "placeholder:text-ground-400",
98
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ground-400/30 focus-visible:border-ground-400",
127
+ "flex h-9 w-full rounded-lg border border-border bg-card pr-8 body text-foreground",
128
+ "placeholder:text-muted-foreground",
129
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/30 focus-visible:border-border",
99
130
  "disabled:cursor-not-allowed disabled:opacity-50",
100
131
  selectedOption?.avatar && !open
101
132
  ? "pl-8"
@@ -113,15 +144,16 @@ function Combobox({
113
144
  setOpen(true);
114
145
  setQuery("");
115
146
  }}
147
+ onKeyDown={handleInputKeyDown}
116
148
  />
117
149
  <button
118
150
  type="button"
119
151
  tabIndex={-1}
120
- className="absolute inset-y-0 right-0 flex items-center px-2 text-ground-400 hover:text-ground-700 transition-colors"
152
+ 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"
121
154
  onClick={() => {
122
155
  if (open) {
123
- setOpen(false);
124
- setQuery("");
156
+ closeDropdown();
125
157
  } else {
126
158
  setOpen(true);
127
159
  inputRef.current?.focus();
@@ -134,37 +166,38 @@ function Combobox({
134
166
 
135
167
  {/* Dropdown */}
136
168
  {open && (
137
- <div className="absolute z-50 mt-1 w-full overflow-hidden rounded-lg border border-ground-200 bg-white shadow-elevated">
138
- <ul role="listbox" className="max-h-60 overflow-auto py-1">
169
+ <div className="absolute z-50 mt-1 w-full overflow-hidden rounded-lg border border-border bg-card shadow-elevated">
170
+ <ul id={listboxId} role="listbox" className="max-h-60 overflow-auto py-1">
139
171
  {filtered.length === 0 ? (
140
- <li className="px-3 py-2 body text-ground-400">{emptyText}</li>
172
+ <li className="px-3 py-2 body text-muted-foreground">{emptyText}</li>
141
173
  ) : (
142
- filtered.map((option) => {
174
+ filtered.map((option, idx) => {
143
175
  const isSelected = option.value === value;
176
+ const isActive = idx === activeIndex;
144
177
  return (
145
178
  <li
146
179
  key={option.value}
180
+ id={`${listboxId}-option-${idx}`}
147
181
  role="option"
148
182
  aria-selected={isSelected}
149
183
  className={cn(
150
184
  "flex cursor-pointer select-none items-center gap-2.5 px-3 py-2 body transition-colors",
151
185
  isSelected
152
- ? "bg-brand-primary text-white"
153
- : "text-ground-900 hover:bg-ground-50",
186
+ ? "bg-brand-primary text-background"
187
+ : isActive
188
+ ? "bg-muted text-foreground"
189
+ : "text-foreground hover:bg-muted",
154
190
  )}
155
191
  onMouseDown={(e) => e.preventDefault()}
156
- onClick={() => {
157
- onValueChange?.(option.value);
158
- setQuery("");
159
- setOpen(false);
160
- }}
192
+ onMouseEnter={() => setActiveIndex(idx)}
193
+ onClick={() => selectOption(option)}
161
194
  >
162
195
  {/* Avatar */}
163
196
  {option.avatar && (
164
197
  <div
165
198
  className={cn(
166
199
  "flex size-6 shrink-0 items-center justify-center rounded-full caption-xs font-semibold",
167
- isSelected ? "bg-white/20 text-white" : "bg-ground-200 text-ground-700",
200
+ isSelected ? "bg-card/20 text-background" : "bg-muted text-muted-foreground",
168
201
  )}
169
202
  >
170
203
  {option.avatar}
@@ -185,7 +218,7 @@ function Combobox({
185
218
  <p
186
219
  className={cn(
187
220
  "caption truncate",
188
- isSelected ? "text-white/70" : "text-ground-400",
221
+ isSelected ? "text-background/70" : "text-muted-foreground",
189
222
  )}
190
223
  >
191
224
  {option.description}
@@ -204,4 +237,6 @@ function Combobox({
204
237
  );
205
238
  }
206
239
 
240
+ Combobox.displayName = "Combobox";
241
+
207
242
  export { Combobox };
@@ -73,12 +73,12 @@ function CommandPalette({
73
73
  <Dialog open={open} onOpenChange={(v) => !v && onClose()}>
74
74
  <DialogContent className="gap-0 overflow-hidden p-0 sm:max-w-xl">
75
75
  {/* Search input */}
76
- <div className="flex items-center gap-3 border-b border-ground-100 px-4">
77
- <Search size={16} className="shrink-0 text-ground-400" />
76
+ <div className="flex items-center gap-3 border-b border-border px-4">
77
+ <Search size={16} className="shrink-0 text-muted-foreground" />
78
78
  <input
79
79
  ref={inputRef}
80
80
  type="text"
81
- className="h-12 flex-1 bg-transparent body text-ground-900 placeholder:text-ground-400 focus:outline-none"
81
+ className="h-12 flex-1 bg-transparent body text-foreground placeholder:text-muted-foreground focus:outline-none"
82
82
  placeholder={placeholder}
83
83
  value={query}
84
84
  onChange={(e) => setQuery(e.target.value)}
@@ -88,7 +88,7 @@ function CommandPalette({
88
88
  }}
89
89
  />
90
90
  <kbd className="hidden items-center gap-0.5 sm:flex">
91
- <span className="caption-xs font-medium text-ground-400 rounded border border-ground-200 px-1.5 py-0.5">
91
+ <span className="caption-xs font-medium text-muted-foreground rounded border border-border px-1.5 py-0.5">
92
92
  esc
93
93
  </span>
94
94
  </kbd>
@@ -97,31 +97,31 @@ function CommandPalette({
97
97
  {/* Results */}
98
98
  <div className="max-h-80 overflow-y-auto">
99
99
  {filtered.length === 0 ? (
100
- <p className="px-4 py-8 text-center body text-ground-400">{emptyText}</p>
100
+ <p className="px-4 py-8 text-center body text-muted-foreground">{emptyText}</p>
101
101
  ) : (
102
102
  <ul role="list" className="py-2">
103
103
  {categories.map((cat) => (
104
104
  <li key={cat}>
105
- {cat && <p className="label px-4 py-2 text-ground-400">{cat}</p>}
105
+ {cat && <p className="label px-4 py-2 text-muted-foreground">{cat}</p>}
106
106
  {grouped[cat].map((item, i) => (
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-ground-50 focus-visible:bg-ground-50 focus-visible:outline-none"
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"
111
111
  onClick={() => handleSelect(item)}
112
112
  >
113
113
  {item.icon && (
114
- <span className="flex size-8 shrink-0 items-center justify-center rounded-lg border border-ground-200 bg-white text-ground-500">
114
+ <span className="flex size-8 shrink-0 items-center justify-center rounded-lg border border-border bg-card text-muted-foreground">
115
115
  {item.icon}
116
116
  </span>
117
117
  )}
118
118
  <div className="min-w-0 flex-1">
119
- <p className="font-medium text-ground-900 truncate">{item.label}</p>
119
+ <p className="font-medium text-foreground truncate">{item.label}</p>
120
120
  {item.description && (
121
- <p className="caption text-ground-400 truncate">{item.description}</p>
121
+ <p className="caption text-muted-foreground truncate">{item.description}</p>
122
122
  )}
123
123
  </div>
124
- <ArrowRight size={13} className="shrink-0 text-ground-300" />
124
+ <ArrowRight size={13} className="shrink-0 text-muted-foreground" />
125
125
  </button>
126
126
  ))}
127
127
  </li>
@@ -134,4 +134,6 @@ function CommandPalette({
134
134
  );
135
135
  }
136
136
 
137
+ CommandPalette.displayName = "CommandPalette";
138
+
137
139
  export { CommandPalette };
@@ -44,7 +44,7 @@ function Command({ className, children, onSelect, ...props }: CommandProps) {
44
44
  <CommandVisibleCtx.Provider value={visibleCount}>
45
45
  <div
46
46
  className={cn(
47
- "flex flex-col overflow-hidden rounded-xl border border-ground-200 bg-white",
47
+ "flex flex-col overflow-hidden rounded-xl border border-border bg-card",
48
48
  className,
49
49
  )}
50
50
  {...props}
@@ -62,8 +62,8 @@ const CommandInput = React.forwardRef<
62
62
  >(({ className, ...props }, ref) => {
63
63
  const { query, setQuery } = React.useContext(CommandCtx);
64
64
  return (
65
- <div className="flex items-center gap-2 border-b border-ground-100 px-3">
66
- <Search size={14} className="shrink-0 text-ground-400" />
65
+ <div className="flex items-center gap-2 border-b border-border px-3">
66
+ <Search size={14} className="shrink-0 text-muted-foreground" />
67
67
  <input
68
68
  ref={ref}
69
69
  type="text"
@@ -71,8 +71,8 @@ const CommandInput = React.forwardRef<
71
71
  autoCorrect="off"
72
72
  spellCheck={false}
73
73
  className={cn(
74
- "flex h-10 w-full bg-transparent body text-ground-900",
75
- "placeholder:text-ground-400 focus:outline-none",
74
+ "flex h-10 w-full bg-transparent body text-foreground",
75
+ "placeholder:text-muted-foreground focus:outline-none",
76
76
  className,
77
77
  )}
78
78
  value={query}
@@ -135,7 +135,7 @@ const CommandEmpty = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLD
135
135
  return (
136
136
  <div
137
137
  ref={ref}
138
- className={cn("py-6 text-center caption text-ground-400", className)}
138
+ className={cn("py-6 text-center caption text-muted-foreground", className)}
139
139
  {...props}
140
140
  >
141
141
  {children}
@@ -152,7 +152,7 @@ interface CommandGroupProps extends React.HTMLAttributes<HTMLDivElement> {
152
152
  const CommandGroup = React.forwardRef<HTMLDivElement, CommandGroupProps>(
153
153
  ({ className, heading, children, ...props }, ref) => (
154
154
  <div ref={ref} role="group" className={cn("py-1", className)} {...props}>
155
- {heading && <p className="px-3 pb-1 pt-0.5 label text-ground-400">{heading}</p>}
155
+ {heading && <p className="px-3 pb-1 pt-0.5 label text-muted-foreground">{heading}</p>}
156
156
  {children}
157
157
  </div>
158
158
  ),
@@ -197,9 +197,9 @@ const CommandItem = React.forwardRef<HTMLDivElement, CommandItemProps>(
197
197
  tabIndex={disabled ? undefined : 0}
198
198
  className={cn(
199
199
  "relative flex cursor-default select-none items-center gap-2 rounded-md px-2.5 py-1.5 mx-1",
200
- "body text-ground-700 outline-none transition-colors",
201
- "hover:bg-ground-50 hover:text-ground-900",
202
- "focus:bg-ground-50 focus:text-ground-900",
200
+ "body text-muted-foreground outline-none transition-colors",
201
+ "hover:bg-muted hover:text-foreground",
202
+ "focus:bg-muted focus:text-foreground",
203
203
  disabled && "pointer-events-none opacity-40",
204
204
  className,
205
205
  )}
@@ -221,7 +221,7 @@ CommandItem.displayName = "CommandItem";
221
221
 
222
222
  const CommandSeparator = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
223
223
  ({ className, ...props }, ref) => (
224
- <div ref={ref} className={cn("my-1 h-px bg-ground-100", className)} {...props} />
224
+ <div ref={ref} className={cn("my-1 h-px bg-muted", className)} {...props} />
225
225
  ),
226
226
  );
227
227
  CommandSeparator.displayName = "CommandSeparator";
@@ -229,13 +229,15 @@ CommandSeparator.displayName = "CommandSeparator";
229
229
  function CommandShortcut({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) {
230
230
  return (
231
231
  <span
232
- className={cn("ml-auto caption text-ground-300 tracking-widest font-medium", className)}
232
+ className={cn("ml-auto caption text-muted-foreground tracking-widest font-medium", className)}
233
233
  {...props}
234
234
  />
235
235
  );
236
236
  }
237
237
  CommandShortcut.displayName = "CommandShortcut";
238
238
 
239
+ Command.displayName = "Command";
240
+
239
241
  export {
240
242
  Command,
241
243
  CommandInput,