create-app-ui 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 (128) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +117 -0
  3. package/boilerplate/README.md +18 -0
  4. package/boilerplate/react-base/.env.example +1 -0
  5. package/boilerplate/react-base/README.md +3 -0
  6. package/boilerplate/react-base/components.json +19 -0
  7. package/boilerplate/react-base/eslint.config.js +32 -0
  8. package/boilerplate/react-base/index.html +12 -0
  9. package/boilerplate/react-base/package.json +71 -0
  10. package/boilerplate/react-base/postcss.config.js +6 -0
  11. package/boilerplate/react-base/prettier.config.js +6 -0
  12. package/boilerplate/react-base/src/api/axios.ts +20 -0
  13. package/boilerplate/react-base/src/app/store.ts +13 -0
  14. package/boilerplate/react-base/src/components/data-table.tsx +919 -0
  15. package/boilerplate/react-base/src/components/ui/accordion.tsx +44 -0
  16. package/boilerplate/react-base/src/components/ui/alert-dialog.tsx +105 -0
  17. package/boilerplate/react-base/src/components/ui/alert.tsx +40 -0
  18. package/boilerplate/react-base/src/components/ui/avatar.tsx +30 -0
  19. package/boilerplate/react-base/src/components/ui/badge.tsx +27 -0
  20. package/boilerplate/react-base/src/components/ui/bar-chart.tsx +76 -0
  21. package/boilerplate/react-base/src/components/ui/breadcrumb.tsx +87 -0
  22. package/boilerplate/react-base/src/components/ui/button.tsx +34 -0
  23. package/boilerplate/react-base/src/components/ui/calendar.tsx +63 -0
  24. package/boilerplate/react-base/src/components/ui/card.tsx +36 -0
  25. package/boilerplate/react-base/src/components/ui/chart.tsx +280 -0
  26. package/boilerplate/react-base/src/components/ui/checkbox.tsx +51 -0
  27. package/boilerplate/react-base/src/components/ui/context-menu.tsx +173 -0
  28. package/boilerplate/react-base/src/components/ui/date-picker.tsx +42 -0
  29. package/boilerplate/react-base/src/components/ui/dialog.tsx +87 -0
  30. package/boilerplate/react-base/src/components/ui/drawer.tsx +81 -0
  31. package/boilerplate/react-base/src/components/ui/dropdown-menu.tsx +81 -0
  32. package/boilerplate/react-base/src/components/ui/dropdown-types.ts +28 -0
  33. package/boilerplate/react-base/src/components/ui/field.tsx +194 -0
  34. package/boilerplate/react-base/src/components/ui/hover-card.tsx +26 -0
  35. package/boilerplate/react-base/src/components/ui/input-group.tsx +98 -0
  36. package/boilerplate/react-base/src/components/ui/input-otp.tsx +63 -0
  37. package/boilerplate/react-base/src/components/ui/input.tsx +12 -0
  38. package/boilerplate/react-base/src/components/ui/item.tsx +152 -0
  39. package/boilerplate/react-base/src/components/ui/kbd.tsx +13 -0
  40. package/boilerplate/react-base/src/components/ui/label.tsx +14 -0
  41. package/boilerplate/react-base/src/components/ui/line-chart.tsx +65 -0
  42. package/boilerplate/react-base/src/components/ui/menubar.tsx +217 -0
  43. package/boilerplate/react-base/src/components/ui/multi-select-dropdown.tsx +200 -0
  44. package/boilerplate/react-base/src/components/ui/navigation-menu.tsx +120 -0
  45. package/boilerplate/react-base/src/components/ui/pie-chart.tsx +87 -0
  46. package/boilerplate/react-base/src/components/ui/popover.tsx +29 -0
  47. package/boilerplate/react-base/src/components/ui/progress.tsx +19 -0
  48. package/boilerplate/react-base/src/components/ui/radio-group.tsx +36 -0
  49. package/boilerplate/react-base/src/components/ui/scroll-area.tsx +38 -0
  50. package/boilerplate/react-base/src/components/ui/searchable-dropdown.tsx +118 -0
  51. package/boilerplate/react-base/src/components/ui/select.tsx +140 -0
  52. package/boilerplate/react-base/src/components/ui/separator.tsx +20 -0
  53. package/boilerplate/react-base/src/components/ui/sheet.tsx +70 -0
  54. package/boilerplate/react-base/src/components/ui/sidebar.tsx +470 -0
  55. package/boilerplate/react-base/src/components/ui/skeleton.tsx +11 -0
  56. package/boilerplate/react-base/src/components/ui/slider.tsx +23 -0
  57. package/boilerplate/react-base/src/components/ui/sonner.tsx +21 -0
  58. package/boilerplate/react-base/src/components/ui/sparkline.tsx +38 -0
  59. package/boilerplate/react-base/src/components/ui/spinner.tsx +10 -0
  60. package/boilerplate/react-base/src/components/ui/switch.tsx +16 -0
  61. package/boilerplate/react-base/src/components/ui/table.tsx +80 -0
  62. package/boilerplate/react-base/src/components/ui/tabs.tsx +32 -0
  63. package/boilerplate/react-base/src/components/ui/textarea.tsx +12 -0
  64. package/boilerplate/react-base/src/components/ui/toggle-group.tsx +49 -0
  65. package/boilerplate/react-base/src/components/ui/toggle.tsx +33 -0
  66. package/boilerplate/react-base/src/components/ui/tooltip.tsx +23 -0
  67. package/boilerplate/react-base/src/components/ui/typography.tsx +76 -0
  68. package/boilerplate/react-base/src/config/constants.ts +3 -0
  69. package/boilerplate/react-base/src/config/theme.ts +432 -0
  70. package/boilerplate/react-base/src/config/user.ts +52 -0
  71. package/boilerplate/react-base/src/context/theme-provider.tsx +12 -0
  72. package/boilerplate/react-base/src/features/auth/authSlice.ts +19 -0
  73. package/boilerplate/react-base/src/hooks/index.ts +1 -0
  74. package/boilerplate/react-base/src/hooks/use-mobile.ts +17 -0
  75. package/boilerplate/react-base/src/lib/utils.ts +6 -0
  76. package/boilerplate/react-base/src/routes/index.tsx +7 -0
  77. package/boilerplate/react-base/src/styles/globals.css +15 -0
  78. package/boilerplate/react-base/src/vite-env.d.ts +31 -0
  79. package/boilerplate/react-base/tailwind.config.ts +75 -0
  80. package/boilerplate/react-base/tsconfig.app.json +20 -0
  81. package/boilerplate/react-base/tsconfig.json +7 -0
  82. package/boilerplate/react-base/tsconfig.node.json +16 -0
  83. package/boilerplate/react-base/vite.config.ts +12 -0
  84. package/dist/bin/index.js +8 -0
  85. package/dist/src/cli-args.js +52 -0
  86. package/dist/src/generator.js +85 -0
  87. package/dist/src/installer.js +7 -0
  88. package/dist/src/paths.js +61 -0
  89. package/dist/src/prompts.js +79 -0
  90. package/dist/src/replace-placeholders.js +22 -0
  91. package/dist/src/utils.js +16 -0
  92. package/package.json +63 -0
  93. package/templates/admin-portal/README.md +26 -0
  94. package/templates/admin-portal/src/App.tsx +85 -0
  95. package/templates/admin-portal/src/assets/auth-hero.jpg +0 -0
  96. package/templates/admin-portal/src/assets/brand-logo.png +0 -0
  97. package/templates/admin-portal/src/components/app-breadcrumb.tsx +41 -0
  98. package/templates/admin-portal/src/components/app-header.tsx +20 -0
  99. package/templates/admin-portal/src/components/app-sidebar.tsx +78 -0
  100. package/templates/admin-portal/src/components/auth-layout.tsx +66 -0
  101. package/templates/admin-portal/src/components/dashboard-metric-card.tsx +105 -0
  102. package/templates/admin-portal/src/components/data-table.tsx +919 -0
  103. package/templates/admin-portal/src/components/layout-shell.tsx +23 -0
  104. package/templates/admin-portal/src/components/notifications-sheet.tsx +91 -0
  105. package/templates/admin-portal/src/components/sidebar-nav.tsx +164 -0
  106. package/templates/admin-portal/src/components/user-avatar.tsx +26 -0
  107. package/templates/admin-portal/src/components/user-menu.tsx +163 -0
  108. package/templates/admin-portal/src/config/branding.ts +17 -0
  109. package/templates/admin-portal/src/config/chart-data.ts +44 -0
  110. package/templates/admin-portal/src/config/navigation.ts +42 -0
  111. package/templates/admin-portal/src/context/auth-context.tsx +32 -0
  112. package/templates/admin-portal/src/lib/breadcrumbs.ts +58 -0
  113. package/templates/admin-portal/src/main.tsx +18 -0
  114. package/templates/admin-portal/src/pages/components/demo-columns.tsx +170 -0
  115. package/templates/admin-portal/src/pages/components.tsx +1368 -0
  116. package/templates/admin-portal/src/pages/dashboard.tsx +143 -0
  117. package/templates/admin-portal/src/pages/login.tsx +81 -0
  118. package/templates/admin-portal/src/pages/settings/notifications.tsx +31 -0
  119. package/templates/admin-portal/src/pages/settings/profile.tsx +26 -0
  120. package/templates/admin-portal/src/pages/signup.tsx +81 -0
  121. package/templates/admin-portal/src/pages/users.tsx +12 -0
  122. package/templates/admin-portal/tsconfig.json +10 -0
  123. package/templates/blank/README.md +15 -0
  124. package/templates/blank/src/App.tsx +5 -0
  125. package/templates/blank/src/main.tsx +15 -0
  126. package/templates/blank/src/pages/home.tsx +20 -0
  127. package/templates/blank/tsconfig.json +10 -0
  128. package/templates/tsconfig.overlay.base.json +7 -0
