create-z3 0.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.
Files changed (65) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.js +50 -0
  3. package/package.json +54 -0
  4. package/templates/tanstack-start/.env.example +45 -0
  5. package/templates/tanstack-start/.prettierignore +18 -0
  6. package/templates/tanstack-start/README.md +221 -0
  7. package/templates/tanstack-start/components.json +24 -0
  8. package/templates/tanstack-start/convex/_generated/api.d.ts +65 -0
  9. package/templates/tanstack-start/convex/_generated/api.js +23 -0
  10. package/templates/tanstack-start/convex/_generated/dataModel.d.ts +60 -0
  11. package/templates/tanstack-start/convex/_generated/server.d.ts +143 -0
  12. package/templates/tanstack-start/convex/_generated/server.js +93 -0
  13. package/templates/tanstack-start/convex/auth/adapter/index.ts +222 -0
  14. package/templates/tanstack-start/convex/auth/adapter/utils.ts +597 -0
  15. package/templates/tanstack-start/convex/auth/api.ts +8 -0
  16. package/templates/tanstack-start/convex/auth/config.ts +8 -0
  17. package/templates/tanstack-start/convex/auth/db.ts +299 -0
  18. package/templates/tanstack-start/convex/auth/index.ts +62 -0
  19. package/templates/tanstack-start/convex/auth/plugins/index.ts +7 -0
  20. package/templates/tanstack-start/convex/auth/sessions.ts +60 -0
  21. package/templates/tanstack-start/convex/http.ts +44 -0
  22. package/templates/tanstack-start/convex/schema.ts +69 -0
  23. package/templates/tanstack-start/eslint.config.js +77 -0
  24. package/templates/tanstack-start/package.json +74 -0
  25. package/templates/tanstack-start/prettier.config.js +35 -0
  26. package/templates/tanstack-start/public/favicon.ico +0 -0
  27. package/templates/tanstack-start/public/logo192.png +0 -0
  28. package/templates/tanstack-start/public/logo512.png +0 -0
  29. package/templates/tanstack-start/public/manifest.json +25 -0
  30. package/templates/tanstack-start/public/robots.txt +3 -0
  31. package/templates/tanstack-start/public/tanstack-circle-logo.png +0 -0
  32. package/templates/tanstack-start/public/tanstack-word-logo-white.svg +1 -0
  33. package/templates/tanstack-start/src/components/component-example.tsx +470 -0
  34. package/templates/tanstack-start/src/components/example.tsx +52 -0
  35. package/templates/tanstack-start/src/components/ui/alert-dialog.tsx +160 -0
  36. package/templates/tanstack-start/src/components/ui/badge.tsx +49 -0
  37. package/templates/tanstack-start/src/components/ui/button.tsx +58 -0
  38. package/templates/tanstack-start/src/components/ui/card.tsx +92 -0
  39. package/templates/tanstack-start/src/components/ui/combobox.tsx +271 -0
  40. package/templates/tanstack-start/src/components/ui/dropdown-menu.tsx +244 -0
  41. package/templates/tanstack-start/src/components/ui/field.tsx +222 -0
  42. package/templates/tanstack-start/src/components/ui/input-group.tsx +146 -0
  43. package/templates/tanstack-start/src/components/ui/input.tsx +20 -0
  44. package/templates/tanstack-start/src/components/ui/label.tsx +20 -0
  45. package/templates/tanstack-start/src/components/ui/select.tsx +189 -0
  46. package/templates/tanstack-start/src/components/ui/separator.tsx +19 -0
  47. package/templates/tanstack-start/src/components/ui/textarea.tsx +18 -0
  48. package/templates/tanstack-start/src/db/constants/auth.ts +41 -0
  49. package/templates/tanstack-start/src/db/constants/index.ts +8 -0
  50. package/templates/tanstack-start/src/env.ts +94 -0
  51. package/templates/tanstack-start/src/lib/auth/client.ts +18 -0
  52. package/templates/tanstack-start/src/lib/auth/server.ts +14 -0
  53. package/templates/tanstack-start/src/lib/utils.ts +6 -0
  54. package/templates/tanstack-start/src/logo.svg +12 -0
  55. package/templates/tanstack-start/src/providers.tsx +38 -0
  56. package/templates/tanstack-start/src/routeTree.gen.ts +127 -0
  57. package/templates/tanstack-start/src/router.tsx +41 -0
  58. package/templates/tanstack-start/src/routes/__root.tsx +92 -0
  59. package/templates/tanstack-start/src/routes/account/$accountView.tsx +15 -0
  60. package/templates/tanstack-start/src/routes/api/auth/$.tsx +11 -0
  61. package/templates/tanstack-start/src/routes/auth/$authView.tsx +15 -0
  62. package/templates/tanstack-start/src/routes/index.tsx +9 -0
  63. package/templates/tanstack-start/src/styles.css +156 -0
  64. package/templates/tanstack-start/tsconfig.json +42 -0
  65. package/templates/tanstack-start/vite.config.ts +32 -0
