@wealthx/shadcn 0.0.2 → 1.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.
- package/.turbo/turbo-build.log +135 -11
- package/CHANGELOG.md +12 -0
- package/CHANGES.md +345 -0
- package/README.md +128 -0
- package/dist/chunk-2WZVSBAY.mjs +232 -0
- package/dist/chunk-2Y7YJKPE.mjs +47 -0
- package/dist/chunk-3U7SD3MS.mjs +55 -0
- package/dist/chunk-3VQNJ235.mjs +114 -0
- package/dist/chunk-55CEW76V.mjs +35 -0
- package/dist/chunk-6AFMNC42.mjs +146 -0
- package/dist/chunk-6OJF6XRN.mjs +117 -0
- package/dist/chunk-7LDIMXGM.mjs +181 -0
- package/dist/chunk-AMJ23O53.mjs +122 -0
- package/dist/chunk-BBJBJSXQ.mjs +44 -0
- package/dist/chunk-BGP2N52Z.mjs +126 -0
- package/dist/chunk-BMFN37JH.mjs +41 -0
- package/dist/chunk-CGOKTPXU.mjs +79 -0
- package/dist/chunk-CZ3BW5GL.mjs +81 -0
- package/dist/chunk-DBHJ5KC3.mjs +55 -0
- package/dist/chunk-DDPA2XXS.mjs +97 -0
- package/dist/chunk-DS2AMHN2.mjs +30 -0
- package/dist/chunk-E3K6O4FZ.mjs +57 -0
- package/dist/chunk-FWCSY2DS.mjs +37 -0
- package/dist/chunk-GPRJQ24C.mjs +28 -0
- package/dist/chunk-HS7TFG7V.mjs +24 -0
- package/dist/chunk-HUVTPUV2.mjs +256 -0
- package/dist/chunk-IAOOZCUY.mjs +90 -0
- package/dist/chunk-JF4PHPD5.mjs +111 -0
- package/dist/chunk-JU2RUWHF.mjs +123 -0
- package/dist/chunk-KKHTJNMM.mjs +86 -0
- package/dist/chunk-MJIEMGRD.mjs +266 -0
- package/dist/chunk-MKFL5MNH.mjs +372 -0
- package/dist/chunk-MQ72DIBH.mjs +105 -0
- package/dist/chunk-NGYG2EA6.mjs +148 -0
- package/dist/chunk-NWZ46DJL.mjs +213 -0
- package/dist/chunk-OXQQNQZI.mjs +75 -0
- package/dist/chunk-PMKODV6M.mjs +161 -0
- package/dist/chunk-QOJ2DQD6.mjs +57 -0
- package/dist/chunk-RL772EH7.mjs +126 -0
- package/dist/chunk-SLWCCURD.mjs +99 -0
- package/dist/chunk-V7CNWJT3.mjs +10 -0
- package/dist/chunk-VG6UF6UT.mjs +68 -0
- package/dist/chunk-VYMHBV6D.mjs +123 -0
- package/dist/chunk-VZ2NR7L3.mjs +195 -0
- package/dist/chunk-YN5SYTOO.mjs +117 -0
- package/dist/chunk-Z3MK2KKZ.mjs +83 -0
- package/dist/chunk-ZN2QKLF6.mjs +187 -0
- package/dist/chunk-ZZV5JVNW.mjs +34 -0
- package/dist/components/ui/accordion.js +142 -0
- package/dist/components/ui/accordion.mjs +14 -0
- package/dist/components/ui/alert-dialog.js +413 -0
- package/dist/components/ui/alert-dialog.mjs +34 -0
- package/dist/components/ui/alert.js +134 -0
- package/dist/components/ui/alert.mjs +12 -0
- package/dist/components/ui/avatar.js +173 -0
- package/dist/components/ui/avatar.mjs +18 -0
- package/dist/components/ui/badge.js +163 -0
- package/dist/components/ui/badge.mjs +11 -0
- package/dist/components/ui/button.js +198 -0
- package/dist/components/ui/button.mjs +11 -0
- package/dist/components/ui/calendar.js +408 -0
- package/dist/components/ui/calendar.mjs +12 -0
- package/dist/components/ui/card.js +156 -0
- package/dist/components/ui/card.mjs +20 -0
- package/dist/components/ui/checkbox.js +166 -0
- package/dist/components/ui/checkbox.mjs +11 -0
- package/dist/components/ui/chip.js +199 -0
- package/dist/components/ui/chip.mjs +10 -0
- package/dist/components/ui/data-table.js +925 -0
- package/dist/components/ui/data-table.mjs +29 -0
- package/dist/components/ui/date-picker.js +561 -0
- package/dist/components/ui/date-picker.mjs +15 -0
- package/dist/components/ui/dialog.js +378 -0
- package/dist/components/ui/dialog.mjs +30 -0
- package/dist/components/ui/drawer.js +213 -0
- package/dist/components/ui/drawer.mjs +28 -0
- package/dist/components/ui/dropdown-menu.js +338 -0
- package/dist/components/ui/dropdown-menu.mjs +38 -0
- package/dist/components/ui/empty.js +173 -0
- package/dist/components/ui/empty.mjs +18 -0
- package/dist/components/ui/field.js +359 -0
- package/dist/components/ui/field.mjs +28 -0
- package/dist/components/ui/input-group.js +406 -0
- package/dist/components/ui/input-group.mjs +22 -0
- package/dist/components/ui/input-otp.js +149 -0
- package/dist/components/ui/input-otp.mjs +14 -0
- package/dist/components/ui/input.js +81 -0
- package/dist/components/ui/input.mjs +8 -0
- package/dist/components/ui/label.js +85 -0
- package/dist/components/ui/label.mjs +8 -0
- package/dist/components/ui/pagination.js +333 -0
- package/dist/components/ui/pagination.mjs +22 -0
- package/dist/components/ui/popover.js +167 -0
- package/dist/components/ui/popover.mjs +22 -0
- package/dist/components/ui/progress.js +97 -0
- package/dist/components/ui/progress.mjs +8 -0
- package/dist/components/ui/radio-group.js +178 -0
- package/dist/components/ui/radio-group.mjs +12 -0
- package/dist/components/ui/select.js +262 -0
- package/dist/components/ui/select.mjs +28 -0
- package/dist/components/ui/separator.js +86 -0
- package/dist/components/ui/separator.mjs +8 -0
- package/dist/components/ui/sheet.js +227 -0
- package/dist/components/ui/sheet.mjs +26 -0
- package/dist/components/ui/skeleton.js +75 -0
- package/dist/components/ui/skeleton.mjs +8 -0
- package/dist/components/ui/sonner.js +86 -0
- package/dist/components/ui/sonner.mjs +7 -0
- package/dist/components/ui/spinner.js +93 -0
- package/dist/components/ui/spinner.mjs +10 -0
- package/dist/components/ui/switch.js +178 -0
- package/dist/components/ui/switch.mjs +11 -0
- package/dist/components/ui/table.js +184 -0
- package/dist/components/ui/table.mjs +22 -0
- package/dist/components/ui/tabs.js +181 -0
- package/dist/components/ui/tabs.mjs +16 -0
- package/dist/components/ui/textarea.js +79 -0
- package/dist/components/ui/textarea.mjs +8 -0
- package/dist/components/ui/toggle-group.js +184 -0
- package/dist/components/ui/toggle-group.mjs +12 -0
- package/dist/components/ui/toggle.js +108 -0
- package/dist/components/ui/toggle.mjs +11 -0
- package/dist/components/ui/tooltip.js +140 -0
- package/dist/components/ui/tooltip.mjs +16 -0
- package/dist/index.js +4312 -90
- package/dist/index.mjs +459 -158
- package/dist/lib/colors.js +84 -0
- package/dist/lib/colors.mjs +13 -0
- package/dist/lib/theme-provider.js +150 -0
- package/dist/lib/theme-provider.mjs +13 -0
- package/dist/lib/typography.js +157 -0
- package/dist/lib/typography.mjs +25 -0
- package/dist/lib/utils.js +34 -0
- package/dist/lib/utils.mjs +7 -0
- package/dist/styles.css +1 -1
- package/package.json +228 -11
- package/scripts/build-css.ts +15 -9
- package/src/components/index.tsx +443 -0
- package/src/components/ui/accordion.tsx +99 -0
- package/src/components/ui/alert-dialog.tsx +239 -0
- package/src/components/ui/alert.tsx +81 -0
- package/src/components/ui/avatar.tsx +130 -0
- package/src/components/ui/badge.tsx +57 -0
- package/src/components/ui/button.tsx +69 -37
- package/src/components/ui/calendar.tsx +252 -0
- package/src/components/ui/card.tsx +106 -0
- package/src/components/ui/checkbox.tsx +111 -0
- package/src/components/ui/chip.tsx +65 -0
- package/src/components/ui/data-table.tsx +490 -0
- package/src/components/ui/date-picker.tsx +133 -0
- package/src/components/ui/dialog.tsx +195 -0
- package/src/components/ui/drawer.tsx +169 -0
- package/src/components/ui/dropdown-menu.tsx +315 -0
- package/src/components/ui/empty.tsx +128 -0
- package/src/components/ui/field.tsx +273 -0
- package/src/components/ui/input-group.tsx +190 -0
- package/src/components/ui/input-otp.tsx +90 -0
- package/src/components/ui/input.tsx +28 -0
- package/src/components/ui/label.tsx +24 -0
- package/src/components/ui/pagination.tsx +148 -0
- package/src/components/ui/popover.tsx +112 -0
- package/src/components/ui/progress.tsx +40 -0
- package/src/components/ui/radio-group.tsx +129 -0
- package/src/components/ui/select.tsx +201 -0
- package/src/components/ui/separator.tsx +26 -0
- package/src/components/ui/sheet.tsx +182 -0
- package/src/components/ui/skeleton.tsx +22 -0
- package/src/components/ui/sonner.tsx +48 -0
- package/src/components/ui/spinner.tsx +41 -0
- package/src/components/ui/switch.tsx +126 -0
- package/src/components/ui/table.tsx +143 -0
- package/src/components/ui/tabs.tsx +119 -0
- package/src/components/ui/textarea.tsx +28 -0
- package/src/components/ui/toggle-group.tsx +94 -0
- package/src/components/ui/toggle.tsx +59 -0
- package/src/components/ui/tooltip.tsx +80 -0
- package/src/index.ts +15 -3
- package/src/lib/colors.ts +74 -0
- package/src/lib/slot.tsx +68 -0
- package/src/lib/theme-provider.tsx +134 -0
- package/src/lib/typography.ts +153 -0
- package/src/lib/utils.ts +1 -1
- package/src/styles/globals.css +377 -107
- package/src/styles/styles-css.ts +1 -1
- package/tsup.config.ts +48 -2
- package/dist/index.d.mts +0 -27
- package/dist/index.d.ts +0 -27
- package/src/provider/ShadcnProvider.tsx +0 -89
- package/src/provider/index.ts +0 -2
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { type ReactElement } from "react"
|
|
2
|
+
import * as React from "react"
|
|
3
|
+
import {
|
|
4
|
+
ChevronDownIcon,
|
|
5
|
+
ChevronLeftIcon,
|
|
6
|
+
ChevronRightIcon,
|
|
7
|
+
} from "lucide-react"
|
|
8
|
+
import {
|
|
9
|
+
DayPicker,
|
|
10
|
+
getDefaultClassNames,
|
|
11
|
+
type DayButton,
|
|
12
|
+
} from "react-day-picker"
|
|
13
|
+
import { cn } from "@/lib/utils"
|
|
14
|
+
import { Button, buttonVariants } from "@/components/ui/button"
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Calendar — shadcn/WealthX
|
|
18
|
+
* Base: npx shadcn\@latest add calendar (latest)
|
|
19
|
+
* Figma: Design-System---shadcn?node-id=72-2720
|
|
20
|
+
*
|
|
21
|
+
* WealthX:
|
|
22
|
+
* - font-sans for consistent Figtree typography
|
|
23
|
+
* - border + shadow-sm on root (square corners — no border radius)
|
|
24
|
+
* - captionLayout defaults to "dropdown" (Figma shows month/year dropdown pills)
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
export type CalendarProps = React.ComponentProps<typeof DayPicker> & {
|
|
28
|
+
buttonVariant?: React.ComponentProps<typeof Button>["variant"]
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function CalendarRoot({
|
|
32
|
+
className,
|
|
33
|
+
rootRef,
|
|
34
|
+
...props
|
|
35
|
+
}: {
|
|
36
|
+
className?: string
|
|
37
|
+
rootRef?: React.Ref<HTMLDivElement>
|
|
38
|
+
} & React.ComponentProps<"div">): ReactElement {
|
|
39
|
+
return (
|
|
40
|
+
<div
|
|
41
|
+
className={cn(className)}
|
|
42
|
+
data-slot="calendar"
|
|
43
|
+
ref={rootRef}
|
|
44
|
+
{...props}
|
|
45
|
+
/>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function CalendarChevron({
|
|
50
|
+
className,
|
|
51
|
+
orientation,
|
|
52
|
+
...props
|
|
53
|
+
}: {
|
|
54
|
+
className?: string
|
|
55
|
+
orientation?: string
|
|
56
|
+
} & React.ComponentProps<"svg">): ReactElement {
|
|
57
|
+
if (orientation === "left") {
|
|
58
|
+
return (
|
|
59
|
+
<ChevronLeftIcon className={cn("size-4", className)} {...props} />
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (orientation === "right") {
|
|
64
|
+
return (
|
|
65
|
+
<ChevronRightIcon
|
|
66
|
+
className={cn("size-4", className)}
|
|
67
|
+
{...props}
|
|
68
|
+
/>
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<ChevronDownIcon className={cn("size-4", className)} {...props} />
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function CalendarWeekNumber({
|
|
78
|
+
children,
|
|
79
|
+
...props
|
|
80
|
+
}: React.ComponentProps<"td">): ReactElement {
|
|
81
|
+
return (
|
|
82
|
+
<td {...props}>
|
|
83
|
+
<div className="flex size-(--cell-size) items-center justify-center text-center">
|
|
84
|
+
{children}
|
|
85
|
+
</div>
|
|
86
|
+
</td>
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function Calendar({
|
|
91
|
+
className,
|
|
92
|
+
classNames,
|
|
93
|
+
showOutsideDays = true,
|
|
94
|
+
captionLayout = "dropdown",
|
|
95
|
+
buttonVariant = "ghost",
|
|
96
|
+
formatters,
|
|
97
|
+
components,
|
|
98
|
+
...props
|
|
99
|
+
}: CalendarProps): ReactElement {
|
|
100
|
+
const defaultClassNames = getDefaultClassNames()
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<DayPicker
|
|
104
|
+
captionLayout={captionLayout}
|
|
105
|
+
className={cn(
|
|
106
|
+
"group/calendar bg-background p-3 font-sans border border-border shadow-sm [--cell-size:--spacing(8)] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent",
|
|
107
|
+
String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
|
|
108
|
+
String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
|
|
109
|
+
className
|
|
110
|
+
)}
|
|
111
|
+
classNames={{
|
|
112
|
+
root: cn("w-fit", defaultClassNames.root),
|
|
113
|
+
months: cn(
|
|
114
|
+
"relative flex flex-col gap-4 md:flex-row",
|
|
115
|
+
defaultClassNames.months
|
|
116
|
+
),
|
|
117
|
+
month: cn("flex w-full flex-col gap-4", defaultClassNames.month),
|
|
118
|
+
nav: cn(
|
|
119
|
+
"absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1",
|
|
120
|
+
defaultClassNames.nav
|
|
121
|
+
),
|
|
122
|
+
button_previous: cn(
|
|
123
|
+
buttonVariants({ variant: buttonVariant }),
|
|
124
|
+
"size-(--cell-size) p-0 select-none aria-disabled:opacity-50",
|
|
125
|
+
defaultClassNames.button_previous
|
|
126
|
+
),
|
|
127
|
+
button_next: cn(
|
|
128
|
+
buttonVariants({ variant: buttonVariant }),
|
|
129
|
+
"size-(--cell-size) p-0 select-none aria-disabled:opacity-50",
|
|
130
|
+
defaultClassNames.button_next
|
|
131
|
+
),
|
|
132
|
+
month_caption: cn(
|
|
133
|
+
"flex h-(--cell-size) w-full items-center justify-center px-(--cell-size)",
|
|
134
|
+
defaultClassNames.month_caption
|
|
135
|
+
),
|
|
136
|
+
dropdowns: cn(
|
|
137
|
+
"flex h-(--cell-size) w-full items-center justify-center gap-1.5 text-sm font-medium",
|
|
138
|
+
defaultClassNames.dropdowns
|
|
139
|
+
),
|
|
140
|
+
dropdown_root: cn(
|
|
141
|
+
"relative border border-input shadow-xs has-focus:border-ring has-focus:ring-[3px] has-focus:ring-ring/50",
|
|
142
|
+
defaultClassNames.dropdown_root
|
|
143
|
+
),
|
|
144
|
+
dropdown: cn(
|
|
145
|
+
"absolute inset-0 bg-popover opacity-0",
|
|
146
|
+
defaultClassNames.dropdown
|
|
147
|
+
),
|
|
148
|
+
caption_label: cn(
|
|
149
|
+
"font-medium select-none",
|
|
150
|
+
captionLayout === "label"
|
|
151
|
+
? "text-sm"
|
|
152
|
+
: "flex h-8 items-center gap-1 pr-1 pl-2 text-sm [&>svg]:size-3.5 [&>svg]:text-muted-foreground",
|
|
153
|
+
defaultClassNames.caption_label
|
|
154
|
+
),
|
|
155
|
+
table: "w-full border-collapse",
|
|
156
|
+
weekdays: cn("flex", defaultClassNames.weekdays),
|
|
157
|
+
weekday: cn(
|
|
158
|
+
"flex-1 text-[0.8rem] font-normal text-muted-foreground select-none",
|
|
159
|
+
defaultClassNames.weekday
|
|
160
|
+
),
|
|
161
|
+
week: cn("mt-2 flex w-full", defaultClassNames.week),
|
|
162
|
+
week_number_header: cn(
|
|
163
|
+
"w-(--cell-size) select-none",
|
|
164
|
+
defaultClassNames.week_number_header
|
|
165
|
+
),
|
|
166
|
+
week_number: cn(
|
|
167
|
+
"text-[0.8rem] text-muted-foreground select-none",
|
|
168
|
+
defaultClassNames.week_number
|
|
169
|
+
),
|
|
170
|
+
day: cn(
|
|
171
|
+
"group/day relative aspect-square h-full w-full p-0 text-center select-none",
|
|
172
|
+
defaultClassNames.day
|
|
173
|
+
),
|
|
174
|
+
range_start: cn("bg-accent", defaultClassNames.range_start),
|
|
175
|
+
range_middle: cn("rounded-none", defaultClassNames.range_middle),
|
|
176
|
+
range_end: cn("bg-accent", defaultClassNames.range_end),
|
|
177
|
+
today: cn(
|
|
178
|
+
"bg-accent text-accent-foreground",
|
|
179
|
+
defaultClassNames.today
|
|
180
|
+
),
|
|
181
|
+
outside: cn(
|
|
182
|
+
"text-muted-foreground aria-selected:text-muted-foreground",
|
|
183
|
+
defaultClassNames.outside
|
|
184
|
+
),
|
|
185
|
+
disabled: cn(
|
|
186
|
+
"text-muted-foreground opacity-50",
|
|
187
|
+
defaultClassNames.disabled
|
|
188
|
+
),
|
|
189
|
+
hidden: cn("invisible", defaultClassNames.hidden),
|
|
190
|
+
...classNames,
|
|
191
|
+
}}
|
|
192
|
+
components={{
|
|
193
|
+
Root: CalendarRoot,
|
|
194
|
+
Chevron: CalendarChevron,
|
|
195
|
+
DayButton: CalendarDayButton,
|
|
196
|
+
WeekNumber: CalendarWeekNumber,
|
|
197
|
+
...components,
|
|
198
|
+
}}
|
|
199
|
+
formatters={{
|
|
200
|
+
formatMonthDropdown: (date) =>
|
|
201
|
+
date.toLocaleString("default", { month: "short" }),
|
|
202
|
+
...formatters,
|
|
203
|
+
}}
|
|
204
|
+
showOutsideDays={showOutsideDays}
|
|
205
|
+
{...props}
|
|
206
|
+
/>
|
|
207
|
+
)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export type CalendarDayButtonProps = React.ComponentProps<typeof DayButton>
|
|
211
|
+
|
|
212
|
+
function CalendarDayButton({
|
|
213
|
+
className,
|
|
214
|
+
day,
|
|
215
|
+
modifiers,
|
|
216
|
+
...props
|
|
217
|
+
}: CalendarDayButtonProps): ReactElement {
|
|
218
|
+
const defaultClassNames = getDefaultClassNames()
|
|
219
|
+
|
|
220
|
+
const ref = React.useRef<HTMLButtonElement>(null)
|
|
221
|
+
React.useEffect(() => {
|
|
222
|
+
if (modifiers.focused) ref.current?.focus()
|
|
223
|
+
}, [modifiers.focused])
|
|
224
|
+
|
|
225
|
+
const selectedSingle =
|
|
226
|
+
modifiers.selected &&
|
|
227
|
+
!modifiers.range_start &&
|
|
228
|
+
!modifiers.range_end
|
|
229
|
+
? !modifiers.range_middle
|
|
230
|
+
: null
|
|
231
|
+
|
|
232
|
+
return (
|
|
233
|
+
<Button
|
|
234
|
+
className={cn(
|
|
235
|
+
"flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 leading-none font-normal rounded-none group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-[3px] group-data-[focused=true]/day:ring-ring/50 data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground data-[range-middle=true]:rounded-none data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground dark:hover:text-accent-foreground [&>span]:text-xs [&>span]:opacity-70",
|
|
236
|
+
defaultClassNames.day,
|
|
237
|
+
className
|
|
238
|
+
)}
|
|
239
|
+
data-day={day.date.toLocaleDateString()}
|
|
240
|
+
data-range-end={modifiers.range_end}
|
|
241
|
+
data-range-middle={modifiers.range_middle}
|
|
242
|
+
data-range-start={modifiers.range_start}
|
|
243
|
+
data-selected-single={selectedSingle}
|
|
244
|
+
ref={ref}
|
|
245
|
+
size="icon"
|
|
246
|
+
variant="ghost"
|
|
247
|
+
{...props}
|
|
248
|
+
/>
|
|
249
|
+
)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export { Calendar, CalendarDayButton }
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { type ReactElement } from "react"
|
|
2
|
+
import * as React from "react"
|
|
3
|
+
import { cn } from "@/lib/utils"
|
|
4
|
+
|
|
5
|
+
export type CardProps = React.ComponentProps<"div">
|
|
6
|
+
|
|
7
|
+
function Card({ className, ...props }: CardProps): ReactElement {
|
|
8
|
+
return (
|
|
9
|
+
<div
|
|
10
|
+
className={cn(
|
|
11
|
+
"flex flex-col gap-6 border bg-card py-6 text-card-foreground shadow-sm",
|
|
12
|
+
className
|
|
13
|
+
)}
|
|
14
|
+
data-slot="card"
|
|
15
|
+
{...props}
|
|
16
|
+
/>
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type CardHeaderProps = React.ComponentProps<"div">
|
|
21
|
+
|
|
22
|
+
function CardHeader({ className, ...props }: CardHeaderProps): ReactElement {
|
|
23
|
+
return (
|
|
24
|
+
<div
|
|
25
|
+
className={cn(
|
|
26
|
+
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
|
|
27
|
+
className
|
|
28
|
+
)}
|
|
29
|
+
data-slot="card-header"
|
|
30
|
+
{...props}
|
|
31
|
+
/>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type CardTitleProps = React.ComponentProps<"div">
|
|
36
|
+
|
|
37
|
+
function CardTitle({ className, ...props }: CardTitleProps): ReactElement {
|
|
38
|
+
return (
|
|
39
|
+
<div
|
|
40
|
+
className={cn("leading-none font-semibold", className)}
|
|
41
|
+
data-slot="card-title"
|
|
42
|
+
{...props}
|
|
43
|
+
/>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export type CardDescriptionProps = React.ComponentProps<"div">
|
|
48
|
+
|
|
49
|
+
function CardDescription({ className, ...props }: CardDescriptionProps): ReactElement {
|
|
50
|
+
return (
|
|
51
|
+
<div
|
|
52
|
+
className={cn("text-sm text-muted-foreground", className)}
|
|
53
|
+
data-slot="card-description"
|
|
54
|
+
{...props}
|
|
55
|
+
/>
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export type CardActionProps = React.ComponentProps<"div">
|
|
60
|
+
|
|
61
|
+
function CardAction({ className, ...props }: CardActionProps): ReactElement {
|
|
62
|
+
return (
|
|
63
|
+
<div
|
|
64
|
+
className={cn(
|
|
65
|
+
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
|
|
66
|
+
className
|
|
67
|
+
)}
|
|
68
|
+
data-slot="card-action"
|
|
69
|
+
{...props}
|
|
70
|
+
/>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export type CardContentProps = React.ComponentProps<"div">
|
|
75
|
+
|
|
76
|
+
function CardContent({ className, ...props }: CardContentProps): ReactElement {
|
|
77
|
+
return (
|
|
78
|
+
<div
|
|
79
|
+
className={cn("px-6", className)}
|
|
80
|
+
data-slot="card-content"
|
|
81
|
+
{...props}
|
|
82
|
+
/>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export type CardFooterProps = React.ComponentProps<"div">
|
|
87
|
+
|
|
88
|
+
function CardFooter({ className, ...props }: CardFooterProps): ReactElement {
|
|
89
|
+
return (
|
|
90
|
+
<div
|
|
91
|
+
className={cn("flex items-center px-6 [.border-t]:pt-6", className)}
|
|
92
|
+
data-slot="card-footer"
|
|
93
|
+
{...props}
|
|
94
|
+
/>
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export {
|
|
99
|
+
Card,
|
|
100
|
+
CardHeader,
|
|
101
|
+
CardFooter,
|
|
102
|
+
CardTitle,
|
|
103
|
+
CardAction,
|
|
104
|
+
CardDescription,
|
|
105
|
+
CardContent,
|
|
106
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { type ReactElement, useState, type ComponentProps } from "react"
|
|
4
|
+
import { CheckIcon, MinusIcon } from "lucide-react"
|
|
5
|
+
import { Checkbox as CheckboxPrimitive } from "@base-ui/react/checkbox"
|
|
6
|
+
import { cn } from "@/lib/utils"
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Checkbox — shadcn/WealthX Design System
|
|
10
|
+
* Figma: https://www.figma.com/design/9V9F0NGVsif8LGmEhVjOcT/Design-System---shadcn?node-id=72-2723
|
|
11
|
+
*
|
|
12
|
+
* States: unchecked | checked | indeterminate × default | disabled | error
|
|
13
|
+
* White-label: checked/indeterminate use `primary` token → adapts to tenant color.
|
|
14
|
+
* Error+checked/indeterminate: stacked variant overrides primary with destructive (higher specificity).
|
|
15
|
+
*/
|
|
16
|
+
export type CheckboxProps = ComponentProps<typeof CheckboxPrimitive.Root>
|
|
17
|
+
|
|
18
|
+
function Checkbox({ className, ...props }: CheckboxProps): ReactElement {
|
|
19
|
+
return (
|
|
20
|
+
<CheckboxPrimitive.Root
|
|
21
|
+
className={cn(
|
|
22
|
+
"peer group inline-flex size-4 shrink-0 rounded-[4px] border border-input shadow-xs transition-all outline-none",
|
|
23
|
+
"focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50",
|
|
24
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
25
|
+
"aria-invalid:border-destructive aria-invalid:ring-destructive/20",
|
|
26
|
+
"data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground",
|
|
27
|
+
"data-indeterminate:border-primary data-indeterminate:bg-primary data-indeterminate:text-primary-foreground",
|
|
28
|
+
// Dark mode (upstream shadcn)
|
|
29
|
+
"dark:bg-input/30 dark:aria-invalid:ring-destructive/40 dark:data-checked:bg-primary",
|
|
30
|
+
// Stacked (2 attr selectors) → wins over single-attr rules above
|
|
31
|
+
"aria-invalid:data-checked:border-destructive aria-invalid:data-checked:bg-destructive aria-invalid:data-checked:text-destructive-foreground",
|
|
32
|
+
"aria-invalid:data-indeterminate:border-destructive aria-invalid:data-indeterminate:bg-destructive aria-invalid:data-indeterminate:text-destructive-foreground",
|
|
33
|
+
className
|
|
34
|
+
)}
|
|
35
|
+
data-slot="checkbox"
|
|
36
|
+
{...props}
|
|
37
|
+
>
|
|
38
|
+
<CheckboxPrimitive.Indicator
|
|
39
|
+
className="grid place-content-center text-current transition-none"
|
|
40
|
+
data-slot="checkbox-indicator"
|
|
41
|
+
>
|
|
42
|
+
<CheckIcon className="size-3.5 group-data-indeterminate:hidden" />
|
|
43
|
+
<MinusIcon className="size-3.5 hidden group-data-indeterminate:block" />
|
|
44
|
+
</CheckboxPrimitive.Indicator>
|
|
45
|
+
</CheckboxPrimitive.Root>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* CheckboxCard — card wrapper with label + optional description.
|
|
51
|
+
* Figma: Checkbox_card (3029:12381)
|
|
52
|
+
*
|
|
53
|
+
* Card background: primary/5 when checked/indeterminate; destructive/5 when error+checked.
|
|
54
|
+
* White-label: opacity modifier on primary token → adapts to tenant color.
|
|
55
|
+
*/
|
|
56
|
+
export type CheckboxCardProps = ComponentProps<typeof CheckboxPrimitive.Root> & {
|
|
57
|
+
label: string
|
|
58
|
+
description?: string
|
|
59
|
+
error?: boolean
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function CheckboxCard({
|
|
63
|
+
className,
|
|
64
|
+
checked,
|
|
65
|
+
defaultChecked,
|
|
66
|
+
onCheckedChange,
|
|
67
|
+
disabled,
|
|
68
|
+
error,
|
|
69
|
+
label,
|
|
70
|
+
description,
|
|
71
|
+
...props
|
|
72
|
+
}: CheckboxCardProps): ReactElement {
|
|
73
|
+
const [internalChecked, setInternalChecked] = useState<boolean>(
|
|
74
|
+
Boolean(defaultChecked)
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
const resolvedChecked = checked ?? internalChecked
|
|
78
|
+
const isTinted = resolvedChecked
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<label
|
|
82
|
+
className={cn(
|
|
83
|
+
"flex items-start gap-3 border border-border p-4 font-sans transition-colors cursor-pointer",
|
|
84
|
+
error
|
|
85
|
+
? ["border-destructive", isTinted && "bg-destructive/5"]
|
|
86
|
+
: isTinted && "border-primary bg-primary/5",
|
|
87
|
+
disabled && "cursor-not-allowed opacity-50",
|
|
88
|
+
className
|
|
89
|
+
)}
|
|
90
|
+
data-slot="checkbox-card"
|
|
91
|
+
>
|
|
92
|
+
<Checkbox
|
|
93
|
+
aria-invalid={error || undefined}
|
|
94
|
+
checked={resolvedChecked}
|
|
95
|
+
className="mt-0.5"
|
|
96
|
+
disabled={disabled}
|
|
97
|
+
onCheckedChange={(value, event) => {
|
|
98
|
+
setInternalChecked(value as boolean)
|
|
99
|
+
onCheckedChange?.(value, event)
|
|
100
|
+
}}
|
|
101
|
+
{...props}
|
|
102
|
+
/>
|
|
103
|
+
<div className="flex flex-col gap-1">
|
|
104
|
+
<span className="text-sm font-medium leading-none">{label}</span>
|
|
105
|
+
{description ? <span className="text-sm text-muted-foreground">{description}</span> : null}
|
|
106
|
+
</div>
|
|
107
|
+
</label>
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export { Checkbox, CheckboxCard }
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Chip — WealthX DS (built on Badge)
|
|
2
|
+
//
|
|
3
|
+
// Badge extended with an optional dismiss button.
|
|
4
|
+
// Passes all Badge props (variant, className, etc.) through unchanged.
|
|
5
|
+
//
|
|
6
|
+
// Usage:
|
|
7
|
+
// <Chip>Label</Chip>
|
|
8
|
+
// <Chip onRemove={() => handleRemove(id)}>Label</Chip>
|
|
9
|
+
// <Chip variant="outline" disabled onRemove={...}>Label</Chip>
|
|
10
|
+
import { type ReactElement } from "react"
|
|
11
|
+
import * as React from "react"
|
|
12
|
+
import { X } from "lucide-react"
|
|
13
|
+
import type { VariantProps } from "class-variance-authority"
|
|
14
|
+
import { cn } from "@/lib/utils"
|
|
15
|
+
import { badgeVariants } from "@/components/ui/badge"
|
|
16
|
+
|
|
17
|
+
export interface ChipProps
|
|
18
|
+
extends React.ComponentProps<"span">,
|
|
19
|
+
VariantProps<typeof badgeVariants> {
|
|
20
|
+
/** When provided, renders a dismiss (×) button inside the chip. */
|
|
21
|
+
onRemove?: () => void
|
|
22
|
+
disabled?: boolean
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function Chip({
|
|
26
|
+
className,
|
|
27
|
+
variant = "secondary",
|
|
28
|
+
onRemove,
|
|
29
|
+
disabled,
|
|
30
|
+
children,
|
|
31
|
+
...props
|
|
32
|
+
}: ChipProps): ReactElement {
|
|
33
|
+
return (
|
|
34
|
+
<span
|
|
35
|
+
aria-disabled={disabled}
|
|
36
|
+
className={cn(
|
|
37
|
+
badgeVariants({ variant }),
|
|
38
|
+
// extra right padding only when dismiss button is present
|
|
39
|
+
onRemove && "pr-1",
|
|
40
|
+
disabled && "pointer-events-none opacity-50",
|
|
41
|
+
className
|
|
42
|
+
)}
|
|
43
|
+
data-slot="chip"
|
|
44
|
+
data-variant={variant}
|
|
45
|
+
{...props}
|
|
46
|
+
>
|
|
47
|
+
{children}
|
|
48
|
+
{onRemove ? <button
|
|
49
|
+
aria-label="Remove"
|
|
50
|
+
className="ml-0.5 inline-flex shrink-0 items-center justify-center rounded-full p-0.5 opacity-60 hover:opacity-100 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none"
|
|
51
|
+
data-slot="chip-remove"
|
|
52
|
+
disabled={disabled}
|
|
53
|
+
onClick={(e) => {
|
|
54
|
+
e.stopPropagation()
|
|
55
|
+
onRemove()
|
|
56
|
+
}}
|
|
57
|
+
type="button"
|
|
58
|
+
>
|
|
59
|
+
<X className="size-3" />
|
|
60
|
+
</button> : null}
|
|
61
|
+
</span>
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export { Chip }
|