@hilum/ui 2.0.0 → 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 (75) hide show
  1. package/README.md +2 -2
  2. package/dist/index.d.ts +350 -290
  3. package/dist/index.js +489 -435
  4. package/dist/index.js.map +1 -1
  5. package/llms.txt +9 -9
  6. package/package.json +1 -1
  7. package/src/components/accordion.tsx +5 -5
  8. package/src/components/action-panel.tsx +8 -6
  9. package/src/components/activity-feed.tsx +7 -5
  10. package/src/components/alert-dialog.tsx +5 -5
  11. package/src/components/alert.tsx +5 -5
  12. package/src/components/avatar-stack.tsx +3 -3
  13. package/src/components/avatar.tsx +4 -4
  14. package/src/components/badge.tsx +7 -7
  15. package/src/components/breadcrumb.tsx +5 -6
  16. package/src/components/button-group.tsx +7 -4
  17. package/src/components/button.tsx +7 -7
  18. package/src/components/calendar.tsx +10 -10
  19. package/src/components/card-heading.tsx +3 -3
  20. package/src/components/card.tsx +4 -4
  21. package/src/components/chart.tsx +10 -10
  22. package/src/components/checkbox.tsx +2 -2
  23. package/src/components/color-input.tsx +7 -5
  24. package/src/components/color-picker.tsx +8 -6
  25. package/src/components/combobox.tsx +66 -31
  26. package/src/components/command-palette.tsx +13 -11
  27. package/src/components/command.tsx +14 -12
  28. package/src/components/context-menu.tsx +16 -16
  29. package/src/components/data-table.tsx +18 -7
  30. package/src/components/date-picker.tsx +2 -2
  31. package/src/components/description-list.tsx +10 -8
  32. package/src/components/dialog.tsx +4 -4
  33. package/src/components/drawer.tsx +5 -5
  34. package/src/components/dropdown-menu.tsx +16 -16
  35. package/src/components/empty-state.tsx +5 -3
  36. package/src/components/field.tsx +4 -4
  37. package/src/components/grid-list.tsx +17 -13
  38. package/src/components/hover-card.tsx +1 -1
  39. package/src/components/input-group.tsx +10 -10
  40. package/src/components/input-number.tsx +7 -7
  41. package/src/components/input-otp.tsx +3 -3
  42. package/src/components/input.tsx +4 -4
  43. package/src/components/kbd.tsx +1 -1
  44. package/src/components/label.tsx +1 -1
  45. package/src/components/media-object.tsx +2 -0
  46. package/src/components/menubar.tsx +21 -21
  47. package/src/components/native-select.tsx +5 -5
  48. package/src/components/navigation-menu.tsx +10 -10
  49. package/src/components/notification.tsx +13 -11
  50. package/src/components/page-heading.tsx +8 -8
  51. package/src/components/pagination.tsx +1 -1
  52. package/src/components/popover.tsx +1 -1
  53. package/src/components/progress.tsx +1 -1
  54. package/src/components/property-row.tsx +3 -1
  55. package/src/components/radio-card.tsx +10 -8
  56. package/src/components/radio-group.tsx +4 -4
  57. package/src/components/resizable.tsx +3 -3
  58. package/src/components/scroll-area.tsx +1 -1
  59. package/src/components/section-heading.tsx +3 -3
  60. package/src/components/select.tsx +13 -13
  61. package/src/components/separator.tsx +1 -1
  62. package/src/components/sheet.tsx +4 -4
  63. package/src/components/sidebar.tsx +20 -20
  64. package/src/components/skeleton.tsx +1 -1
  65. package/src/components/slider.tsx +2 -2
  66. package/src/components/sonner.tsx +9 -8
  67. package/src/components/stacked-list.tsx +5 -5
  68. package/src/components/stat-card.tsx +9 -7
  69. package/src/components/steps.tsx +16 -14
  70. package/src/components/switch.tsx +2 -2
  71. package/src/components/table.tsx +9 -9
  72. package/src/components/tabs.tsx +2 -2
  73. package/src/components/textarea.tsx +4 -4
  74. package/src/components/toggle.tsx +9 -9
  75. package/src/components/tooltip.tsx +1 -1
@@ -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,
@@ -20,7 +20,7 @@ const ContextMenuContent = React.forwardRef<
20
20
  <ContextMenu.Content
21
21
  ref={ref}
