apex-design-cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.js +747 -0
  3. package/package.json +57 -0
  4. package/registry/components/accordion.json +26 -0
  5. package/registry/components/alert.json +25 -0
  6. package/registry/components/avatar.json +26 -0
  7. package/registry/components/badge.json +24 -0
  8. package/registry/components/breadcrumb.json +28 -0
  9. package/registry/components/button.json +25 -0
  10. package/registry/components/card.json +28 -0
  11. package/registry/components/checkbox.json +23 -0
  12. package/registry/components/command.json +31 -0
  13. package/registry/components/dialog.json +32 -0
  14. package/registry/components/divider.json +22 -0
  15. package/registry/components/dropdown-menu.json +36 -0
  16. package/registry/components/empty-state.json +21 -0
  17. package/registry/components/error-message.json +20 -0
  18. package/registry/components/field-group.json +20 -0
  19. package/registry/components/helper-text.json +20 -0
  20. package/registry/components/input.json +21 -0
  21. package/registry/components/label.json +20 -0
  22. package/registry/components/progress.json +22 -0
  23. package/registry/components/radio.json +23 -0
  24. package/registry/components/select.json +32 -0
  25. package/registry/components/spinner.json +20 -0
  26. package/registry/components/switch.json +22 -0
  27. package/registry/components/table.json +27 -0
  28. package/registry/components/tabs.json +25 -0
  29. package/registry/components/textarea.json +21 -0
  30. package/registry/components/theme-toggler.json +24 -0
  31. package/registry/components/toast.json +31 -0
  32. package/registry/components/tooltip.json +26 -0
  33. package/registry/components/use-theme.json +19 -0
  34. package/registry/components/utils.json +21 -0
  35. package/registry/registry.json +35 -0
  36. package/registry/source/accordion.tsx +55 -0
  37. package/registry/source/alert.tsx +102 -0
  38. package/registry/source/avatar.tsx +137 -0
  39. package/registry/source/badge.tsx +38 -0
  40. package/registry/source/breadcrumb.tsx +109 -0
  41. package/registry/source/button.tsx +58 -0
  42. package/registry/source/card.tsx +108 -0
  43. package/registry/source/checkbox.tsx +170 -0
  44. package/registry/source/command.tsx +195 -0
  45. package/registry/source/dialog.tsx +133 -0
  46. package/registry/source/divider.tsx +84 -0
  47. package/registry/source/dropdown-menu.tsx +209 -0
  48. package/registry/source/empty-state.tsx +88 -0
  49. package/registry/source/error-message.tsx +49 -0
  50. package/registry/source/field-group.tsx +53 -0
  51. package/registry/source/helper-text.tsx +40 -0
  52. package/registry/source/input.tsx +219 -0
  53. package/registry/source/label.tsx +60 -0
  54. package/registry/source/progress.tsx +84 -0
  55. package/registry/source/radio.tsx +161 -0
  56. package/registry/source/select.tsx +278 -0
  57. package/registry/source/spinner.tsx +84 -0
  58. package/registry/source/switch.tsx +104 -0
  59. package/registry/source/table.tsx +116 -0
  60. package/registry/source/tabs.tsx +55 -0
  61. package/registry/source/textarea.tsx +129 -0
  62. package/registry/source/theme-toggler.tsx +94 -0
  63. package/registry/source/toast.tsx +166 -0
  64. package/registry/source/tooltip.tsx +55 -0
  65. package/registry/source/use-theme.tsx +102 -0
  66. package/registry/source/utils.ts +13 -0
