@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.
Files changed (65) hide show
  1. package/dist/{chunk-SAPJG4NO.js → chunk-6JCWMKSY.js} +7 -4
  2. package/dist/{chunk-SAPJG4NO.js.map → chunk-6JCWMKSY.js.map} +1 -1
  3. package/dist/cli.js +749 -866
  4. package/dist/cli.js.map +1 -1
  5. package/dist/drizzle-config-EDKOEZ6G.js +7 -0
  6. package/package.json +1 -1
  7. package/templates/ui/accordion.tsx +73 -42
  8. package/templates/ui/alert-dialog.tsx +155 -90
  9. package/templates/ui/alert.tsx +46 -26
  10. package/templates/ui/aspect-ratio.tsx +4 -2
  11. package/templates/ui/avatar.tsx +92 -43
  12. package/templates/ui/badge.tsx +27 -12
  13. package/templates/ui/breadcrumb.tsx +63 -60
  14. package/templates/ui/button-group.tsx +8 -8
  15. package/templates/ui/button.tsx +44 -26
  16. package/templates/ui/calendar.tsx +43 -34
  17. package/templates/ui/card.tsx +71 -34
  18. package/templates/ui/carousel.tsx +111 -115
  19. package/templates/ui/chart.tsx +197 -207
  20. package/templates/ui/checkbox.tsx +21 -20
  21. package/templates/ui/collapsible.tsx +14 -4
  22. package/templates/ui/combobox.tsx +272 -0
  23. package/templates/ui/command.tsx +139 -101
  24. package/templates/ui/context-menu.tsx +214 -156
  25. package/templates/ui/dialog.tsx +118 -77
  26. package/templates/ui/direction.tsx +20 -0
  27. package/templates/ui/drawer.tsx +89 -69
  28. package/templates/ui/dropdown-menu.tsx +228 -164
  29. package/templates/ui/empty.tsx +8 -5
  30. package/templates/ui/field.tsx +25 -32
  31. package/templates/ui/hover-card.tsx +29 -20
  32. package/templates/ui/input-group.tsx +20 -37
  33. package/templates/ui/input-otp.tsx +57 -42
  34. package/templates/ui/input.tsx +14 -17
  35. package/templates/ui/item.tsx +27 -17
  36. package/templates/ui/kbd.tsx +1 -3
  37. package/templates/ui/label.tsx +14 -14
  38. package/templates/ui/markdown-editor.tsx +1 -1
  39. package/templates/ui/menubar.tsx +220 -188
  40. package/templates/ui/native-select.tsx +42 -0
  41. package/templates/ui/navigation-menu.tsx +130 -90
  42. package/templates/ui/pagination.tsx +88 -73
  43. package/templates/ui/popover.tsx +67 -26
  44. package/templates/ui/progress.tsx +24 -18
  45. package/templates/ui/radio-group.tsx +26 -20
  46. package/templates/ui/resizable.tsx +29 -29
  47. package/templates/ui/scroll-area.tsx +47 -38
  48. package/templates/ui/select.tsx +158 -125
  49. package/templates/ui/separator.tsx +21 -19
  50. package/templates/ui/sheet.tsx +104 -95
  51. package/templates/ui/sidebar.tsx +77 -183
  52. package/templates/ui/skeleton.tsx +8 -2
  53. package/templates/ui/slider.tsx +46 -17
  54. package/templates/ui/sonner.tsx +19 -9
  55. package/templates/ui/spinner.tsx +2 -2
  56. package/templates/ui/switch.tsx +24 -20
  57. package/templates/ui/table.tsx +68 -73
  58. package/templates/ui/tabs.tsx +71 -46
  59. package/templates/ui/textarea.tsx +13 -16
  60. package/templates/ui/toggle-group.tsx +57 -28
  61. package/templates/ui/toggle.tsx +21 -20
  62. package/templates/ui/tooltip.tsx +44 -23
  63. package/dist/drizzle-config-KISB26BA.js +0 -7
  64. package/templates/ui/use-mobile.tsx +0 -19
  65. /package/dist/{drizzle-config-KISB26BA.js.map → drizzle-config-EDKOEZ6G.js.map} +0 -0
@@ -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-6',
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-3 font-medium',
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-7 data-[slot=checkbox-group]:gap-3 [&>[data-slot=field-group]]:gap-4',
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('group/field data-[invalid=true]:text-destructive flex w-full gap-3', {
54
+ const fieldVariants = cva('data-[invalid=true]:text-destructive gap-2 group/field flex w-full', {
57
55
  variants: {
58
56
  orientation: {
59
- vertical: ['flex-col [&>*]:w-full [&>.sr-only]:w-auto'],
60
- horizontal: [
61
- 'flex-row items-center',
62
- '[&>[data-slot=field-label]]:flex-auto',
63
- 'has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px has-[>[data-slot=field-content]]:items-start'
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-1.5 leading-snug', className)}
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 has-[>[data-slot=field]]:rounded-md has-[>[data-slot=field]]:border [&>[data-slot=field]]:p-4',
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 leading-snug group-data-[disabled=true]/field:opacity-50',
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 leading-normal',
137
- 'nth-last-2:-mt-1 last:mt-0 [[data-variant=legend]+&]:-mt-1.5',
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="bg-background text-muted-foreground relative mx-auto block w-fit px-2"
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
- if (errors?.length === 1 && errors[0]?.message) {
194
- return errors[0].message
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
- {errors.map((error, index) => error?.message && <li key={index}>{error.message}</li>)}
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 * as HoverCardPrimitive from '@radix-ui/react-hover-card'
5
- import * as React from 'react'
4
+ import { HoverCard as HoverCardPrimitive } from 'radix-ui'
5
+ import type * as React from 'react'
6
6
 
7
- const HoverCard = HoverCardPrimitive.Root
7
+ function HoverCard({ ...props }: React.ComponentProps<typeof HoverCardPrimitive.Root>) {
8
+ return <HoverCardPrimitive.Root data-slot="hover-card" {...props} />
9
+ }
8
10
 
9
- const HoverCardTrigger = HoverCardPrimitive.Trigger
11
+ function HoverCardTrigger({ ...props }: React.ComponentProps<typeof HoverCardPrimitive.Trigger>) {
12
+ return <HoverCardPrimitive.Trigger data-slot="hover-card-trigger" {...props} />
13
+ }
10
14
 
11
- const HoverCardContent = React.forwardRef<
12
- React.ElementRef<typeof HoverCardPrimitive.Content>,
13
- React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Content>
14
- >(({ className, align = 'center', sideOffset = 4, ...props }, ref) => (
15
- <HoverCardPrimitive.Content
16
- ref={ref}
17
- align={align}
18
- sideOffset={sideOffset}
19
- className={cn(
20
- '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 origin-[--radix-hover-card-content-transform-origin]',
21
- className
22
- )}
23
- {...props}
24
- />
25
- ))
26
- HoverCardContent.displayName = HoverCardPrimitive.Content.displayName
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
- 'group/input-group border-input-border dark:bg-input/30 shadow-xs relative flex w-full items-center rounded-md border outline-none transition-[color,box-shadow]',
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 flex h-auto cursor-text select-none items-center justify-center 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",
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': 'order-first pl-3 has-[>button]:ml-[-0.45rem] has-[>kbd]:ml-[-0.35rem]',
44
- 'inline-end': 'order-last pr-3 has-[>button]:mr-[-0.4rem] has-[>kbd]:mr-[-0.35rem]',
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
- '[.border-b]:pb-3 order-first w-full justify-start px-3 pt-3 group-has-[>input]/input-group:pt-2.5',
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
- '[.border-t]:pt-3 order-last w-full justify-start px-3 pb-3 group-has-[>input]/input-group:pb-2.5'
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
- // Focus input when clicking addon area (but not buttons inside)
72
- if (!(e.target as HTMLElement).closest('button')) {
73
- e.currentTarget.parentElement?.querySelector('input')?.focus()
55
+ if ((e.target as HTMLElement).closest('button')) {
56
+ return
74
57
  }
75
- onClick?.(e)
58
+ e.currentTarget.parentElement?.querySelector('input')?.focus()
76
59
  }}
77
60
  {...props}
78
61
  />
79
62
  )
80
63
  }
81
64
 
82
- const inputGroupButtonVariants = cva('flex items-center gap-2 text-sm shadow-none', {
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)-5px)] px-2 has-[>svg]:px-2 [&>svg:not([class*='size-'])]:size-3.5",
86
- sm: 'h-8 gap-1.5 rounded-md px-2.5 has-[>svg]:px-2.5',
87
- 'icon-xs': 'size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0',
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 [&_svg]:pointer-events-none",
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-3 shadow-none focus-visible:ring-0 dark:bg-transparent',
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
- const InputOTP = React.forwardRef<
9
- React.ElementRef<typeof OTPInput>,
10
- React.ComponentPropsWithoutRef<typeof OTPInput>
11
- >(({ className, containerClassName, ...props }, ref) => (
12
- <OTPInput
13
- ref={ref}
14
- containerClassName={cn(
15
- 'flex items-center gap-2 has-[:disabled]:opacity-50',
16
- containerClassName
17
- )}
18
- className={cn('disabled:cursor-not-allowed', className)}
19
- {...props}
20
- />
21
- ))
22
- InputOTP.displayName = 'InputOTP'
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
- const InputOTPGroup = React.forwardRef<
25
- React.ElementRef<'div'>,
26
- React.ComponentPropsWithoutRef<'div'>
27
- >(({ className, ...props }, ref) => (
28
- <div ref={ref} className={cn('flex items-center', className)} {...props} />
29
- ))
30
- InputOTPGroup.displayName = 'InputOTPGroup'
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
- const InputOTPSlot = React.forwardRef<
33
- React.ElementRef<'div'>,
34
- React.ComponentPropsWithoutRef<'div'> & { index: number }
35
- >(({ index, className, ...props }, ref) => {
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.slots[index]
50
+ const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {}
38
51
 
39
52
  return (
40
53
  <div
41
- ref={ref}
54
+ data-slot="input-otp-slot"
55
+ data-active={isActive}
42
56
  className={cn(
43
- 'relative flex h-9 w-9 items-center justify-center border-y border-r border-input-border text-sm shadow-sm transition-all first:rounded-l-md first:border-l last:rounded-r-md',
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="h-4 w-px animate-caret-blink bg-foreground duration-1000" />
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
- const InputOTPSeparator = React.forwardRef<
61
- React.ElementRef<'div'>,
62
- React.ComponentPropsWithoutRef<'div'>
63
- >(({ ...props }, ref) => (
64
- <div ref={ref} role="presentation" aria-hidden="true" {...props}>
65
- <Minus />
66
- </div>
67
- ))
68
- InputOTPSeparator.displayName = 'InputOTPSeparator'
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 }
@@ -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
- const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<'input'>>(
5
- ({ className, type, ...props }, ref) => {
6
- return (
7
- <input
8
- type={type}
9
- className={cn(
10
- 'flex h-9 w-full rounded-md border border-input-border-border bg-input px-3 py-1 text-base transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
11
- className
12
- )}
13
- ref={ref}
14
- {...props}
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 }
@@ -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('group/item-group flex flex-col', className)}
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-0', className)}
26
+ className={cn('my-2', className)}
24
27
  {...props}
25
28
  />
26
29
  )
27
30
  }
28
31
 
29
32
  const itemVariants = cva(
30
- 'group/item [a]:hover:bg-accent/50 focus-visible:border-ring focus-visible:ring-ring/50 [a]:transition-colors flex flex-wrap items-center rounded-md border border-transparent text-sm outline-none transition-colors duration-100 focus-visible:ring-[3px]',
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: 'bg-transparent',
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-4 p-4 ',
40
- sm: 'gap-2.5 px-4 py-3'
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
- 'flex shrink-0 items-center justify-center gap-2 group-has-[[data-slot=item-description]]/item:translate-y-0.5 group-has-[[data-slot=item-description]]/item:self-start [&_svg]:pointer-events-none',
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: "bg-muted size-8 rounded-sm border [&_svg:not([class*='size-'])]:size-4",
76
- image: 'size-10 overflow-hidden rounded-sm [&_img]:size-full [&_img]:object-cover'
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('flex flex-1 flex-col gap-1 [&+[data-slot=item-content]]:flex-none', className)}
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('flex w-fit items-center gap-2 text-sm font-medium leading-snug', className)}
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 leading-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}
@@ -5,9 +5,7 @@ function Kbd({ className, ...props }: React.ComponentProps<'kbd'>) {
5
5
  <kbd
6
6
  data-slot="kbd"
7
7
  className={cn(
8
- 'bg-muted text-muted-foreground pointer-events-none inline-flex h-5 w-fit min-w-5 select-none items-center justify-center gap-1 rounded-sm px-1 font-sans text-xs font-medium',
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}