tokka 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/compiler/generators/css.ts +146 -0
  2. package/compiler/generators/figma.ts +147 -0
  3. package/compiler/generators/tailwind.ts +106 -0
  4. package/compiler/generators/typescript.ts +113 -0
  5. package/compiler/index.ts +45 -0
  6. package/compiler/loader.ts +92 -0
  7. package/compiler/resolver.ts +177 -0
  8. package/compiler/types.ts +118 -0
  9. package/compiler/validator.ts +194 -0
  10. package/components/accordion.tsx +55 -0
  11. package/components/alert-dialog.tsx +138 -0
  12. package/components/alert.tsx +58 -0
  13. package/components/aspect-ratio.tsx +5 -0
  14. package/components/avatar.tsx +47 -0
  15. package/components/badge.tsx +35 -0
  16. package/components/breadcrumb.tsx +114 -0
  17. package/components/button.tsx +56 -0
  18. package/components/calendar.tsx +63 -0
  19. package/components/card.tsx +74 -0
  20. package/components/carousel.tsx +259 -0
  21. package/components/chart.tsx +9 -0
  22. package/components/checkbox.tsx +27 -0
  23. package/components/collapsible.tsx +9 -0
  24. package/components/combobox.tsx +8 -0
  25. package/components/command.tsx +152 -0
  26. package/components/context-menu.tsx +197 -0
  27. package/components/data-table.tsx +9 -0
  28. package/components/date-picker.tsx +8 -0
  29. package/components/dialog.tsx +119 -0
  30. package/components/drawer.tsx +115 -0
  31. package/components/dropdown-menu.tsx +197 -0
  32. package/components/form.tsx +175 -0
  33. package/components/hover-card.tsx +26 -0
  34. package/components/input-otp.tsx +68 -0
  35. package/components/input.tsx +48 -0
  36. package/components/label.tsx +23 -0
  37. package/components/lib/utils.ts +6 -0
  38. package/components/menubar.tsx +233 -0
  39. package/components/native-select.tsx +29 -0
  40. package/components/navigation-menu.tsx +127 -0
  41. package/components/pagination.tsx +116 -0
  42. package/components/popover.tsx +28 -0
  43. package/components/progress.tsx +25 -0
  44. package/components/radio-group.tsx +41 -0
  45. package/components/resizable.tsx +42 -0
  46. package/components/scroll-area.tsx +45 -0
  47. package/components/select.tsx +157 -0
  48. package/components/separator.tsx +28 -0
  49. package/components/sheet.tsx +137 -0
  50. package/components/sidebar.tsx +249 -0
  51. package/components/skeleton.tsx +15 -0
  52. package/components/slider.tsx +25 -0
  53. package/components/sonner.tsx +25 -0
  54. package/components/spinner.tsx +33 -0
  55. package/components/switch.tsx +26 -0
  56. package/components/table.tsx +116 -0
  57. package/components/tabs.tsx +52 -0
  58. package/components/textarea.tsx +23 -0
  59. package/components/toggle-group.tsx +58 -0
  60. package/components/toggle.tsx +42 -0
  61. package/components/tooltip.tsx +27 -0
  62. package/package.json +5 -3
  63. package/systems/README.md +56 -0
  64. package/systems/accessible/system.json +17 -0
  65. package/systems/accessible/tokens/primitives.json +9 -0
  66. package/systems/accessible/tokens/semantics.json +11 -0
  67. package/systems/brutalist/system.json +17 -0
  68. package/systems/brutalist/tokens/primitives.json +10 -0
  69. package/systems/brutalist/tokens/semantics.json +12 -0
  70. package/systems/corporate/system.json +20 -0
  71. package/systems/corporate/tokens/primitives.json +60 -0
  72. package/systems/corporate/tokens/semantics.json +68 -0
  73. package/systems/dark-mode/system.json +17 -0
  74. package/systems/dark-mode/tokens/primitives.json +10 -0
  75. package/systems/dark-mode/tokens/semantics.json +11 -0
  76. package/systems/package.json +14 -0
  77. package/systems/soft-saas/system.json +20 -0
  78. package/systems/soft-saas/tokens/primitives.json +235 -0
  79. package/systems/soft-saas/tokens/semantics.json +190 -0
  80. package/dist/index.js +0 -434
