@wealthx/shadcn 0.0.1 → 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 (186) hide show
  1. package/.turbo/turbo-build.log +160 -0
  2. package/CHANGELOG.md +13 -0
  3. package/CHANGES.md +345 -0
  4. package/dist/chunk-2WZVSBAY.mjs +232 -0
  5. package/dist/chunk-2Y7YJKPE.mjs +47 -0
  6. package/dist/chunk-3U7SD3MS.mjs +55 -0
  7. package/dist/chunk-3VQNJ235.mjs +114 -0
  8. package/dist/chunk-55CEW76V.mjs +35 -0
  9. package/dist/chunk-6AFMNC42.mjs +146 -0
  10. package/dist/chunk-6OJF6XRN.mjs +117 -0
  11. package/dist/chunk-7LDIMXGM.mjs +181 -0
  12. package/dist/chunk-AMJ23O53.mjs +122 -0
  13. package/dist/chunk-BBJBJSXQ.mjs +44 -0
  14. package/dist/chunk-BGP2N52Z.mjs +126 -0
  15. package/dist/chunk-BMFN37JH.mjs +41 -0
  16. package/dist/chunk-CGOKTPXU.mjs +79 -0
  17. package/dist/chunk-CZ3BW5GL.mjs +81 -0
  18. package/dist/chunk-DBHJ5KC3.mjs +55 -0
  19. package/dist/chunk-DDPA2XXS.mjs +97 -0
  20. package/dist/chunk-DS2AMHN2.mjs +30 -0
  21. package/dist/chunk-E3K6O4FZ.mjs +57 -0
  22. package/dist/chunk-FWCSY2DS.mjs +37 -0
  23. package/dist/chunk-GPRJQ24C.mjs +28 -0
  24. package/dist/chunk-HS7TFG7V.mjs +24 -0
  25. package/dist/chunk-HUVTPUV2.mjs +256 -0
  26. package/dist/chunk-IAOOZCUY.mjs +90 -0
  27. package/dist/chunk-JF4PHPD5.mjs +111 -0
  28. package/dist/chunk-JU2RUWHF.mjs +123 -0
  29. package/dist/chunk-KKHTJNMM.mjs +86 -0
  30. package/dist/chunk-MJIEMGRD.mjs +266 -0
  31. package/dist/chunk-MKFL5MNH.mjs +372 -0
  32. package/dist/chunk-MQ72DIBH.mjs +105 -0
  33. package/dist/chunk-NGYG2EA6.mjs +148 -0
  34. package/dist/chunk-NWZ46DJL.mjs +213 -0
  35. package/dist/chunk-OXQQNQZI.mjs +75 -0
  36. package/dist/chunk-PMKODV6M.mjs +161 -0
  37. package/dist/chunk-QOJ2DQD6.mjs +57 -0
  38. package/dist/chunk-RL772EH7.mjs +126 -0
  39. package/dist/chunk-SLWCCURD.mjs +99 -0
  40. package/dist/chunk-V7CNWJT3.mjs +10 -0
  41. package/dist/chunk-VG6UF6UT.mjs +68 -0
  42. package/dist/chunk-VYMHBV6D.mjs +123 -0
  43. package/dist/chunk-VZ2NR7L3.mjs +195 -0
  44. package/dist/chunk-YN5SYTOO.mjs +117 -0
  45. package/dist/chunk-Z3MK2KKZ.mjs +83 -0
  46. package/dist/chunk-ZN2QKLF6.mjs +187 -0
  47. package/dist/chunk-ZZV5JVNW.mjs +34 -0
  48. package/dist/components/ui/accordion.js +142 -0
  49. package/dist/components/ui/accordion.mjs +14 -0
  50. package/dist/components/ui/alert-dialog.js +413 -0
  51. package/dist/components/ui/alert-dialog.mjs +34 -0
  52. package/dist/components/ui/alert.js +134 -0
  53. package/dist/components/ui/alert.mjs +12 -0
  54. package/dist/components/ui/avatar.js +173 -0
  55. package/dist/components/ui/avatar.mjs +18 -0
  56. package/dist/components/ui/badge.js +163 -0
  57. package/dist/components/ui/badge.mjs +11 -0
  58. package/dist/components/ui/button.js +198 -0
  59. package/dist/components/ui/button.mjs +11 -0
  60. package/dist/components/ui/calendar.js +408 -0
  61. package/dist/components/ui/calendar.mjs +12 -0
  62. package/dist/components/ui/card.js +156 -0
  63. package/dist/components/ui/card.mjs +20 -0
  64. package/dist/components/ui/checkbox.js +166 -0
  65. package/dist/components/ui/checkbox.mjs +11 -0
  66. package/dist/components/ui/chip.js +199 -0
  67. package/dist/components/ui/chip.mjs +10 -0
  68. package/dist/components/ui/data-table.js +925 -0
  69. package/dist/components/ui/data-table.mjs +29 -0
  70. package/dist/components/ui/date-picker.js +561 -0
  71. package/dist/components/ui/date-picker.mjs +15 -0
  72. package/dist/components/ui/dialog.js +378 -0
  73. package/dist/components/ui/dialog.mjs +30 -0
  74. package/dist/components/ui/drawer.js +213 -0
  75. package/dist/components/ui/drawer.mjs +28 -0
  76. package/dist/components/ui/dropdown-menu.js +338 -0
  77. package/dist/components/ui/dropdown-menu.mjs +38 -0
  78. package/dist/components/ui/empty.js +173 -0
  79. package/dist/components/ui/empty.mjs +18 -0
  80. package/dist/components/ui/field.js +359 -0
  81. package/dist/components/ui/field.mjs +28 -0
  82. package/dist/components/ui/input-group.js +406 -0
  83. package/dist/components/ui/input-group.mjs +22 -0
  84. package/dist/components/ui/input-otp.js +149 -0
  85. package/dist/components/ui/input-otp.mjs +14 -0
  86. package/dist/components/ui/input.js +81 -0
  87. package/dist/components/ui/input.mjs +8 -0
  88. package/dist/components/ui/label.js +85 -0
  89. package/dist/components/ui/label.mjs +8 -0
  90. package/dist/components/ui/pagination.js +333 -0
  91. package/dist/components/ui/pagination.mjs +22 -0
  92. package/dist/components/ui/popover.js +167 -0
  93. package/dist/components/ui/popover.mjs +22 -0
  94. package/dist/components/ui/progress.js +97 -0
  95. package/dist/components/ui/progress.mjs +8 -0
  96. package/dist/components/ui/radio-group.js +178 -0
  97. package/dist/components/ui/radio-group.mjs +12 -0
  98. package/dist/components/ui/select.js +262 -0
  99. package/dist/components/ui/select.mjs +28 -0
  100. package/dist/components/ui/separator.js +86 -0
  101. package/dist/components/ui/separator.mjs +8 -0
  102. package/dist/components/ui/sheet.js +227 -0
  103. package/dist/components/ui/sheet.mjs +26 -0
  104. package/dist/components/ui/skeleton.js +75 -0
  105. package/dist/components/ui/skeleton.mjs +8 -0
  106. package/dist/components/ui/sonner.js +86 -0
  107. package/dist/components/ui/sonner.mjs +7 -0
  108. package/dist/components/ui/spinner.js +93 -0
  109. package/dist/components/ui/spinner.mjs +10 -0
  110. package/dist/components/ui/switch.js +178 -0
  111. package/dist/components/ui/switch.mjs +11 -0
  112. package/dist/components/ui/table.js +184 -0
  113. package/dist/components/ui/table.mjs +22 -0
  114. package/dist/components/ui/tabs.js +181 -0
  115. package/dist/components/ui/tabs.mjs +16 -0
  116. package/dist/components/ui/textarea.js +79 -0
  117. package/dist/components/ui/textarea.mjs +8 -0
  118. package/dist/components/ui/toggle-group.js +184 -0
  119. package/dist/components/ui/toggle-group.mjs +12 -0
  120. package/dist/components/ui/toggle.js +108 -0
  121. package/dist/components/ui/toggle.mjs +11 -0
  122. package/dist/components/ui/tooltip.js +140 -0
  123. package/dist/components/ui/tooltip.mjs +16 -0
  124. package/dist/index.js +4409 -0
  125. package/dist/index.mjs +462 -0
  126. package/dist/lib/colors.js +84 -0
  127. package/dist/lib/colors.mjs +13 -0
  128. package/dist/lib/theme-provider.js +150 -0
  129. package/dist/lib/theme-provider.mjs +13 -0
  130. package/dist/lib/typography.js +157 -0
  131. package/dist/lib/typography.mjs +25 -0
  132. package/dist/lib/utils.js +34 -0
  133. package/dist/lib/utils.mjs +7 -0
  134. package/dist/styles.css +2 -0
  135. package/package.json +228 -11
  136. package/scripts/build-css.ts +15 -9
  137. package/src/components/index.tsx +443 -0
  138. package/src/components/ui/accordion.tsx +99 -0
  139. package/src/components/ui/alert-dialog.tsx +239 -0
  140. package/src/components/ui/alert.tsx +81 -0
  141. package/src/components/ui/avatar.tsx +130 -0
  142. package/src/components/ui/badge.tsx +57 -0
  143. package/src/components/ui/button.tsx +69 -37
  144. package/src/components/ui/calendar.tsx +252 -0
  145. package/src/components/ui/card.tsx +106 -0
  146. package/src/components/ui/checkbox.tsx +111 -0
  147. package/src/components/ui/chip.tsx +65 -0
  148. package/src/components/ui/data-table.tsx +490 -0
  149. package/src/components/ui/date-picker.tsx +133 -0
  150. package/src/components/ui/dialog.tsx +195 -0
  151. package/src/components/ui/drawer.tsx +169 -0
  152. package/src/components/ui/dropdown-menu.tsx +315 -0
  153. package/src/components/ui/empty.tsx +128 -0
  154. package/src/components/ui/field.tsx +273 -0
  155. package/src/components/ui/input-group.tsx +190 -0
  156. package/src/components/ui/input-otp.tsx +90 -0
  157. package/src/components/ui/input.tsx +28 -0
  158. package/src/components/ui/label.tsx +24 -0
  159. package/src/components/ui/pagination.tsx +148 -0
  160. package/src/components/ui/popover.tsx +112 -0
  161. package/src/components/ui/progress.tsx +40 -0
  162. package/src/components/ui/radio-group.tsx +129 -0
  163. package/src/components/ui/select.tsx +201 -0
  164. package/src/components/ui/separator.tsx +26 -0
  165. package/src/components/ui/sheet.tsx +182 -0
  166. package/src/components/ui/skeleton.tsx +22 -0
  167. package/src/components/ui/sonner.tsx +48 -0
  168. package/src/components/ui/spinner.tsx +41 -0
  169. package/src/components/ui/switch.tsx +126 -0
  170. package/src/components/ui/table.tsx +143 -0
  171. package/src/components/ui/tabs.tsx +119 -0
  172. package/src/components/ui/textarea.tsx +28 -0
  173. package/src/components/ui/toggle-group.tsx +94 -0
  174. package/src/components/ui/toggle.tsx +59 -0
  175. package/src/components/ui/tooltip.tsx +80 -0
  176. package/src/index.ts +15 -3
  177. package/src/lib/colors.ts +74 -0
  178. package/src/lib/slot.tsx +68 -0
  179. package/src/lib/theme-provider.tsx +134 -0
  180. package/src/lib/typography.ts +153 -0
  181. package/src/lib/utils.ts +1 -1
  182. package/src/styles/globals.css +377 -107
  183. package/src/styles/styles-css.ts +1 -1
  184. package/tsup.config.ts +48 -2
  185. package/src/provider/ShadcnProvider.tsx +0 -89
  186. package/src/provider/index.ts +0 -2
