create-ec-app 1.8.0 → 1.10.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 (104) hide show
  1. package/README.md +72 -17
  2. package/dist/cssScope.js +3 -5
  3. package/dist/cssScope.js.map +1 -1
  4. package/dist/index.d.ts +46 -1
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +129 -53
  7. package/dist/index.js.map +1 -1
  8. package/dist/libFunctions.d.ts +13 -6
  9. package/dist/libFunctions.d.ts.map +1 -1
  10. package/dist/libFunctions.js +24 -9
  11. package/dist/libFunctions.js.map +1 -1
  12. package/dist/pcf.d.ts.map +1 -1
  13. package/dist/pcf.js +4 -1
  14. package/dist/pcf.js.map +1 -1
  15. package/dist/portalContainers.js +7 -5
  16. package/dist/portalContainers.js.map +1 -1
  17. package/package.json +18 -11
  18. package/scripts/build-generated.mjs +59 -0
  19. package/scripts/refresh-shadcn-template.ts +406 -0
  20. package/scripts/smoke-scaffold.mjs +245 -0
  21. package/templates/base/eslint.config.js +1 -1
  22. package/templates/base/package-lock.json +380 -476
  23. package/templates/base/package.json +14 -19
  24. package/templates/pcf/base/package-lock.json +35 -53
  25. package/templates/targets/code-apps/AGENTS.md +43 -1
  26. package/templates/targets/code-apps/CLAUDE.md +1 -0
  27. package/templates/targets/code-apps/package.patch.json +1 -1
  28. package/templates/targets/power-pages/AGENTS.md +43 -1
  29. package/templates/targets/power-pages/CLAUDE.md +1 -0
  30. package/templates/targets/power-pages/README.md +22 -2
  31. package/templates/targets/power-pages/src/App.patch.tsx +3 -1
  32. package/templates/targets/power-pages/src/components/shared/AuthError.tsx +18 -0
  33. package/templates/targets/power-pages/src/context/AuthContext.tsx +0 -4
  34. package/templates/targets/swa/AGENTS.md +42 -0
  35. package/templates/targets/swa/CLAUDE.md +1 -0
  36. package/templates/targets/webresource/AGENTS.md +47 -4
  37. package/templates/targets/webresource/CLAUDE.md +1 -0
  38. package/templates/targets/webresource/README.md +5 -5
  39. package/templates/ui/kendo/package.patch.json +2 -2
  40. package/templates/ui/shadcn-ui/SHADCN_TEMPLATE.md +20 -0
  41. package/templates/ui/shadcn-ui/package.patch.json +18 -9
  42. package/templates/ui/shadcn-ui/src/components/ui/accordion.tsx +79 -0
  43. package/templates/ui/shadcn-ui/src/components/ui/alert-dialog.tsx +199 -0
  44. package/templates/ui/shadcn-ui/src/components/ui/alert.tsx +76 -0
  45. package/templates/ui/shadcn-ui/src/components/ui/aspect-ratio.tsx +11 -0
  46. package/templates/ui/shadcn-ui/src/components/ui/attachment.tsx +206 -0
  47. package/templates/ui/shadcn-ui/src/components/ui/avatar.tsx +110 -0
  48. package/templates/ui/shadcn-ui/src/components/ui/badge.tsx +49 -0
  49. package/templates/ui/shadcn-ui/src/components/ui/breadcrumb.tsx +122 -0
  50. package/templates/ui/shadcn-ui/src/components/ui/bubble.tsx +125 -0
  51. package/templates/ui/shadcn-ui/src/components/ui/button-group.tsx +83 -0
  52. package/templates/ui/shadcn-ui/src/components/ui/button.tsx +67 -0
  53. package/templates/ui/shadcn-ui/src/components/ui/calendar.tsx +222 -0
  54. package/templates/ui/shadcn-ui/src/components/ui/card.tsx +103 -0
  55. package/templates/ui/shadcn-ui/src/components/ui/carousel.tsx +240 -0
  56. package/templates/ui/shadcn-ui/src/components/ui/chart.tsx +373 -0
  57. package/templates/ui/shadcn-ui/src/components/ui/checkbox.tsx +31 -0
  58. package/templates/ui/shadcn-ui/src/components/ui/collapsible.tsx +33 -0
  59. package/templates/ui/shadcn-ui/src/components/ui/combobox.tsx +299 -0
  60. package/templates/ui/shadcn-ui/src/components/ui/command.tsx +195 -0
  61. package/templates/ui/shadcn-ui/src/components/ui/context-menu.tsx +264 -0
  62. package/templates/ui/shadcn-ui/src/components/ui/dialog.tsx +170 -0
  63. package/templates/ui/shadcn-ui/src/components/ui/direction.tsx +22 -0
  64. package/templates/ui/shadcn-ui/src/components/ui/drawer.tsx +134 -0
  65. package/templates/ui/shadcn-ui/src/components/ui/dropdown-menu.tsx +272 -0
  66. package/templates/ui/shadcn-ui/src/components/ui/empty.tsx +104 -0
  67. package/templates/ui/shadcn-ui/src/components/ui/field.tsx +236 -0
  68. package/templates/ui/shadcn-ui/src/components/ui/hover-card.tsx +44 -0
  69. package/templates/ui/shadcn-ui/src/components/ui/input-group.tsx +156 -0
  70. package/templates/ui/shadcn-ui/src/components/ui/input-otp.tsx +87 -0
  71. package/templates/ui/shadcn-ui/src/components/ui/input.tsx +19 -0
  72. package/templates/ui/shadcn-ui/src/components/ui/item.tsx +196 -0
  73. package/templates/ui/shadcn-ui/src/components/ui/kbd.tsx +26 -0
  74. package/templates/ui/shadcn-ui/src/components/ui/label.tsx +22 -0
  75. package/templates/ui/shadcn-ui/src/components/ui/marker.tsx +69 -0
  76. package/templates/ui/shadcn-ui/src/components/ui/menubar.tsx +282 -0
  77. package/templates/ui/shadcn-ui/src/components/ui/message-scroller.tsx +129 -0
  78. package/templates/ui/shadcn-ui/src/components/ui/message.tsx +92 -0
  79. package/templates/ui/shadcn-ui/src/components/ui/native-select.tsx +61 -0
  80. package/templates/ui/shadcn-ui/src/components/ui/navigation-menu.tsx +164 -0
  81. package/templates/ui/shadcn-ui/src/components/ui/pagination.tsx +129 -0
  82. package/templates/ui/shadcn-ui/src/components/ui/popover.tsx +89 -0
  83. package/templates/ui/shadcn-ui/src/components/ui/progress.tsx +31 -0
  84. package/templates/ui/shadcn-ui/src/components/ui/radio-group.tsx +42 -0
  85. package/templates/ui/shadcn-ui/src/components/ui/resizable.tsx +50 -0
  86. package/templates/ui/shadcn-ui/src/components/ui/scroll-area.tsx +53 -0
  87. package/templates/ui/shadcn-ui/src/components/ui/select.tsx +194 -0
  88. package/templates/ui/shadcn-ui/src/components/ui/separator.tsx +26 -0
  89. package/templates/ui/shadcn-ui/src/components/ui/sheet.tsx +149 -0
  90. package/templates/ui/shadcn-ui/src/components/ui/sidebar.tsx +702 -0
  91. package/templates/ui/shadcn-ui/src/components/ui/skeleton.tsx +13 -0
  92. package/templates/ui/shadcn-ui/src/components/ui/slider.tsx +59 -0
  93. package/templates/ui/shadcn-ui/src/components/ui/sonner.tsx +47 -0
  94. package/templates/ui/shadcn-ui/src/components/ui/spinner.tsx +10 -0
  95. package/templates/ui/shadcn-ui/src/components/ui/switch.tsx +33 -0
  96. package/templates/ui/shadcn-ui/src/components/ui/table.tsx +114 -0
  97. package/templates/ui/shadcn-ui/src/components/ui/tabs.tsx +90 -0
  98. package/templates/ui/shadcn-ui/src/components/ui/textarea.tsx +18 -0
  99. package/templates/ui/shadcn-ui/src/components/ui/toggle-group.tsx +87 -0
  100. package/templates/ui/shadcn-ui/src/components/ui/toggle.tsx +45 -0
  101. package/templates/ui/shadcn-ui/src/components/ui/tooltip.tsx +59 -0
  102. package/templates/ui/shadcn-ui/src/index.patch.css +0 -118
  103. package/templates/ui/shadcn-ui/src/runtime/PortalContainer.ts +8 -0
  104. package/templates/base/biome.json +0 -54
@@ -0,0 +1,272 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui"
5
+
6
+ import { cn } from "@/lib/utils"
7
+ import { CheckIcon, ChevronRightIcon } from "lucide-react"
8
+ import { usePortalContainer } from "@/runtime/PortalContainer"
9
+
10
+ function DropdownMenu({
11
+ ...props
12
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
13
+ return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />
14
+ }
15
+
16
+ function DropdownMenuPortal({
17
+ ...props
18
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
19
+ const portalContainer = usePortalContainer()
20
+ return (
21
+ <DropdownMenuPrimitive.Portal container={portalContainer ?? undefined} data-slot="dropdown-menu-portal" {...props} />
22
+ )
23
+ }
24
+
25
+ function DropdownMenuTrigger({
26
+ ...props
27
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
28
+ return (
29
+ <DropdownMenuPrimitive.Trigger
30
+ data-slot="dropdown-menu-trigger"
31
+ {...props}
32
+ />
33
+ )
34
+ }
35
+
36
+ function DropdownMenuContent({
37
+ className,
38
+ align = "start",
39
+ sideOffset = 4,
40
+ ...props
41
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
42
+ const portalContainer = usePortalContainer()
43
+ return (
44
+ <DropdownMenuPrimitive.Portal container={portalContainer ?? undefined}>
45
+ <DropdownMenuPrimitive.Content
46
+ data-slot="dropdown-menu-content"
47
+ sideOffset={sideOffset}
48
+ align={align}
49
+ className={cn("z-50 max-h-(--radix-dropdown-menu-content-available-height) w-(--radix-dropdown-menu-trigger-width) min-w-32 origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 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 data-[state=closed]:overflow-hidden data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className )}
50
+ {...props}
51
+ />
52
+ </DropdownMenuPrimitive.Portal>
53
+ )
54
+ }
55
+
56
+ function DropdownMenuGroup({
57
+ ...props
58
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
59
+ return (
60
+ <DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
61
+ )
62
+ }
63
+
64
+ function DropdownMenuItem({
65
+ className,
66
+ inset,
67
+ variant = "default",
68
+ ...props
69
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
70
+ inset?: boolean
71
+ variant?: "default" | "destructive"
72
+ }) {
73
+ return (
74
+ <DropdownMenuPrimitive.Item
75
+ data-slot="dropdown-menu-item"
76
+ data-inset={inset}
77
+ data-variant={variant}
78
+ className={cn(
79
+ "group/dropdown-menu-item relative flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive",
80
+ className
81
+ )}
82
+ {...props}
83
+ />
84
+ )
85
+ }
86
+
87
+ function DropdownMenuCheckboxItem({
88
+ className,
89
+ children,
90
+ checked,
91
+ inset,
92
+ ...props
93
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem> & {
94
+ inset?: boolean
95
+ }) {
96
+ return (
97
+ <DropdownMenuPrimitive.CheckboxItem
98
+ data-slot="dropdown-menu-checkbox-item"
99
+ data-inset={inset}
100
+ className={cn(
101
+ "relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
102
+ className
103
+ )}
104
+ checked={checked}
105
+ {...props}
106
+ >
107
+ <span
108
+ className="pointer-events-none absolute right-2 flex items-center justify-center"
109
+ data-slot="dropdown-menu-checkbox-item-indicator"
110
+ >
111
+ <DropdownMenuPrimitive.ItemIndicator>
112
+ <CheckIcon
113
+ />
114
+ </DropdownMenuPrimitive.ItemIndicator>
115
+ </span>
116
+ {children}
117
+ </DropdownMenuPrimitive.CheckboxItem>
118
+ )
119
+ }
120
+
121
+ function DropdownMenuRadioGroup({
122
+ ...props
123
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
124
+ return (
125
+ <DropdownMenuPrimitive.RadioGroup
126
+ data-slot="dropdown-menu-radio-group"
127
+ {...props}
128
+ />
129
+ )
130
+ }
131
+
132
+ function DropdownMenuRadioItem({
133
+ className,
134
+ children,
135
+ inset,
136
+ ...props
137
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem> & {
138
+ inset?: boolean
139
+ }) {
140
+ return (
141
+ <DropdownMenuPrimitive.RadioItem
142
+ data-slot="dropdown-menu-radio-item"
143
+ data-inset={inset}
144
+ className={cn(
145
+ "relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
146
+ className
147
+ )}
148
+ {...props}
149
+ >
150
+ <span
151
+ className="pointer-events-none absolute right-2 flex items-center justify-center"
152
+ data-slot="dropdown-menu-radio-item-indicator"
153
+ >
154
+ <DropdownMenuPrimitive.ItemIndicator>
155
+ <CheckIcon
156
+ />
157
+ </DropdownMenuPrimitive.ItemIndicator>
158
+ </span>
159
+ {children}
160
+ </DropdownMenuPrimitive.RadioItem>
161
+ )
162
+ }
163
+
164
+ function DropdownMenuLabel({
165
+ className,
166
+ inset,
167
+ ...props
168
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
169
+ inset?: boolean
170
+ }) {
171
+ return (
172
+ <DropdownMenuPrimitive.Label
173
+ data-slot="dropdown-menu-label"
174
+ data-inset={inset}
175
+ className={cn(
176
+ "px-1.5 py-1 text-xs font-medium text-muted-foreground data-inset:pl-7",
177
+ className
178
+ )}
179
+ {...props}
180
+ />
181
+ )
182
+ }
183
+
184
+ function DropdownMenuSeparator({
185
+ className,
186
+ ...props
187
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
188
+ return (
189
+ <DropdownMenuPrimitive.Separator
190
+ data-slot="dropdown-menu-separator"
191
+ className={cn("-mx-1 my-1 h-px bg-border", className)}
192
+ {...props}
193
+ />
194
+ )
195
+ }
196
+
197
+ function DropdownMenuShortcut({
198
+ className,
199
+ ...props
200
+ }: React.ComponentProps<"span">) {
201
+ return (
202
+ <span
203
+ data-slot="dropdown-menu-shortcut"
204
+ className={cn(
205
+ "ml-auto text-xs tracking-widest text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground",
206
+ className
207
+ )}
208
+ {...props}
209
+ />
210
+ )
211
+ }
212
+
213
+ function DropdownMenuSub({
214
+ ...props
215
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
216
+ return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />
217
+ }
218
+
219
+ function DropdownMenuSubTrigger({
220
+ className,
221
+ inset,
222
+ children,
223
+ ...props
224
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
225
+ inset?: boolean
226
+ }) {
227
+ return (
228
+ <DropdownMenuPrimitive.SubTrigger
229
+ data-slot="dropdown-menu-sub-trigger"
230
+ data-inset={inset}
231
+ className={cn(
232
+ "flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-open:bg-accent data-open:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
233
+ className
234
+ )}
235
+ {...props}
236
+ >
237
+ {children}
238
+ <ChevronRightIcon className="ml-auto" />
239
+ </DropdownMenuPrimitive.SubTrigger>
240
+ )
241
+ }
242
+
243
+ function DropdownMenuSubContent({
244
+ className,
245
+ ...props
246
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
247
+ return (
248
+ <DropdownMenuPrimitive.SubContent
249
+ data-slot="dropdown-menu-sub-content"
250
+ className={cn("z-50 min-w-[96px] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-lg bg-popover p-1 text-popover-foreground shadow-lg ring-1 ring-foreground/10 duration-100 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 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className )}
251
+ {...props}
252
+ />
253
+ )
254
+ }
255
+
256
+ export {
257
+ DropdownMenu,
258
+ DropdownMenuPortal,
259
+ DropdownMenuTrigger,
260
+ DropdownMenuContent,
261
+ DropdownMenuGroup,
262
+ DropdownMenuLabel,
263
+ DropdownMenuItem,
264
+ DropdownMenuCheckboxItem,
265
+ DropdownMenuRadioGroup,
266
+ DropdownMenuRadioItem,
267
+ DropdownMenuSeparator,
268
+ DropdownMenuShortcut,
269
+ DropdownMenuSub,
270
+ DropdownMenuSubTrigger,
271
+ DropdownMenuSubContent,
272
+ }
@@ -0,0 +1,104 @@
1
+ import { cva, type VariantProps } from "class-variance-authority"
2
+
3
+ import { cn } from "@/lib/utils"
4
+
5
+ function Empty({ className, ...props }: React.ComponentProps<"div">) {
6
+ return (
7
+ <div
8
+ data-slot="empty"
9
+ className={cn(
10
+ "flex w-full min-w-0 flex-1 flex-col items-center justify-center gap-4 rounded-xl border-dashed p-6 text-center text-balance",
11
+ className
12
+ )}
13
+ {...props}
14
+ />
15
+ )
16
+ }
17
+
18
+ function EmptyHeader({ className, ...props }: React.ComponentProps<"div">) {
19
+ return (
20
+ <div
21
+ data-slot="empty-header"
22
+ className={cn("flex max-w-sm flex-col items-center gap-2", className)}
23
+ {...props}
24
+ />
25
+ )
26
+ }
27
+
28
+ const emptyMediaVariants = cva(
29
+ "mb-2 flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0",
30
+ {
31
+ variants: {
32
+ variant: {
33
+ default: "bg-transparent",
34
+ icon: "flex size-8 shrink-0 items-center justify-center rounded-lg bg-muted text-foreground [&_svg:not([class*='size-'])]:size-4",
35
+ },
36
+ },
37
+ defaultVariants: {
38
+ variant: "default",
39
+ },
40
+ }
41
+ )
42
+
43
+ function EmptyMedia({
44
+ className,
45
+ variant = "default",
46
+ ...props
47
+ }: React.ComponentProps<"div"> & VariantProps<typeof emptyMediaVariants>) {
48
+ return (
49
+ <div
50
+ data-slot="empty-icon"
51
+ data-variant={variant}
52
+ className={cn(emptyMediaVariants({ variant, className }))}
53
+ {...props}
54
+ />
55
+ )
56
+ }
57
+
58
+ function EmptyTitle({ className, ...props }: React.ComponentProps<"div">) {
59
+ return (
60
+ <div
61
+ data-slot="empty-title"
62
+ className={cn(
63
+ "text-sm font-medium tracking-tight",
64
+ className
65
+ )}
66
+ {...props}
67
+ />
68
+ )
69
+ }
70
+
71
+ function EmptyDescription({ className, ...props }: React.ComponentProps<"p">) {
72
+ return (
73
+ <div
74
+ data-slot="empty-description"
75
+ className={cn(
76
+ "text-sm/relaxed text-muted-foreground [&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary",
77
+ className
78
+ )}
79
+ {...props}
80
+ />
81
+ )
82
+ }
83
+
84
+ function EmptyContent({ className, ...props }: React.ComponentProps<"div">) {
85
+ return (
86
+ <div
87
+ data-slot="empty-content"
88
+ className={cn(
89
+ "flex w-full max-w-sm min-w-0 flex-col items-center gap-2.5 text-sm text-balance",
90
+ className
91
+ )}
92
+ {...props}
93
+ />
94
+ )
95
+ }
96
+
97
+ export {
98
+ Empty,
99
+ EmptyHeader,
100
+ EmptyTitle,
101
+ EmptyDescription,
102
+ EmptyContent,
103
+ EmptyMedia,
104
+ }
@@ -0,0 +1,236 @@
1
+ import { useMemo } from "react"
2
+ import { cva, type VariantProps } from "class-variance-authority"
3
+
4
+ import { cn } from "@/lib/utils"
5
+ import { Label } from "@/components/ui/label"
6
+ import { Separator } from "@/components/ui/separator"
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-4 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-1.5 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-5 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(
53
+ "group/field flex w-full gap-2 data-[invalid=true]:text-destructive",
54
+ {
55
+ variants: {
56
+ orientation: {
57
+ vertical: "flex-col *:w-full [&>.sr-only]:w-auto",
58
+ horizontal:
59
+ "flex-row items-center has-[>[data-slot=field-content]]:items-start *:data-[slot=field-label]:flex-auto has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
60
+ responsive:
61
+ "flex-col *:w-full @md/field-group:flex-row @md/field-group:items-center @md/field-group:*:w-auto @md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:*:data-[slot=field-label]:flex-auto [&>.sr-only]:w-auto @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
62
+ },
63
+ },
64
+ defaultVariants: {
65
+ orientation: "vertical",
66
+ },
67
+ }
68
+ )
69
+
70
+ function Field({
71
+ className,
72
+ orientation = "vertical",
73
+ ...props
74
+ }: React.ComponentProps<"div"> & VariantProps<typeof fieldVariants>) {
75
+ return (
76
+ <div
77
+ role="group"
78
+ data-slot="field"
79
+ data-orientation={orientation}
80
+ className={cn(fieldVariants({ orientation }), className)}
81
+ {...props}
82
+ />
83
+ )
84
+ }
85
+
86
+ function FieldContent({ className, ...props }: React.ComponentProps<"div">) {
87
+ return (
88
+ <div
89
+ data-slot="field-content"
90
+ className={cn(
91
+ "group/field-content flex flex-1 flex-col gap-0.5 leading-snug",
92
+ className
93
+ )}
94
+ {...props}
95
+ />
96
+ )
97
+ }
98
+
99
+ function FieldLabel({
100
+ className,
101
+ ...props
102
+ }: React.ComponentProps<typeof Label>) {
103
+ return (
104
+ <Label
105
+ data-slot="field-label"
106
+ className={cn(
107
+ "group/field-label peer/field-label flex w-fit gap-2 leading-snug group-data-[disabled=true]/field:opacity-50 has-data-checked:border-primary/30 has-data-checked:bg-primary/5 has-[>[data-slot=field]]:rounded-lg has-[>[data-slot=field]]:border *:data-[slot=field]:p-2.5 dark:has-data-checked:border-primary/20 dark:has-data-checked:bg-primary/10",
108
+ "has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col",
109
+ className
110
+ )}
111
+ {...props}
112
+ />
113
+ )
114
+ }
115
+
116
+ function FieldTitle({ className, ...props }: React.ComponentProps<"div">) {
117
+ return (
118
+ <div
119
+ data-slot="field-label"
120
+ className={cn(
121
+ "flex w-fit items-center gap-2 text-sm font-medium group-data-[disabled=true]/field:opacity-50",
122
+ className
123
+ )}
124
+ {...props}
125
+ />
126
+ )
127
+ }
128
+
129
+ function FieldDescription({ className, ...props }: React.ComponentProps<"p">) {
130
+ return (
131
+ <p
132
+ data-slot="field-description"
133
+ className={cn(
134
+ "text-left text-sm leading-normal font-normal text-muted-foreground group-has-data-horizontal/field:text-balance [[data-variant=legend]+&]:-mt-1.5",
135
+ "last:mt-0 nth-last-2:-mt-1",
136
+ "[&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary",
137
+ className
138
+ )}
139
+ {...props}
140
+ />
141
+ )
142
+ }
143
+
144
+ function FieldSeparator({
145
+ children,
146
+ className,
147
+ ...props
148
+ }: React.ComponentProps<"div"> & {
149
+ children?: React.ReactNode
150
+ }) {
151
+ return (
152
+ <div
153
+ data-slot="field-separator"
154
+ data-content={!!children}
155
+ className={cn(
156
+ "relative -my-2 h-5 text-sm group-data-[variant=outline]/field-group:-mb-2",
157
+ className
158
+ )}
159
+ {...props}
160
+ >
161
+ <Separator className="absolute inset-0 top-1/2" />
162
+ {children && (
163
+ <span
164
+ className="relative mx-auto block w-fit bg-background px-2 text-muted-foreground"
165
+ data-slot="field-separator-content"
166
+ >
167
+ {children}
168
+ </span>
169
+ )}
170
+ </div>
171
+ )
172
+ }
173
+
174
+ function FieldError({
175
+ className,
176
+ children,
177
+ errors,
178
+ ...props
179
+ }: React.ComponentProps<"div"> & {
180
+ errors?: Array<{ message?: string } | undefined>
181
+ }) {
182
+ const content = useMemo(() => {
183
+ if (children) {
184
+ return children
185
+ }
186
+
187
+ if (!errors?.length) {
188
+ return null
189
+ }
190
+
191
+ const uniqueErrors = [
192
+ ...new Map(errors.map((error) => [error?.message, error])).values(),
193
+ ]
194
+
195
+ if (uniqueErrors?.length == 1) {
196
+ return uniqueErrors[0]?.message
197
+ }
198
+
199
+ return (
200
+ <ul className="ml-4 flex list-disc flex-col gap-1">
201
+ {uniqueErrors.map(
202
+ (error, index) =>
203
+ error?.message && <li key={index}>{error.message}</li>
204
+ )}
205
+ </ul>
206
+ )
207
+ }, [children, errors])
208
+
209
+ if (!content) {
210
+ return null
211
+ }
212
+
213
+ return (
214
+ <div
215
+ role="alert"
216
+ data-slot="field-error"
217
+ className={cn("text-sm font-normal text-destructive", className)}
218
+ {...props}
219
+ >
220
+ {content}
221
+ </div>
222
+ )
223
+ }
224
+
225
+ export {
226
+ Field,
227
+ FieldLabel,
228
+ FieldDescription,
229
+ FieldError,
230
+ FieldGroup,
231
+ FieldLegend,
232
+ FieldSeparator,
233
+ FieldSet,
234
+ FieldContent,
235
+ FieldTitle,
236
+ }
@@ -0,0 +1,44 @@
1
+ import * as React from "react"
2
+ import { HoverCard as HoverCardPrimitive } from "radix-ui"
3
+
4
+ import { cn } from "@/lib/utils"
5
+ import { usePortalContainer } from "@/runtime/PortalContainer"
6
+
7
+ function HoverCard({
8
+ ...props
9
+ }: React.ComponentProps<typeof HoverCardPrimitive.Root>) {
10
+ return <HoverCardPrimitive.Root data-slot="hover-card" {...props} />
11
+ }
12
+
13
+ function HoverCardTrigger({
14
+ ...props
15
+ }: React.ComponentProps<typeof HoverCardPrimitive.Trigger>) {
16
+ return (
17
+ <HoverCardPrimitive.Trigger data-slot="hover-card-trigger" {...props} />
18
+ )
19
+ }
20
+
21
+ function HoverCardContent({
22
+ className,
23
+ align = "center",
24
+ sideOffset = 4,
25
+ ...props
26
+ }: React.ComponentProps<typeof HoverCardPrimitive.Content>) {
27
+ const portalContainer = usePortalContainer()
28
+ return (
29
+ <HoverCardPrimitive.Portal container={portalContainer ?? undefined} data-slot="hover-card-portal">
30
+ <HoverCardPrimitive.Content
31
+ data-slot="hover-card-content"
32
+ align={align}
33
+ sideOffset={sideOffset}
34
+ className={cn(
35
+ "z-50 w-64 origin-(--radix-hover-card-content-transform-origin) rounded-lg bg-popover p-2.5 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden duration-100 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 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
36
+ className
37
+ )}
38
+ {...props}
39
+ />
40
+ </HoverCardPrimitive.Portal>
41
+ )
42
+ }
43
+
44
+ export { HoverCard, HoverCardTrigger, HoverCardContent }