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.
- package/dist/index.d.ts +1 -0
- package/dist/index.js +747 -0
- package/package.json +57 -0
- package/registry/components/accordion.json +26 -0
- package/registry/components/alert.json +25 -0
- package/registry/components/avatar.json +26 -0
- package/registry/components/badge.json +24 -0
- package/registry/components/breadcrumb.json +28 -0
- package/registry/components/button.json +25 -0
- package/registry/components/card.json +28 -0
- package/registry/components/checkbox.json +23 -0
- package/registry/components/command.json +31 -0
- package/registry/components/dialog.json +32 -0
- package/registry/components/divider.json +22 -0
- package/registry/components/dropdown-menu.json +36 -0
- package/registry/components/empty-state.json +21 -0
- package/registry/components/error-message.json +20 -0
- package/registry/components/field-group.json +20 -0
- package/registry/components/helper-text.json +20 -0
- package/registry/components/input.json +21 -0
- package/registry/components/label.json +20 -0
- package/registry/components/progress.json +22 -0
- package/registry/components/radio.json +23 -0
- package/registry/components/select.json +32 -0
- package/registry/components/spinner.json +20 -0
- package/registry/components/switch.json +22 -0
- package/registry/components/table.json +27 -0
- package/registry/components/tabs.json +25 -0
- package/registry/components/textarea.json +21 -0
- package/registry/components/theme-toggler.json +24 -0
- package/registry/components/toast.json +31 -0
- package/registry/components/tooltip.json +26 -0
- package/registry/components/use-theme.json +19 -0
- package/registry/components/utils.json +21 -0
- package/registry/registry.json +35 -0
- package/registry/source/accordion.tsx +55 -0
- package/registry/source/alert.tsx +102 -0
- package/registry/source/avatar.tsx +137 -0
- package/registry/source/badge.tsx +38 -0
- package/registry/source/breadcrumb.tsx +109 -0
- package/registry/source/button.tsx +58 -0
- package/registry/source/card.tsx +108 -0
- package/registry/source/checkbox.tsx +170 -0
- package/registry/source/command.tsx +195 -0
- package/registry/source/dialog.tsx +133 -0
- package/registry/source/divider.tsx +84 -0
- package/registry/source/dropdown-menu.tsx +209 -0
- package/registry/source/empty-state.tsx +88 -0
- package/registry/source/error-message.tsx +49 -0
- package/registry/source/field-group.tsx +53 -0
- package/registry/source/helper-text.tsx +40 -0
- package/registry/source/input.tsx +219 -0
- package/registry/source/label.tsx +60 -0
- package/registry/source/progress.tsx +84 -0
- package/registry/source/radio.tsx +161 -0
- package/registry/source/select.tsx +278 -0
- package/registry/source/spinner.tsx +84 -0
- package/registry/source/switch.tsx +104 -0
- package/registry/source/table.tsx +116 -0
- package/registry/source/tabs.tsx +55 -0
- package/registry/source/textarea.tsx +129 -0
- package/registry/source/theme-toggler.tsx +94 -0
- package/registry/source/toast.tsx +166 -0
- package/registry/source/tooltip.tsx +55 -0
- package/registry/source/use-theme.tsx +102 -0
- package/registry/source/utils.ts +13 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
3
|
+
import { Loader2 } from 'lucide-react';
|
|
4
|
+
import { cn } from '../../lib/utils';
|
|
5
|
+
|
|
6
|
+
const buttonVariants = cva(
|
|
7
|
+
'inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-semantic-focus focus-visible:ring-offset-2 ring-offset-semantic-offset disabled:pointer-events-none',
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
primary: 'bg-semantic-action-primary text-semantic-fg-inverse hover:bg-semantic-action-primary-hover disabled:bg-semantic-action-primary-disabled-bg disabled:text-semantic-action-primary-disabled-fg',
|
|
12
|
+
secondary: 'bg-semantic-bg-sunken text-semantic-fg-primary hover:bg-semantic-bg-hover disabled:bg-semantic-bg-disabled disabled:text-semantic-fg-disabled',
|
|
13
|
+
outline: 'border border-semantic-border-strong bg-semantic-bg-elevated hover:bg-semantic-bg-hover hover:text-semantic-fg-primary disabled:border-semantic-border-default disabled:text-semantic-fg-disabled',
|
|
14
|
+
ghost: 'hover:bg-semantic-bg-hover hover:text-semantic-fg-primary disabled:text-semantic-fg-disabled',
|
|
15
|
+
danger: 'bg-semantic-action-danger text-semantic-fg-inverse hover:bg-semantic-action-danger-hover disabled:bg-semantic-action-danger-disabled-bg disabled:text-semantic-action-danger-disabled-fg',
|
|
16
|
+
},
|
|
17
|
+
size: {
|
|
18
|
+
sm: 'h-9 px-3',
|
|
19
|
+
md: 'h-10 px-4 py-2',
|
|
20
|
+
lg: 'h-11 px-8',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
defaultVariants: {
|
|
24
|
+
variant: 'primary',
|
|
25
|
+
size: 'md',
|
|
26
|
+
},
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
export interface ButtonProps
|
|
31
|
+
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
32
|
+
VariantProps<typeof buttonVariants> {
|
|
33
|
+
isLoading?: boolean;
|
|
34
|
+
leftIcon?: React.ReactNode;
|
|
35
|
+
rightIcon?: React.ReactNode;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
39
|
+
({ className, variant, size, isLoading, leftIcon, rightIcon, children, disabled, ...props }, ref) => {
|
|
40
|
+
return (
|
|
41
|
+
<button
|
|
42
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
43
|
+
ref={ref}
|
|
44
|
+
disabled={isLoading || disabled}
|
|
45
|
+
aria-busy={isLoading || undefined}
|
|
46
|
+
{...props}
|
|
47
|
+
>
|
|
48
|
+
{isLoading && <Loader2 className="mr-2 h-4 w-4 animate-spin" aria-hidden="true" />}
|
|
49
|
+
{!isLoading && leftIcon && <span className="mr-2" aria-hidden="true">{leftIcon}</span>}
|
|
50
|
+
{children}
|
|
51
|
+
{!isLoading && rightIcon && <span className="ml-2" aria-hidden="true">{rightIcon}</span>}
|
|
52
|
+
</button>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
Button.displayName = 'Button';
|
|
57
|
+
|
|
58
|
+
export { Button, buttonVariants };
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
3
|
+
import { cn } from '../../lib/utils';
|
|
4
|
+
|
|
5
|
+
const cardVariants = cva(
|
|
6
|
+
'rounded-lg border bg-semantic-bg-elevated text-semantic-fg-primary shadow-sm',
|
|
7
|
+
{
|
|
8
|
+
variants: {
|
|
9
|
+
variant: {
|
|
10
|
+
default: 'border-semantic-border-default',
|
|
11
|
+
elevated: 'border-transparent shadow-md',
|
|
12
|
+
outlined: 'border-semantic-border-strong shadow-none',
|
|
13
|
+
},
|
|
14
|
+
padding: {
|
|
15
|
+
none: '',
|
|
16
|
+
sm: 'p-4',
|
|
17
|
+
md: 'p-6',
|
|
18
|
+
lg: 'p-8',
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
defaultVariants: {
|
|
22
|
+
variant: 'default',
|
|
23
|
+
padding: 'md',
|
|
24
|
+
},
|
|
25
|
+
}
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
export interface CardProps
|
|
29
|
+
extends React.HTMLAttributes<HTMLDivElement>,
|
|
30
|
+
VariantProps<typeof cardVariants> {
|
|
31
|
+
hover?: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const Card = React.forwardRef<HTMLDivElement, CardProps>(
|
|
35
|
+
({ className, variant, padding, hover, ...props }, ref) => (
|
|
36
|
+
<div
|
|
37
|
+
ref={ref}
|
|
38
|
+
className={cn(
|
|
39
|
+
cardVariants({ variant, padding }),
|
|
40
|
+
hover && 'transition-shadow hover:shadow-lg',
|
|
41
|
+
className
|
|
42
|
+
)}
|
|
43
|
+
{...props}
|
|
44
|
+
/>
|
|
45
|
+
)
|
|
46
|
+
);
|
|
47
|
+
Card.displayName = 'Card';
|
|
48
|
+
|
|
49
|
+
const CardHeader = React.forwardRef<
|
|
50
|
+
HTMLDivElement,
|
|
51
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
52
|
+
>(({ className, ...props }, ref) => (
|
|
53
|
+
<div
|
|
54
|
+
ref={ref}
|
|
55
|
+
className={cn('flex flex-col space-y-2', className)}
|
|
56
|
+
{...props}
|
|
57
|
+
/>
|
|
58
|
+
));
|
|
59
|
+
CardHeader.displayName = 'CardHeader';
|
|
60
|
+
|
|
61
|
+
const CardTitle = React.forwardRef<
|
|
62
|
+
HTMLParagraphElement,
|
|
63
|
+
React.HTMLAttributes<HTMLHeadingElement>
|
|
64
|
+
>(({ className, ...props }, ref) => (
|
|
65
|
+
<h3
|
|
66
|
+
ref={ref}
|
|
67
|
+
className={cn(
|
|
68
|
+
'text-lg font-semibold leading-tight tracking-tight text-semantic-fg-primary',
|
|
69
|
+
className
|
|
70
|
+
)}
|
|
71
|
+
{...props}
|
|
72
|
+
/>
|
|
73
|
+
));
|
|
74
|
+
CardTitle.displayName = 'CardTitle';
|
|
75
|
+
|
|
76
|
+
const CardDescription = React.forwardRef<
|
|
77
|
+
HTMLParagraphElement,
|
|
78
|
+
React.HTMLAttributes<HTMLParagraphElement>
|
|
79
|
+
>(({ className, ...props }, ref) => (
|
|
80
|
+
<p
|
|
81
|
+
ref={ref}
|
|
82
|
+
className={cn('text-sm leading-relaxed text-semantic-fg-secondary', className)}
|
|
83
|
+
{...props}
|
|
84
|
+
/>
|
|
85
|
+
));
|
|
86
|
+
CardDescription.displayName = 'CardDescription';
|
|
87
|
+
|
|
88
|
+
const CardContent = React.forwardRef<
|
|
89
|
+
HTMLDivElement,
|
|
90
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
91
|
+
>(({ className, ...props }, ref) => (
|
|
92
|
+
<div ref={ref} className={cn('pt-4', className)} {...props} />
|
|
93
|
+
));
|
|
94
|
+
CardContent.displayName = 'CardContent';
|
|
95
|
+
|
|
96
|
+
const CardFooter = React.forwardRef<
|
|
97
|
+
HTMLDivElement,
|
|
98
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
99
|
+
>(({ className, ...props }, ref) => (
|
|
100
|
+
<div
|
|
101
|
+
ref={ref}
|
|
102
|
+
className={cn('flex items-center gap-2 pt-4', className)}
|
|
103
|
+
{...props}
|
|
104
|
+
/>
|
|
105
|
+
));
|
|
106
|
+
CardFooter.displayName = 'CardFooter';
|
|
107
|
+
|
|
108
|
+
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent, cardVariants };
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
|
|
3
|
+
import { Check, Minus } from 'lucide-react';
|
|
4
|
+
import { cn } from '../../lib/utils';
|
|
5
|
+
|
|
6
|
+
// ===================
|
|
7
|
+
// CHECKBOX PRIMITIVE
|
|
8
|
+
// ===================
|
|
9
|
+
|
|
10
|
+
const CheckboxRoot = React.forwardRef<
|
|
11
|
+
React.ElementRef<typeof CheckboxPrimitive.Root>,
|
|
12
|
+
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root> & {
|
|
13
|
+
error?: boolean;
|
|
14
|
+
size?: 'sm' | 'md' | 'lg';
|
|
15
|
+
}
|
|
16
|
+
>(({ className, error = false, size = 'md', ...props }, ref) => {
|
|
17
|
+
const sizeClasses = {
|
|
18
|
+
sm: 'h-4 w-4',
|
|
19
|
+
md: 'h-5 w-5',
|
|
20
|
+
lg: 'h-6 w-6',
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const iconSizes = {
|
|
24
|
+
sm: 12,
|
|
25
|
+
md: 16,
|
|
26
|
+
lg: 20,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<CheckboxPrimitive.Root
|
|
31
|
+
ref={ref}
|
|
32
|
+
className={cn(
|
|
33
|
+
'peer shrink-0 rounded border-2 ring-offset-semantic-offset transition-colors',
|
|
34
|
+
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-semantic-focus focus-visible:ring-offset-2',
|
|
35
|
+
'disabled:cursor-not-allowed disabled:opacity-50',
|
|
36
|
+
'data-[state=checked]:bg-semantic-control-bg-checked data-[state=checked]:text-semantic-fg-inverse data-[state=checked]:border-semantic-control-bg-checked',
|
|
37
|
+
'data-[state=indeterminate]:bg-semantic-control-bg-checked data-[state=indeterminate]:text-semantic-fg-inverse data-[state=indeterminate]:border-semantic-control-bg-checked',
|
|
38
|
+
error
|
|
39
|
+
? 'border-semantic-control-border-error data-[state=checked]:bg-semantic-action-danger data-[state=checked]:border-semantic-action-danger'
|
|
40
|
+
: 'border-semantic-control-border hover:border-semantic-control-border-hover',
|
|
41
|
+
sizeClasses[size],
|
|
42
|
+
className
|
|
43
|
+
)}
|
|
44
|
+
{...props}
|
|
45
|
+
>
|
|
46
|
+
<CheckboxPrimitive.Indicator className="flex items-center justify-center text-current">
|
|
47
|
+
{props.checked === 'indeterminate' ? (
|
|
48
|
+
<Minus size={iconSizes[size]} strokeWidth={3} />
|
|
49
|
+
) : (
|
|
50
|
+
<Check size={iconSizes[size]} strokeWidth={3} />
|
|
51
|
+
)}
|
|
52
|
+
</CheckboxPrimitive.Indicator>
|
|
53
|
+
</CheckboxPrimitive.Root>
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
CheckboxRoot.displayName = CheckboxPrimitive.Root.displayName;
|
|
57
|
+
|
|
58
|
+
// ===================
|
|
59
|
+
// CHECKBOX WITH LABEL (Componente completo)
|
|
60
|
+
// ===================
|
|
61
|
+
|
|
62
|
+
export interface CheckboxProps
|
|
63
|
+
extends Omit<React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>, 'type'> {
|
|
64
|
+
/** Label text */
|
|
65
|
+
label?: string;
|
|
66
|
+
/** Helper text shown below checkbox */
|
|
67
|
+
helperText?: string;
|
|
68
|
+
/** Error message shown when error={true} */
|
|
69
|
+
errorMessage?: string;
|
|
70
|
+
/** Error state */
|
|
71
|
+
error?: boolean;
|
|
72
|
+
/** Checkbox size */
|
|
73
|
+
size?: 'sm' | 'md' | 'lg';
|
|
74
|
+
/** Additional CSS classes for the container */
|
|
75
|
+
containerClassName?: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const Checkbox = React.forwardRef<
|
|
79
|
+
React.ElementRef<typeof CheckboxPrimitive.Root>,
|
|
80
|
+
CheckboxProps
|
|
81
|
+
>(
|
|
82
|
+
(
|
|
83
|
+
{
|
|
84
|
+
className,
|
|
85
|
+
label,
|
|
86
|
+
helperText,
|
|
87
|
+
errorMessage,
|
|
88
|
+
error = false,
|
|
89
|
+
size = 'md',
|
|
90
|
+
id,
|
|
91
|
+
containerClassName,
|
|
92
|
+
...props
|
|
93
|
+
},
|
|
94
|
+
ref
|
|
95
|
+
) => {
|
|
96
|
+
const checkboxId = id || React.useId();
|
|
97
|
+
const helperTextId = `${checkboxId}-helper`;
|
|
98
|
+
const errorMessageId = `${checkboxId}-error`;
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
<div className={cn('flex flex-col', containerClassName)}>
|
|
102
|
+
<div className="flex items-start gap-2">
|
|
103
|
+
<CheckboxRoot
|
|
104
|
+
ref={ref}
|
|
105
|
+
id={checkboxId}
|
|
106
|
+
error={error}
|
|
107
|
+
size={size}
|
|
108
|
+
className={className}
|
|
109
|
+
aria-invalid={error ? 'true' : 'false'}
|
|
110
|
+
aria-describedby={
|
|
111
|
+
error && errorMessage
|
|
112
|
+
? errorMessageId
|
|
113
|
+
: helperText
|
|
114
|
+
? helperTextId
|
|
115
|
+
: undefined
|
|
116
|
+
}
|
|
117
|
+
{...props}
|
|
118
|
+
/>
|
|
119
|
+
|
|
120
|
+
{label && (
|
|
121
|
+
<label
|
|
122
|
+
htmlFor={checkboxId}
|
|
123
|
+
className={cn(
|
|
124
|
+
'cursor-pointer select-none font-medium leading-none',
|
|
125
|
+
'peer-disabled:cursor-not-allowed peer-disabled:opacity-70',
|
|
126
|
+
size === 'sm' ? 'text-sm' : size === 'lg' ? 'text-lg' : 'text-base',
|
|
127
|
+
error ? 'text-semantic-fg-error' : 'text-semantic-fg-primary'
|
|
128
|
+
)}
|
|
129
|
+
>
|
|
130
|
+
{label}
|
|
131
|
+
</label>
|
|
132
|
+
)}
|
|
133
|
+
</div>
|
|
134
|
+
|
|
135
|
+
{!error && helperText && (
|
|
136
|
+
<p
|
|
137
|
+
id={helperTextId}
|
|
138
|
+
className={cn(
|
|
139
|
+
'text-sm text-semantic-fg-secondary',
|
|
140
|
+
size === 'sm' ? 'ml-6' : size === 'lg' ? 'ml-8' : 'ml-7',
|
|
141
|
+
'mt-1.5'
|
|
142
|
+
)}
|
|
143
|
+
>
|
|
144
|
+
{helperText}
|
|
145
|
+
</p>
|
|
146
|
+
)}
|
|
147
|
+
|
|
148
|
+
{error && errorMessage && (
|
|
149
|
+
<p
|
|
150
|
+
id={errorMessageId}
|
|
151
|
+
className={cn(
|
|
152
|
+
'text-sm text-semantic-fg-error',
|
|
153
|
+
size === 'sm' ? 'ml-6' : size === 'lg' ? 'ml-8' : 'ml-7',
|
|
154
|
+
'mt-1.5'
|
|
155
|
+
)}
|
|
156
|
+
>
|
|
157
|
+
{errorMessage}
|
|
158
|
+
</p>
|
|
159
|
+
)}
|
|
160
|
+
</div>
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
);
|
|
164
|
+
Checkbox.displayName = 'Checkbox';
|
|
165
|
+
|
|
166
|
+
// ===================
|
|
167
|
+
// EXPORTS
|
|
168
|
+
// ===================
|
|
169
|
+
|
|
170
|
+
export { Checkbox, CheckboxRoot };
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Command as CommandPrimitive } from 'cmdk';
|
|
3
|
+
import { Search } from 'lucide-react';
|
|
4
|
+
import { cn } from '../../lib/utils';
|
|
5
|
+
|
|
6
|
+
const Command = React.forwardRef<
|
|
7
|
+
React.ElementRef<typeof CommandPrimitive>,
|
|
8
|
+
React.ComponentPropsWithoutRef<typeof CommandPrimitive>
|
|
9
|
+
>(({ className, ...props }, ref) => (
|
|
10
|
+
<CommandPrimitive
|
|
11
|
+
ref={ref}
|
|
12
|
+
className={cn(
|
|
13
|
+
'flex h-full w-full flex-col overflow-hidden rounded-md',
|
|
14
|
+
'bg-semantic-bg-elevated',
|
|
15
|
+
className
|
|
16
|
+
)}
|
|
17
|
+
{...props}
|
|
18
|
+
/>
|
|
19
|
+
));
|
|
20
|
+
Command.displayName = 'Command';
|
|
21
|
+
|
|
22
|
+
interface CommandDialogProps {
|
|
23
|
+
open?: boolean;
|
|
24
|
+
onOpenChange?: (open: boolean) => void;
|
|
25
|
+
children?: React.ReactNode;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const CommandDialog = ({ open, onOpenChange, children }: CommandDialogProps) => {
|
|
29
|
+
const [isOpen, setIsOpen] = React.useState(open ?? false);
|
|
30
|
+
|
|
31
|
+
const handleOpenChange = React.useCallback(
|
|
32
|
+
(value: boolean) => {
|
|
33
|
+
setIsOpen(value);
|
|
34
|
+
onOpenChange?.(value);
|
|
35
|
+
},
|
|
36
|
+
[onOpenChange]
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
React.useEffect(() => {
|
|
40
|
+
if (open !== undefined) {
|
|
41
|
+
setIsOpen(open);
|
|
42
|
+
}
|
|
43
|
+
}, [open]);
|
|
44
|
+
|
|
45
|
+
React.useEffect(() => {
|
|
46
|
+
const down = (e: KeyboardEvent) => {
|
|
47
|
+
if (e.key === 'k' && (e.metaKey || e.ctrlKey)) {
|
|
48
|
+
e.preventDefault();
|
|
49
|
+
handleOpenChange(!isOpen);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
document.addEventListener('keydown', down);
|
|
54
|
+
return () => document.removeEventListener('keydown', down);
|
|
55
|
+
}, [isOpen, handleOpenChange]);
|
|
56
|
+
|
|
57
|
+
if (!isOpen) return null;
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<div className="fixed inset-0 z-50">
|
|
61
|
+
{/* Backdrop */}
|
|
62
|
+
<div
|
|
63
|
+
className="fixed inset-0 bg-semantic-bg-overlay backdrop-blur-sm"
|
|
64
|
+
onClick={() => handleOpenChange(false)}
|
|
65
|
+
/>
|
|
66
|
+
{/* Dialog */}
|
|
67
|
+
<div className="fixed left-1/2 top-1/2 z-50 w-full max-w-lg -translate-x-1/2 -translate-y-1/2 p-4">
|
|
68
|
+
<Command
|
|
69
|
+
className={cn(
|
|
70
|
+
'rounded-lg border border-semantic-border-default shadow-2xl',
|
|
71
|
+
)}
|
|
72
|
+
>
|
|
73
|
+
{children}
|
|
74
|
+
</Command>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const CommandInput = React.forwardRef<
|
|
81
|
+
React.ElementRef<typeof CommandPrimitive.Input>,
|
|
82
|
+
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
|
|
83
|
+
>(({ className, ...props }, ref) => (
|
|
84
|
+
<div className="flex items-center border-b border-semantic-border-default px-3">
|
|
85
|
+
<Search className="mr-2 h-4 w-4 shrink-0 text-semantic-fg-muted" aria-hidden="true" />
|
|
86
|
+
<CommandPrimitive.Input
|
|
87
|
+
ref={ref}
|
|
88
|
+
className={cn(
|
|
89
|
+
'flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none',
|
|
90
|
+
'placeholder:text-semantic-control-placeholder',
|
|
91
|
+
'disabled:cursor-not-allowed disabled:text-semantic-fg-disabled',
|
|
92
|
+
className
|
|
93
|
+
)}
|
|
94
|
+
{...props}
|
|
95
|
+
/>
|
|
96
|
+
</div>
|
|
97
|
+
));
|
|
98
|
+
CommandInput.displayName = 'CommandInput';
|
|
99
|
+
|
|
100
|
+
const CommandList = React.forwardRef<
|
|
101
|
+
React.ElementRef<typeof CommandPrimitive.List>,
|
|
102
|
+
React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
|
|
103
|
+
>(({ className, ...props }, ref) => (
|
|
104
|
+
<CommandPrimitive.List
|
|
105
|
+
ref={ref}
|
|
106
|
+
className={cn('max-h-[300px] overflow-y-auto overflow-x-hidden', className)}
|
|
107
|
+
{...props}
|
|
108
|
+
/>
|
|
109
|
+
));
|
|
110
|
+
CommandList.displayName = 'CommandList';
|
|
111
|
+
|
|
112
|
+
const CommandEmpty = React.forwardRef<
|
|
113
|
+
React.ElementRef<typeof CommandPrimitive.Empty>,
|
|
114
|
+
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
|
|
115
|
+
>((props, ref) => (
|
|
116
|
+
<CommandPrimitive.Empty
|
|
117
|
+
ref={ref}
|
|
118
|
+
className="py-6 text-center text-sm text-semantic-fg-muted"
|
|
119
|
+
{...props}
|
|
120
|
+
/>
|
|
121
|
+
));
|
|
122
|
+
CommandEmpty.displayName = 'CommandEmpty';
|
|
123
|
+
|
|
124
|
+
const CommandGroup = React.forwardRef<
|
|
125
|
+
React.ElementRef<typeof CommandPrimitive.Group>,
|
|
126
|
+
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
|
|
127
|
+
>(({ className, ...props }, ref) => (
|
|
128
|
+
<CommandPrimitive.Group
|
|
129
|
+
ref={ref}
|
|
130
|
+
className={cn(
|
|
131
|
+
'overflow-hidden p-1',
|
|
132
|
+
'[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5',
|
|
133
|
+
'[&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium',
|
|
134
|
+
'[&_[cmdk-group-heading]]:text-semantic-fg-muted',
|
|
135
|
+
className
|
|
136
|
+
)}
|
|
137
|
+
{...props}
|
|
138
|
+
/>
|
|
139
|
+
));
|
|
140
|
+
CommandGroup.displayName = 'CommandGroup';
|
|
141
|
+
|
|
142
|
+
const CommandSeparator = React.forwardRef<
|
|
143
|
+
React.ElementRef<typeof CommandPrimitive.Separator>,
|
|
144
|
+
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
|
|
145
|
+
>(({ className, ...props }, ref) => (
|
|
146
|
+
<CommandPrimitive.Separator
|
|
147
|
+
ref={ref}
|
|
148
|
+
className={cn('-mx-1 h-px bg-semantic-border-default', className)}
|
|
149
|
+
{...props}
|
|
150
|
+
/>
|
|
151
|
+
));
|
|
152
|
+
CommandSeparator.displayName = 'CommandSeparator';
|
|
153
|
+
|
|
154
|
+
const CommandItem = React.forwardRef<
|
|
155
|
+
React.ElementRef<typeof CommandPrimitive.Item>,
|
|
156
|
+
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
|
|
157
|
+
>(({ className, ...props }, ref) => (
|
|
158
|
+
<CommandPrimitive.Item
|
|
159
|
+
ref={ref}
|
|
160
|
+
className={cn(
|
|
161
|
+
'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none',
|
|
162
|
+
'data-[selected=true]:bg-semantic-bg-selected data-[selected=true]:text-semantic-fg-primary',
|
|
163
|
+
'data-[disabled=true]:pointer-events-none data-[disabled=true]:text-semantic-fg-disabled',
|
|
164
|
+
className
|
|
165
|
+
)}
|
|
166
|
+
{...props}
|
|
167
|
+
/>
|
|
168
|
+
));
|
|
169
|
+
CommandItem.displayName = 'CommandItem';
|
|
170
|
+
|
|
171
|
+
const CommandShortcut = ({
|
|
172
|
+
className,
|
|
173
|
+
...props
|
|
174
|
+
}: React.HTMLAttributes<HTMLSpanElement>) => (
|
|
175
|
+
<span
|
|
176
|
+
className={cn(
|
|
177
|
+
'ml-auto text-xs tracking-widest text-semantic-fg-muted',
|
|
178
|
+
className
|
|
179
|
+
)}
|
|
180
|
+
{...props}
|
|
181
|
+
/>
|
|
182
|
+
);
|
|
183
|
+
CommandShortcut.displayName = 'CommandShortcut';
|
|
184
|
+
|
|
185
|
+
export {
|
|
186
|
+
Command,
|
|
187
|
+
CommandDialog,
|
|
188
|
+
CommandInput,
|
|
189
|
+
CommandList,
|
|
190
|
+
CommandEmpty,
|
|
191
|
+
CommandGroup,
|
|
192
|
+
CommandItem,
|
|
193
|
+
CommandSeparator,
|
|
194
|
+
CommandShortcut,
|
|
195
|
+
};
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|
3
|
+
import { X } from 'lucide-react';
|
|
4
|
+
import { cn } from '../../lib/utils';
|
|
5
|
+
|
|
6
|
+
const Dialog = DialogPrimitive.Root;
|
|
7
|
+
|
|
8
|
+
const DialogTrigger = DialogPrimitive.Trigger;
|
|
9
|
+
|
|
10
|
+
const DialogPortal = DialogPrimitive.Portal;
|
|
11
|
+
|
|
12
|
+
const DialogClose = DialogPrimitive.Close;
|
|
13
|
+
|
|
14
|
+
const DialogOverlay = React.forwardRef<
|
|
15
|
+
React.ElementRef<typeof DialogPrimitive.Overlay>,
|
|
16
|
+
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
|
|
17
|
+
>(({ className, ...props }, ref) => (
|
|
18
|
+
<DialogPrimitive.Overlay
|
|
19
|
+
ref={ref}
|
|
20
|
+
className={cn(
|
|
21
|
+
'fixed inset-0 z-50 bg-semantic-bg-overlay backdrop-blur-sm',
|
|
22
|
+
'data-[state=open]:animate-in data-[state=closed]:animate-out',
|
|
23
|
+
'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
|
|
24
|
+
className
|
|
25
|
+
)}
|
|
26
|
+
{...props}
|
|
27
|
+
/>
|
|
28
|
+
));
|
|
29
|
+
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
|
30
|
+
|
|
31
|
+
const DialogContent = React.forwardRef<
|
|
32
|
+
React.ElementRef<typeof DialogPrimitive.Content>,
|
|
33
|
+
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {
|
|
34
|
+
showClose?: boolean;
|
|
35
|
+
}
|
|
36
|
+
>(({ className, children, showClose = true, ...props }, ref) => (
|
|
37
|
+
<DialogPortal>
|
|
38
|
+
<DialogOverlay />
|
|
39
|
+
<DialogPrimitive.Content
|
|
40
|
+
ref={ref}
|
|
41
|
+
className={cn(
|
|
42
|
+
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4',
|
|
43
|
+
'border border-semantic-border-default bg-semantic-bg-elevated p-6 shadow-lg duration-200',
|
|
44
|
+
'data-[state=open]:animate-in data-[state=closed]:animate-out',
|
|
45
|
+
'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
|
|
46
|
+
'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',
|
|
47
|
+
'data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%]',
|
|
48
|
+
'data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]',
|
|
49
|
+
'rounded-lg',
|
|
50
|
+
'sm:rounded-lg',
|
|
51
|
+
className
|
|
52
|
+
)}
|
|
53
|
+
{...props}
|
|
54
|
+
>
|
|
55
|
+
{children}
|
|
56
|
+
{showClose && (
|
|
57
|
+
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-semantic-offset transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-semantic-focus focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-semantic-bg-hover data-[state=open]:text-semantic-fg-secondary">
|
|
58
|
+
<X className="h-4 w-4" />
|
|
59
|
+
<span className="sr-only">Close</span>
|
|
60
|
+
</DialogPrimitive.Close>
|
|
61
|
+
)}
|
|
62
|
+
</DialogPrimitive.Content>
|
|
63
|
+
</DialogPortal>
|
|
64
|
+
));
|
|
65
|
+
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
|
66
|
+
|
|
67
|
+
const DialogHeader = ({
|
|
68
|
+
className,
|
|
69
|
+
...props
|
|
70
|
+
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
71
|
+
<div
|
|
72
|
+
className={cn(
|
|
73
|
+
'flex flex-col space-y-1.5 text-center sm:text-left',
|
|
74
|
+
className
|
|
75
|
+
)}
|
|
76
|
+
{...props}
|
|
77
|
+
/>
|
|
78
|
+
);
|
|
79
|
+
DialogHeader.displayName = 'DialogHeader';
|
|
80
|
+
|
|
81
|
+
const DialogFooter = ({
|
|
82
|
+
className,
|
|
83
|
+
...props
|
|
84
|
+
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
85
|
+
<div
|
|
86
|
+
className={cn(
|
|
87
|
+
'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',
|
|
88
|
+
className
|
|
89
|
+
)}
|
|
90
|
+
{...props}
|
|
91
|
+
/>
|
|
92
|
+
);
|
|
93
|
+
DialogFooter.displayName = 'DialogFooter';
|
|
94
|
+
|
|
95
|
+
const DialogTitle = React.forwardRef<
|
|
96
|
+
React.ElementRef<typeof DialogPrimitive.Title>,
|
|
97
|
+
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
|
|
98
|
+
>(({ className, ...props }, ref) => (
|
|
99
|
+
<DialogPrimitive.Title
|
|
100
|
+
ref={ref}
|
|
101
|
+
className={cn(
|
|
102
|
+
'text-lg font-semibold leading-none tracking-tight text-semantic-fg-primary',
|
|
103
|
+
className
|
|
104
|
+
)}
|
|
105
|
+
{...props}
|
|
106
|
+
/>
|
|
107
|
+
));
|
|
108
|
+
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
|
109
|
+
|
|
110
|
+
const DialogDescription = React.forwardRef<
|
|
111
|
+
React.ElementRef<typeof DialogPrimitive.Description>,
|
|
112
|
+
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
|
|
113
|
+
>(({ className, ...props }, ref) => (
|
|
114
|
+
<DialogPrimitive.Description
|
|
115
|
+
ref={ref}
|
|
116
|
+
className={cn('text-sm text-semantic-fg-secondary', className)}
|
|
117
|
+
{...props}
|
|
118
|
+
/>
|
|
119
|
+
));
|
|
120
|
+
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
|
121
|
+
|
|
122
|
+
export {
|
|
123
|
+
Dialog,
|
|
124
|
+
DialogPortal,
|
|
125
|
+
DialogOverlay,
|
|
126
|
+
DialogClose,
|
|
127
|
+
DialogTrigger,
|
|
128
|
+
DialogContent,
|
|
129
|
+
DialogHeader,
|
|
130
|
+
DialogFooter,
|
|
131
|
+
DialogTitle,
|
|
132
|
+
DialogDescription,
|
|
133
|
+
};
|