@@ -0,0 +1,239 @@
1
+ /**
2
+ * AlertDialog — WealthX DS overrides (shadcn / \@base-ui alert-dialog)
3
+ *
4
+ * Changes from shadcn default:
5
+ * - AlertDialogOverlay: `bg-black/50` → `bg-foreground/50` — DS foreground token (matches Figma)
6
+ * - AlertDialogContent: `rounded-lg` removed — sharp corners per Figma
7
+ * - AlertDialogContent: `shadow-lg` removed — flat panels per Figma
8
+ * - AlertDialogFooter: always row, right-aligned; `border-t border-border pt-4` separator
9
+ * - AlertDialogMedia: borderless icon slot — `size-10` default, `size-8` sm
10
+ */
11
+ import { type ReactElement } from "react"
12
+ import * as React from "react"
13
+ import { AlertDialog as AlertDialogPrimitive } from "@base-ui/react/alert-dialog"
14
+ import { cn } from "@/lib/utils"
15
+ import { useThemeVars } from "@/lib/theme-provider"
16
+ import { buttonVariants } from "@/components/ui/button"
17
+
18
+ export type AlertDialogProps = React.ComponentProps<typeof AlertDialogPrimitive.Root>
19
+
20
+ function AlertDialog({
21
+ ...props
22
+ }: AlertDialogProps): ReactElement {
23
+ return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />
24
+ }
25
+
26
+ export type AlertDialogTriggerProps = React.ComponentProps<typeof AlertDialogPrimitive.Trigger>
27
+
28
+ function AlertDialogTrigger({
29
+ ...props
30
+ }: AlertDialogTriggerProps): ReactElement {
31
+ return (
32
+ <AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />
33
+ )
34
+ }
35
+
36
+ export type AlertDialogPortalProps = React.ComponentProps<typeof AlertDialogPrimitive.Portal>
37
+
38
+ function AlertDialogPortal({
39
+ ...props
40
+ }: AlertDialogPortalProps): ReactElement {
41
+ return (
42
+ <AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />
43
+ )
44
+ }
45
+
46
+ export type AlertDialogOverlayProps = React.ComponentProps<typeof AlertDialogPrimitive.Backdrop>
47
+
48
+ function AlertDialogOverlay({
49
+ className,
50
+ ...props
51
+ }: AlertDialogOverlayProps): ReactElement {
52
+ return (
53
+ <AlertDialogPrimitive.Backdrop
54
+ className={cn(
55
+ // WealthX: foreground/50 scrim — matches Figma foreground token at 50% opacity
56
+ "fixed inset-0 z-50 bg-foreground/50 data-ending-style:animate-out data-ending-style:fade-out-0 data-ending-style:fill-mode-forwards data-open:animate-in data-open:fade-in-0",
57
+ className
58
+ )}
59
+ data-slot="alert-dialog-overlay"
60
+ {...props}
61
+ />
62
+ )
63
+ }
64
+
65
+ export type AlertDialogContentProps = React.ComponentProps<typeof AlertDialogPrimitive.Popup> & {
66
+ size?: "default" | "sm"
67
+ }
68
+
69
+ function AlertDialogContent({
70
+ className,
71
+ size = "default",
72
+ style,
73
+ ...props
74
+ }: AlertDialogContentProps): ReactElement {
75
+ const themeVars = useThemeVars();
76
+ return (
77
+ <AlertDialogPortal>
78
+ <AlertDialogOverlay />
79
+ <AlertDialogPrimitive.Popup
80
+ className={cn(
81
+ // WealthX: removed rounded-lg (sharp corners), shadow-lg (flat panels)
82
+ "group/alert-dialog-content fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 duration-200 data-[size=sm]:max-w-xs data-ending-style:animate-out data-ending-style:fade-out-0 data-ending-style:zoom-out-95 data-ending-style:fill-mode-forwards data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-[size=default]:sm:max-w-lg",
83
+ className
84
+ )}
85
+ data-size={size}
86
+ data-slot="alert-dialog-content"
87
+ style={{ ...themeVars, ...style } as React.CSSProperties}
88
+ {...props}
89
+ />
90
+ </AlertDialogPortal>
91
+ )
92
+ }
93
+
94
+ export type AlertDialogHeaderProps = React.ComponentProps<"div">
95
+
96
+ function AlertDialogHeader({
97
+ className,
98
+ ...props
99
+ }: AlertDialogHeaderProps): ReactElement {
100
+ return (
101
+ <div
102
+ className={cn(
103
+ "grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-6 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]",
104
+ className
105
+ )}
106
+ data-slot="alert-dialog-header"
107
+ {...props}
108
+ />
109
+ )
110
+ }
111
+
112
+ export type AlertDialogFooterProps = React.ComponentProps<"div">
113
+
114
+ function AlertDialogFooter({
115
+ className,
116
+ ...props
117
+ }: AlertDialogFooterProps): ReactElement {
118
+ return (
119
+ <div
120
+ className={cn(
121
+ // WealthX: always row, right-aligned, separator above footer (matches Figma)
122
+ "flex flex-row justify-end gap-2 border-t border-border pt-4",
123
+ className
124
+ )}
125
+ data-slot="alert-dialog-footer"
126
+ {...props}
127
+ />
128
+ )
129
+ }
130
+
131
+ export type AlertDialogTitleProps = React.ComponentProps<typeof AlertDialogPrimitive.Title>
132
+
133
+ function AlertDialogTitle({
134
+ className,
135
+ ...props
136
+ }: AlertDialogTitleProps): ReactElement {
137
+ return (
138
+ <AlertDialogPrimitive.Title
139
+ className={cn(
140
+ "text-lg font-semibold sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2",
141
+ className
142
+ )}
143
+ data-slot="alert-dialog-title"
144
+ {...props}
145
+ />
146
+ )
147
+ }
148
+
149
+ export type AlertDialogDescriptionProps = React.ComponentProps<typeof AlertDialogPrimitive.Description>
150
+
151
+ function AlertDialogDescription({
152
+ className,
153
+ ...props
154
+ }: AlertDialogDescriptionProps): ReactElement {
155
+ return (
156
+ <AlertDialogPrimitive.Description
157
+ className={cn(
158
+ "text-sm text-muted-foreground sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2",
159
+ className
160
+ )}
161
+ data-slot="alert-dialog-description"
162
+ {...props}
163
+ />
164
+ )
165
+ }
166
+
167
+ export type AlertDialogMediaProps = React.ComponentProps<"div">
168
+
169
+ function AlertDialogMedia({
170
+ className,
171
+ ...props
172
+ }: AlertDialogMediaProps): ReactElement {
173
+ return (
174
+ <div
175
+ className={cn(
176
+ // WealthX: borderless icon slot — size-10 default, size-8 sm
177
+ "mb-2 inline-flex size-10 items-center justify-center group-data-[size=sm]/alert-dialog-content:size-8 sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-5",
178
+ className
179
+ )}
180
+ data-slot="alert-dialog-media"
181
+ {...props}
182
+ />
183
+ )
184
+ }
185
+
186
+ export type AlertDialogActionProps = React.ComponentProps<typeof AlertDialogPrimitive.Close> & {
187
+ variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link"
188
+ size?: "default" | "sm" | "lg" | "xs" | "icon"
189
+ }
190
+
191
+ function AlertDialogAction({
192
+ className,
193
+ variant = "default",
194
+ size = "default",
195
+ ...props
196
+ }: AlertDialogActionProps): ReactElement {
197
+ return (
198
+ <AlertDialogPrimitive.Close
199
+ className={cn(buttonVariants({ variant, size }), className)}
200
+ data-slot="alert-dialog-action"
201
+ {...props}
202
+ />
203
+ )
204
+ }
205
+
206
+ export type AlertDialogCancelProps = React.ComponentProps<typeof AlertDialogPrimitive.Close> & {
207
+ variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link"
208
+ size?: "default" | "sm" | "lg" | "xs" | "icon"
209
+ }
210
+
211
+ function AlertDialogCancel({
212
+ className,
213
+ variant = "outline",
214
+ size = "default",
215
+ ...props
216
+ }: AlertDialogCancelProps): ReactElement {
217
+ return (
218
+ <AlertDialogPrimitive.Close
219
+ className={cn(buttonVariants({ variant, size }), className)}
220
+ data-slot="alert-dialog-cancel"
221
+ {...props}
222
+ />
223
+ )
224
+ }
225
+
226
+ export {
227
+ AlertDialog,
228
+ AlertDialogAction,
229
+ AlertDialogCancel,
230
+ AlertDialogContent,
231
+ AlertDialogDescription,
232
+ AlertDialogFooter,
233
+ AlertDialogHeader,
234
+ AlertDialogMedia,
235
+ AlertDialogOverlay,
236
+ AlertDialogPortal,
237
+ AlertDialogTitle,
238
+ AlertDialogTrigger,
239
+ }
@@ -0,0 +1,81 @@
1
+ import { type ReactElement } from "react"
2
+ import * as React from "react"
3
+ import { cva, type VariantProps } from "class-variance-authority"
4
+ import { cn } from "@/lib/utils"
5
+
6
+ /**
7
+ * Alert — WealthX Design System
8
+ * Figma: https://www.figma.com/design/9V9F0NGVsif8LGmEhVjOcT/Design-System---shadcn?node-id=72-2633
9
+ *
10
+ * Base: official shadcn alert (npx shadcn\@latest add alert)
11
+ * WealthX overrides: sharp corners (no rounded-lg), added warning/success/info variants
12
+ */
13
+ const alertVariants = cva(
14
+ "relative grid w-full grid-cols-[0_1fr] items-start gap-y-0.5 border px-4 py-3 text-sm has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] has-[>svg]:gap-x-3 [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current",
15
+ {
16
+ variants: {
17
+ variant: {
18
+ default: "border-border bg-card text-card-foreground",
19
+ destructive: "border-destructive/40 bg-destructive/10 text-destructive *:data-[slot=alert-description]:text-destructive/90 [&>svg]:text-destructive",
20
+ warning: "border-warning/40 bg-warning/10 text-warning *:data-[slot=alert-description]:text-warning/90 [&>svg]:text-warning",
21
+ success: "border-success/40 bg-success/10 text-success *:data-[slot=alert-description]:text-success/90 [&>svg]:text-success",
22
+ info: "border-info/40 bg-info/10 text-info *:data-[slot=alert-description]:text-info/90 [&>svg]:text-info",
23
+ },
24
+ },
25
+ defaultVariants: {
26
+ variant: "default",
27
+ },
28
+ }
29
+ )
30
+
31
+ export type AlertProps = React.ComponentProps<"div"> & VariantProps<typeof alertVariants>
32
+
33
+ function Alert({
34
+ className,
35
+ variant,
36
+ ...props
37
+ }: AlertProps): ReactElement {
38
+ return (
39
+ <div
40
+ className={cn(alertVariants({ variant }), className)}
41
+ data-slot="alert"
42
+ role="alert"
43
+ {...props}
44
+ />
45
+ )
46
+ }
47
+
48
+ export type AlertTitleProps = React.ComponentProps<"div">
49
+
50
+ function AlertTitle({ className, ...props }: AlertTitleProps): ReactElement {
51
+ return (
52
+ <div
53
+ className={cn(
54
+ "col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight",
55
+ className
56
+ )}
57
+ data-slot="alert-title"
58
+ {...props}
59
+ />
60
+ )
61
+ }
62
+
63
+ export type AlertDescriptionProps = React.ComponentProps<"div">
64
+
65
+ function AlertDescription({
66
+ className,
67
+ ...props
68
+ }: AlertDescriptionProps): ReactElement {
69
+ return (
70
+ <div
71
+ className={cn(
72
+ "col-start-2 grid justify-items-start gap-1 text-sm text-muted-foreground [&_p]:leading-relaxed",
73
+ className
74
+ )}
75
+ data-slot="alert-description"
76
+ {...props}
77
+ />
78
+ )
79
+ }
80
+
81
+ export { Alert, AlertTitle, AlertDescription }
@@ -0,0 +1,130 @@
1
+ import { type ReactElement } from "react"
2
+ import * as React from "react"
3
+ import { Avatar as AvatarPrimitive } from "@base-ui/react/avatar"
4
+ import { cn } from "@/lib/utils"
5
+
6
+ /**
7
+ * Avatar — shadcn/WealthX
8
+ * Base: npx shadcn\@latest add avatar (latest)
9
+ * Figma: Design-System---shadcn?node-id=72-2717
10
+ *
11
+ * WealthX:
12
+ * - Removed overflow-hidden from Avatar root → moved to AvatarImage/AvatarFallback
13
+ * so AvatarBadge (absolute positioned) is not clipped by the parent.
14
+ * - Added font-sans to AvatarFallback for consistent typography.
15
+ */
16
+
17
+ export type AvatarProps = React.ComponentProps<typeof AvatarPrimitive.Root> & {
18
+ size?: "default" | "sm" | "lg"
19
+ }
20
+
21
+ function Avatar({
22
+ className,
23
+ size = "default",
24
+ ...props
25
+ }: AvatarProps): ReactElement {
26
+ return (
27
+ <AvatarPrimitive.Root
28
+ className={cn(
29
+ "group/avatar relative flex size-8 shrink-0 rounded-full select-none data-[size=lg]:size-10 data-[size=sm]:size-6",
30
+ className
31
+ )}
32
+ data-size={size}
33
+ data-slot="avatar"
34
+ {...props}
35
+ />
36
+ )
37
+ }
38
+
39
+ export type AvatarImageProps = React.ComponentProps<typeof AvatarPrimitive.Image>
40
+
41
+ function AvatarImage({
42
+ className,
43
+ ...props
44
+ }: AvatarImageProps): ReactElement {
45
+ return (
46
+ <AvatarPrimitive.Image
47
+ className={cn("aspect-square size-full rounded-full", className)}
48
+ data-slot="avatar-image"
49
+ {...props}
50
+ />
51
+ )
52
+ }
53
+
54
+ export type AvatarFallbackProps = React.ComponentProps<typeof AvatarPrimitive.Fallback>
55
+
56
+ function AvatarFallback({
57
+ className,
58
+ ...props
59
+ }: AvatarFallbackProps): ReactElement {
60
+ return (
61
+ <AvatarPrimitive.Fallback
62
+ className={cn(
63
+ "flex size-full items-center justify-center rounded-full overflow-hidden bg-muted text-sm font-sans text-muted-foreground group-data-[size=sm]/avatar:text-xs",
64
+ className
65
+ )}
66
+ data-slot="avatar-fallback"
67
+ {...props}
68
+ />
69
+ )
70
+ }
71
+
72
+ export type AvatarBadgeProps = React.ComponentProps<"span">
73
+
74
+ function AvatarBadge({ className, ...props }: AvatarBadgeProps): ReactElement {
75
+ return (
76
+ <span
77
+ className={cn(
78
+ "absolute right-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground ring-2 ring-background select-none",
79
+ "group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden",
80
+ "group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2",
81
+ "group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2",
82
+ className
83
+ )}
84
+ data-slot="avatar-badge"
85
+ {...props}
86
+ />
87
+ )
88
+ }
89
+
90
+ export type AvatarGroupProps = React.ComponentProps<"div">
91
+
92
+ function AvatarGroup({ className, ...props }: AvatarGroupProps): ReactElement {
93
+ return (
94
+ <div
95
+ className={cn(
96
+ "group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-background",
97
+ className
98
+ )}
99
+ data-slot="avatar-group"
100
+ {...props}
101
+ />
102
+ )
103
+ }
104
+
105
+ export type AvatarGroupCountProps = React.ComponentProps<"div">
106
+
107
+ function AvatarGroupCount({
108
+ className,
109
+ ...props
110
+ }: AvatarGroupCountProps): ReactElement {
111
+ return (
112
+ <div
113
+ className={cn(
114
+ "relative flex size-8 shrink-0 items-center justify-center rounded-full bg-muted text-sm text-muted-foreground ring-2 ring-background group-has-data-[size=lg]/avatar-group:size-10 group-has-data-[size=sm]/avatar-group:size-6 [&>svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3",
115
+ className
116
+ )}
117
+ data-slot="avatar-group-count"
118
+ {...props}
119
+ />
120
+ )
121
+ }
122
+
123
+ export {
124
+ Avatar,
125
+ AvatarImage,
126
+ AvatarFallback,
127
+ AvatarBadge,
128
+ AvatarGroup,
129
+ AvatarGroupCount,
130
+ }
@@ -0,0 +1,57 @@
1
+ import { type ReactElement } from "react"
2
+ import * as React from "react"
3
+ import { cva, type VariantProps } from "class-variance-authority"
4
+ import { cn } from "@/lib/utils"
5
+ import { Slot } from "@/lib/slot"
6
+
7
+ /**
8
+ * Badge — shadcn/WealthX
9
+ * Base: npx shadcn\@latest add badge (latest)
10
+ * Figma: Design-System---shadcn?node-id=665-2024
11
+ *
12
+ * WealthX: added font-sans. All 6 shadcn variants preserved.
13
+ */
14
+ const badgeVariants = cva(
15
+ "inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-full border border-transparent px-2 py-0.5 text-xs font-medium font-sans whitespace-nowrap transition-[color,box-shadow] focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3",
16
+ {
17
+ variants: {
18
+ variant: {
19
+ default: "bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
20
+ secondary:
21
+ "bg-muted text-muted-foreground [a&]:hover:bg-muted/80",
22
+ destructive:
23
+ "bg-destructive text-destructive-foreground focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40 [a&]:hover:bg-destructive/90",
24
+ outline:
25
+ "border-border text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
26
+ ghost: "[a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
27
+ link: "text-primary underline-offset-4 [a&]:hover:underline",
28
+ },
29
+ },
30
+ defaultVariants: {
31
+ variant: "default",
32
+ },
33
+ }
34
+ )
35
+
36
+ export type BadgeProps = React.ComponentProps<"span"> &
37
+ VariantProps<typeof badgeVariants> & { asChild?: boolean }
38
+
39
+ function Badge({
40
+ className,
41
+ variant = "default",
42
+ asChild = false,
43
+ ...props
44
+ }: BadgeProps): ReactElement {
45
+ const Comp = asChild ? Slot : "span"
46
+
47
+ return (
48
+ <Comp
49
+ className={cn(badgeVariants({ variant }), className)}
50
+ data-slot="badge"
51
+ data-variant={variant}
52
+ {...props}
53
+ />
54
+ )
55
+ }
56
+
57
+ export { Badge, badgeVariants }
@@ -1,37 +1,47 @@
1
- import * as React from "react"
1
+ import { type ReactElement, type ComponentProps, forwardRef } from "react"
2
2
  import { cva, type VariantProps } from "class-variance-authority"
