@betterstart/cli 0.1.28 → 0.1.30
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.
- package/dist/{chunk-SAPJG4NO.js → chunk-6JCWMKSY.js} +7 -4
- package/dist/{chunk-SAPJG4NO.js.map → chunk-6JCWMKSY.js.map} +1 -1
- package/dist/cli.js +749 -866
- package/dist/cli.js.map +1 -1
- package/dist/drizzle-config-EDKOEZ6G.js +7 -0
- package/package.json +1 -1
- package/templates/ui/accordion.tsx +73 -42
- package/templates/ui/alert-dialog.tsx +155 -90
- package/templates/ui/alert.tsx +46 -26
- package/templates/ui/aspect-ratio.tsx +4 -2
- package/templates/ui/avatar.tsx +92 -43
- package/templates/ui/badge.tsx +27 -12
- package/templates/ui/breadcrumb.tsx +63 -60
- package/templates/ui/button-group.tsx +8 -8
- package/templates/ui/button.tsx +44 -26
- package/templates/ui/calendar.tsx +43 -34
- package/templates/ui/card.tsx +71 -34
- package/templates/ui/carousel.tsx +111 -115
- package/templates/ui/chart.tsx +197 -207
- package/templates/ui/checkbox.tsx +21 -20
- package/templates/ui/collapsible.tsx +14 -4
- package/templates/ui/combobox.tsx +272 -0
- package/templates/ui/command.tsx +139 -101
- package/templates/ui/context-menu.tsx +214 -156
- package/templates/ui/dialog.tsx +118 -77
- package/templates/ui/direction.tsx +20 -0
- package/templates/ui/drawer.tsx +89 -69
- package/templates/ui/dropdown-menu.tsx +228 -164
- package/templates/ui/empty.tsx +8 -5
- package/templates/ui/field.tsx +25 -32
- package/templates/ui/hover-card.tsx +29 -20
- package/templates/ui/input-group.tsx +20 -37
- package/templates/ui/input-otp.tsx +57 -42
- package/templates/ui/input.tsx +14 -17
- package/templates/ui/item.tsx +27 -17
- package/templates/ui/kbd.tsx +1 -3
- package/templates/ui/label.tsx +14 -14
- package/templates/ui/markdown-editor.tsx +1 -1
- package/templates/ui/menubar.tsx +220 -188
- package/templates/ui/native-select.tsx +42 -0
- package/templates/ui/navigation-menu.tsx +130 -90
- package/templates/ui/pagination.tsx +88 -73
- package/templates/ui/popover.tsx +67 -26
- package/templates/ui/progress.tsx +24 -18
- package/templates/ui/radio-group.tsx +26 -20
- package/templates/ui/resizable.tsx +29 -29
- package/templates/ui/scroll-area.tsx +47 -38
- package/templates/ui/select.tsx +158 -125
- package/templates/ui/separator.tsx +21 -19
- package/templates/ui/sheet.tsx +104 -95
- package/templates/ui/sidebar.tsx +77 -183
- package/templates/ui/skeleton.tsx +8 -2
- package/templates/ui/slider.tsx +46 -17
- package/templates/ui/sonner.tsx +19 -9
- package/templates/ui/spinner.tsx +2 -2
- package/templates/ui/switch.tsx +24 -20
- package/templates/ui/table.tsx +68 -73
- package/templates/ui/tabs.tsx +71 -46
- package/templates/ui/textarea.tsx +13 -16
- package/templates/ui/toggle-group.tsx +57 -28
- package/templates/ui/toggle.tsx +21 -20
- package/templates/ui/tooltip.tsx +44 -23
- package/dist/drizzle-config-KISB26BA.js +0 -7
- package/templates/ui/use-mobile.tsx +0 -19
- /package/dist/{drizzle-config-KISB26BA.js.map → drizzle-config-EDKOEZ6G.js.map} +0 -0
package/templates/ui/field.tsx
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
+
import { Label } from '@cms/components/ui/label'
|
|
4
|
+
import { Separator } from '@cms/components/ui/separator'
|
|
5
|
+
|
|
3
6
|
import { cn } from '@cms/utils/cn'
|
|
4
7
|
import { cva, type VariantProps } from 'class-variance-authority'
|
|
5
8
|
import { useMemo } from 'react'
|
|
6
|
-
import { Label } from './label'
|
|
7
|
-
import { Separator } from './separator'
|
|
8
9
|
|
|
9
10
|
function FieldSet({ className, ...props }: React.ComponentProps<'fieldset'>) {
|
|
10
11
|
return (
|
|
11
12
|
<fieldset
|
|
12
13
|
data-slot="field-set"
|
|
13
14
|
className={cn(
|
|
14
|
-
'flex flex-col gap-
|
|
15
|
-
'has-[>[data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3',
|
|
15
|
+
'flex flex-col gap-4 has-[>[data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3',
|
|
16
16
|
className
|
|
17
17
|
)}
|
|
18
18
|
{...props}
|
|
@@ -30,9 +30,7 @@ function FieldLegend({
|
|
|
30
30
|
data-slot="field-legend"
|
|
31
31
|
data-variant={variant}
|
|
32
32
|
className={cn(
|
|
33
|
-
'mb-
|
|
34
|
-
'data-[variant=legend]:text-base',
|
|
35
|
-
'data-[variant=label]:text-sm',
|
|
33
|
+
'mb-1.5 font-medium data-[variant=label]:text-sm data-[variant=legend]:text-base',
|
|
36
34
|
className
|
|
37
35
|
)}
|
|
38
36
|
{...props}
|
|
@@ -45,7 +43,7 @@ function FieldGroup({ className, ...props }: React.ComponentProps<'div'>) {
|
|
|
45
43
|
<div
|
|
46
44
|
data-slot="field-group"
|
|
47
45
|
className={cn(
|
|
48
|
-
'group/field-group @container/field-group flex w-full flex-col gap-
|
|
46
|
+
'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',
|
|
49
47
|
className
|
|
50
48
|
)}
|
|
51
49
|
{...props}
|
|
@@ -53,20 +51,14 @@ function FieldGroup({ className, ...props }: React.ComponentProps<'div'>) {
|
|
|
53
51
|
)
|
|
54
52
|
}
|
|
55
53
|
|
|
56
|
-
const fieldVariants = cva('
|
|
54
|
+
const fieldVariants = cva('data-[invalid=true]:text-destructive gap-2 group/field flex w-full', {
|
|
57
55
|
variants: {
|
|
58
56
|
orientation: {
|
|
59
|
-
vertical:
|
|
60
|
-
horizontal:
|
|
61
|
-
'flex-row items-center',
|
|
62
|
-
|
|
63
|
-
'
|
|
64
|
-
],
|
|
65
|
-
responsive: [
|
|
66
|
-
'@md/field-group:flex-row @md/field-group:items-center @md/field-group:[&>*]:w-auto flex-col [&>*]:w-full [&>.sr-only]:w-auto',
|
|
67
|
-
'@md/field-group:[&>[data-slot=field-label]]:flex-auto',
|
|
68
|
-
'@md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px'
|
|
69
|
-
]
|
|
57
|
+
vertical: 'flex-col *:w-full [&>.sr-only]:w-auto',
|
|
58
|
+
horizontal:
|
|
59
|
+
'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',
|
|
60
|
+
responsive:
|
|
61
|
+
'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'
|
|
70
62
|
}
|
|
71
63
|
},
|
|
72
64
|
defaultVariants: {
|
|
@@ -94,7 +86,7 @@ function FieldContent({ className, ...props }: React.ComponentProps<'div'>) {
|
|
|
94
86
|
return (
|
|
95
87
|
<div
|
|
96
88
|
data-slot="field-content"
|
|
97
|
-
className={cn('group/field-content flex flex-1 flex-col gap-
|
|
89
|
+
className={cn('group/field-content flex flex-1 flex-col gap-0.5 leading-snug', className)}
|
|
98
90
|
{...props}
|
|
99
91
|
/>
|
|
100
92
|
)
|
|
@@ -105,9 +97,8 @@ function FieldLabel({ className, ...props }: React.ComponentProps<typeof Label>)
|
|
|
105
97
|
<Label
|
|
106
98
|
data-slot="field-label"
|
|
107
99
|
className={cn(
|
|
108
|
-
'group/field-label peer/field-label flex w-fit gap-2 leading-snug group-data-[disabled=true]/field:opacity-50',
|
|
109
|
-
'has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col
|
|
110
|
-
'has-data-[state=checked]:bg-primary/5 has-data-[state=checked]:border-primary dark:has-data-[state=checked]:bg-primary/10',
|
|
100
|
+
'has-data-checked:bg-primary/5 has-data-checked:border-primary/30 dark:has-data-checked:border-primary/20 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-lg has-[>[data-slot=field]]:border *:data-[slot=field]:p-2.5',
|
|
101
|
+
'has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col',
|
|
111
102
|
className
|
|
112
103
|
)}
|
|
113
104
|
{...props}
|
|
@@ -120,7 +111,7 @@ function FieldTitle({ className, ...props }: React.ComponentProps<'div'>) {
|
|
|
120
111
|
<div
|
|
121
112
|
data-slot="field-label"
|
|
122
113
|
className={cn(
|
|
123
|
-
'flex w-fit items-center gap-2 text-sm font-medium
|
|
114
|
+
'flex w-fit items-center gap-2 text-sm leading-snug font-medium group-data-[disabled=true]/field:opacity-50',
|
|
124
115
|
className
|
|
125
116
|
)}
|
|
126
117
|
{...props}
|
|
@@ -133,8 +124,8 @@ function FieldDescription({ className, ...props }: React.ComponentProps<'p'>) {
|
|
|
133
124
|
<p
|
|
134
125
|
data-slot="field-description"
|
|
135
126
|
className={cn(
|
|
136
|
-
'text-muted-foreground text-sm font-normal
|
|
137
|
-
'
|
|
127
|
+
'text-muted-foreground text-left text-sm leading-normal font-normal group-has-data-horizontal/field:text-balance [[data-variant=legend]+&]:-mt-1.5',
|
|
128
|
+
'last:mt-0 nth-last-2:-mt-1',
|
|
138
129
|
'[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4',
|
|
139
130
|
className
|
|
140
131
|
)}
|
|
@@ -163,7 +154,7 @@ function FieldSeparator({
|
|
|
163
154
|
<Separator className="absolute inset-0 top-1/2" />
|
|
164
155
|
{children && (
|
|
165
156
|
<span
|
|
166
|
-
className="
|
|
157
|
+
className="text-muted-foreground bg-background relative mx-auto block w-fit px-2"
|
|
167
158
|
data-slot="field-separator-content"
|
|
168
159
|
>
|
|
169
160
|
{children}
|
|
@@ -186,17 +177,19 @@ function FieldError({
|
|
|
186
177
|
return children
|
|
187
178
|
}
|
|
188
179
|
|
|
189
|
-
if (!errors) {
|
|
180
|
+
if (!errors?.length) {
|
|
190
181
|
return null
|
|
191
182
|
}
|
|
192
183
|
|
|
193
|
-
|
|
194
|
-
|
|
184
|
+
const uniqueErrors = [...new Map(errors.map((error) => [error?.message, error])).values()]
|
|
185
|
+
|
|
186
|
+
if (uniqueErrors?.length === 1) {
|
|
187
|
+
return uniqueErrors[0]?.message
|
|
195
188
|
}
|
|
196
189
|
|
|
197
190
|
return (
|
|
198
191
|
<ul className="ml-4 flex list-disc flex-col gap-1">
|
|
199
|
-
{
|
|
192
|
+
{uniqueErrors.map((error, index) => error?.message && <li key={index}>{error.message}</li>)}
|
|
200
193
|
</ul>
|
|
201
194
|
)
|
|
202
195
|
}, [children, errors])
|
|
@@ -1,28 +1,37 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
import { cn } from '@cms/utils/cn'
|
|
4
|
-
import
|
|
5
|
-
import * as React from 'react'
|
|
4
|
+
import { HoverCard as HoverCardPrimitive } from 'radix-ui'
|
|
5
|
+
import type * as React from 'react'
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
function HoverCard({ ...props }: React.ComponentProps<typeof HoverCardPrimitive.Root>) {
|
|
8
|
+
return <HoverCardPrimitive.Root data-slot="hover-card" {...props} />
|
|
9
|
+
}
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
function HoverCardTrigger({ ...props }: React.ComponentProps<typeof HoverCardPrimitive.Trigger>) {
|
|
12
|
+
return <HoverCardPrimitive.Trigger data-slot="hover-card-trigger" {...props} />
|
|
13
|
+
}
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
15
|
+
function HoverCardContent({
|
|
16
|
+
className,
|
|
17
|
+
align = 'center',
|
|
18
|
+
sideOffset = 4,
|
|
19
|
+
...props
|
|
20
|
+
}: React.ComponentProps<typeof HoverCardPrimitive.Content>) {
|
|
21
|
+
return (
|
|
22
|
+
<HoverCardPrimitive.Portal data-slot="hover-card-portal">
|
|
23
|
+
<HoverCardPrimitive.Content
|
|
24
|
+
data-slot="hover-card-content"
|
|
25
|
+
align={align}
|
|
26
|
+
sideOffset={sideOffset}
|
|
27
|
+
className={cn(
|
|
28
|
+
'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 w-64 origin-(--radix-hover-card-content-transform-origin) rounded-lg p-2.5 text-sm shadow-md ring-1 outline-hidden duration-100',
|
|
29
|
+
className
|
|
30
|
+
)}
|
|
31
|
+
{...props}
|
|
32
|
+
/>
|
|
33
|
+
</HoverCardPrimitive.Portal>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
27
36
|
|
|
28
37
|
export { HoverCard, HoverCardTrigger, HoverCardContent }
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
+
import { Button } from '@cms/components/ui/button'
|
|
4
|
+
import { Input } from '@cms/components/ui/input'
|
|
5
|
+
import { Textarea } from '@cms/components/ui/textarea'
|
|
3
6
|
import { cn } from '@cms/utils/cn'
|
|
4
7
|
import { cva, type VariantProps } from 'class-variance-authority'
|
|
5
8
|
import type * as React from 'react'
|
|
6
|
-
import { Button } from './button'
|
|
7
|
-
import { Input } from './input'
|
|
8
|
-
import { Textarea } from './textarea'
|
|
9
9
|
|
|
10
10
|
function InputGroup({ className, ...props }: React.ComponentProps<'div'>) {
|
|
11
11
|
return (
|
|
@@ -13,21 +13,7 @@ function InputGroup({ className, ...props }: React.ComponentProps<'div'>) {
|
|
|
13
13
|
data-slot="input-group"
|
|
14
14
|
role="group"
|
|
15
15
|
className={cn(
|
|
16
|
-
'
|
|
17
|
-
'h-9 has-[>textarea]:h-auto',
|
|
18
|
-
|
|
19
|
-
// Variants based on alignment.
|
|
20
|
-
'has-[>[data-align=inline-start]]:[&>input]:pl-2',
|
|
21
|
-
'has-[>[data-align=inline-end]]:[&>input]:pr-2',
|
|
22
|
-
'has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3',
|
|
23
|
-
'has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3',
|
|
24
|
-
|
|
25
|
-
// Focus state.
|
|
26
|
-
'has-[[data-slot=input-group-control]:focus-visible]:ring-ring has-[[data-slot=input-group-control]:focus-visible]:ring-1',
|
|
27
|
-
|
|
28
|
-
// Error state.
|
|
29
|
-
'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',
|
|
30
|
-
|
|
16
|
+
'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 has-disabled:bg-input/50 dark:has-disabled:bg-input/80 group/input-group relative flex h-8 w-full min-w-0 items-center rounded-lg border transition-colors outline-none in-data-[slot=combobox-content]:focus-within:border-inherit in-data-[slot=combobox-content]:focus-within:ring-0 has-disabled:opacity-50 has-[[data-slot=input-group-control]:focus-visible]:ring-3 has-[[data-slot][aria-invalid=true]]:ring-3 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',
|
|
31
17
|
className
|
|
32
18
|
)}
|
|
33
19
|
{...props}
|
|
@@ -36,16 +22,16 @@ function InputGroup({ className, ...props }: React.ComponentProps<'div'>) {
|
|
|
36
22
|
}
|
|
37
23
|
|
|
38
24
|
const inputGroupAddonVariants = cva(
|
|
39
|
-
"text-muted-foreground
|
|
25
|
+
"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",
|
|
40
26
|
{
|
|
41
27
|
variants: {
|
|
42
28
|
align: {
|
|
43
|
-
'inline-start': '
|
|
44
|
-
'inline-end': '
|
|
29
|
+
'inline-start': 'pl-2 has-[>button]:ml-[-0.3rem] has-[>kbd]:ml-[-0.15rem] order-first',
|
|
30
|
+
'inline-end': 'pr-2 has-[>button]:mr-[-0.3rem] has-[>kbd]:mr-[-0.15rem] order-last',
|
|
45
31
|
'block-start':
|
|
46
|
-
'
|
|
32
|
+
'px-2.5 pt-2 group-has-[>input]/input-group:pt-2 [.border-b]:pb-2 order-first w-full justify-start',
|
|
47
33
|
'block-end':
|
|
48
|
-
'
|
|
34
|
+
'px-2.5 pb-2 group-has-[>input]/input-group:pb-2 [.border-t]:pt-2 order-last w-full justify-start'
|
|
49
35
|
}
|
|
50
36
|
},
|
|
51
37
|
defaultVariants: {
|
|
@@ -57,34 +43,31 @@ const inputGroupAddonVariants = cva(
|
|
|
57
43
|
function InputGroupAddon({
|
|
58
44
|
className,
|
|
59
45
|
align = 'inline-start',
|
|
60
|
-
onClick,
|
|
61
46
|
...props
|
|
62
47
|
}: React.ComponentProps<'div'> & VariantProps<typeof inputGroupAddonVariants>) {
|
|
63
48
|
return (
|
|
64
|
-
// biome-ignore lint/a11y/noStaticElementInteractions: Click-to-focus is a mouse convenience, keyboard users can tab directly to input
|
|
65
|
-
// biome-ignore lint/a11y/useKeyWithClickEvents: Keyboard users can tab directly to input field
|
|
66
49
|
<div
|
|
50
|
+
role="group"
|
|
67
51
|
data-slot="input-group-addon"
|
|
68
52
|
data-align={align}
|
|
69
53
|
className={cn(inputGroupAddonVariants({ align }), className)}
|
|
70
54
|
onClick={(e) => {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
e.currentTarget.parentElement?.querySelector('input')?.focus()
|
|
55
|
+
if ((e.target as HTMLElement).closest('button')) {
|
|
56
|
+
return
|
|
74
57
|
}
|
|
75
|
-
|
|
58
|
+
e.currentTarget.parentElement?.querySelector('input')?.focus()
|
|
76
59
|
}}
|
|
77
60
|
{...props}
|
|
78
61
|
/>
|
|
79
62
|
)
|
|
80
63
|
}
|
|
81
64
|
|
|
82
|
-
const inputGroupButtonVariants = cva('
|
|
65
|
+
const inputGroupButtonVariants = cva('gap-2 text-sm shadow-none flex items-center', {
|
|
83
66
|
variants: {
|
|
84
67
|
size: {
|
|
85
|
-
xs: "h-6 gap-1 rounded-[calc(var(--radius)-
|
|
86
|
-
sm: '
|
|
87
|
-
'icon-xs': 'size-6 rounded-[calc(var(--radius)-
|
|
68
|
+
xs: "h-6 gap-1 rounded-[calc(var(--radius)-3px)] px-1.5 [&>svg:not([class*='size-'])]:size-3.5",
|
|
69
|
+
sm: '',
|
|
70
|
+
'icon-xs': 'size-6 rounded-[calc(var(--radius)-3px)] p-0 has-[>svg]:p-0',
|
|
88
71
|
'icon-sm': 'size-8 p-0 has-[>svg]:p-0'
|
|
89
72
|
}
|
|
90
73
|
},
|
|
@@ -116,7 +99,7 @@ function InputGroupText({ className, ...props }: React.ComponentProps<'span'>) {
|
|
|
116
99
|
return (
|
|
117
100
|
<span
|
|
118
101
|
className={cn(
|
|
119
|
-
"text-muted-foreground flex items-center gap-2 text-sm [&_svg:not([class*='size-'])]:size-4
|
|
102
|
+
"text-muted-foreground flex items-center gap-2 text-sm [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
|
|
120
103
|
className
|
|
121
104
|
)}
|
|
122
105
|
{...props}
|
|
@@ -129,7 +112,7 @@ function InputGroupInput({ className, ...props }: React.ComponentProps<'input'>)
|
|
|
129
112
|
<Input
|
|
130
113
|
data-slot="input-group-control"
|
|
131
114
|
className={cn(
|
|
132
|
-
'flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent',
|
|
115
|
+
'flex-1 rounded-none border-0 bg-transparent shadow-none ring-0 focus-visible:ring-0 disabled:bg-transparent aria-invalid:ring-0 dark:bg-transparent dark:disabled:bg-transparent',
|
|
133
116
|
className
|
|
134
117
|
)}
|
|
135
118
|
{...props}
|
|
@@ -142,7 +125,7 @@ function InputGroupTextarea({ className, ...props }: React.ComponentProps<'texta
|
|
|
142
125
|
<Textarea
|
|
143
126
|
data-slot="input-group-control"
|
|
144
127
|
className={cn(
|
|
145
|
-
'flex-1 resize-none rounded-none border-0 bg-transparent py-
|
|
128
|
+
'flex-1 resize-none rounded-none border-0 bg-transparent py-2 shadow-none ring-0 focus-visible:ring-0 disabled:bg-transparent aria-invalid:ring-0 dark:bg-transparent dark:disabled:bg-transparent',
|
|
146
129
|
className
|
|
147
130
|
)}
|
|
148
131
|
{...props}
|
|
@@ -5,43 +5,56 @@ import { OTPInput, OTPInputContext } from 'input-otp'
|
|
|
5
5
|
import { Minus } from 'lucide-react'
|
|
6
6
|
import * as React from 'react'
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
)
|
|
22
|
-
|
|
8
|
+
function InputOTP({
|
|
9
|
+
className,
|
|
10
|
+
containerClassName,
|
|
11
|
+
...props
|
|
12
|
+
}: React.ComponentProps<typeof OTPInput> & {
|
|
13
|
+
containerClassName?: string
|
|
14
|
+
}) {
|
|
15
|
+
return (
|
|
16
|
+
<OTPInput
|
|
17
|
+
data-slot="input-otp"
|
|
18
|
+
containerClassName={cn(
|
|
19
|
+
'cn-input-otp flex items-center has-disabled:opacity-50',
|
|
20
|
+
containerClassName
|
|
21
|
+
)}
|
|
22
|
+
spellCheck={false}
|
|
23
|
+
className={cn('disabled:cursor-not-allowed', className)}
|
|
24
|
+
{...props}
|
|
25
|
+
/>
|
|
26
|
+
)
|
|
27
|
+
}
|
|
23
28
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
function InputOTPGroup({ className, ...props }: React.ComponentProps<'div'>) {
|
|
30
|
+
return (
|
|
31
|
+
<div
|
|
32
|
+
data-slot="input-otp-group"
|
|
33
|
+
className={cn(
|
|
34
|
+
'has-aria-invalid:ring-destructive/20 dark:has-aria-invalid:ring-destructive/40 has-aria-invalid:border-destructive flex items-center rounded-lg has-aria-invalid:ring-3',
|
|
35
|
+
className
|
|
36
|
+
)}
|
|
37
|
+
{...props}
|
|
38
|
+
/>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
31
41
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
42
|
+
function InputOTPSlot({
|
|
43
|
+
index,
|
|
44
|
+
className,
|
|
45
|
+
...props
|
|
46
|
+
}: React.ComponentProps<'div'> & {
|
|
47
|
+
index: number
|
|
48
|
+
}) {
|
|
36
49
|
const inputOTPContext = React.useContext(OTPInputContext)
|
|
37
|
-
const { char, hasFakeCaret, isActive } = inputOTPContext
|
|
50
|
+
const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {}
|
|
38
51
|
|
|
39
52
|
return (
|
|
40
53
|
<div
|
|
41
|
-
|
|
54
|
+
data-slot="input-otp-slot"
|
|
55
|
+
data-active={isActive}
|
|
42
56
|
className={cn(
|
|
43
|
-
'relative flex
|
|
44
|
-
isActive && 'z-10 ring-1 ring-ring',
|
|
57
|
+
'dark:bg-input/30 border-input data-[active=true]:border-ring data-[active=true]:ring-ring/50 data-[active=true]:aria-invalid:ring-destructive/20 dark:data-[active=true]:aria-invalid:ring-destructive/40 aria-invalid:border-destructive data-[active=true]:aria-invalid:border-destructive relative flex size-8 items-center justify-center border-y border-r text-sm transition-all outline-none first:rounded-l-lg first:border-l last:rounded-r-lg data-[active=true]:z-10 data-[active=true]:ring-3',
|
|
45
58
|
className
|
|
46
59
|
)}
|
|
47
60
|
{...props}
|
|
@@ -49,22 +62,24 @@ const InputOTPSlot = React.forwardRef<
|
|
|
49
62
|
{char}
|
|
50
63
|
{hasFakeCaret && (
|
|
51
64
|
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
|
|
52
|
-
<div className="
|
|
65
|
+
<div className="animate-caret-blink bg-foreground h-4 w-px duration-1000" />
|
|
53
66
|
</div>
|
|
54
67
|
)}
|
|
55
68
|
</div>
|
|
56
69
|
)
|
|
57
|
-
}
|
|
58
|
-
InputOTPSlot.displayName = 'InputOTPSlot'
|
|
70
|
+
}
|
|
59
71
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
72
|
+
function InputOTPSeparator({ ...props }: React.ComponentProps<'div'>) {
|
|
73
|
+
return (
|
|
74
|
+
<div
|
|
75
|
+
data-slot="input-otp-separator"
|
|
76
|
+
className="flex items-center [&_svg:not([class*='size-'])]:size-4"
|
|
77
|
+
role="separator"
|
|
78
|
+
{...props}
|
|
79
|
+
>
|
|
80
|
+
<Minus />
|
|
81
|
+
</div>
|
|
82
|
+
)
|
|
83
|
+
}
|
|
69
84
|
|
|
70
85
|
export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator }
|
package/templates/ui/input.tsx
CHANGED
|
@@ -1,21 +1,18 @@
|
|
|
1
1
|
import { cn } from '@cms/utils/cn'
|
|
2
|
-
import * as React from 'react'
|
|
2
|
+
import type * as React from 'react'
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
(
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
)
|
|
19
|
-
Input.displayName = 'Input'
|
|
4
|
+
function Input({ className, type, ...props }: React.ComponentProps<'input'>) {
|
|
5
|
+
return (
|
|
6
|
+
<input
|
|
7
|
+
type={type}
|
|
8
|
+
data-slot="input"
|
|
9
|
+
className={cn(
|
|
10
|
+
'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 disabled:bg-input/50 dark:disabled:bg-input/80 file:text-foreground placeholder:text-muted-foreground h-8 w-full min-w-0 rounded-lg border bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:ring-3 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:ring-3 md:text-sm',
|
|
11
|
+
className
|
|
12
|
+
)}
|
|
13
|
+
{...props}
|
|
14
|
+
/>
|
|
15
|
+
)
|
|
16
|
+
}
|
|
20
17
|
|
|
21
18
|
export { Input }
|
package/templates/ui/item.tsx
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
|
+
import { Separator } from '@cms/components/ui/separator'
|
|
1
2
|
import { cn } from '@cms/utils/cn'
|
|
2
|
-
import { Slot } from '@radix-ui/react-slot'
|
|
3
3
|
import { cva, type VariantProps } from 'class-variance-authority'
|
|
4
|
+
import { Slot } from 'radix-ui'
|
|
4
5
|
import type * as React from 'react'
|
|
5
|
-
import { Separator } from './separator'
|
|
6
6
|
|
|
7
7
|
function ItemGroup({ className, ...props }: React.ComponentProps<'div'>) {
|
|
8
8
|
return (
|
|
9
9
|
<div
|
|
10
10
|
role="list"
|
|
11
11
|
data-slot="item-group"
|
|
12
|
-
className={cn(
|
|
12
|
+
className={cn(
|
|
13
|
+
'group/item-group flex w-full flex-col gap-4 has-data-[size=sm]:gap-2.5 has-data-[size=xs]:gap-2',
|
|
14
|
+
className
|
|
15
|
+
)}
|
|
13
16
|
{...props}
|
|
14
17
|
/>
|
|
15
18
|
)
|
|
@@ -20,24 +23,25 @@ function ItemSeparator({ className, ...props }: React.ComponentProps<typeof Sepa
|
|
|
20
23
|
<Separator
|
|
21
24
|
data-slot="item-separator"
|
|
22
25
|
orientation="horizontal"
|
|
23
|
-
className={cn('my-
|
|
26
|
+
className={cn('my-2', className)}
|
|
24
27
|
{...props}
|
|
25
28
|
/>
|
|
26
29
|
)
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
const itemVariants = cva(
|
|
30
|
-
'
|
|
33
|
+
'[a]:hover:bg-muted rounded-lg border text-sm w-full group/item focus-visible:border-ring focus-visible:ring-ring/50 flex items-center flex-wrap outline-none transition-colors duration-100 focus-visible:ring-[3px] [a]:transition-colors',
|
|
31
34
|
{
|
|
32
35
|
variants: {
|
|
33
36
|
variant: {
|
|
34
|
-
default: '
|
|
37
|
+
default: 'border-transparent',
|
|
35
38
|
outline: 'border-border',
|
|
36
|
-
muted: 'bg-muted/50'
|
|
39
|
+
muted: 'bg-muted/50 border-transparent'
|
|
37
40
|
},
|
|
38
41
|
size: {
|
|
39
|
-
default: 'gap-
|
|
40
|
-
sm: 'gap-2.5 px-
|
|
42
|
+
default: 'gap-2.5 px-3 py-2.5',
|
|
43
|
+
sm: 'gap-2.5 px-3 py-2.5',
|
|
44
|
+
xs: 'gap-2 px-2.5 py-2 in-data-[slot=dropdown-menu-content]:p-0'
|
|
41
45
|
}
|
|
42
46
|
},
|
|
43
47
|
defaultVariants: {
|
|
@@ -54,7 +58,7 @@ function Item({
|
|
|
54
58
|
asChild = false,
|
|
55
59
|
...props
|
|
56
60
|
}: React.ComponentProps<'div'> & VariantProps<typeof itemVariants> & { asChild?: boolean }) {
|
|
57
|
-
const Comp = asChild ? Slot : 'div'
|
|
61
|
+
const Comp = asChild ? Slot.Root : 'div'
|
|
58
62
|
return (
|
|
59
63
|
<Comp
|
|
60
64
|
data-slot="item"
|
|
@@ -67,13 +71,14 @@ function Item({
|
|
|
67
71
|
}
|
|
68
72
|
|
|
69
73
|
const itemMediaVariants = cva(
|
|
70
|
-
'
|
|
74
|
+
'gap-2 group-has-data-[slot=item-description]/item:translate-y-0.5 group-has-data-[slot=item-description]/item:self-start flex shrink-0 items-center justify-center [&_svg]:pointer-events-none',
|
|
71
75
|
{
|
|
72
76
|
variants: {
|
|
73
77
|
variant: {
|
|
74
78
|
default: 'bg-transparent',
|
|
75
|
-
icon: "
|
|
76
|
-
image:
|
|
79
|
+
icon: "[&_svg:not([class*='size-'])]:size-4",
|
|
80
|
+
image:
|
|
81
|
+
'size-10 overflow-hidden rounded-sm group-data-[size=sm]/item:size-8 group-data-[size=xs]/item:size-6 [&_img]:size-full [&_img]:object-cover'
|
|
77
82
|
}
|
|
78
83
|
},
|
|
79
84
|
defaultVariants: {
|
|
@@ -101,7 +106,10 @@ function ItemContent({ className, ...props }: React.ComponentProps<'div'>) {
|
|
|
101
106
|
return (
|
|
102
107
|
<div
|
|
103
108
|
data-slot="item-content"
|
|
104
|
-
className={cn(
|
|
109
|
+
className={cn(
|
|
110
|
+
'flex flex-1 flex-col gap-1 group-data-[size=xs]/item:gap-0 [&+[data-slot=item-content]]:flex-none',
|
|
111
|
+
className
|
|
112
|
+
)}
|
|
105
113
|
{...props}
|
|
106
114
|
/>
|
|
107
115
|
)
|
|
@@ -111,7 +119,10 @@ function ItemTitle({ className, ...props }: React.ComponentProps<'div'>) {
|
|
|
111
119
|
return (
|
|
112
120
|
<div
|
|
113
121
|
data-slot="item-title"
|
|
114
|
-
className={cn(
|
|
122
|
+
className={cn(
|
|
123
|
+
'line-clamp-1 flex w-fit items-center gap-2 text-sm leading-snug font-medium underline-offset-4',
|
|
124
|
+
className
|
|
125
|
+
)}
|
|
115
126
|
{...props}
|
|
116
127
|
/>
|
|
117
128
|
)
|
|
@@ -122,8 +133,7 @@ function ItemDescription({ className, ...props }: React.ComponentProps<'p'>) {
|
|
|
122
133
|
<p
|
|
123
134
|
data-slot="item-description"
|
|
124
135
|
className={cn(
|
|
125
|
-
'text-muted-foreground line-clamp-2 text-sm font-normal
|
|
126
|
-
'[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4',
|
|
136
|
+
'text-muted-foreground [&>a:hover]:text-primary line-clamp-2 text-left text-sm leading-normal font-normal group-data-[size=xs]/item:text-xs [&>a]:underline [&>a]:underline-offset-4',
|
|
127
137
|
className
|
|
128
138
|
)}
|
|
129
139
|
{...props}
|
package/templates/ui/kbd.tsx
CHANGED
|
@@ -5,9 +5,7 @@ function Kbd({ className, ...props }: React.ComponentProps<'kbd'>) {
|
|
|
5
5
|
<kbd
|
|
6
6
|
data-slot="kbd"
|
|
7
7
|
className={cn(
|
|
8
|
-
|
|
9
|
-
"[&_svg:not([class*='size-'])]:size-3",
|
|
10
|
-
'[[data-slot=tooltip-content]_&]:bg-background/20 [[data-slot=tooltip-content]_&]:text-background dark:[[data-slot=tooltip-content]_&]:bg-background/10',
|
|
8
|
+
"bg-muted text-muted-foreground in-data-[slot=tooltip-content]:bg-background/20 in-data-[slot=tooltip-content]:text-background dark:in-data-[slot=tooltip-content]:bg-background/10 pointer-events-none inline-flex h-5 w-fit min-w-5 items-center justify-center gap-1 rounded-sm px-1 font-sans text-xs font-medium select-none [&_svg:not([class*='size-'])]:size-3",
|
|
11
9
|
className
|
|
12
10
|
)}
|
|
13
11
|
{...props}
|