@@ -0,0 +1,119 @@
1
+ import * as React from "react"
2
+ import * as DialogPrimitive from "@radix-ui/react-dialog"
3
+ import { X } from "lucide-react"
4
+ import { cn } from "./lib/utils"
5
+
6
+ const Dialog = DialogPrimitive.Root
7
+
8
+ const DialogTrigger = DialogPrimitive.Trigger
9
+
10
+ const DialogPortal = DialogPrimitive.Portal
11
+
12
+ const DialogClose = DialogPrimitive.Close
13
+
14
+ const DialogOverlay = React.forwardRef<
15
+ React.ElementRef<typeof DialogPrimitive.Overlay>,
16
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
17
+ >(({ className, ...props }, ref) => (
18
+ <DialogPrimitive.Overlay
19
+ ref={ref}
20
+ className={cn(
21
+ "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
22
+ className
23
+ )}
24
+ {...props}
25
+ />
26
+ ))
27
+ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
28
+
29
+ const DialogContent = React.forwardRef<
30
+ React.ElementRef<typeof DialogPrimitive.Content>,
31
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
32
+ >(({ className, children, ...props }, ref) => (
33
+ <DialogPortal>
34
+ <DialogOverlay />
35
+ <DialogPrimitive.Content
36
+ ref={ref}
37
+ className={cn(
38
+ "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
39
+ className
40
+ )}
41
+ {...props}
42
+ >
43
+ {children}
44
+ <DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
45
+ <X className="size-4" />
46
+ <span className="sr-only">Close</span>
47
+ </DialogPrimitive.Close>
48
+ </DialogPrimitive.Content>
49
+ </DialogPortal>
50
+ ))
51
+ DialogContent.displayName = DialogPrimitive.Content.displayName
52
+
53
+ const DialogHeader = ({
54
+ className,
55
+ ...props
56
+ }: React.HTMLAttributes<HTMLDivElement>) => (
57
+ <div
58
+ className={cn(
59
+ "flex flex-col space-y-1.5 text-center sm:text-left",
60
+ className
61
+ )}
62
+ {...props}
63
+ />
64
+ )
65
+ DialogHeader.displayName = "DialogHeader"
66
+
67
+ const DialogFooter = ({
68
+ className,
69
+ ...props
70
+ }: React.HTMLAttributes<HTMLDivElement>) => (
71
+ <div
72
+ className={cn(
73
+ "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
74
+ className
75
+ )}
76
+ {...props}
77
+ />
78
+ )
79
+ DialogFooter.displayName = "DialogFooter"
80
+
81
+ const DialogTitle = React.forwardRef<
82
+ React.ElementRef<typeof DialogPrimitive.Title>,
83
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
84
+ >(({ className, ...props }, ref) => (
85
+ <DialogPrimitive.Title
86
+ ref={ref}
87
+ className={cn(
88
+ "text-lg font-semibold leading-none tracking-tight",
89
+ className
90
+ )}
91
+ {...props}
92
+ />
93
+ ))
94
+ DialogTitle.displayName = DialogPrimitive.Title.displayName
95
+
96
+ const DialogDescription = React.forwardRef<
97
+ React.ElementRef<typeof DialogPrimitive.Description>,
98
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
99
+ >(({ className, ...props }, ref) => (
100
+ <DialogPrimitive.Description
101
+ ref={ref}
102
+ className={cn("text-sm text-muted-foreground", className)}
103
+ {...props}
104
+ />
105
+ ))
106
+ DialogDescription.displayName = DialogPrimitive.Description.displayName
107
+
108
+ export {
109
+ Dialog,
110
+ DialogPortal,
111
+ DialogOverlay,
112
+ DialogClose,
113
+ DialogTrigger,
114
+ DialogContent,
115
+ DialogHeader,
116
+ DialogFooter,
117
+ DialogTitle,
118
+ DialogDescription,
119
+ }
@@ -0,0 +1,115 @@
1
+ import * as React from "react"
2
+ import { Drawer as DrawerPrimitive } from "vaul"
3
+ import { cn } from "./lib/utils"
4
+
5
+ const Drawer = ({
6
+ shouldScaleBackground = true,
7
+ ...props
8
+ }: React.ComponentProps<typeof DrawerPrimitive.Root>) => (
9
+ <DrawerPrimitive.Root
10
+ shouldScaleBackground={shouldScaleBackground}
11
+ {...props}
12
+ />
13
+ )
14
+ Drawer.displayName = "Drawer"
15
+
16
+ const DrawerTrigger = DrawerPrimitive.Trigger
17
+
18
+ const DrawerPortal = DrawerPrimitive.Portal
19
+
20
+ const DrawerClose = DrawerPrimitive.Close
21
+
22
+ const DrawerOverlay = React.forwardRef<
23
+ React.ElementRef<typeof DrawerPrimitive.Overlay>,
24
+ React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay>
25
+ >(({ className, ...props }, ref) => (
26
+ <DrawerPrimitive.Overlay
27
+ ref={ref}
28
+ className={cn("fixed inset-0 z-50 bg-black/80", className)}
29
+ {...props}
30
+ />
31
+ ))
32
+ DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName
33
+
34
+ const DrawerContent = React.forwardRef<
35
+ React.ElementRef<typeof DrawerPrimitive.Content>,
36
+ React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>
37
+ >(({ className, children, ...props }, ref) => (
38
+ <DrawerPortal>
39
+ <DrawerOverlay />
40
+ <DrawerPrimitive.Content
41
+ ref={ref}
42
+ className={cn(
43
+ "fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background",
44
+ className
45
+ )}
46
+ {...props}
47
+ >
48
+ <div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
49
+ {children}
50
+ </DrawerPrimitive.Content>
51
+ </DrawerPortal>
52
+ ))
53
+ DrawerContent.displayName = "DrawerContent"
54
+
55
+ const DrawerHeader = ({
56
+ className,
57
+ ...props
58
+ }: React.HTMLAttributes<HTMLDivElement>) => (
59
+ <div
60
+ className={cn("grid gap-1.5 p-4 text-center sm:text-left", className)}
61
+ {...props}
62
+ />
63
+ )
64
+ DrawerHeader.displayName = "DrawerHeader"
65
+
66
+ const DrawerFooter = ({
67
+ className,
68
+ ...props
69
+ }: React.HTMLAttributes<HTMLDivElement>) => (
70
+ <div
71
+ className={cn("mt-auto flex flex-col gap-2 p-4", className)}
72
+ {...props}
73
+ />
74
+ )
75
+ DrawerFooter.displayName = "DrawerFooter"
76
+
77
+ const DrawerTitle = React.forwardRef<
78
+ React.ElementRef<typeof DrawerPrimitive.Title>,
79
+ React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>
80
+ >(({ className, ...props }, ref) => (
81
+ <DrawerPrimitive.Title
82
+ ref={ref}
83
+ className={cn(
84
+ "text-lg font-semibold leading-none tracking-tight",
85
+ className
86
+ )}
87
+ {...props}
88
+ />
89
+ ))
90
+ DrawerTitle.displayName = DrawerPrimitive.Title.displayName
91
+
92
+ const DrawerDescription = React.forwardRef<
93
+ React.ElementRef<typeof DrawerPrimitive.Description>,
94
+ React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description>
95
+ >(({ className, ...props }, ref) => (
96
+ <DrawerPrimitive.Description
97
+ ref={ref}
98
+ className={cn("text-sm text-muted-foreground", className)}
99
+ {...props}
100
+ />
101
+ ))
102
+ DrawerDescription.displayName = DrawerPrimitive.Description.displayName
103
+
104
+ export {
105
+ Drawer,
106
+ DrawerPortal,
107
+ DrawerOverlay,
108
+ DrawerTrigger,
109
+ DrawerClose,
110
+ DrawerContent,
111
+ DrawerHeader,
112
+ DrawerFooter,
113
+ DrawerTitle,
114
+ DrawerDescription,
115
+ }
@@ -0,0 +1,197 @@
1
+ import * as React from "react"
2
+ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
3
+ import { Check, ChevronRight, Circle } from "lucide-react"
4
+ import { cn } from "./lib/utils"
5
+
6
+ const DropdownMenu = DropdownMenuPrimitive.Root
7
+
8
+ const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
9
+
10
+ const DropdownMenuGroup = DropdownMenuPrimitive.Group
11
+
12
+ const DropdownMenuPortal = DropdownMenuPrimitive.Portal
13
+
14
+ const DropdownMenuSub = DropdownMenuPrimitive.Sub
15
+
16
+ const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
17
+
18
+ const DropdownMenuSubTrigger = React.forwardRef<
19
+ React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
20
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
21
+ inset?: boolean
22
+ }
23
+ >(({ className, inset, children, ...props }, ref) => (
24
+ <DropdownMenuPrimitive.SubTrigger
25
+ ref={ref}
26
+ className={cn(
27
+ "flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent",
28
+ inset && "pl-8",
29
+ className
30
+ )}
31
+ {...props}
32
+ >
33
+ {children}
34
+ <ChevronRight className="ml-auto size-4" />
35
+ </DropdownMenuPrimitive.SubTrigger>
36
+ ))
37
+ DropdownMenuSubTrigger.displayName =
38
+ DropdownMenuPrimitive.SubTrigger.displayName
39
+
40
+ const DropdownMenuSubContent = React.forwardRef<
41
+ React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
42
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
43
+ >(({ className, ...props }, ref) => (
44
+ <DropdownMenuPrimitive.SubContent
45
+ ref={ref}
46
+ className={cn(
47
+ "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=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",
48
+ className
49
+ )}
50
+ {...props}
51
+ />
52
+ ))
53
+ DropdownMenuSubContent.displayName =
54
+ DropdownMenuPrimitive.SubContent.displayName
55
+
56
+ const DropdownMenuContent = React.forwardRef<
57
+ React.ElementRef<typeof DropdownMenuPrimitive.Content>,
58
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
59
+ >(({ className, sideOffset = 4, ...props }, ref) => (
60
+ <DropdownMenuPrimitive.Portal>
61
+ <DropdownMenuPrimitive.Content
62
+ ref={ref}
63
+ sideOffset={sideOffset}
64
+ className={cn(
65
+ "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=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",
66
+ className
67
+ )}
68
+ {...props}
69
+ />
70
+ </DropdownMenuPrimitive.Portal>
71
+ ))
72
+ DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
73
+
74
+ const DropdownMenuItem = React.forwardRef<
75
+ React.ElementRef<typeof DropdownMenuPrimitive.Item>,
76
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
77
+ inset?: boolean
78
+ }
79
+ >(({ className, inset, ...props }, ref) => (
80
+ <DropdownMenuPrimitive.Item
81
+ ref={ref}
82
+ className={cn(
83
+ "relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
84
+ inset && "pl-8",
85
+ className
86
+ )}
87
+ {...props}
88
+ />
89
+ ))
90
+ DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
91
+
92
+ const DropdownMenuCheckboxItem = React.forwardRef<
93
+ React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
94
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
95
+ >(({ className, children, checked, ...props }, ref) => (
96
+ <DropdownMenuPrimitive.CheckboxItem
97
+ ref={ref}
98
+ className={cn(
99
+ "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
100
+ className
101
+ )}
102
+ checked={checked}
103
+ {...props}
104
+ >
105
+ <span className="absolute left-2 flex size-3.5 items-center justify-center">
106
+ <DropdownMenuPrimitive.ItemIndicator>
107
+ <Check className="size-4" />
108
+ </DropdownMenuPrimitive.ItemIndicator>
109
+ </span>
110
+ {children}
111
+ </DropdownMenuPrimitive.CheckboxItem>
112
+ ))
113
+ DropdownMenuCheckboxItem.displayName =
114
+ DropdownMenuPrimitive.CheckboxItem.displayName
115
+
116
+ const DropdownMenuRadioItem = React.forwardRef<
117
+ React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
118
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
119
+ >(({ className, children, ...props }, ref) => (
120
+ <DropdownMenuPrimitive.RadioItem
121
+ ref={ref}
122
+ className={cn(
123
+ "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
124
+ className
125
+ )}
126
+ {...props}
127
+ >
128
+ <span className="absolute left-2 flex size-3.5 items-center justify-center">
129
+ <DropdownMenuPrimitive.ItemIndicator>
130
+ <Circle className="size-2 fill-current" />
131
+ </DropdownMenuPrimitive.ItemIndicator>
132
+ </span>
133
+ {children}
134
+ </DropdownMenuPrimitive.RadioItem>
135
+ ))
136
+ DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
137
+
138
+ const DropdownMenuLabel = React.forwardRef<
139
+ React.ElementRef<typeof DropdownMenuPrimitive.Label>,
140
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
141
+ inset?: boolean
142
+ }
143
+ >(({ className, inset, ...props }, ref) => (
144
+ <DropdownMenuPrimitive.Label
145
+ ref={ref}
146
+ className={cn(
147
+ "px-2 py-1.5 text-sm font-semibold",
148
+ inset && "pl-8",
149
+ className
150
+ )}
151
+ {...props}
152
+ />
153
+ ))
154
+ DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
155
+
156
+ const DropdownMenuSeparator = React.forwardRef<
157
+ React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
158
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
159
+ >(({ className, ...props }, ref) => (
160
+ <DropdownMenuPrimitive.Separator
161
+ ref={ref}
162
+ className={cn("-mx-1 my-1 h-px bg-muted", className)}
163
+ {...props}
164
+ />
165
+ ))
166
+ DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
167
+
168
+ const DropdownMenuShortcut = ({
169
+ className,
170
+ ...props
171
+ }: React.HTMLAttributes<HTMLSpanElement>) => {
172
+ return (
173
+ <span
174
+ className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
175
+ {...props}
176
+ />
177
+ )
178
+ }
179
+ DropdownMenuShortcut.displayName = "DropdownMenuShortcut"
180
+
181
+ export {
182
+ DropdownMenu,
183
+ DropdownMenuTrigger,
184
+ DropdownMenuContent,
185
+ DropdownMenuItem,
186
+ DropdownMenuCheckboxItem,
187
+ DropdownMenuRadioItem,
188
+ DropdownMenuLabel,
189
+ DropdownMenuSeparator,
190
+ DropdownMenuShortcut,
191
+ DropdownMenuGroup,
192
+ DropdownMenuPortal,
193
+ DropdownMenuSub,
194
+ DropdownMenuSubContent,
195
+ DropdownMenuSubTrigger,
196
+ DropdownMenuRadioGroup,
197
+ }
@@ -0,0 +1,175 @@
1
+ import * as React from "react"
2
+ import * as LabelPrimitive from "@radix-ui/react-label"
3
+ import { Slot } from "@radix-ui/react-slot"
4
+ import {
5
+ Controller,
6
+ type ControllerProps,
7
+ type FieldPath,
8
+ type FieldValues,
9
+ FormProvider,
10
+ useFormContext,
11
+ } from "react-hook-form"
12
+ import { cn } from "./lib/utils"
13
+ import { Label } from "./label"
14
+
15
+ const Form = FormProvider
16
+
17
+ type FormFieldContextValue<
18
+ TFieldValues extends FieldValues = FieldValues,
19
+ TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
20
+ > = {
21
+ name: TName
22
+ }
23
+
24
+ const FormFieldContext = React.createContext<FormFieldContextValue>(
25
+ {} as FormFieldContextValue
26
+ )
27
+
28
+ const FormField = <
29
+ TFieldValues extends FieldValues = FieldValues,
30
+ TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
31
+ >({
32
+ ...props
33
+ }: ControllerProps<TFieldValues, TName>) => {
34
+ return (
35
+ <FormFieldContext.Provider value={{ name: props.name }}>
36
+ <Controller {...props} />
37
+ </FormFieldContext.Provider>
38
+ )
39
+ }
40
+
41
+ const useFormField = () => {
42
+ const fieldContext = React.useContext(FormFieldContext)
43
+ const itemContext = React.useContext(FormItemContext)
44
+ const { getFieldState, formState } = useFormContext()
45
+
46
+ const fieldState = getFieldState(fieldContext.name, formState)
47
+
48
+ if (!fieldContext) {
49
+ throw new Error("useFormField should be used within <FormField>")
50
+ }
51
+
52
+ const { id } = itemContext
53
+
54
+ return {
55
+ id,
56
+ name: fieldContext.name,
57
+ formItemId: `${id}-form-item`,
58
+ formDescriptionId: `${id}-form-item-description`,
59
+ formMessageId: `${id}-form-item-message`,
60
+ ...fieldState,
61
+ }
62
+ }
63
+
64
+ type FormItemContextValue = {
65
+ id: string
66
+ }
67
+
68
+ const FormItemContext = React.createContext<FormItemContextValue>(
69
+ {} as FormItemContextValue
70
+ )
71
+
72
+ const FormItem = React.forwardRef<
73
+ HTMLDivElement,
74
+ React.HTMLAttributes<HTMLDivElement>
75
+ >(({ className, ...props }, ref) => {
76
+ const id = React.useId()
77
+
78
+ return (
79
+ <FormItemContext.Provider value={{ id }}>
80
+ <div ref={ref} className={cn("space-y-2", className)} {...props} />
81
+ </FormItemContext.Provider>
82
+ )
83
+ })
84
+ FormItem.displayName = "FormItem"
85
+
86
+ const FormLabel = React.forwardRef<
87
+ React.ElementRef<typeof LabelPrimitive.Root>,
88
+ React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
89
+ >(({ className, ...props }, ref) => {
90
+ const { error, formItemId } = useFormField()
91
+
92
+ return (
93
+ <Label
94
+ ref={ref}
95
+ className={cn(error && "text-destructive", className)}
96
+ htmlFor={formItemId}
97
+ {...props}
98
+ />
99
+ )
100
+ })
101
+ FormLabel.displayName = "FormLabel"
102
+
103
+ const FormControl = React.forwardRef<
104
+ React.ElementRef<typeof Slot>,
105
+ React.ComponentPropsWithoutRef<typeof Slot>
106
+ >(({ ...props }, ref) => {
107
+ const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
108
+
109
+ return (
110
+ <Slot
111
+ ref={ref}
112
+ id={formItemId}
113
+ aria-describedby={
114
+ !error
115
+ ? `${formDescriptionId}`
116
+ : `${formDescriptionId} ${formMessageId}`
117
+ }
118
+ aria-invalid={!!error}
119
+ {...props}
120
+ />
121
+ )
122
+ })
123
+ FormControl.displayName = "FormControl"
124
+
125
+ const FormDescription = React.forwardRef<
126
+ HTMLParagraphElement,
127
+ React.HTMLAttributes<HTMLParagraphElement>
128
+ >(({ className, ...props }, ref) => {
129
+ const { formDescriptionId } = useFormField()
130
+
131
+ return (
132
+ <p
133
+ ref={ref}
134
+ id={formDescriptionId}
135
+ className={cn("text-sm text-muted-foreground", className)}
136
+ {...props}
137
+ />
138
+ )
139
+ })
140
+ FormDescription.displayName = "FormDescription"
141
+
142
+ const FormMessage = React.forwardRef<
143
+ HTMLParagraphElement,
144
+ React.HTMLAttributes<HTMLParagraphElement>
145
+ >(({ className, children, ...props }, ref) => {
146
+ const { error, formMessageId } = useFormField()
147
+ const body = error ? String(error?.message) : children
148
+
149
+ if (!body) {
150
+ return null
151
+ }
152
+
153
+ return (
154
+ <p
155
+ ref={ref}
156
+ id={formMessageId}
157
+ className={cn("text-sm font-medium text-destructive", className)}
158
+ {...props}
159
+ >
160
+ {body}
161
+ </p>
162
+ )
163
+ })
164
+ FormMessage.displayName = "FormMessage"
165
+
166
+ export {
167
+ useFormField,
168
+ Form,
169
+ FormItem,
170
+ FormLabel,
171
+ FormControl,
172
+ FormDescription,
173
+ FormMessage,
174
+ FormField,
175
+ }
@@ -0,0 +1,26 @@
1
+ import * as React from "react"
2
+ import * as HoverCardPrimitive from "@radix-ui/react-hover-card"
3
+ import { cn } from "./lib/utils"
4
+
5
+ const HoverCard = HoverCardPrimitive.Root
6
+
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
+ "z-50 w-64 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=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",
19
+ className
20
+ )}
21
+ {...props}
22
+ />
23
+ ))
24
+ HoverCardContent.displayName = HoverCardPrimitive.Content.displayName
25
+
26
+ export { HoverCard, HoverCardTrigger, HoverCardContent }
@@ -0,0 +1,68 @@
1
+ import * as React from "react"
2
+ import { OTPInput, OTPInputContext } from "input-otp"
3
+ import { Dot } from "lucide-react"
4
+ import { cn } from "./lib/utils"
5
+
6
+ const InputOTP = React.forwardRef<
7
+ React.ElementRef<typeof OTPInput>,
8
+ React.ComponentPropsWithoutRef<typeof OTPInput>
9
+ >(({ className, containerClassName, ...props }, ref) => (
10
+ <OTPInput
11
+ ref={ref}
12
+ containerClassName={cn(
13
+ "flex items-center gap-2 has-[:disabled]:opacity-50",
14
+ containerClassName
15
+ )}
16
+ className={cn("disabled:cursor-not-allowed", className)}
17
+ {...props}
18
+ />
19
+ ))
20
+ InputOTP.displayName = "InputOTP"
21
+
22
+ const InputOTPGroup = React.forwardRef<
23
+ React.ElementRef<"div">,
24
+ React.ComponentPropsWithoutRef<"div">
25
+ >(({ className, ...props }, ref) => (
26
+ <div ref={ref} className={cn("flex items-center", className)} {...props} />
27
+ ))
28
+ InputOTPGroup.displayName = "InputOTPGroup"
29
+
30
+ const InputOTPSlot = React.forwardRef<
31
+ React.ElementRef<"div">,
32
+ React.ComponentPropsWithoutRef<"div"> & { index: number }
33
+ >(({ index, className, ...props }, ref) => {
34
+ const inputOTPContext = React.useContext(OTPInputContext)
35
+ const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index]
36
+
37
+ return (
38
+ <div
39
+ ref={ref}
40
+ className={cn(
41
+ "relative flex size-10 items-center justify-center border-y border-r border-input text-sm transition-all first:rounded-l-md first:border-l last:rounded-r-md",
42
+ isActive && "z-10 ring-2 ring-ring ring-offset-background",
43
+ className
44
+ )}
45
+ {...props}
46
+ >
47
+ {char}
48
+ {hasFakeCaret && (
49
+ <div className="pointer-events-none absolute inset-0 flex items-center justify-center">
50
+ <div className="h-4 w-px animate-caret-blink bg-foreground duration-1000" />
51
+ </div>
52
+ )}
53
+ </div>
54
+ )
55
+ })
56
+ InputOTPSlot.displayName = "InputOTPSlot"
57
+
58
+ const InputOTPSeparator = React.forwardRef<
59
+ React.ElementRef<"div">,
60
+ React.ComponentPropsWithoutRef<"div">
61
+ >(({ ...props }, ref) => (
62
+ <div ref={ref} role="separator" {...props}>
63
+ <Dot />
64
+ </div>
65
+ ))
66
+ InputOTPSeparator.displayName = "InputOTPSeparator"
67
+
68
+ export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator }