@thangnqdev/ui 0.2.0 → 0.2.2
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/LICENSE +21 -21
- package/README.md +144 -142
- package/bin/cli.js +125 -0
- package/dist/bento/index.cjs.map +1 -1
- package/dist/bento/index.js +2 -2
- package/dist/buttons/index.cjs.map +1 -1
- package/dist/buttons/index.js +3 -3
- package/dist/{chunk-77KTYOMQ.js → chunk-2OXZK6IP.js} +3 -3
- package/dist/chunk-2OXZK6IP.js.map +1 -0
- package/dist/{chunk-4CRFNALF.js → chunk-4GNFT2ZJ.js} +7 -7
- package/dist/chunk-4GNFT2ZJ.js.map +1 -0
- package/dist/{chunk-2YJBW4E2.js → chunk-4S6L5V7X.js} +2 -2
- package/dist/chunk-4S6L5V7X.js.map +1 -0
- package/dist/{chunk-I2FQBMVW.js → chunk-66VWUJEI.js} +3 -3
- package/dist/chunk-66VWUJEI.js.map +1 -0
- package/dist/{chunk-YOCGBORV.js → chunk-7NMB2Y64.js} +4 -4
- package/dist/chunk-7NMB2Y64.js.map +1 -0
- package/dist/{chunk-V52JOSDF.js → chunk-A7P3O5Z5.js} +3 -3
- package/dist/chunk-A7P3O5Z5.js.map +1 -0
- package/dist/{chunk-ME4XILG5.js → chunk-ATYGDTMK.js} +5 -5
- package/dist/chunk-ATYGDTMK.js.map +1 -0
- package/dist/{chunk-S6XJMYME.js → chunk-C4SUXMI3.js} +3 -3
- package/dist/chunk-C4SUXMI3.js.map +1 -0
- package/dist/{chunk-EXFR2BFJ.js → chunk-DUPPPGXY.js} +7 -7
- package/dist/chunk-DUPPPGXY.js.map +1 -0
- package/dist/{chunk-I5O2WCGF.js → chunk-EU2LPUYP.js} +3 -3
- package/dist/chunk-EU2LPUYP.js.map +1 -0
- package/dist/{chunk-D7FB3TCA.js → chunk-GXI2H5XA.js} +3 -3
- package/dist/chunk-GXI2H5XA.js.map +1 -0
- package/dist/{chunk-ADO3SVUA.js → chunk-IABPUCAQ.js} +2 -2
- package/dist/chunk-IABPUCAQ.js.map +1 -0
- package/dist/{chunk-PC5SZFZC.js → chunk-JOKEKOP3.js} +8 -8
- package/dist/chunk-JOKEKOP3.js.map +1 -0
- package/dist/{chunk-GXWB6BSY.js → chunk-KUQWUTZA.js} +4 -4
- package/dist/chunk-KUQWUTZA.js.map +1 -0
- package/dist/{chunk-ZEDXARXW.js → chunk-U3J4UPV3.js} +2 -2
- package/dist/chunk-U3J4UPV3.js.map +1 -0
- package/dist/{chunk-DSEL7ELZ.js → chunk-VE2PNSDQ.js} +4 -4
- package/dist/chunk-VE2PNSDQ.js.map +1 -0
- package/dist/{chunk-YJ64RI7J.js → chunk-WAFHC4DQ.js} +3 -3
- package/dist/chunk-WAFHC4DQ.js.map +1 -0
- package/dist/{chunk-W5WNWTQC.js → chunk-YJ67WYVW.js} +5 -5
- package/dist/chunk-YJ67WYVW.js.map +1 -0
- package/dist/{chunk-4MS6ZHFQ.js → chunk-Z427NPMU.js} +7 -7
- package/dist/chunk-Z427NPMU.js.map +1 -0
- package/dist/core/index.cjs +4 -4
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.js +2 -2
- package/dist/data-display/index.cjs.map +1 -1
- package/dist/data-display/index.js +5 -5
- package/dist/feedback/index.cjs.map +1 -1
- package/dist/feedback/index.js +2 -2
- package/dist/forms/index.cjs.map +1 -1
- package/dist/forms/index.js +8 -8
- package/dist/glass/index.cjs.map +1 -1
- package/dist/glass/index.js +2 -2
- package/dist/index.cjs +4 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +19 -19
- package/dist/layout/index.cjs.map +1 -1
- package/dist/layout/index.js +2 -2
- package/dist/navigation/index.cjs.map +1 -1
- package/dist/navigation/index.js +6 -6
- package/dist/overlays/index.cjs.map +1 -1
- package/dist/overlays/index.js +7 -7
- package/dist/reset.css +45 -45
- package/dist/tokens.css +11 -11
- package/dist/typography/index.cjs.map +1 -1
- package/dist/typography/index.js +4 -4
- package/llms.txt +3 -3
- package/package.json +166 -159
- package/scripts/postinstall.js +125 -0
- package/src/bento/BentoCard.tsx +140 -140
- package/src/bento/BentoGrid.tsx +50 -50
- package/src/bento/index.ts +2 -2
- package/src/bento/tokens.css +46 -46
- package/src/buttons/Button.tsx +104 -104
- package/src/buttons/ButtonGroup.tsx +43 -43
- package/src/buttons/IconButton.tsx +79 -79
- package/src/buttons/SplitButton.tsx +186 -186
- package/src/buttons/ToggleButton.tsx +157 -157
- package/src/buttons/index.ts +5 -5
- package/src/buttons/tokens.css +6 -6
- package/src/core/ThemeProvider.tsx +133 -133
- package/src/core/index.ts +2 -2
- package/src/core/tokens.css +134 -134
- package/src/data-display/Accordion.tsx +147 -147
- package/src/data-display/Avatar.tsx +134 -134
- package/src/data-display/Card.tsx +112 -112
- package/src/data-display/Chip.tsx +74 -74
- package/src/data-display/DataTablePro.tsx +534 -534
- package/src/data-display/StatCard.tsx +60 -60
- package/src/data-display/Table.tsx +74 -74
- package/src/data-display/Timeline.tsx +62 -62
- package/src/data-display/TreeView.tsx +279 -279
- package/src/data-display/tokens.css +4 -4
- package/src/feedback/Alert.tsx +80 -80
- package/src/feedback/EmptyState.tsx +45 -45
- package/src/feedback/Skeleton.tsx +66 -66
- package/src/feedback/Spinner.tsx +65 -65
- package/src/feedback/index.ts +5 -5
- package/src/feedback/tokens.css +4 -4
- package/src/forms/Checkbox.tsx +149 -149
- package/src/forms/CheckboxGroup.tsx +76 -76
- package/src/forms/Combobox.tsx +512 -512
- package/src/forms/DatePicker.tsx +784 -784
- package/src/forms/FileUpload.tsx +266 -266
- package/src/forms/FormField.tsx +115 -115
- package/src/forms/Input.tsx +151 -151
- package/src/forms/NumberInput.tsx +262 -262
- package/src/forms/PasswordInput.tsx +35 -35
- package/src/forms/PinInput.tsx +139 -139
- package/src/forms/Radio.tsx +142 -142
- package/src/forms/RangeSlider.tsx +237 -237
- package/src/forms/SearchInput.tsx +34 -34
- package/src/forms/Select.tsx +103 -103
- package/src/forms/Slider.tsx +85 -85
- package/src/forms/Textarea.tsx +114 -114
- package/src/forms/tokens.css +6 -6
- package/src/glass/GlassButton.tsx +59 -59
- package/src/glass/GlassCard.tsx +71 -71
- package/src/glass/index.ts +3 -3
- package/src/glass/tokens.css +81 -81
- package/src/index.ts +26 -26
- package/src/layout/AspectRatio.tsx +39 -39
- package/src/layout/Container.tsx +53 -53
- package/src/layout/Divider.tsx +61 -61
- package/src/layout/Flex.tsx +79 -79
- package/src/layout/Grid.tsx +124 -124
- package/src/layout/PageLayout.tsx +59 -59
- package/src/layout/Section.tsx +47 -47
- package/src/layout/Spacer.tsx +30 -30
- package/src/layout/Stack.tsx +88 -88
- package/src/layout/tokens.css +8 -8
- package/src/navigation/Breadcrumb.tsx +73 -73
- package/src/navigation/CommandPalette.tsx +142 -142
- package/src/navigation/DropdownMenu.tsx +244 -244
- package/src/navigation/Pagination.tsx +114 -114
- package/src/navigation/Stepper.tsx +93 -93
- package/src/navigation/Tabs.tsx +265 -265
- package/src/navigation/index.ts +6 -6
- package/src/navigation/tokens.css +4 -4
- package/src/overlays/AlertDialog.tsx +63 -63
- package/src/overlays/BottomSheet.tsx +143 -143
- package/src/overlays/ContextMenu.tsx +161 -161
- package/src/overlays/Drawer.tsx +160 -160
- package/src/overlays/FocusTrap.tsx +122 -122
- package/src/overlays/Modal.tsx +296 -296
- package/src/overlays/Popover.tsx +156 -156
- package/src/overlays/Portal.tsx +23 -23
- package/src/overlays/Toast.tsx +175 -175
- package/src/overlays/Tooltip.tsx +125 -125
- package/src/overlays/tokens.css +8 -8
- package/src/registry/components.ts +1368 -1368
- package/src/styles/components.css +39 -39
- package/src/styles/index.css +5 -5
- package/src/styles/reset.css +45 -45
- package/src/styles/tokens.css +11 -11
- package/src/typography/Blockquote.tsx +32 -32
- package/src/typography/Code.tsx +89 -89
- package/src/typography/Heading.tsx +56 -56
- package/src/typography/Kbd.tsx +25 -25
- package/src/typography/Label.tsx +47 -47
- package/src/typography/Link.tsx +56 -56
- package/src/typography/Text.tsx +62 -62
- package/src/typography/index.ts +7 -7
- package/src/typography/tokens.css +5 -5
- package/src/utils/cn.ts +6 -6
- package/src/utils/scroll-lock.ts +19 -19
- package/src/utils/useControllableState.ts +54 -54
- package/ui-contract.json +1 -1
- package/dist/chunk-2YJBW4E2.js.map +0 -1
- package/dist/chunk-4CRFNALF.js.map +0 -1
- package/dist/chunk-4MS6ZHFQ.js.map +0 -1
- package/dist/chunk-77KTYOMQ.js.map +0 -1
- package/dist/chunk-ADO3SVUA.js.map +0 -1
- package/dist/chunk-D7FB3TCA.js.map +0 -1
- package/dist/chunk-DSEL7ELZ.js.map +0 -1
- package/dist/chunk-EXFR2BFJ.js.map +0 -1
- package/dist/chunk-GXWB6BSY.js.map +0 -1
- package/dist/chunk-I2FQBMVW.js.map +0 -1
- package/dist/chunk-I5O2WCGF.js.map +0 -1
- package/dist/chunk-ME4XILG5.js.map +0 -1
- package/dist/chunk-PC5SZFZC.js.map +0 -1
- package/dist/chunk-S6XJMYME.js.map +0 -1
- package/dist/chunk-V52JOSDF.js.map +0 -1
- package/dist/chunk-W5WNWTQC.js.map +0 -1
- package/dist/chunk-YJ64RI7J.js.map +0 -1
- package/dist/chunk-YOCGBORV.js.map +0 -1
- package/dist/chunk-ZEDXARXW.js.map +0 -1
|
@@ -1,134 +1,134 @@
|
|
|
1
|
-
import React, { forwardRef, useState } from 'react';
|
|
2
|
-
import { cva, type VariantProps } from 'class-variance-authority';
|
|
3
|
-
import { cn } from '../utils/cn';
|
|
4
|
-
|
|
5
|
-
export const avatarVariants = cva(
|
|
6
|
-
'relative inline-flex shrink-0 items-center justify-center overflow-hidden rounded-full bg-[var(--ui-bg-tertiary)] select-none border border-[var(--ui-border-subtle)]',
|
|
7
|
-
{
|
|
8
|
-
variants: {
|
|
9
|
-
size: {
|
|
10
|
-
xs: 'h-6 w-6 text-[10px]',
|
|
11
|
-
sm: 'h-8 w-8 text-xs',
|
|
12
|
-
md: 'h-10 w-10 text-sm font-semibold',
|
|
13
|
-
lg: 'h-12 w-12 text-base font-semibold',
|
|
14
|
-
xl: 'h-16 w-16 text-lg font-bold',
|
|
15
|
-
},
|
|
16
|
-
},
|
|
17
|
-
defaultVariants: {
|
|
18
|
-
size: 'md',
|
|
19
|
-
},
|
|
20
|
-
}
|
|
21
|
-
);
|
|
22
|
-
|
|
23
|
-
export const statusVariants = cva(
|
|
24
|
-
'absolute bottom-0 right-0 rounded-full ring-2 ring-[var(--ui-bg-surface)]',
|
|
25
|
-
{
|
|
26
|
-
variants: {
|
|
27
|
-
status: {
|
|
28
|
-
online: 'bg-[var(--ui-success)]',
|
|
29
|
-
offline: 'bg-[var(--ui-text-muted)]',
|
|
30
|
-
busy: 'bg-[var(--ui-error)]',
|
|
31
|
-
away: 'bg-[var(--ui-warning)]',
|
|
32
|
-
},
|
|
33
|
-
size: {
|
|
34
|
-
xs: 'h-1.5 w-1.5',
|
|
35
|
-
sm: 'h-2 w-2',
|
|
36
|
-
md: 'h-2.5 w-2.5',
|
|
37
|
-
lg: 'h-3 w-3',
|
|
38
|
-
xl: 'h-4 w-4',
|
|
39
|
-
},
|
|
40
|
-
},
|
|
41
|
-
defaultVariants: {
|
|
42
|
-
status: 'online',
|
|
43
|
-
size: 'md',
|
|
44
|
-
},
|
|
45
|
-
}
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
export interface AvatarProps
|
|
49
|
-
extends React.HTMLAttributes<HTMLDivElement>,
|
|
50
|
-
VariantProps<typeof avatarVariants> {
|
|
51
|
-
src?: string;
|
|
52
|
-
alt?: string;
|
|
53
|
-
name?: string;
|
|
54
|
-
status?: 'online' | 'offline' | 'busy' | 'away';
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export const Avatar = forwardRef<HTMLDivElement, AvatarProps>(
|
|
58
|
-
({ className, size = 'md', src, alt, name, status, children, ...props }, ref) => {
|
|
59
|
-
const [hasError, setHasError] = useState(false);
|
|
60
|
-
|
|
61
|
-
const getInitials = (n?: string) => {
|
|
62
|
-
if (!n) return '';
|
|
63
|
-
const parts = n.trim().split(' ');
|
|
64
|
-
if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
|
|
65
|
-
return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
const initials = name ? getInitials(name) : '';
|
|
69
|
-
|
|
70
|
-
return (
|
|
71
|
-
<div ref={ref} className={cn(avatarVariants({ size }), className)} {...props}>
|
|
72
|
-
{src && !hasError ? (
|
|
73
|
-
<img
|
|
74
|
-
src={src}
|
|
75
|
-
alt={alt || name || 'Avatar'}
|
|
76
|
-
onError={() => setHasError(true)}
|
|
77
|
-
className="h-full w-full object-cover"
|
|
78
|
-
/>
|
|
79
|
-
) : initials ? (
|
|
80
|
-
<span className="font-semibold text-[var(--ui-text-secondary)]">{initials}</span>
|
|
81
|
-
) : (
|
|
82
|
-
children || <span className="font-semibold text-[var(--ui-text-muted)]">?</span>
|
|
83
|
-
)}
|
|
84
|
-
|
|
85
|
-
{status && (
|
|
86
|
-
<span
|
|
87
|
-
aria-label={`Status: ${status}`}
|
|
88
|
-
className={cn(statusVariants({ status, size }))}
|
|
89
|
-
/>
|
|
90
|
-
)}
|
|
91
|
-
</div>
|
|
92
|
-
);
|
|
93
|
-
}
|
|
94
|
-
);
|
|
95
|
-
Avatar.displayName = 'Avatar';
|
|
96
|
-
|
|
97
|
-
export interface AvatarGroupProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
98
|
-
max?: number;
|
|
99
|
-
spacing?: 'tight' | 'normal';
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export const AvatarGroup = forwardRef<HTMLDivElement, AvatarGroupProps>(
|
|
103
|
-
({ className, max = 4, spacing = 'tight', children, ...props }, ref) => {
|
|
104
|
-
const childArray = React.Children.toArray(children);
|
|
105
|
-
const visibleChildren = childArray.slice(0, max);
|
|
106
|
-
const remainingCount = childArray.length - max;
|
|
107
|
-
|
|
108
|
-
return (
|
|
109
|
-
<div
|
|
110
|
-
ref={ref}
|
|
111
|
-
role="group"
|
|
112
|
-
className={cn(
|
|
113
|
-
'flex items-center',
|
|
114
|
-
spacing === 'tight' ? '-space-x-3' : '-space-x-1.5',
|
|
115
|
-
className
|
|
116
|
-
)}
|
|
117
|
-
{...props}
|
|
118
|
-
>
|
|
119
|
-
{visibleChildren.map((child, i) => (
|
|
120
|
-
<div key={i} className="ring-2 ring-[var(--ui-bg-surface)] rounded-full">
|
|
121
|
-
{child}
|
|
122
|
-
</div>
|
|
123
|
-
))}
|
|
124
|
-
|
|
125
|
-
{remainingCount > 0 && (
|
|
126
|
-
<div className="relative inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-[var(--ui-bg-secondary)] border border-[var(--ui-border-default)] ring-2 ring-[var(--ui-bg-surface)] text-xs font-bold text-[var(--ui-text-secondary)] select-none">
|
|
127
|
-
+{remainingCount}
|
|
128
|
-
</div>
|
|
129
|
-
)}
|
|
130
|
-
</div>
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
);
|
|
134
|
-
AvatarGroup.displayName = 'AvatarGroup';
|
|
1
|
+
import React, { forwardRef, useState } from 'react';
|
|
2
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
3
|
+
import { cn } from '../utils/cn';
|
|
4
|
+
|
|
5
|
+
export const avatarVariants = cva(
|
|
6
|
+
'relative inline-flex shrink-0 items-center justify-center overflow-hidden rounded-full bg-[var(--ui-bg-tertiary)] select-none border border-[var(--ui-border-subtle)]',
|
|
7
|
+
{
|
|
8
|
+
variants: {
|
|
9
|
+
size: {
|
|
10
|
+
xs: 'h-6 w-6 text-[10px]',
|
|
11
|
+
sm: 'h-8 w-8 text-xs',
|
|
12
|
+
md: 'h-10 w-10 text-sm font-semibold',
|
|
13
|
+
lg: 'h-12 w-12 text-base font-semibold',
|
|
14
|
+
xl: 'h-16 w-16 text-lg font-bold',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
defaultVariants: {
|
|
18
|
+
size: 'md',
|
|
19
|
+
},
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
export const statusVariants = cva(
|
|
24
|
+
'absolute bottom-0 right-0 rounded-full ring-2 ring-[var(--ui-bg-surface)]',
|
|
25
|
+
{
|
|
26
|
+
variants: {
|
|
27
|
+
status: {
|
|
28
|
+
online: 'bg-[var(--ui-success)]',
|
|
29
|
+
offline: 'bg-[var(--ui-text-muted)]',
|
|
30
|
+
busy: 'bg-[var(--ui-error)]',
|
|
31
|
+
away: 'bg-[var(--ui-warning)]',
|
|
32
|
+
},
|
|
33
|
+
size: {
|
|
34
|
+
xs: 'h-1.5 w-1.5',
|
|
35
|
+
sm: 'h-2 w-2',
|
|
36
|
+
md: 'h-2.5 w-2.5',
|
|
37
|
+
lg: 'h-3 w-3',
|
|
38
|
+
xl: 'h-4 w-4',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
defaultVariants: {
|
|
42
|
+
status: 'online',
|
|
43
|
+
size: 'md',
|
|
44
|
+
},
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
export interface AvatarProps
|
|
49
|
+
extends React.HTMLAttributes<HTMLDivElement>,
|
|
50
|
+
VariantProps<typeof avatarVariants> {
|
|
51
|
+
src?: string;
|
|
52
|
+
alt?: string;
|
|
53
|
+
name?: string;
|
|
54
|
+
status?: 'online' | 'offline' | 'busy' | 'away';
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export const Avatar = forwardRef<HTMLDivElement, AvatarProps>(
|
|
58
|
+
({ className, size = 'md', src, alt, name, status, children, ...props }, ref) => {
|
|
59
|
+
const [hasError, setHasError] = useState(false);
|
|
60
|
+
|
|
61
|
+
const getInitials = (n?: string) => {
|
|
62
|
+
if (!n) return '';
|
|
63
|
+
const parts = n.trim().split(' ');
|
|
64
|
+
if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
|
|
65
|
+
return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const initials = name ? getInitials(name) : '';
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<div ref={ref} className={cn(avatarVariants({ size }), className)} {...props}>
|
|
72
|
+
{src && !hasError ? (
|
|
73
|
+
<img
|
|
74
|
+
src={src}
|
|
75
|
+
alt={alt || name || 'Avatar'}
|
|
76
|
+
onError={() => setHasError(true)}
|
|
77
|
+
className="h-full w-full object-cover"
|
|
78
|
+
/>
|
|
79
|
+
) : initials ? (
|
|
80
|
+
<span className="font-semibold text-[var(--ui-text-secondary)]">{initials}</span>
|
|
81
|
+
) : (
|
|
82
|
+
children || <span className="font-semibold text-[var(--ui-text-muted)]">?</span>
|
|
83
|
+
)}
|
|
84
|
+
|
|
85
|
+
{status && (
|
|
86
|
+
<span
|
|
87
|
+
aria-label={`Status: ${status}`}
|
|
88
|
+
className={cn(statusVariants({ status, size }))}
|
|
89
|
+
/>
|
|
90
|
+
)}
|
|
91
|
+
</div>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
);
|
|
95
|
+
Avatar.displayName = 'Avatar';
|
|
96
|
+
|
|
97
|
+
export interface AvatarGroupProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
98
|
+
max?: number;
|
|
99
|
+
spacing?: 'tight' | 'normal';
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export const AvatarGroup = forwardRef<HTMLDivElement, AvatarGroupProps>(
|
|
103
|
+
({ className, max = 4, spacing = 'tight', children, ...props }, ref) => {
|
|
104
|
+
const childArray = React.Children.toArray(children);
|
|
105
|
+
const visibleChildren = childArray.slice(0, max);
|
|
106
|
+
const remainingCount = childArray.length - max;
|
|
107
|
+
|
|
108
|
+
return (
|
|
109
|
+
<div
|
|
110
|
+
ref={ref}
|
|
111
|
+
role="group"
|
|
112
|
+
className={cn(
|
|
113
|
+
'flex items-center',
|
|
114
|
+
spacing === 'tight' ? '-space-x-3' : '-space-x-1.5',
|
|
115
|
+
className
|
|
116
|
+
)}
|
|
117
|
+
{...props}
|
|
118
|
+
>
|
|
119
|
+
{visibleChildren.map((child, i) => (
|
|
120
|
+
<div key={i} className="ring-2 ring-[var(--ui-bg-surface)] rounded-full">
|
|
121
|
+
{child}
|
|
122
|
+
</div>
|
|
123
|
+
))}
|
|
124
|
+
|
|
125
|
+
{remainingCount > 0 && (
|
|
126
|
+
<div className="relative inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-[var(--ui-bg-secondary)] border border-[var(--ui-border-default)] ring-2 ring-[var(--ui-bg-surface)] text-xs font-bold text-[var(--ui-text-secondary)] select-none">
|
|
127
|
+
+{remainingCount}
|
|
128
|
+
</div>
|
|
129
|
+
)}
|
|
130
|
+
</div>
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
);
|
|
134
|
+
AvatarGroup.displayName = 'AvatarGroup';
|
|
@@ -1,112 +1,112 @@
|
|
|
1
|
-
import React, { forwardRef } from 'react';
|
|
2
|
-
import { cva, type VariantProps } from 'class-variance-authority';
|
|
3
|
-
import { cn } from '../utils/cn';
|
|
4
|
-
|
|
5
|
-
export const cardVariants = cva(
|
|
6
|
-
'relative overflow-hidden rounded-[var(--ui-radius-xl)] transition-all duration-200 border',
|
|
7
|
-
{
|
|
8
|
-
variants: {
|
|
9
|
-
variant: {
|
|
10
|
-
default:
|
|
11
|
-
'bg-[var(--ui-bg-surface)] backdrop-blur-xl border-[var(--ui-border-default)] shadow-[var(--ui-shadow-md)] text-[var(--ui-text-primary)]',
|
|
12
|
-
bordered:
|
|
13
|
-
'bg-transparent border-[var(--ui-border-strong)] text-[var(--ui-text-primary)]',
|
|
14
|
-
elevated:
|
|
15
|
-
'bg-[var(--ui-bg-surface)] backdrop-blur-2xl border-[var(--ui-border-default)] shadow-[var(--ui-shadow-xl)] hover:shadow-2xl text-[var(--ui-text-primary)]',
|
|
16
|
-
interactive:
|
|
17
|
-
'bg-[var(--ui-bg-surface)] backdrop-blur-xl border-[var(--ui-border-default)] shadow-[var(--ui-shadow-md)] hover:border-[var(--ui-primary)] cursor-pointer hover:-translate-y-1 hover:shadow-[0_12px_32px_rgba(99,102,241,0.15)] text-[var(--ui-text-primary)] active:translate-y-0',
|
|
18
|
-
glow:
|
|
19
|
-
'bg-[var(--ui-bg-surface)] backdrop-blur-xl border-indigo-500/30 shadow-[0_0_30px_rgba(99,102,241,0.12)] text-[var(--ui-text-primary)]',
|
|
20
|
-
},
|
|
21
|
-
padding: {
|
|
22
|
-
none: 'p-0',
|
|
23
|
-
sm: 'p-4 sm:p-5',
|
|
24
|
-
md: 'p-6 sm:p-7',
|
|
25
|
-
lg: 'p-8 sm:p-10',
|
|
26
|
-
},
|
|
27
|
-
specular: {
|
|
28
|
-
true: 'before:absolute before:inset-x-0 before:top-0 before:h-px before:bg-gradient-to-r before:from-transparent before:via-white/30 before:to-transparent before:pointer-events-none',
|
|
29
|
-
false: '',
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
defaultVariants: {
|
|
33
|
-
variant: 'default',
|
|
34
|
-
padding: 'md',
|
|
35
|
-
specular: true,
|
|
36
|
-
},
|
|
37
|
-
}
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
export interface CardProps
|
|
41
|
-
extends React.HTMLAttributes<HTMLDivElement>,
|
|
42
|
-
VariantProps<typeof cardVariants> {}
|
|
43
|
-
|
|
44
|
-
export const Card = forwardRef<HTMLDivElement, CardProps>(
|
|
45
|
-
({ className, variant, padding, specular = true, children, ...props }, ref) => {
|
|
46
|
-
return (
|
|
47
|
-
<div
|
|
48
|
-
ref={ref}
|
|
49
|
-
className={cn(cardVariants({ variant, padding, specular }), className)}
|
|
50
|
-
{...props}
|
|
51
|
-
>
|
|
52
|
-
{children}
|
|
53
|
-
</div>
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
);
|
|
57
|
-
Card.displayName = 'Card';
|
|
58
|
-
|
|
59
|
-
export const CardHeader = forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
|
60
|
-
({ className, children, ...props }, ref) => {
|
|
61
|
-
return (
|
|
62
|
-
<div ref={ref} className={cn('flex flex-col space-y-1.5 mb-5', className)} {...props}>
|
|
63
|
-
{children}
|
|
64
|
-
</div>
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
);
|
|
68
|
-
CardHeader.displayName = 'CardHeader';
|
|
69
|
-
|
|
70
|
-
export const CardTitle = forwardRef<HTMLHeadingElement, React.HTMLAttributes<HTMLHeadingElement>>(
|
|
71
|
-
({ className, children, ...props }, ref) => {
|
|
72
|
-
return (
|
|
73
|
-
<h3 ref={ref} className={cn('text-lg sm:text-xl font-bold tracking-tight text-[var(--ui-text-primary)]', className)} {...props}>
|
|
74
|
-
{children}
|
|
75
|
-
</h3>
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
);
|
|
79
|
-
CardTitle.displayName = 'CardTitle';
|
|
80
|
-
|
|
81
|
-
export const CardDescription = forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(
|
|
82
|
-
({ className, children, ...props }, ref) => {
|
|
83
|
-
return (
|
|
84
|
-
<p ref={ref} className={cn('text-xs sm:text-sm text-[var(--ui-text-muted)] font-normal leading-relaxed', className)} {...props}>
|
|
85
|
-
{children}
|
|
86
|
-
</p>
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
);
|
|
90
|
-
CardDescription.displayName = 'CardDescription';
|
|
91
|
-
|
|
92
|
-
export const CardContent = forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
|
93
|
-
({ className, children, ...props }, ref) => {
|
|
94
|
-
return (
|
|
95
|
-
<div ref={ref} className={cn('pt-0', className)} {...props}>
|
|
96
|
-
{children}
|
|
97
|
-
</div>
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
);
|
|
101
|
-
CardContent.displayName = 'CardContent';
|
|
102
|
-
|
|
103
|
-
export const CardFooter = forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
|
104
|
-
({ className, children, ...props }, ref) => {
|
|
105
|
-
return (
|
|
106
|
-
<div ref={ref} className={cn('flex items-center pt-4 mt-5 border-t border-[var(--ui-border-subtle)]', className)} {...props}>
|
|
107
|
-
{children}
|
|
108
|
-
</div>
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
);
|
|
112
|
-
CardFooter.displayName = 'CardFooter';
|
|
1
|
+
import React, { forwardRef } from 'react';
|
|
2
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
3
|
+
import { cn } from '../utils/cn';
|
|
4
|
+
|
|
5
|
+
export const cardVariants = cva(
|
|
6
|
+
'relative overflow-hidden rounded-[var(--ui-radius-xl)] transition-all duration-200 border',
|
|
7
|
+
{
|
|
8
|
+
variants: {
|
|
9
|
+
variant: {
|
|
10
|
+
default:
|
|
11
|
+
'bg-[var(--ui-bg-surface)] backdrop-blur-xl border-[var(--ui-border-default)] shadow-[var(--ui-shadow-md)] text-[var(--ui-text-primary)]',
|
|
12
|
+
bordered:
|
|
13
|
+
'bg-transparent border-[var(--ui-border-strong)] text-[var(--ui-text-primary)]',
|
|
14
|
+
elevated:
|
|
15
|
+
'bg-[var(--ui-bg-surface)] backdrop-blur-2xl border-[var(--ui-border-default)] shadow-[var(--ui-shadow-xl)] hover:shadow-2xl text-[var(--ui-text-primary)]',
|
|
16
|
+
interactive:
|
|
17
|
+
'bg-[var(--ui-bg-surface)] backdrop-blur-xl border-[var(--ui-border-default)] shadow-[var(--ui-shadow-md)] hover:border-[var(--ui-primary)] cursor-pointer hover:-translate-y-1 hover:shadow-[0_12px_32px_rgba(99,102,241,0.15)] text-[var(--ui-text-primary)] active:translate-y-0',
|
|
18
|
+
glow:
|
|
19
|
+
'bg-[var(--ui-bg-surface)] backdrop-blur-xl border-indigo-500/30 shadow-[0_0_30px_rgba(99,102,241,0.12)] text-[var(--ui-text-primary)]',
|
|
20
|
+
},
|
|
21
|
+
padding: {
|
|
22
|
+
none: 'p-0',
|
|
23
|
+
sm: 'p-4 sm:p-5',
|
|
24
|
+
md: 'p-6 sm:p-7',
|
|
25
|
+
lg: 'p-8 sm:p-10',
|
|
26
|
+
},
|
|
27
|
+
specular: {
|
|
28
|
+
true: 'before:absolute before:inset-x-0 before:top-0 before:h-px before:bg-gradient-to-r before:from-transparent before:via-white/30 before:to-transparent before:pointer-events-none',
|
|
29
|
+
false: '',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
defaultVariants: {
|
|
33
|
+
variant: 'default',
|
|
34
|
+
padding: 'md',
|
|
35
|
+
specular: true,
|
|
36
|
+
},
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
export interface CardProps
|
|
41
|
+
extends React.HTMLAttributes<HTMLDivElement>,
|
|
42
|
+
VariantProps<typeof cardVariants> {}
|
|
43
|
+
|
|
44
|
+
export const Card = forwardRef<HTMLDivElement, CardProps>(
|
|
45
|
+
({ className, variant, padding, specular = true, children, ...props }, ref) => {
|
|
46
|
+
return (
|
|
47
|
+
<div
|
|
48
|
+
ref={ref}
|
|
49
|
+
className={cn(cardVariants({ variant, padding, specular }), className)}
|
|
50
|
+
{...props}
|
|
51
|
+
>
|
|
52
|
+
{children}
|
|
53
|
+
</div>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
Card.displayName = 'Card';
|
|
58
|
+
|
|
59
|
+
export const CardHeader = forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
|
60
|
+
({ className, children, ...props }, ref) => {
|
|
61
|
+
return (
|
|
62
|
+
<div ref={ref} className={cn('flex flex-col space-y-1.5 mb-5', className)} {...props}>
|
|
63
|
+
{children}
|
|
64
|
+
</div>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
CardHeader.displayName = 'CardHeader';
|
|
69
|
+
|
|
70
|
+
export const CardTitle = forwardRef<HTMLHeadingElement, React.HTMLAttributes<HTMLHeadingElement>>(
|
|
71
|
+
({ className, children, ...props }, ref) => {
|
|
72
|
+
return (
|
|
73
|
+
<h3 ref={ref} className={cn('text-lg sm:text-xl font-bold tracking-tight text-[var(--ui-text-primary)]', className)} {...props}>
|
|
74
|
+
{children}
|
|
75
|
+
</h3>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
CardTitle.displayName = 'CardTitle';
|
|
80
|
+
|
|
81
|
+
export const CardDescription = forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(
|
|
82
|
+
({ className, children, ...props }, ref) => {
|
|
83
|
+
return (
|
|
84
|
+
<p ref={ref} className={cn('text-xs sm:text-sm text-[var(--ui-text-muted)] font-normal leading-relaxed', className)} {...props}>
|
|
85
|
+
{children}
|
|
86
|
+
</p>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
);
|
|
90
|
+
CardDescription.displayName = 'CardDescription';
|
|
91
|
+
|
|
92
|
+
export const CardContent = forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
|
93
|
+
({ className, children, ...props }, ref) => {
|
|
94
|
+
return (
|
|
95
|
+
<div ref={ref} className={cn('pt-0', className)} {...props}>
|
|
96
|
+
{children}
|
|
97
|
+
</div>
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
);
|
|
101
|
+
CardContent.displayName = 'CardContent';
|
|
102
|
+
|
|
103
|
+
export const CardFooter = forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
|
104
|
+
({ className, children, ...props }, ref) => {
|
|
105
|
+
return (
|
|
106
|
+
<div ref={ref} className={cn('flex items-center pt-4 mt-5 border-t border-[var(--ui-border-subtle)]', className)} {...props}>
|
|
107
|
+
{children}
|
|
108
|
+
</div>
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
);
|
|
112
|
+
CardFooter.displayName = 'CardFooter';
|
|
@@ -1,74 +1,74 @@
|
|
|
1
|
-
import React, { forwardRef } from 'react';
|
|
2
|
-
import { cva, type VariantProps } from 'class-variance-authority';
|
|
3
|
-
import { X } from 'lucide-react';
|
|
4
|
-
import { cn } from '../utils/cn';
|
|
5
|
-
|
|
6
|
-
export const chipVariants = cva(
|
|
7
|
-
'inline-flex items-center gap-1.5 rounded-full font-medium transition-colors select-none',
|
|
8
|
-
{
|
|
9
|
-
variants: {
|
|
10
|
-
variant: {
|
|
11
|
-
default: 'bg-[var(--ui-bg-tertiary)] text-[var(--ui-text-primary)] border border-[var(--ui-border-default)]',
|
|
12
|
-
primary: 'bg-[var(--ui-primary)]/15 text-[var(--ui-primary)] border border-[var(--ui-primary)]/30',
|
|
13
|
-
secondary: 'bg-[var(--ui-secondary)]/15 text-[var(--ui-secondary)] border border-[var(--ui-secondary)]/30',
|
|
14
|
-
success: 'bg-[var(--ui-success-subtle)] text-[var(--ui-success)] border border-[var(--ui-success)]/30',
|
|
15
|
-
warning: 'bg-[var(--ui-warning-subtle)] text-[var(--ui-warning)] border border-[var(--ui-warning)]/30',
|
|
16
|
-
error: 'bg-[var(--ui-error-subtle)] text-[var(--ui-error)] border border-[var(--ui-error)]/30',
|
|
17
|
-
},
|
|
18
|
-
size: {
|
|
19
|
-
sm: 'h-6 px-2.5 text-xs',
|
|
20
|
-
md: 'h-7 px-3 text-xs',
|
|
21
|
-
lg: 'h-8 px-3.5 text-sm',
|
|
22
|
-
},
|
|
23
|
-
clickable: {
|
|
24
|
-
true: 'cursor-pointer hover:opacity-80 active:scale-95',
|
|
25
|
-
false: '',
|
|
26
|
-
},
|
|
27
|
-
},
|
|
28
|
-
defaultVariants: {
|
|
29
|
-
variant: 'default',
|
|
30
|
-
size: 'md',
|
|
31
|
-
clickable: false,
|
|
32
|
-
},
|
|
33
|
-
}
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
export interface ChipProps
|
|
37
|
-
extends React.HTMLAttributes<HTMLDivElement>,
|
|
38
|
-
VariantProps<typeof chipVariants> {
|
|
39
|
-
onRemove?: () => void;
|
|
40
|
-
icon?: React.ReactNode;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export const Chip = forwardRef<HTMLDivElement, ChipProps>(
|
|
44
|
-
({ className, variant, size, clickable, onRemove, icon, children, onClick, ...props }, ref) => {
|
|
45
|
-
const isClickable = Boolean(clickable || onClick);
|
|
46
|
-
|
|
47
|
-
return (
|
|
48
|
-
<div
|
|
49
|
-
ref={ref}
|
|
50
|
-
onClick={onClick}
|
|
51
|
-
className={cn(chipVariants({ variant, size, clickable: isClickable }), className)}
|
|
52
|
-
{...props}
|
|
53
|
-
>
|
|
54
|
-
{icon && <span className="flex-shrink-0">{icon}</span>}
|
|
55
|
-
<span>{children}</span>
|
|
56
|
-
{onRemove && (
|
|
57
|
-
<button
|
|
58
|
-
type="button"
|
|
59
|
-
onClick={(e) => {
|
|
60
|
-
e.stopPropagation();
|
|
61
|
-
onRemove();
|
|
62
|
-
}}
|
|
63
|
-
aria-label="Remove chip"
|
|
64
|
-
className="p-0.5 rounded-full hover:bg-black/10 dark:hover:bg-white/10 transition-colors -mr-1"
|
|
65
|
-
>
|
|
66
|
-
<X className="w-3 h-3" />
|
|
67
|
-
</button>
|
|
68
|
-
)}
|
|
69
|
-
</div>
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
Chip.displayName = 'Chip';
|
|
1
|
+
import React, { forwardRef } from 'react';
|
|
2
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
3
|
+
import { X } from 'lucide-react';
|
|
4
|
+
import { cn } from '../utils/cn';
|
|
5
|
+
|
|
6
|
+
export const chipVariants = cva(
|
|
7
|
+
'inline-flex items-center gap-1.5 rounded-full font-medium transition-colors select-none',
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
default: 'bg-[var(--ui-bg-tertiary)] text-[var(--ui-text-primary)] border border-[var(--ui-border-default)]',
|
|
12
|
+
primary: 'bg-[var(--ui-primary)]/15 text-[var(--ui-primary)] border border-[var(--ui-primary)]/30',
|
|
13
|
+
secondary: 'bg-[var(--ui-secondary)]/15 text-[var(--ui-secondary)] border border-[var(--ui-secondary)]/30',
|
|
14
|
+
success: 'bg-[var(--ui-success-subtle)] text-[var(--ui-success)] border border-[var(--ui-success)]/30',
|
|
15
|
+
warning: 'bg-[var(--ui-warning-subtle)] text-[var(--ui-warning)] border border-[var(--ui-warning)]/30',
|
|
16
|
+
error: 'bg-[var(--ui-error-subtle)] text-[var(--ui-error)] border border-[var(--ui-error)]/30',
|
|
17
|
+
},
|
|
18
|
+
size: {
|
|
19
|
+
sm: 'h-6 px-2.5 text-xs',
|
|
20
|
+
md: 'h-7 px-3 text-xs',
|
|
21
|
+
lg: 'h-8 px-3.5 text-sm',
|
|
22
|
+
},
|
|
23
|
+
clickable: {
|
|
24
|
+
true: 'cursor-pointer hover:opacity-80 active:scale-95',
|
|
25
|
+
false: '',
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
defaultVariants: {
|
|
29
|
+
variant: 'default',
|
|
30
|
+
size: 'md',
|
|
31
|
+
clickable: false,
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
export interface ChipProps
|
|
37
|
+
extends React.HTMLAttributes<HTMLDivElement>,
|
|
38
|
+
VariantProps<typeof chipVariants> {
|
|
39
|
+
onRemove?: () => void;
|
|
40
|
+
icon?: React.ReactNode;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const Chip = forwardRef<HTMLDivElement, ChipProps>(
|
|
44
|
+
({ className, variant, size, clickable, onRemove, icon, children, onClick, ...props }, ref) => {
|
|
45
|
+
const isClickable = Boolean(clickable || onClick);
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<div
|
|
49
|
+
ref={ref}
|
|
50
|
+
onClick={onClick}
|
|
51
|
+
className={cn(chipVariants({ variant, size, clickable: isClickable }), className)}
|
|
52
|
+
{...props}
|
|
53
|
+
>
|
|
54
|
+
{icon && <span className="flex-shrink-0">{icon}</span>}
|
|
55
|
+
<span>{children}</span>
|
|
56
|
+
{onRemove && (
|
|
57
|
+
<button
|
|
58
|
+
type="button"
|
|
59
|
+
onClick={(e) => {
|
|
60
|
+
e.stopPropagation();
|
|
61
|
+
onRemove();
|
|
62
|
+
}}
|
|
63
|
+
aria-label="Remove chip"
|
|
64
|
+
className="p-0.5 rounded-full hover:bg-black/10 dark:hover:bg-white/10 transition-colors -mr-1"
|
|
65
|
+
>
|
|
66
|
+
<X className="w-3 h-3" />
|
|
67
|
+
</button>
|
|
68
|
+
)}
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
Chip.displayName = 'Chip';
|