3
- import { Slot } from "radix-ui"
4
-
5
- import { cn } from "../../lib/utils"
3
+ import { Loader2 } from "lucide-react"
4
+ import { cn } from "@/lib/utils"
5
+ import { Slot } from "@/lib/slot"
6
6
 
7
+ /**
8
+ * Button — WealthX Design System
9
+ * Figma: https://www.figma.com/design/9V9F0NGVsif8LGmEhVjOcT/Design-System---shadcn?node-id=72-2719
10
+ *
11
+ * Base: official shadcn new-york button (npx shadcn\@latest add button)
12
+ * WealthX overrides: variants, square corners, font-sans, loading state
13
+ */
7
14
  const buttonVariants = cva(
8
- "group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
15
+ "inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 font-sans text-sm font-medium whitespace-nowrap transition-all active:scale-[0.98] outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
9
16
  {
10
17
  variants: {
11
18
  variant: {
12
- default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
13
- outline:
14
- "border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
19
+ default:
20
+ "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
15
21
  secondary:
16
- "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
17
- ghost:
18
- "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
22
+ "bg-brand-secondary text-brand-secondary-foreground shadow-xs hover:bg-brand-secondary/80 focus-visible:ring-brand-secondary/30",
19
23
  destructive:
20
- "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
21
- link: "text-primary underline-offset-4 hover:underline",
24
+ "bg-destructive text-destructive-foreground shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
25
+ outline:
26
+ "border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
27
+ "outline-primary":
28
+ "border border-primary text-foreground bg-transparent shadow-xs hover:bg-primary/5 focus-visible:ring-primary/50",
29
+ "outline-secondary":
30
+ "border border-brand-secondary text-brand-secondary bg-transparent shadow-xs hover:bg-brand-secondary/10 focus-visible:ring-brand-secondary/30",
31
+ ghost:
32
+ "hover:bg-accent hover:text-accent-foreground hover:shadow-xs dark:hover:bg-accent/50",
33
+ link:
34
+ "text-primary underline-offset-4 hover:underline",
22
35
  },
23
36
  size: {
24
- default:
25
- "h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
26
- xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
27
- sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
28
- lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3",
29
- icon: "size-8",
30
- "icon-xs":
31
- "size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",
32
- "icon-sm":
33
- "size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg",
34
- "icon-lg": "size-9",
37
+ default: "h-9 px-4 py-2 has-[>svg]:px-3",
38
+ xs: "h-6 gap-1 px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
39
+ sm: "h-8 gap-1.5 px-3 has-[>svg]:px-2.5",
40
+ lg: "h-10 px-6 has-[>svg]:px-4",
41
+ icon: "size-9",
42
+ "icon-xs": "size-6 [&_svg:not([class*='size-'])]:size-3",
43
+ "icon-sm": "size-8",
44
+ "icon-lg": "size-10",
35
45
  },
36
46
  },
37
47
  defaultVariants: {
@@ -41,27 +51,49 @@ const buttonVariants = cva(
41
51
  }
42
52
  )
43
53
 
44
- function Button({
45
- className,
46
- variant = "default",
47
- size = "default",
48
- asChild = false,
49
- ...props
50
- }: React.ComponentProps<"button"> &
54
+ export type ButtonProps = ComponentProps<"button"> &
51
55
  VariantProps<typeof buttonVariants> & {
52
56
  asChild?: boolean
53
- }) {
54
- const Comp = asChild ? Slot.Root : "button"
57
+ /** Shows spinner and disables the button. Icon-only sizes hide the icon. */
58
+ loading?: boolean
59
+ }
60
+
61
+ const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(
62
+ {
63
+ className,
64
+ variant,
65
+ size,
66
+ asChild = false,
67
+ loading = false,
68
+ disabled,
69
+ children,
70
+ ...props
71
+ },
72
+ ref
73
+ ): ReactElement {
74
+ const Comp = asChild ? Slot : "button"
75
+ const isIconOnly = size === "icon" || size === "icon-xs" || size === "icon-sm" || size === "icon-lg"
55
76
 
56
77
  return (
57
78
  <Comp
79
+ className={cn(buttonVariants({ variant, size, className }))}
80
+ data-size={size}
58
81
  data-slot="button"
59
82
  data-variant={variant}
60
- data-size={size}
61
- className={cn(buttonVariants({ variant, size, className }))}
83
+ disabled={loading || disabled}
84
+ ref={ref}
62
85
  {...props}
63
- />
86
+ >
87
+ {loading ? (
88
+ <>
89
+ <Loader2 aria-hidden="true" className="animate-spin" />
90
+ {!isIconOnly && children}
91
+ </>
92
+ ) : (
93
+ children
94
+ )}
95
+ </Comp>
64
96
  )
65
- }
97
+ })
66
98
 
67
99
  export { Button, buttonVariants }