@@ -0,0 +1,244 @@
1
+ import * as React from 'react'
2
+ import { Menu as MenuPrimitive } from '@base-ui/react/menu'
3
+ import { CheckIcon, ChevronRightIcon } from 'lucide-react'
4
+
5
+ import { cn } from '~/lib/utils'
6
+
7
+ function DropdownMenu({ ...props }: MenuPrimitive.Root.Props) {
8
+ return <MenuPrimitive.Root data-slot="dropdown-menu" {...props} />
9
+ }
10
+
11
+ function DropdownMenuPortal({ ...props }: MenuPrimitive.Portal.Props) {
12
+ return <MenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
13
+ }
14
+
15
+ function DropdownMenuTrigger({ ...props }: MenuPrimitive.Trigger.Props) {
16
+ return <MenuPrimitive.Trigger data-slot="dropdown-menu-trigger" {...props} />
17
+ }
18
+
19
+ function DropdownMenuContent({
20
+ align = 'start',
21
+ alignOffset = 0,
22
+ side = 'bottom',
23
+ sideOffset = 4,
24
+ className,
25
+ ...props
26
+ }: MenuPrimitive.Popup.Props &
27
+ Pick<MenuPrimitive.Positioner.Props, 'align' | 'alignOffset' | 'side' | 'sideOffset'>) {
28
+ return (
29
+ <MenuPrimitive.Portal>
30
+ <MenuPrimitive.Positioner
31
+ className="isolate z-50 outline-none"
32
+ align={align}
33
+ alignOffset={alignOffset}
34
+ side={side}
35
+ sideOffset={sideOffset}
36
+ >
37
+ <MenuPrimitive.Popup
38
+ data-slot="dropdown-menu-content"
39
+ className={cn(
40
+ 'data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 bg-popover text-popover-foreground z-50 max-h-(--available-height) w-(--anchor-width) min-w-32 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-md p-1 shadow-md ring-1 duration-100 outline-none data-closed:overflow-hidden',
41
+ className,
42
+ )}
43
+ {...props}
44
+ />
45
+ </MenuPrimitive.Positioner>
46
+ </MenuPrimitive.Portal>
47
+ )
48
+ }
49
+
50
+ function DropdownMenuGroup({ ...props }: MenuPrimitive.Group.Props) {
51
+ return <MenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
52
+ }
53
+
54
+ function DropdownMenuLabel({
55
+ className,
56
+ inset,
57
+ ...props
58
+ }: MenuPrimitive.GroupLabel.Props & {
59
+ inset?: boolean
60
+ }) {
61
+ return (
62
+ <MenuPrimitive.GroupLabel
63
+ data-slot="dropdown-menu-label"
64
+ data-inset={inset}
65
+ className={cn(
66
+ 'text-muted-foreground px-2 py-1.5 text-xs font-medium data-[inset]:pl-8',
67
+ className,
68
+ )}
69
+ {...props}
70
+ />
71
+ )
72
+ }
73
+
74
+ function DropdownMenuItem({
75
+ className,
76
+ inset,
77
+ variant = 'default',
78
+ ...props
79
+ }: MenuPrimitive.Item.Props & {
80
+ inset?: boolean
81
+ variant?: 'default' | 'destructive'
82
+ }) {
83
+ return (
84
+ <MenuPrimitive.Item
85
+ data-slot="dropdown-menu-item"
86
+ data-inset={inset}
87
+ data-variant={variant}
88
+ className={cn(
89
+ "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:text-destructive not-data-[variant=destructive]:focus:**:text-accent-foreground group/dropdown-menu-item relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
90
+ className,
91
+ )}
92
+ {...props}
93
+ />
94
+ )
95
+ }
96
+
97
+ function DropdownMenuSub({ ...props }: MenuPrimitive.SubmenuRoot.Props) {
98
+ return <MenuPrimitive.SubmenuRoot data-slot="dropdown-menu-sub" {...props} />
99
+ }
100
+
101
+ function DropdownMenuSubTrigger({
102
+ className,
103
+ inset,
104
+ children,
105
+ ...props
106
+ }: MenuPrimitive.SubmenuTrigger.Props & {
107
+ inset?: boolean
108
+ }) {
109
+ return (
110
+ <MenuPrimitive.SubmenuTrigger
111
+ data-slot="dropdown-menu-sub-trigger"
112
+ data-inset={inset}
113
+ className={cn(
114
+ "focus:bg-accent focus:text-accent-foreground data-open:bg-accent data-open:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
115
+ className,
116
+ )}
117
+ {...props}
118
+ >
119
+ {children}
120
+ <ChevronRightIcon className="ml-auto" />
121
+ </MenuPrimitive.SubmenuTrigger>
122
+ )
123
+ }
124
+
125
+ function DropdownMenuSubContent({
126
+ align = 'start',
127
+ alignOffset = -3,
128
+ side = 'right',
129
+ sideOffset = 0,
130
+ className,
131
+ ...props
132
+ }: React.ComponentProps<typeof DropdownMenuContent>) {
133
+ return (
134
+ <DropdownMenuContent
135
+ data-slot="dropdown-menu-sub-content"
136
+ className={cn(
137
+ 'data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 bg-popover text-popover-foreground w-auto min-w-[96px] rounded-md p-1 shadow-lg ring-1 duration-100',
138
+ className,
139
+ )}
140
+ align={align}
141
+ alignOffset={alignOffset}
142
+ side={side}
143
+ sideOffset={sideOffset}
144
+ {...props}
145
+ />
146
+ )
147
+ }
148
+
149
+ function DropdownMenuCheckboxItem({
150
+ className,
151
+ children,
152
+ checked,
153
+ ...props
154
+ }: MenuPrimitive.CheckboxItem.Props) {
155
+ return (
156
+ <MenuPrimitive.CheckboxItem
157
+ data-slot="dropdown-menu-checkbox-item"
158
+ className={cn(
159
+ "focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
160
+ className,
161
+ )}
162
+ checked={checked}
163
+ {...props}
164
+ >
165
+ <span
166
+ className="pointer-events-none absolute right-2 flex items-center justify-center"
167
+ data-slot="dropdown-menu-checkbox-item-indicator"
168
+ >
169
+ <MenuPrimitive.CheckboxItemIndicator>
170
+ <CheckIcon />
171
+ </MenuPrimitive.CheckboxItemIndicator>
172
+ </span>
173
+ {children}
174
+ </MenuPrimitive.CheckboxItem>
175
+ )
176
+ }
177
+
178
+ function DropdownMenuRadioGroup({ ...props }: MenuPrimitive.RadioGroup.Props) {
179
+ return <MenuPrimitive.RadioGroup data-slot="dropdown-menu-radio-group" {...props} />
180
+ }
181
+
182
+ function DropdownMenuRadioItem({ className, children, ...props }: MenuPrimitive.RadioItem.Props) {
183
+ return (
184
+ <MenuPrimitive.RadioItem
185
+ data-slot="dropdown-menu-radio-item"
186
+ className={cn(
187
+ "focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
188
+ className,
189
+ )}
190
+ {...props}
191
+ >
192
+ <span
193
+ className="pointer-events-none absolute right-2 flex items-center justify-center"
194
+ data-slot="dropdown-menu-radio-item-indicator"
195
+ >
196
+ <MenuPrimitive.RadioItemIndicator>
197
+ <CheckIcon />
198
+ </MenuPrimitive.RadioItemIndicator>
199
+ </span>
200
+ {children}
201
+ </MenuPrimitive.RadioItem>
202
+ )
203
+ }
204
+
205
+ function DropdownMenuSeparator({ className, ...props }: MenuPrimitive.Separator.Props) {
206
+ return (
207
+ <MenuPrimitive.Separator
208
+ data-slot="dropdown-menu-separator"
209
+ className={cn('bg-border -mx-1 my-1 h-px', className)}
210
+ {...props}
211
+ />
212
+ )
213
+ }
214
+
215
+ function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<'span'>) {
216
+ return (
217
+ <span
218
+ data-slot="dropdown-menu-shortcut"
219
+ className={cn(
220
+ 'text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground ml-auto text-xs tracking-widest',
221
+ className,
222
+ )}
223
+ {...props}
224
+ />
225
+ )
226
+ }
227
+
228
+ export {
229
+ DropdownMenu,
230
+ DropdownMenuPortal,
231
+ DropdownMenuTrigger,
232
+ DropdownMenuContent,
233
+ DropdownMenuGroup,
234
+ DropdownMenuLabel,
235
+ DropdownMenuItem,
236
+ DropdownMenuCheckboxItem,
237
+ DropdownMenuRadioGroup,
238
+ DropdownMenuRadioItem,
239
+ DropdownMenuSeparator,
240
+ DropdownMenuShortcut,
241
+ DropdownMenuSub,
242
+ DropdownMenuSubTrigger,
243
+ DropdownMenuSubContent,
244
+ }
@@ -0,0 +1,222 @@
1
+ import { useMemo } from 'react'
2
+ import { cva, type VariantProps } from 'class-variance-authority'
3
+
4
+ import { Label } from '~/components/ui/label'
5
+ import { Separator } from '~/components/ui/separator'
6
+ import { cn } from '~/lib/utils'
7
+
8
+ function FieldSet({ className, ...props }: React.ComponentProps<'fieldset'>) {
9
+ return (
10
+ <fieldset
11
+ data-slot="field-set"
12
+ className={cn(
13
+ 'flex flex-col gap-6 has-[>[data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3',
14
+ className,
15
+ )}
16
+ {...props}
17
+ />
18
+ )
19
+ }
20
+
21
+ function FieldLegend({
22
+ className,
23
+ variant = 'legend',
24
+ ...props
25
+ }: React.ComponentProps<'legend'> & { variant?: 'legend' | 'label' }) {
26
+ return (
27
+ <legend
28
+ data-slot="field-legend"
29
+ data-variant={variant}
30
+ className={cn(
31
+ 'mb-3 font-medium data-[variant=label]:text-sm data-[variant=legend]:text-base',
32
+ className,
33
+ )}
34
+ {...props}
35
+ />
36
+ )
37
+ }
38
+
39
+ function FieldGroup({ className, ...props }: React.ComponentProps<'div'>) {
40
+ return (
41
+ <div
42
+ data-slot="field-group"
43
+ className={cn(
44
+ 'group/field-group @container/field-group flex w-full flex-col gap-7 data-[slot=checkbox-group]:gap-3 [&>[data-slot=field-group]]:gap-4',
45
+ className,
46
+ )}
47
+ {...props}
48
+ />
49
+ )
50
+ }
51
+
52
+ const fieldVariants = cva('data-[invalid=true]:text-destructive gap-3 group/field flex w-full', {
53
+ variants: {
54
+ orientation: {
55
+ vertical: 'flex-col [&>*]:w-full [&>.sr-only]:w-auto',
56
+ horizontal:
57
+ 'flex-row items-center [&>[data-slot=field-label]]:flex-auto has-[>[data-slot=field-content]]:items-start has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px',
58
+ responsive:
59
+ 'flex-col [&>*]:w-full [&>.sr-only]:w-auto @md/field-group:flex-row @md/field-group:items-center @md/field-group:[&>*]:w-auto @md/field-group:[&>[data-slot=field-label]]:flex-auto @md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px',
60
+ },
61
+ },
62
+ defaultVariants: {
63
+ orientation: 'vertical',
64
+ },
65
+ })
66
+
67
+ function Field({
68
+ className,
69
+ orientation = 'vertical',
70
+ ...props
71
+ }: React.ComponentProps<'div'> & VariantProps<typeof fieldVariants>) {
72
+ return (
73
+ <div
74
+ role="group"
75
+ data-slot="field"
76
+ data-orientation={orientation}
77
+ className={cn(fieldVariants({ orientation }), className)}
78
+ {...props}
79
+ />
80
+ )
81
+ }
82
+
83
+ function FieldContent({ className, ...props }: React.ComponentProps<'div'>) {
84
+ return (
85
+ <div
86
+ data-slot="field-content"
87
+ className={cn('group/field-content flex flex-1 flex-col gap-1 leading-snug', className)}
88
+ {...props}
89
+ />
90
+ )
91
+ }
92
+
93
+ function FieldLabel({ className, ...props }: React.ComponentProps<typeof Label>) {
94
+ return (
95
+ <Label
96
+ data-slot="field-label"
97
+ className={cn(
98
+ 'has-data-checked:bg-primary/5 has-data-checked:border-primary dark:has-data-checked:bg-primary/10 group/field-label peer/field-label flex w-fit gap-2 leading-snug group-data-[disabled=true]/field:opacity-50 has-[>[data-slot=field]]:rounded-md has-[>[data-slot=field]]:border [&>*]:data-[slot=field]:p-3',
99
+ 'has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col',
100
+ className,
101
+ )}
102
+ {...props}
103
+ />
104
+ )
105
+ }
106
+
107
+ function FieldTitle({ className, ...props }: React.ComponentProps<'div'>) {
108
+ return (
109
+ <div
110
+ data-slot="field-label"
111
+ className={cn(
112
+ 'flex w-fit items-center gap-2 text-sm leading-snug font-medium group-data-[disabled=true]/field:opacity-50',
113
+ className,
114
+ )}
115
+ {...props}
116
+ />
117
+ )
118
+ }
119
+
120
+ function FieldDescription({ className, ...props }: React.ComponentProps<'p'>) {
121
+ return (
122
+ <p
123
+ data-slot="field-description"
124
+ className={cn(
125
+ 'text-muted-foreground text-left text-sm leading-normal font-normal group-has-[[data-orientation=horizontal]]/field:text-balance [[data-variant=legend]+&]:-mt-1.5',
126
+ 'last:mt-0 nth-last-2:-mt-1',
127
+ '[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4',
128
+ className,
129
+ )}
130
+ {...props}
131
+ />
132
+ )
133
+ }
134
+
135
+ function FieldSeparator({
136
+ children,
137
+ className,
138
+ ...props
139
+ }: React.ComponentProps<'div'> & {
140
+ children?: React.ReactNode
141
+ }) {
142
+ return (
143
+ <div
144
+ data-slot="field-separator"
145
+ data-content={!!children}
146
+ className={cn(
147
+ 'relative -my-2 h-5 text-sm group-data-[variant=outline]/field-group:-mb-2',
148
+ className,
149
+ )}
150
+ {...props}
151
+ >
152
+ <Separator className="absolute inset-0 top-1/2" />
153
+ {children && (
154
+ <span
155
+ className="text-muted-foreground bg-background relative mx-auto block w-fit px-2"
156
+ data-slot="field-separator-content"
157
+ >
158
+ {children}
159
+ </span>
160
+ )}
161
+ </div>
162
+ )
163
+ }
164
+
165
+ function FieldError({
166
+ className,
167
+ children,
168
+ errors,
169
+ ...props
170
+ }: React.ComponentProps<'div'> & {
171
+ errors?: Array<{ message?: string } | undefined>
172
+ }) {
173
+ const content = useMemo(() => {
174
+ if (children) {
175
+ return children
176
+ }
177
+
178
+ if (!errors?.length) {
179
+ return null
180
+ }
181
+
182
+ const uniqueErrors = [...new Map(errors.map((error) => [error?.message, error])).values()]
183
+
184
+ if (uniqueErrors.length == 1) {
185
+ return uniqueErrors[0]?.message
186
+ }
187
+
188
+ return (
189
+ <ul className="ml-4 flex list-disc flex-col gap-1">
190
+ {uniqueErrors.map((error, index) => error?.message && <li key={index}>{error.message}</li>)}
191
+ </ul>
192
+ )
193
+ }, [children, errors])
194
+
195
+ if (!content) {
196
+ return null
197
+ }
198
+
199
+ return (
200
+ <div
201
+ role="alert"
202
+ data-slot="field-error"
203
+ className={cn('text-destructive text-sm font-normal', className)}
204
+ {...props}
205
+ >
206
+ {content}
207
+ </div>
208
+ )
209
+ }
210
+
211
+ export {
212
+ Field,
213
+ FieldLabel,
214
+ FieldDescription,
215
+ FieldError,
216
+ FieldGroup,
217
+ FieldLegend,
218
+ FieldSeparator,
219
+ FieldSet,
220
+ FieldContent,
221
+ FieldTitle,
222
+ }
@@ -0,0 +1,146 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import { cva, type VariantProps } from 'class-variance-authority'
5
+
6
+ import { Button } from '~/components/ui/button'
7
+ import { Input } from '~/components/ui/input'
8
+ import { Textarea } from '~/components/ui/textarea'
9
+ import { cn } from '~/lib/utils'
10
+
11
+ function InputGroup({ className, ...props }: React.ComponentProps<'div'>) {
12
+ return (
13
+ <div
14
+ data-slot="input-group"
15
+ role="group"
16
+ className={cn(
17
+ 'border-input dark:bg-input/30 has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40 group/input-group relative flex h-9 w-full min-w-0 items-center rounded-md border shadow-xs transition-[color,box-shadow] outline-none has-[[data-slot=input-group-control]:focus-visible]:ring-[3px] has-[[data-slot][aria-invalid=true]]:ring-[3px] has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>textarea]:h-auto has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3 has-[>[data-align=inline-end]]:[&>input]:pr-1.5 has-[>[data-align=inline-start]]:[&>input]:pl-1.5 [[data-slot=combobox-content]_&]:focus-within:border-inherit [[data-slot=combobox-content]_&]:focus-within:ring-0',
18
+ className,
19
+ )}
20
+ {...props}
21
+ />
22
+ )
23
+ }
24
+
25
+ const inputGroupAddonVariants = cva(
26
+ "text-muted-foreground h-auto gap-2 py-1.5 text-sm font-medium group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4 flex cursor-text items-center justify-center select-none",
27
+ {
28
+ variants: {
29
+ align: {
30
+ 'inline-start': 'pl-2 has-[>button]:ml-[-0.25rem] has-[>kbd]:ml-[-0.15rem] order-first',
31
+ 'inline-end': 'pr-2 has-[>button]:mr-[-0.25rem] has-[>kbd]:mr-[-0.15rem] order-last',
32
+ 'block-start':
33
+ 'px-2.5 pt-2 group-has-[>input]/input-group:pt-2 [.border-b]:pb-2 order-first w-full justify-start',
34
+ 'block-end':
35
+ 'px-2.5 pb-2 group-has-[>input]/input-group:pb-2 [.border-t]:pt-2 order-last w-full justify-start',
36
+ },
37
+ },
38
+ defaultVariants: {
39
+ align: 'inline-start',
40
+ },
41
+ },
42
+ )
43
+
44
+ function InputGroupAddon({
45
+ className,
46
+ align = 'inline-start',
47
+ ...props
48
+ }: React.ComponentProps<'div'> & VariantProps<typeof inputGroupAddonVariants>) {
49
+ return (
50
+ <div
51
+ role="group"
52
+ data-slot="input-group-addon"
53
+ data-align={align}
54
+ className={cn(inputGroupAddonVariants({ align }), className)}
55
+ onClick={(e) => {
56
+ if ((e.target as HTMLElement).closest('button')) {
57
+ return
58
+ }
59
+ e.currentTarget.parentElement?.querySelector('input')?.focus()
60
+ }}
61
+ {...props}
62
+ />
63
+ )
64
+ }
65
+
66
+ const inputGroupButtonVariants = cva('gap-2 text-sm shadow-none flex items-center', {
67
+ variants: {
68
+ size: {
69
+ xs: "h-6 gap-1 rounded-[calc(var(--radius)-5px)] px-1.5 [&>svg:not([class*='size-'])]:size-3.5",
70
+ sm: '',
71
+ 'icon-xs': 'size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0',
72
+ 'icon-sm': 'size-8 p-0 has-[>svg]:p-0',
73
+ },
74
+ },
75
+ defaultVariants: {
76
+ size: 'xs',
77
+ },
78
+ })
79
+
80
+ function InputGroupButton({
81
+ className,
82
+ type = 'button',
83
+ variant = 'ghost',
84
+ size = 'xs',
85
+ ...props
86
+ }: Omit<React.ComponentProps<typeof Button>, 'size' | 'type'> &
87
+ VariantProps<typeof inputGroupButtonVariants> & {
88
+ type?: 'button' | 'submit' | 'reset'
89
+ }) {
90
+ return (
91
+ <Button
92
+ type={type}
93
+ data-size={size}
94
+ variant={variant}
95
+ className={cn(inputGroupButtonVariants({ size }), className)}
96
+ {...props}
97
+ />
98
+ )
99
+ }
100
+
101
+ function InputGroupText({ className, ...props }: React.ComponentProps<'span'>) {
102
+ return (
103
+ <span
104
+ className={cn(
105
+ "text-muted-foreground flex items-center gap-2 text-sm [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
106
+ className,
107
+ )}
108
+ {...props}
109
+ />
110
+ )
111
+ }
112
+
113
+ function InputGroupInput({ className, ...props }: React.ComponentProps<'input'>) {
114
+ return (
115
+ <Input
116
+ data-slot="input-group-control"
117
+ className={cn(
118
+ 'flex-1 rounded-none border-0 bg-transparent shadow-none ring-0 focus-visible:ring-0 aria-invalid:ring-0 dark:bg-transparent',
119
+ className,
120
+ )}
121
+ {...props}
122
+ />
123
+ )
124
+ }
125
+
126
+ function InputGroupTextarea({ className, ...props }: React.ComponentProps<'textarea'>) {
127
+ return (
128
+ <Textarea
129
+ data-slot="input-group-control"
130
+ className={cn(
131
+ 'flex-1 resize-none rounded-none border-0 bg-transparent py-2 shadow-none ring-0 focus-visible:ring-0 aria-invalid:ring-0 dark:bg-transparent',
132
+ className,
133
+ )}
134
+ {...props}
135
+ />
136
+ )
137
+ }
138
+
139
+ export {
140
+ InputGroup,
141
+ InputGroupAddon,
142
+ InputGroupButton,
143
+ InputGroupText,
144
+ InputGroupInput,
145
+ InputGroupTextarea,
146
+ }
@@ -0,0 +1,20 @@
1
+ import * as React from 'react'
2
+ import { Input as InputPrimitive } from '@base-ui/react/input'
3
+
4
+ import { cn } from '~/lib/utils'
5
+
6
+ function Input({ className, type, ...props }: React.ComponentProps<'input'>) {
7
+ return (
8
+ <InputPrimitive
9
+ type={type}
10
+ data-slot="input"
11
+ className={cn(
12
+ 'dark:bg-input/30 border-input focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 file:text-foreground placeholder:text-muted-foreground h-9 w-full min-w-0 rounded-md border bg-transparent px-2.5 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:ring-[3px] disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:ring-[3px] md:text-sm',
13
+ className,
14
+ )}
15
+ {...props}
16
+ />
17
+ )
18
+ }
19
+
20
+ export { Input }
@@ -0,0 +1,20 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+
5
+ import { cn } from '~/lib/utils'
6
+
7
+ function Label({ className, ...props }: React.ComponentProps<'label'>) {
8
+ return (
9
+ <label
10
+ data-slot="label"
11
+ className={cn(
12
+ 'flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50',
13
+ className,
14
+ )}
15
+ {...props}
16
+ />
17
+ )
18
+ }
19
+
20
+ export { Label }