@@ -0,0 +1,81 @@
1
+ import * as React from "react";
2
+ import { Drawer as DrawerPrimitive } from "vaul";
3
+ import { ui } from "@/config/theme";
4
+ import { cn } from "@/lib/utils";
5
+
6
+ const Drawer = ({ shouldScaleBackground = true, ...props }: React.ComponentProps<typeof DrawerPrimitive.Root>) => (
7
+ <DrawerPrimitive.Root shouldScaleBackground={shouldScaleBackground} {...props} />
8
+ );
9
+ Drawer.displayName = "Drawer";
10
+
11
+ const DrawerTrigger = DrawerPrimitive.Trigger;
12
+ const DrawerPortal = DrawerPrimitive.Portal;
13
+ const DrawerClose = DrawerPrimitive.Close;
14
+
15
+ const DrawerOverlay = React.forwardRef<
16
+ React.ElementRef<typeof DrawerPrimitive.Overlay>,
17
+ React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay>
18
+ >(({ className, ...props }, ref) => (
19
+ <DrawerPrimitive.Overlay ref={ref} className={cn(ui("overlay"), className)} {...props} />
20
+ ));
21
+ DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName;
22
+
23
+ const DrawerContent = React.forwardRef<
24
+ React.ElementRef<typeof DrawerPrimitive.Content>,
25
+ React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>
26
+ >(({ className, children, ...props }, ref) => (
27
+ <DrawerPortal>
28
+ <DrawerOverlay />
29
+ <DrawerPrimitive.Content
30
+ ref={ref}
31
+ className={cn(
32
+ ui("drawerContent"),
33
+ className,
34
+ )}
35
+ {...props}
36
+ >
37
+ <div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
38
+ {children}
39
+ </DrawerPrimitive.Content>
40
+ </DrawerPortal>
41
+ ));
42
+ DrawerContent.displayName = "DrawerContent";
43
+
44
+ function DrawerHeader({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
45
+ return <div className={cn("grid gap-1.5 p-4 text-center sm:text-left", className)} {...props} />;
46
+ }
47
+ DrawerHeader.displayName = "DrawerHeader";
48
+
49
+ function DrawerFooter({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
50
+ return <div className={cn("mt-auto flex flex-col gap-2 p-4", className)} {...props} />;
51
+ }
52
+ DrawerFooter.displayName = "DrawerFooter";
53
+
54
+ const DrawerTitle = React.forwardRef<
55
+ React.ElementRef<typeof DrawerPrimitive.Title>,
56
+ React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>
57
+ >(({ className, ...props }, ref) => (
58
+ <DrawerPrimitive.Title ref={ref} className={cn("text-lg font-semibold leading-none tracking-tight", className)} {...props} />
59
+ ));
60
+ DrawerTitle.displayName = DrawerPrimitive.Title.displayName;
61
+
62
+ const DrawerDescription = React.forwardRef<
63
+ React.ElementRef<typeof DrawerPrimitive.Description>,
64
+ React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description>
65
+ >(({ className, ...props }, ref) => (
66
+ <DrawerPrimitive.Description ref={ref} className={cn(ui("typographyMuted"), className)} {...props} />
67
+ ));
68
+ DrawerDescription.displayName = DrawerPrimitive.Description.displayName;
69
+
70
+ export {
71
+ Drawer,
72
+ DrawerClose,
73
+ DrawerContent,
74
+ DrawerDescription,
75
+ DrawerFooter,
76
+ DrawerHeader,
77
+ DrawerOverlay,
78
+ DrawerPortal,
79
+ DrawerTitle,
80
+ DrawerTrigger,
81
+ };
@@ -0,0 +1,81 @@
1
+ import * as React from "react";
2
+ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
3
+ import { Check } from "lucide-react";
4
+ import { ui } from "@/config/theme";
5
+ import { cn } from "@/lib/utils";
6
+
7
+ export const DropdownMenu = DropdownMenuPrimitive.Root;
8
+ export const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
9
+
10
+ export const DropdownMenuContent = React.forwardRef<
11
+ React.ElementRef<typeof DropdownMenuPrimitive.Content>,
12
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
13
+ >(({ className, sideOffset = 4, ...props }, ref) => (
14
+ <DropdownMenuPrimitive.Portal>
15
+ <DropdownMenuPrimitive.Content
16
+ ref={ref}
17
+ sideOffset={sideOffset}
18
+ className={cn(ui("dropdownContent"), className)}
19
+ {...props}
20
+ />
21
+ </DropdownMenuPrimitive.Portal>
22
+ ));
23
+ DropdownMenuContent.displayName = "DropdownMenuContent";
24
+
25
+ export const DropdownMenuItem = React.forwardRef<
26
+ React.ElementRef<typeof DropdownMenuPrimitive.Item>,
27
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item>
28
+ >(({ className, ...props }, ref) => (
29
+ <DropdownMenuPrimitive.Item
30
+ ref={ref}
31
+ className={cn(
32
+ "relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
33
+ className,
34
+ )}
35
+ {...props}
36
+ />
37
+ ));
38
+ DropdownMenuItem.displayName = "DropdownMenuItem";
39
+
40
+ export const DropdownMenuCheckboxItem = React.forwardRef<
41
+ React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
42
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
43
+ >(({ className, children, checked, ...props }, ref) => (
44
+ <DropdownMenuPrimitive.CheckboxItem
45
+ ref={ref}
46
+ className={cn(
47
+ "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
48
+ className,
49
+ )}
50
+ checked={checked}
51
+ {...props}
52
+ >
53
+ <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
54
+ <DropdownMenuPrimitive.ItemIndicator>
55
+ <Check className="h-4 w-4" />
56
+ </DropdownMenuPrimitive.ItemIndicator>
57
+ </span>
58
+ {children}
59
+ </DropdownMenuPrimitive.CheckboxItem>
60
+ ));
61
+ DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
62
+
63
+ export const DropdownMenuLabel = React.forwardRef<
64
+ React.ElementRef<typeof DropdownMenuPrimitive.Label>,
65
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & { inset?: boolean }
66
+ >(({ className, inset, ...props }, ref) => (
67
+ <DropdownMenuPrimitive.Label
68
+ ref={ref}
69
+ className={cn("px-2 py-1.5 text-sm font-semibold", inset && "pl-8", className)}
70
+ {...props}
71
+ />
72
+ ));
73
+ DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
74
+
75
+ export const DropdownMenuSeparator = React.forwardRef<
76
+ React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
77
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
78
+ >(({ className, ...props }, ref) => (
79
+ <DropdownMenuPrimitive.Separator ref={ref} className={cn("-mx-1 my-1 h-px bg-muted", className)} {...props} />
80
+ ));
81
+ DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
@@ -0,0 +1,28 @@
1
+ import { ui } from "@/config/theme";
2
+
3
+ export type DropdownOption = {
4
+ value: string;
5
+ label: string;
6
+ description?: string;
7
+ disabled?: boolean;
8
+ };
9
+
10
+ /** Theme-backed class tokens for searchable & multi-select dropdowns */
11
+ export const dropdownClasses = {
12
+ trigger: ui("dropdownTrigger"),
13
+ triggerMulti: ui("dropdownTriggerMulti"),
14
+ popoverContent: ui("dropdownPopoverContent"),
15
+ searchBar: ui("dropdownSearchBar"),
16
+ searchInput: ui("dropdownSearchInput"),
17
+ searchIcon: ui("dropdownSearchIcon"),
18
+ empty: ui("dropdownEmpty"),
19
+ emptyText: ui("typographyMuted"),
20
+ optionItem: ui("dropdownOptionItem"),
21
+ optionItemActive: ui("dropdownOptionItemActive"),
22
+ optionItemMulti: ui("dropdownOptionItemMulti"),
23
+ optionItemMultiSelected: ui("dropdownOptionItemMultiSelected"),
24
+ optionDescription: ui("typographyMuted"),
25
+ footer: ui("dropdownFooter"),
26
+ checkIcon: ui("dropdownCheckIcon"),
27
+ chevron: ui("dropdownChevron"),
28
+ } as const;
@@ -0,0 +1,194 @@
1
+ import * as React from "react";
2
+ import { Label } from "@/components/ui/label";
3
+ import { Separator } from "@/components/ui/separator";
4
+ import { ui } from "@/config/theme";
5
+ import { cn } from "@/lib/utils";
6
+
7
+ function FieldSet({ className, ...props }: React.ComponentProps<"fieldset">) {
8
+ return (
9
+ <fieldset
10
+ data-slot="field-set"
11
+ className={cn("flex flex-col gap-6", "has-[>[data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3", className)}
12
+ {...props}
13
+ />
14
+ );
15
+ }
16
+
17
+ function FieldLegend({
18
+ className,
19
+ variant = "legend",
20
+ ...props
21
+ }: React.ComponentProps<"legend"> & { variant?: "legend" | "label" }) {
22
+ return (
23
+ <legend
24
+ data-slot="field-legend"
25
+ data-variant={variant}
26
+ className={cn("mb-3 font-medium", variant === "legend" ? "text-base" : "text-sm", className)}
27
+ {...props}
28
+ />
29
+ );
30
+ }
31
+
32
+ function FieldGroup({ className, ...props }: React.ComponentProps<"div">) {
33
+ return (
34
+ <div
35
+ data-slot="field-group"
36
+ className={cn("flex w-full flex-col gap-7 [&>[data-slot=field-group]]:gap-4", className)}
37
+ {...props}
38
+ />
39
+ );
40
+ }
41
+
42
+ function Field({
43
+ className,
44
+ orientation = "vertical",
45
+ ...props
46
+ }: React.ComponentProps<"div"> & {
47
+ orientation?: "vertical" | "horizontal" | "responsive";
48
+ }) {
49
+ return (
50
+ <div
51
+ role="group"
52
+ data-slot="field"
53
+ data-orientation={orientation}
54
+ className={cn(
55
+ "group/field flex w-full gap-3 data-[invalid=true]:text-destructive",
56
+ orientation === "vertical" && "flex-col [&>*]:w-full",
57
+ orientation === "horizontal" && "flex-row items-center [&>[data-slot=field-label]]:min-w-32",
58
+ orientation === "responsive" && "flex-col md:flex-row md:items-center [&>*]:w-full md:[&>*]:w-auto",
59
+ className,
60
+ )}
61
+ {...props}
62
+ />
63
+ );
64
+ }
65
+
66
+ function FieldContent({ className, ...props }: React.ComponentProps<"div">) {
67
+ return (
68
+ <div data-slot="field-content" className={cn("group/field-content flex flex-1 flex-col gap-1.5", className)} {...props} />
69
+ );
70
+ }
71
+
72
+ function FieldLabel({ className, ...props }: React.ComponentProps<typeof Label>) {
73
+ return (
74
+ <Label
75
+ data-slot="field-label"
76
+ className={cn(
77
+ "group/field-label peer/field-label flex w-fit gap-2 leading-snug group-data-[disabled=true]/field:opacity-50",
78
+ className,
79
+ )}
80
+ {...props}
81
+ />
82
+ );
83
+ }
84
+
85
+ function FieldTitle({ className, ...props }: React.ComponentProps<"div">) {
86
+ return (
87
+ <div
88
+ data-slot="field-label"
89
+ className={cn(
90
+ "flex w-fit items-center gap-2 text-sm font-medium leading-snug group-data-[disabled=true]/field:opacity-50",
91
+ className,
92
+ )}
93
+ {...props}
94
+ />
95
+ );
96
+ }
97
+
98
+ function FieldDescription({ className, ...props }: React.ComponentProps<"p">) {
99
+ return (
100
+ <p
101
+ data-slot="field-description"
102
+ className={cn(
103
+ ui("fieldDescription"),
104
+ "[&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary",
105
+ className,
106
+ )}
107
+ {...props}
108
+ />
109
+ );
110
+ }
111
+
112
+ function FieldSeparator({
113
+ children,
114
+ className,
115
+ ...props
116
+ }: React.ComponentProps<"div"> & {
117
+ children?: React.ReactNode;
118
+ }) {
119
+ return (
120
+ <div
121
+ data-slot="field-separator"
122
+ data-content={!!children}
123
+ className={cn("relative -my-2 h-5 text-sm", className)}
124
+ {...props}
125
+ >
126
+ <Separator className="absolute inset-0 top-1/2" />
127
+ {children && (
128
+ <span
129
+ className={cn("relative mx-auto block w-fit bg-background px-2", ui("typographyMuted"))}
130
+ data-slot="field-separator-content"
131
+ >
132
+ {children}
133
+ </span>
134
+ )}
135
+ </div>
136
+ );
137
+ }
138
+
139
+ function FieldError({
140
+ className,
141
+ children,
142
+ errors,
143
+ ...props
144
+ }: React.ComponentProps<"div"> & {
145
+ errors?: Array<{ message?: string } | undefined>;
146
+ }) {
147
+ const content = React.useMemo(() => {
148
+ if (children) {
149
+ return children;
150
+ }
151
+
152
+ if (!errors?.length) {
153
+ return null;
154
+ }
155
+
156
+ if (errors.length === 1 && errors[0]?.message) {
157
+ return errors[0].message;
158
+ }
159
+
160
+ return (
161
+ <ul className="ml-4 flex list-disc flex-col gap-1">
162
+ {errors.map((error, index) => (error?.message ? <li key={index}>{error.message}</li> : null))}
163
+ </ul>
164
+ );
165
+ }, [children, errors]);
166
+
167
+ if (!content) {
168
+ return null;
169
+ }
170
+
171
+ return (
172
+ <div
173
+ role="alert"
174
+ data-slot="field-error"
175
+ className={cn("text-sm font-normal text-destructive", className)}
176
+ {...props}
177
+ >
178
+ {content}
179
+ </div>
180
+ );
181
+ }
182
+
183
+ export {
184
+ Field,
185
+ FieldContent,
186
+ FieldDescription,
187
+ FieldError,
188
+ FieldGroup,
189
+ FieldLabel,
190
+ FieldLegend,
191
+ FieldSeparator,
192
+ FieldSet,
193
+ FieldTitle,
194
+ };
@@ -0,0 +1,26 @@
1
+ import * as React from "react";
2
+ import * as HoverCardPrimitive from "@radix-ui/react-hover-card";
3
+ import { ui } from "@/config/theme";
4
+ import { cn } from "@/lib/utils";
5
+
6
+ const HoverCard = HoverCardPrimitive.Root;
7
+ const HoverCardTrigger = HoverCardPrimitive.Trigger;
8
+
9
+ const HoverCardContent = React.forwardRef<
10
+ React.ElementRef<typeof HoverCardPrimitive.Content>,
11
+ React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Content>
12
+ >(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
13
+ <HoverCardPrimitive.Content
14
+ ref={ref}
15
+ align={align}
16
+ sideOffset={sideOffset}
17
+ className={cn(
18
+ ui("popoverHover"),
19
+ className,
20
+ )}
21
+ {...props}
22
+ />
23
+ ));
24
+ HoverCardContent.displayName = HoverCardPrimitive.Content.displayName;
25
+
26
+ export { HoverCard, HoverCardContent, HoverCardTrigger };
@@ -0,0 +1,98 @@
1
+ import { cva, type VariantProps } from "class-variance-authority";
2
+ import * as React from "react";
3
+ import { Button } from "@/components/ui/button";
4
+ import { Input } from "@/components/ui/input";
5
+ import { ui } from "@/config/theme";
6
+ import { cn } from "@/lib/utils";
7
+
8
+ function InputGroup({ className, ...props }: React.ComponentProps<"div">) {
9
+ return (
10
+ <div
11
+ data-slot="input-group"
12
+ className={cn(ui("inputGroup"), className)}
13
+ {...props}
14
+ />
15
+ );
16
+ }
17
+
18
+ const inputGroupAddonVariants = cva(
19
+ "flex shrink-0 items-center justify-center text-sm text-muted-foreground [&>svg]:size-4",
20
+ {
21
+ variants: {
22
+ align: {
23
+ "inline-start": "order-first pl-3 has-[~[data-slot=input-group-control]]:pr-0",
24
+ "inline-end": "order-last pr-3 has-[~[data-slot=input-group-control]]:pl-0",
25
+ "block-start": "order-first w-full justify-start border-b px-3 py-2",
26
+ "block-end": "order-last w-full justify-start border-t px-3 py-2",
27
+ },
28
+ },
29
+ defaultVariants: {
30
+ align: "inline-start",
31
+ },
32
+ },
33
+ );
34
+
35
+ function InputGroupAddon({
36
+ className,
37
+ align = "inline-start",
38
+ ...props
39
+ }: React.ComponentProps<"div"> & VariantProps<typeof inputGroupAddonVariants>) {
40
+ return (
41
+ <div
42
+ role="group"
43
+ data-slot="input-group-addon"
44
+ data-align={align}
45
+ className={cn(inputGroupAddonVariants({ align }), className)}
46
+ {...props}
47
+ />
48
+ );
49
+ }
50
+
51
+ function InputGroupButton({
52
+ className,
53
+ type = "button",
54
+ variant = "outline",
55
+ size = "sm",
56
+ ...props
57
+ }: React.ComponentProps<typeof Button>) {
58
+ return (
59
+ <Button
60
+ type={type}
61
+ data-size={size}
62
+ variant={variant}
63
+ size={size}
64
+ className={cn(
65
+ "h-8 shrink-0 rounded-none border-0 bg-transparent shadow-none hover:bg-accent",
66
+ className,
67
+ )}
68
+ {...props}
69
+ />
70
+ );
71
+ }
72
+
73
+ function InputGroupText({ className, ...props }: React.ComponentProps<"span">) {
74
+ return (
75
+ <span
76
+ data-slot="input-group-text"
77
+ className={cn("flex items-center gap-2 text-sm text-muted-foreground [&_svg]:size-4", className)}
78
+ {...props}
79
+ />
80
+ );
81
+ }
82
+
83
+ const InputGroupInput = React.forwardRef<HTMLInputElement, React.ComponentProps<typeof Input>>(
84
+ ({ className, ...props }, ref) => (
85
+ <Input
86
+ ref={ref}
87
+ data-slot="input-group-control"
88
+ className={cn(
89
+ "flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 focus-visible:ring-offset-0",
90
+ className,
91
+ )}
92
+ {...props}
93
+ />
94
+ ),
95
+ );
96
+ InputGroupInput.displayName = "InputGroupInput";
97
+
98
+ export { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText };
@@ -0,0 +1,63 @@
1
+ import { Minus } from "lucide-react";
2
+ import { OTPInput, OTPInputContext } from "input-otp";
3
+ import * as React from "react";
4
+ import { ui } from "@/config/theme";
5
+ import { cn } from "@/lib/utils";
6
+
7
+ const InputOTP = React.forwardRef<
8
+ React.ElementRef<typeof OTPInput>,
9
+ React.ComponentPropsWithoutRef<typeof OTPInput> & {
10
+ containerClassName?: string;
11
+ }
12
+ >(({ className, containerClassName, ...props }, ref) => (
13
+ <OTPInput
14
+ ref={ref}
15
+ containerClassName={cn("flex items-center gap-2 has-[:disabled]:opacity-50", containerClassName)}
16
+ className={cn("disabled:cursor-not-allowed", className)}
17
+ {...props}
18
+ />
19
+ ));
20
+ InputOTP.displayName = "InputOTP";
21
+
22
+ const InputOTPGroup = React.forwardRef<HTMLDivElement, React.ComponentProps<"div">>(
23
+ ({ className, ...props }, ref) => <div ref={ref} className={cn("flex items-center", className)} {...props} />,
24
+ );
25
+ InputOTPGroup.displayName = "InputOTPGroup";
26
+
27
+ const InputOTPSlot = React.forwardRef<HTMLDivElement, React.ComponentProps<"div"> & { index: number }>(
28
+ ({ index, className, ...props }, ref) => {
29
+ const inputOTPContext = React.useContext(OTPInputContext);
30
+ const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index];
31
+
32
+ return (
33
+ <div
34
+ ref={ref}
35
+ className={cn(
36
+ ui("inputOtpSlot"),
37
+ isActive && "z-10 ring-1 ring-ring",
38
+ className,
39
+ )}
40
+ {...props}
41
+ >
42
+ {char}
43
+ {hasFakeCaret && (
44
+ <div className="pointer-events-none absolute inset-0 flex items-center justify-center">
45
+ <div className="h-4 w-px animate-caret-blink bg-foreground duration-1000" />
46
+ </div>
47
+ )}
48
+ </div>
49
+ );
50
+ },
51
+ );
52
+ InputOTPSlot.displayName = "InputOTPSlot";
53
+
54
+ const InputOTPSeparator = React.forwardRef<HTMLDivElement, React.ComponentProps<"div">>(
55
+ ({ ...props }, ref) => (
56
+ <div ref={ref} role="separator" {...props}>
57
+ <Minus />
58
+ </div>
59
+ ),
60
+ );
61
+ InputOTPSeparator.displayName = "InputOTPSeparator";
62
+
63
+ export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator };
@@ -0,0 +1,12 @@
1
+ import * as React from "react";
2
+ import { ui } from "@/config/theme";
3
+ import { cn } from "@/lib/utils";
4
+
5
+ const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
6
+ ({ className, type, ...props }, ref) => {
7
+ return <input type={type} className={cn(ui("input"), className)} ref={ref} {...props} />;
8
+ },
9
+ );
10
+ Input.displayName = "Input";
11
+
12
+ export { Input };