22
22
  className={cn(
23
- "z-50 min-w-[8rem] bg-white rounded-xl shadow-natural p-1",
23
+ "z-50 min-w-[8rem] bg-card rounded-xl shadow-natural p-1",
24
24
  "data-[state=open]:animate-in data-[state=closed]:animate-out",
25
25
  "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
26
26
  "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
@@ -47,8 +47,8 @@ const ContextMenuItem = React.forwardRef<
47
47
  "relative flex cursor-default select-none items-center gap-2 rounded-md px-2.5 py-1.5",
48
48
  "body outline-none transition-colors",
49
49
  destructive
50
- ? "text-red-600 focus:bg-red-50 focus:text-red-700"
51
- : "text-ground-700 focus:bg-ground-50 focus:text-ground-900",
50
+ ? "text-destructive focus:bg-destructive/10 focus:text-destructive"
51
+ : "text-muted-foreground focus:bg-muted focus:text-foreground",
52
52
  "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
53
53
  inset && "pl-8",
54
54
  className,
@@ -66,8 +66,8 @@ const ContextMenuCheckboxItem = React.forwardRef<
66
66
  ref={ref}
67
67
  className={cn(
68
68
  "relative flex cursor-default select-none items-center gap-2 rounded-md pl-8 pr-2.5 py-1.5",
69
- "body text-ground-700 outline-none transition-colors",
70
- "focus:bg-ground-50 focus:text-ground-900",
69
+ "body text-muted-foreground outline-none transition-colors",
70
+ "focus:bg-muted focus:text-foreground",
71
71
  "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
72
72
  className,
73
73
  )}
@@ -75,7 +75,7 @@ const ContextMenuCheckboxItem = React.forwardRef<
75
75
  >
76
76
  <span className="absolute left-2 flex size-3.5 items-center justify-center">
77
77
  <ContextMenu.ItemIndicator>
78
- <Check size={13} className="text-ground-900" />
78
+ <Check size={13} className="text-foreground" />
79
79
  </ContextMenu.ItemIndicator>
80
80
  </span>
81
81
  {children}
@@ -91,8 +91,8 @@ const ContextMenuRadioItem = React.forwardRef<
91
91
  ref={ref}
92
92
  className={cn(
93
93
  "relative flex cursor-default select-none items-center gap-2 rounded-md pl-8 pr-2.5 py-1.5",
94
- "body text-ground-700 outline-none transition-colors",
95
- "focus:bg-ground-50 focus:text-ground-900",
94
+ "body text-muted-foreground outline-none transition-colors",
95
+ "focus:bg-muted focus:text-foreground",
96
96
  "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
97
97
  className,
98
98
  )}
@@ -100,7 +100,7 @@ const ContextMenuRadioItem = React.forwardRef<
100
100
  >
101
101
  <span className="absolute left-2 flex size-3.5 items-center justify-center">
102
102
  <ContextMenu.ItemIndicator>
103
- <Circle size={8} className="fill-ground-900 text-ground-900" />
103
+ <Circle size={8} className="fill-foreground text-foreground" />
104
104
  </ContextMenu.ItemIndicator>
105
105
  </span>
106
106
  {children}
@@ -116,7 +116,7 @@ const ContextMenuLabel = React.forwardRef<
116
116
  >(({ className, inset, ...props }, ref) => (
117
117
  <ContextMenu.Label
118
118
  ref={ref}
119
- className={cn("px-2.5 py-1 label text-ground-400", inset && "pl-8", className)}
119
+ className={cn("px-2.5 py-1 label text-muted-foreground", inset && "pl-8", className)}
120
120
  {...props}
121
121
  />
122
122
  ));
@@ -128,7 +128,7 @@ const ContextMenuSeparator = React.forwardRef<
128
128
  >(({ className, ...props }, ref) => (
129
129
  <ContextMenu.Separator
130
130
  ref={ref}
131
- className={cn("mx-1 my-1 h-px bg-ground-100", className)}
131
+ className={cn("mx-1 my-1 h-px bg-muted", className)}
132
132
  {...props}
133
133
  />
134
134
  ));
@@ -144,15 +144,15 @@ const ContextMenuSubTrigger = React.forwardRef<
144
144
  ref={ref}
145
145
  className={cn(
146
146
  "relative flex cursor-default select-none items-center gap-2 rounded-md px-2.5 py-1.5",
147
- "body text-ground-700 outline-none transition-colors",
148
- "focus:bg-ground-50 focus:text-ground-900 data-[state=open]:bg-ground-50",
147
+ "body text-muted-foreground outline-none transition-colors",
148
+ "focus:bg-muted focus:text-foreground data-[state=open]:bg-muted",
149
149
  inset && "pl-8",
150
150
  className,
151
151
  )}
152
152
  {...props}
153
153
  >
154
154
  {children}
155
- <ChevronRight size={14} className="ml-auto text-ground-400" />
155
+ <ChevronRight size={14} className="ml-auto text-muted-foreground" />
156
156
  </ContextMenu.SubTrigger>
157
157
  ));