@@ -0,0 +1,278 @@
1
+ import * as React from 'react';
2
+ import * as SelectPrimitive from '@radix-ui/react-select';
3
+ import { Check, ChevronDown, ChevronUp } from 'lucide-react';
4
+ import { cn } from '../../lib/utils';
5
+
6
+ // ===================
7
+ // SELECT ROOT
8
+ // ===================
9
+
10
+ const Select = SelectPrimitive.Root;
11
+ const SelectGroup = SelectPrimitive.Group;
12
+ const SelectValue = SelectPrimitive.Value;
13
+
14
+ // ===================
15
+ // SELECT TRIGGER (Button que abre el dropdown)
16
+ // ===================
17
+
18
+ interface SelectTriggerProps extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger> {
19
+ size?: 'sm' | 'md' | 'lg';
20
+ error?: boolean;
21
+ }
22
+
23
+ const SelectTrigger = React.forwardRef<
24
+ React.ElementRef<typeof SelectPrimitive.Trigger>,
25
+ SelectTriggerProps
26
+ >(({ className, children, size = 'md', error = false, ...props }, ref) => {
27
+ const sizeClasses = {
28
+ sm: 'h-8 px-3 text-sm',
29
+ md: 'h-10 px-3 text-base',
30
+ lg: 'h-12 px-4 text-lg',
31
+ };
32
+
33
+ return (
34
+ <SelectPrimitive.Trigger
35
+ ref={ref}
36
+ className={cn(
37
+ 'flex w-full items-center justify-between rounded-md border bg-semantic-control-bg',
38
+ 'transition-colors',
39
+ 'focus:outline-none focus:ring-2 focus:ring-offset-0',
40
+ 'disabled:cursor-not-allowed disabled:bg-semantic-bg-disabled disabled:text-semantic-fg-disabled',
41
+ 'placeholder:text-semantic-control-placeholder',
42
+ '[&>span]:line-clamp-1',
43
+ sizeClasses[size],
44
+ error
45
+ ? 'border-semantic-control-border-error text-semantic-control-fg focus:ring-semantic-control-border-error focus:border-semantic-control-border-error'
46
+ : 'border-semantic-control-border text-semantic-control-fg focus:ring-semantic-focus focus:border-semantic-border-focus',
47
+ className
48
+ )}
49
+ {...props}
50
+ >
51
+ {children}
52
+ <SelectPrimitive.Icon asChild>
53
+ <ChevronDown className="h-4 w-4 text-semantic-control-icon" aria-hidden="true" />
54
+ </SelectPrimitive.Icon>
55
+ </SelectPrimitive.Trigger>
56
+ );
57
+ });
58
+ SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
59
+
60
+ // ===================
61
+ // SELECT SCROLL BUTTONS
62
+ // ===================
63
+
64
+ const SelectScrollUpButton = React.forwardRef<
65
+ React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
66
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
67
+ >(({ className, ...props }, ref) => (
68
+ <SelectPrimitive.ScrollUpButton
69
+ ref={ref}
70
+ className={cn('flex cursor-default items-center justify-center py-1', className)}
71
+ aria-hidden="true"
72
+ {...props}
73
+ >
74
+ <ChevronUp className="h-4 w-4" />
75
+ </SelectPrimitive.ScrollUpButton>
76
+ ));
77
+ SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
78
+
79
+ const SelectScrollDownButton = React.forwardRef<
80
+ React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
81
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
82
+ >(({ className, ...props }, ref) => (
83
+ <SelectPrimitive.ScrollDownButton
84
+ ref={ref}
85
+ className={cn('flex cursor-default items-center justify-center py-1', className)}
86
+ aria-hidden="true"
87
+ {...props}
88
+ >
89
+ <ChevronDown className="h-4 w-4" />
90
+ </SelectPrimitive.ScrollDownButton>
91
+ ));
92
+ SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
93
+
94
+ // ===================
95
+ // SELECT CONTENT (Dropdown panel)
96
+ // ===================
97
+
98
+ const SelectContent = React.forwardRef<
99
+ React.ElementRef<typeof SelectPrimitive.Content>,
100
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
101
+ >(({ className, children, position = 'popper', ...props }, ref) => (
102
+ <SelectPrimitive.Portal>
103
+ <SelectPrimitive.Content
104
+ ref={ref}
105
+ className={cn(
106
+ 'relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border border-semantic-border-default bg-semantic-bg-elevated text-semantic-fg-primary shadow-md',
107
+ 'data-[state=open]:animate-in data-[state=closed]:animate-out',
108
+ 'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
109
+ 'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',
110
+ 'data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2',
111
+ 'data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
112
+ position === 'popper' &&
113
+ 'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
114
+ className
115
+ )}
116
+ position={position}
117
+ {...props}
118
+ >
119
+ <SelectScrollUpButton />
120
+ <SelectPrimitive.Viewport
121
+ className={cn(
122
+ 'p-1',
123
+ position === 'popper' &&
124
+ 'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]'
125
+ )}
126
+ >
127
+ {children}
128
+ </SelectPrimitive.Viewport>
129
+ <SelectScrollDownButton />
130
+ </SelectPrimitive.Content>
131
+ </SelectPrimitive.Portal>
132
+ ));
133
+ SelectContent.displayName = SelectPrimitive.Content.displayName;
134
+
135
+ // ===================
136
+ // SELECT LABEL (Heading dentro del dropdown)
137
+ // ===================
138
+
139
+ const SelectLabel = React.forwardRef<
140
+ React.ElementRef<typeof SelectPrimitive.Label>,
141
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
142
+ >(({ className, ...props }, ref) => (
143
+ <SelectPrimitive.Label
144
+ ref={ref}
145
+ className={cn('py-1.5 pl-8 pr-2 text-sm font-semibold text-semantic-fg-primary', className)}
146
+ {...props}
147
+ />
148
+ ));
149
+ SelectLabel.displayName = SelectPrimitive.Label.displayName;
150
+
151
+ // ===================
152
+ // SELECT ITEM (Cada opción)
153
+ // ===================
154
+
155
+ const SelectItem = React.forwardRef<
156
+ React.ElementRef<typeof SelectPrimitive.Item>,
157
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
158
+ >(({ className, children, ...props }, ref) => (
159
+ <SelectPrimitive.Item
160
+ ref={ref}
161
+ className={cn(
162
+ 'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none',
163
+ 'focus:bg-semantic-bg-hover focus:text-semantic-fg-primary',
164
+ 'data-[disabled]:pointer-events-none data-[disabled]:text-semantic-fg-disabled',
165
+ className
166
+ )}
167
+ {...props}
168
+ >
169
+ <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center" aria-hidden="true">
170
+ <SelectPrimitive.ItemIndicator>
171
+ <Check className="h-4 w-4" />
172
+ </SelectPrimitive.ItemIndicator>
173
+ </span>
174
+
175
+ <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
176
+ </SelectPrimitive.Item>
177
+ ));
178
+ SelectItem.displayName = SelectPrimitive.Item.displayName;
179
+
180
+ // ===================
181
+ // SELECT SEPARATOR
182
+ // ===================
183
+
184
+ const SelectSeparator = React.forwardRef<
185
+ React.ElementRef<typeof SelectPrimitive.Separator>,
186
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
187
+ >(({ className, ...props }, ref) => (
188
+ <SelectPrimitive.Separator
189
+ ref={ref}
190
+ className={cn('-mx-1 my-1 h-px bg-semantic-border-default', className)}
191
+ {...props}
192
+ />
193
+ ));
194
+ SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
195
+
196
+ // ===================
197
+ // SELECT WRAPPER (Componente conveniente con label y helper text)
198
+ // ===================
199
+
200
+ export interface SelectWrapperProps {
201
+ /** Label text */
202
+ label?: string;
203
+ /** Helper text shown below select */
204
+ helperText?: string;
205
+ /** Error message shown when error={true} */
206
+ errorMessage?: string;
207
+ /** Error state */
208
+ error?: boolean;
209
+ /** Mark as required */
210
+ required?: boolean;
211
+ /** Select size */
212
+ size?: 'sm' | 'md' | 'lg';
213
+ /** Children (must be Select components) */
214
+ children: React.ReactNode;
215
+ /** Container class name */
216
+ className?: string;
217
+ }
218
+
219
+ const SelectWrapper: React.FC<SelectWrapperProps> = ({
220
+ label,
221
+ helperText,
222
+ errorMessage,
223
+ error = false,
224
+ required = false,
225
+ size: _size = 'md',
226
+ children,
227
+ className,
228
+ }) => {
229
+ const selectId = React.useId();
230
+ const helperTextId = `${selectId}-helper`;
231
+ const errorMessageId = `${selectId}-error`;
232
+
233
+ return (
234
+ <div className={cn('w-full', className)}>
235
+ {label && (
236
+ <label
237
+ htmlFor={selectId}
238
+ className="mb-1.5 block text-sm font-medium text-semantic-fg-secondary"
239
+ >
240
+ {label}
241
+ {required && <span className="ml-1 text-semantic-fg-error">*</span>}
242
+ </label>
243
+ )}
244
+
245
+ {children}
246
+
247
+ {!error && helperText && (
248
+ <p id={helperTextId} className="mt-1.5 text-sm text-semantic-fg-secondary">
249
+ {helperText}
250
+ </p>
251
+ )}
252
+
253
+ {error && errorMessage && (
254
+ <p id={errorMessageId} className="mt-1.5 text-sm text-semantic-fg-error">
255
+ {errorMessage}
256
+ </p>
257
+ )}
258
+ </div>
259
+ );
260
+ };
261
+
262
+ // ===================
263
+ // EXPORTS
264
+ // ===================
265
+
266
+ export {
267
+ Select,
268
+ SelectGroup,
269
+ SelectValue,
270
+ SelectTrigger,
271
+ SelectContent,
272
+ SelectLabel,
273
+ SelectItem,
274
+ SelectSeparator,
275
+ SelectScrollUpButton,
276
+ SelectScrollDownButton,
277
+ SelectWrapper,
278
+ };
@@ -0,0 +1,84 @@
1
+ import * as React from 'react';
2
+ import { cva, type VariantProps } from 'class-variance-authority';
3
+ import { cn } from '../../lib/utils';
4
+ import { Loader2 } from 'lucide-react';
5
+
6
+ const spinnerVariants = cva('animate-spin', {
7
+ variants: {
8
+ size: {
9
+ sm: 'h-4 w-4',
10
+ md: 'h-6 w-6',
11
+ lg: 'h-8 w-8',
12
+ xl: 'h-12 w-12',
13
+ },
14
+ variant: {
15
+ default: 'text-semantic-fg-primary',
16
+ primary: 'text-semantic-action-primary',
17
+ secondary: 'text-semantic-fg-secondary',
18
+ light: 'text-semantic-fg-inverse',
19
+ },
20
+ },
21
+ defaultVariants: {
22
+ size: 'md',
23
+ variant: 'default',
24
+ },
25
+ });
26
+
27
+ export interface SpinnerProps
28
+ extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'>,
29
+ VariantProps<typeof spinnerVariants> {
30
+ label?: string;
31
+ }
32
+
33
+ const Spinner = React.forwardRef<HTMLDivElement, SpinnerProps>(
34
+ ({ className, size, variant, label, ...props }, ref) => {
35
+ const labelColorClass = variant === 'light'
36
+ ? 'text-semantic-fg-inverse'
37
+ : 'text-semantic-fg-secondary';
38
+
39
+ return (
40
+ <div
41
+ ref={ref}
42
+ role="status"
43
+ aria-label={label || 'Loading'}
44
+ className={cn('inline-flex items-center gap-2', className)}
45
+ {...props}
46
+ >
47
+ <Loader2 className={cn(spinnerVariants({ size, variant }))} />
48
+ {label && (
49
+ <span className={cn('text-sm', labelColorClass)}>{label}</span>
50
+ )}
51
+ <span className="sr-only">{label || 'Loading'}</span>
52
+ </div>
53
+ );
54
+ }
55
+ );
56
+ Spinner.displayName = 'Spinner';
57
+
58
+ export interface LoadingOverlayProps extends SpinnerProps {
59
+ show?: boolean;
60
+ transparent?: boolean;
61
+ }
62
+
63
+ const LoadingOverlay = React.forwardRef<HTMLDivElement, LoadingOverlayProps>(
64
+ ({ show = true, transparent = false, label = 'Loading...', ...spinnerProps }, ref) => {
65
+ if (!show) return null;
66
+
67
+ return (
68
+ <div
69
+ ref={ref}
70
+ className={cn(
71
+ 'fixed inset-0 z-50 flex items-center justify-center',
72
+ transparent
73
+ ? 'bg-transparent'
74
+ : 'bg-semantic-bg-loading-overlay backdrop-blur-sm'
75
+ )}
76
+ >
77
+ <Spinner label={label} {...spinnerProps} />
78
+ </div>
79
+ );
80
+ }
81
+ );
82
+ LoadingOverlay.displayName = 'LoadingOverlay';
83
+
84
+ export { Spinner, LoadingOverlay, spinnerVariants };
@@ -0,0 +1,104 @@
1
+ import * as React from 'react';
2
+ import * as SwitchPrimitive from '@radix-ui/react-switch';
3
+ import { cn } from '../../lib/utils';
4
+
5
+ const SwitchRoot = React.forwardRef<
6
+ React.ElementRef<typeof SwitchPrimitive.Root>,
7
+ React.ComponentPropsWithoutRef<typeof SwitchPrimitive.Root> & {
8
+ size?: 'sm' | 'md' | 'lg';
9
+ }
10
+ >(({ className, size = 'md', ...props }, ref) => {
11
+ const sizeClasses = {
12
+ sm: 'h-5 w-9',
13
+ md: 'h-6 w-11',
14
+ lg: 'h-7 w-14',
15
+ };
16
+
17
+ const thumbSizeClasses = {
18
+ sm: 'h-4 w-4 data-[state=checked]:translate-x-4',
19
+ md: 'h-5 w-5 data-[state=checked]:translate-x-5',
20
+ lg: 'h-6 w-6 data-[state=checked]:translate-x-7',
21
+ };
22
+
23
+ return (
24
+ <SwitchPrimitive.Root
25
+ className={cn(
26
+ 'peer inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent',
27
+ 'transition-colors',
28
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-semantic-focus focus-visible:ring-offset-2',
29
+ 'disabled:cursor-not-allowed disabled:bg-semantic-bg-disabled',
30
+ 'data-[state=checked]:bg-semantic-control-bg-checked data-[state=unchecked]:bg-semantic-control-unchecked',
31
+ sizeClasses[size],
32
+ className
33
+ )}
34
+ {...props}
35
+ ref={ref}
36
+ >
37
+ <SwitchPrimitive.Thumb
38
+ className={cn(
39
+ 'pointer-events-none block rounded-full bg-white shadow-lg ring-0 transition-transform',
40
+ 'data-[state=unchecked]:translate-x-0',
41
+ thumbSizeClasses[size]
42
+ )}
43
+ />
44
+ </SwitchPrimitive.Root>
45
+ );
46
+ });
47
+ SwitchRoot.displayName = SwitchPrimitive.Root.displayName;
48
+
49
+ export interface SwitchProps
50
+ extends React.ComponentPropsWithoutRef<typeof SwitchPrimitive.Root> {
51
+ label?: string;
52
+ description?: string;
53
+ size?: 'sm' | 'md' | 'lg';
54
+ labelPosition?: 'left' | 'right';
55
+ }
56
+
57
+ const Switch = React.forwardRef<React.ElementRef<typeof SwitchPrimitive.Root>, SwitchProps>(
58
+ ({ className, label, description, size = 'md', labelPosition = 'right', id, ...props }, ref) => {
59
+ const switchId = id || React.useId();
60
+
61
+ const switchElement = <SwitchRoot ref={ref} id={switchId} size={size} {...props} />;
62
+
63
+ if (!label) {
64
+ return switchElement;
65
+ }
66
+
67
+ return (
68
+ <div className={cn('flex items-start gap-3', className)}>
69
+ {labelPosition === 'left' && (
70
+ <div className="flex-1">
71
+ <label
72
+ htmlFor={switchId}
73
+ className="cursor-pointer select-none text-sm font-medium leading-none text-semantic-fg-primary peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
74
+ >
75
+ {label}
76
+ </label>
77
+ {description && (
78
+ <p className="mt-1 text-sm text-semantic-fg-secondary">{description}</p>
79
+ )}
80
+ </div>
81
+ )}
82
+
83
+ {switchElement}
84
+
85
+ {labelPosition === 'right' && (
86
+ <div className="flex-1">
87
+ <label
88
+ htmlFor={switchId}
89
+ className="cursor-pointer select-none text-sm font-medium leading-none text-semantic-fg-primary peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
90
+ >
91
+ {label}
92
+ </label>
93
+ {description && (
94
+ <p className="mt-1 text-sm text-semantic-fg-secondary">{description}</p>
95
+ )}
96
+ </div>
97
+ )}
98
+ </div>
99
+ );
100
+ }
101
+ );
102
+ Switch.displayName = 'Switch';
103
+
104
+ export { Switch, SwitchRoot };
@@ -0,0 +1,116 @@
1
+ import * as React from 'react';
2
+ import { cn } from '../../lib/utils';
3
+
4
+ const Table = React.forwardRef<
5
+ HTMLTableElement,
6
+ React.HTMLAttributes<HTMLTableElement>
7
+ >(({ className, ...props }, ref) => (
8
+ <div className="relative w-full overflow-auto">
9
+ <table
10
+ ref={ref}
11
+ className={cn('w-full caption-bottom text-sm', className)}
12
+ {...props}
13
+ />
14
+ </div>
15
+ ));
16
+ Table.displayName = 'Table';
17
+
18
+ const TableHeader = React.forwardRef<
19
+ HTMLTableSectionElement,
20
+ React.HTMLAttributes<HTMLTableSectionElement>
21
+ >(({ className, ...props }, ref) => (
22
+ <thead ref={ref} className={cn('[&_tr]:border-b', className)} {...props} />
23
+ ));
24
+ TableHeader.displayName = 'TableHeader';
25
+
26
+ const TableBody = React.forwardRef<
27
+ HTMLTableSectionElement,
28
+ React.HTMLAttributes<HTMLTableSectionElement>
29
+ >(({ className, ...props }, ref) => (
30
+ <tbody
31
+ ref={ref}
32
+ className={cn('[&_tr:last-child]:border-0', className)}
33
+ {...props}
34
+ />
35
+ ));
36
+ TableBody.displayName = 'TableBody';
37
+
38
+ const TableFooter = React.forwardRef<
39
+ HTMLTableSectionElement,
40
+ React.HTMLAttributes<HTMLTableSectionElement>
41
+ >(({ className, ...props }, ref) => (
42
+ <tfoot
43
+ ref={ref}
44
+ className={cn(
45
+ 'border-t bg-semantic-bg-sunken font-medium [&>tr]:last:border-b-0',
46
+ className
47
+ )}
48
+ {...props}
49
+ />
50
+ ));
51
+ TableFooter.displayName = 'TableFooter';
52
+
53
+ const TableRow = React.forwardRef<
54
+ HTMLTableRowElement,
55
+ React.HTMLAttributes<HTMLTableRowElement>
56
+ >(({ className, ...props }, ref) => (
57
+ <tr
58
+ ref={ref}
59
+ className={cn(
60
+ 'border-b border-semantic-border-default transition-colors hover:bg-semantic-bg-hover data-[state=selected]:bg-semantic-bg-selected',
61
+ className
62
+ )}
63
+ {...props}
64
+ />
65
+ ));
66
+ TableRow.displayName = 'TableRow';
67
+
68
+ const TableHead = React.forwardRef<
69
+ HTMLTableCellElement,
70
+ React.ThHTMLAttributes<HTMLTableCellElement>
71
+ >(({ className, ...props }, ref) => (
72
+ <th
73
+ ref={ref}
74
+ className={cn(
75
+ 'h-12 px-4 text-left align-middle font-medium text-semantic-fg-secondary [&:has([role=checkbox])]:pr-0',
76
+ className
77
+ )}
78
+ {...props}
79
+ />
80
+ ));
81
+ TableHead.displayName = 'TableHead';
82
+
83
+ const TableCell = React.forwardRef<
84
+ HTMLTableCellElement,
85
+ React.TdHTMLAttributes<HTMLTableCellElement>
86
+ >(({ className, ...props }, ref) => (
87
+ <td
88
+ ref={ref}
89
+ className={cn('p-4 align-middle [&:has([role=checkbox])]:pr-0', className)}
90
+ {...props}
91
+ />
92
+ ));
93
+ TableCell.displayName = 'TableCell';
94
+
95
+ const TableCaption = React.forwardRef<
96
+ HTMLTableCaptionElement,
97
+ React.HTMLAttributes<HTMLTableCaptionElement>
98
+ >(({ className, ...props }, ref) => (
99
+ <caption
100
+ ref={ref}
101
+ className={cn('mt-4 text-sm text-semantic-fg-secondary', className)}
102
+ {...props}
103
+ />
104
+ ));
105
+ TableCaption.displayName = 'TableCaption';
106
+
107
+ export {
108
+ Table,
109
+ TableHeader,
110
+ TableBody,
111
+ TableFooter,
112
+ TableHead,
113
+ TableRow,
114
+ TableCell,
115
+ TableCaption,
116
+ };
@@ -0,0 +1,55 @@
1
+ import * as React from 'react';
2
+ import * as TabsPrimitive from '@radix-ui/react-tabs';
3
+ import { cn } from '../../lib/utils';
4
+
5
+ const Tabs = TabsPrimitive.Root;
6
+
7
+ const TabsList = React.forwardRef<
8
+ React.ElementRef<typeof TabsPrimitive.List>,
9
+ React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
10
+ >(({ className, ...props }, ref) => (
11
+ <TabsPrimitive.List
12
+ ref={ref}
13
+ className={cn(
14
+ 'inline-flex h-10 items-center justify-center rounded-md bg-semantic-bg-sunken p-1 text-semantic-fg-muted',
15
+ className
16
+ )}
17
+ {...props}
18
+ />
19
+ ));
20
+ TabsList.displayName = TabsPrimitive.List.displayName;
21
+
22
+ const TabsTrigger = React.forwardRef<
23
+ React.ElementRef<typeof TabsPrimitive.Trigger>,
24
+ React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
25
+ >(({ className, ...props }, ref) => (
26
+ <TabsPrimitive.Trigger
27
+ ref={ref}
28
+ className={cn(
29
+ 'inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-semantic-offset transition-all',
30
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-semantic-focus focus-visible:ring-offset-2',
31
+ 'disabled:pointer-events-none disabled:opacity-50',
32
+ 'data-[state=active]:bg-semantic-bg-elevated data-[state=active]:text-semantic-fg-primary data-[state=active]:shadow-sm',
33
+ className
34
+ )}
35
+ {...props}
36
+ />
37
+ ));
38
+ TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
39
+
40
+ const TabsContent = React.forwardRef<
41
+ React.ElementRef<typeof TabsPrimitive.Content>,
42
+ React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
43
+ >(({ className, ...props }, ref) => (
44
+ <TabsPrimitive.Content
45
+ ref={ref}
46
+ className={cn(
47
+ 'mt-2 ring-offset-semantic-offset focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-semantic-focus focus-visible:ring-offset-2',
48
+ className
49
+ )}
50
+ {...props}
51
+ />
52
+ ));
53
+ TabsContent.displayName = TabsPrimitive.Content.displayName;
54
+
55
+ export { Tabs, TabsList, TabsTrigger, TabsContent };