158
158
  ContextMenuSubTrigger.displayName = "ContextMenuSubTrigger";
@@ -164,7 +164,7 @@ const ContextMenuSubContent = React.forwardRef<
164
164
  <ContextMenu.SubContent
165
165
  ref={ref}
166
166
  className={cn(
167
- "z-50 min-w-[8rem] bg-white rounded-xl border border-ground-100 shadow-natural p-1",
167
+ "z-50 min-w-[8rem] bg-card rounded-xl border border-border shadow-natural p-1",
168
168
  "data-[state=open]:animate-in data-[state=closed]:animate-out",
169
169
  "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
170
170
  "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
@@ -177,7 +177,7 @@ const ContextMenuSubContent = React.forwardRef<
177
177
  ContextMenuSubContent.displayName = "ContextMenuSubContent";
178
178
 
179
179
  function ContextMenuShortcut({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) {
180
- return <span className={cn("ml-auto caption text-ground-400", className)} {...props} />;
180
+ return <span className={cn("ml-auto caption text-muted-foreground", className)} {...props} />;
181
181
  }
182
182
  ContextMenuShortcut.displayName = "ContextMenuShortcut";
183
183
 
@@ -67,12 +67,23 @@ function DataTable<TData>({
67
67
  {table.getHeaderGroups().map((headerGroup) => (
68
68
  <TableRow key={headerGroup.id}>
69
69
  {headerGroup.headers.map((header) => (
70
- <TableHead key={header.id}>
70
+ <TableHead
71
+ key={header.id}
72
+ aria-sort={
73
+ header.column.getCanSort()
74
+ ? header.column.getIsSorted() === "asc"
75
+ ? "ascending"
76
+ : header.column.getIsSorted() === "desc"
77
+ ? "descending"
78
+ : "none"
79
+ : undefined
80
+ }
81
+ >
71
82
  {header.isPlaceholder ? null : header.column.getCanSort() ? (
72
83
  <button
73
84
  className={cn(
74
- "flex items-center gap-1 transition-colors hover:text-ground-700",
75
- header.column.getIsSorted() && "text-ground-900",
85
+ "flex items-center gap-1 transition-colors hover:text-muted-foreground",
86
+ header.column.getIsSorted() && "text-foreground",
76
87
  )}
77
88
  onClick={header.column.getToggleSortingHandler()}
78
89
  >
@@ -82,7 +93,7 @@ function DataTable<TData>({
82
93
  ) : header.column.getIsSorted() === "desc" ? (
83
94
  <ChevronDown size={12} className="text-brand-primary" />
84
95
  ) : (
85
- <ChevronsUpDown size={12} className="text-ground-300" />
96
+ <ChevronsUpDown size={12} className="text-muted-foreground" />
86
97
  )}
87
98
  </button>
88
99
  ) : (
@@ -106,7 +117,7 @@ function DataTable<TData>({
106
117
  ))
107
118
  ) : (
108
119
  <TableRow>
109
- <TableCell colSpan={columns.length} className="h-24 text-center text-ground-400">
120
+ <TableCell colSpan={columns.length} className="h-24 text-center text-muted-foreground">
110
121
  No results.
111
122
  </TableCell>
112
123
  </TableRow>
@@ -115,12 +126,12 @@ function DataTable<TData>({
115
126
  </Table>
116
127
  {showPagination && (
117
128
  <div className="flex items-center justify-between">
118
- <p className="caption text-ground-400">
129
+ <p className="caption text-muted-foreground">
119
130
  {table.getFilteredRowModel().rows.length} result
120
131
  {table.getFilteredRowModel().rows.length !== 1 ? "s" : ""}
121
132
  </p>
122
133
  <div className="flex items-center gap-2">
123
- <span className="caption text-ground-400">
134
+ <span className="caption text-muted-foreground">
124
135
  Page {table.getState().pagination.pageIndex + 1} of {table.getPageCount()}
125
136
  </span>
126
137
  <Button
@@ -36,12 +36,12 @@ function DatePicker({
36
36
  variant="outline"
37
37
  className={cn(
38
38
  "w-[240px] justify-start gap-2 text-left font-normal",
39
- !value && "text-ground-400",
39
+ !value && "text-muted-foreground",
40
40
  className,
41
41
  )}
42
42
  disabled={disabled}
43
43
  >
44
- <CalendarIcon size={14} className="text-ground-400 shrink-0" />
44
+ <CalendarIcon size={14} className="text-muted-foreground shrink-0" />
45
45
  {value ? formatDate(value) : <span>{placeholder}</span>}
46
46
  </Button>
47
47
  </PopoverTrigger>