@mostrom/app-shell 0.1.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 (142) hide show
  1. package/.claude/ralph-loop.local.md +9 -0
  2. package/README.md +172 -0
  3. package/bin/init.js +269 -0
  4. package/bun.lock +401 -0
  5. package/components.json +28 -0
  6. package/package.json +74 -0
  7. package/scripts/publish-npm.sh +202 -0
  8. package/src/AppShell.tsx +847 -0
  9. package/src/components/PageHeader.tsx +160 -0
  10. package/src/components/data-table/README.md +447 -0
  11. package/src/components/data-table/data-table-preferences.tsx +184 -0
  12. package/src/components/data-table/data-table-toolbar.tsx +118 -0
  13. package/src/components/data-table/data-table.tsx +37 -0
  14. package/src/components/data-table/index.ts +32 -0
  15. package/src/components/global-header/AllServicesButton.tsx +127 -0
  16. package/src/components/global-header/CategoriesButton.tsx +120 -0
  17. package/src/components/global-header/GlobalHeader.tsx +59 -0
  18. package/src/components/global-header/GlobalHeaderSearch.tsx +57 -0
  19. package/src/components/global-header/HeaderUtilities.tsx +243 -0
  20. package/src/components/global-header/ServicesMenu.tsx +246 -0
  21. package/src/components/layout/AppBreadcrumb.tsx +70 -0
  22. package/src/components/layout/AppFlashbar.tsx +95 -0
  23. package/src/components/layout/AppLayout.tsx +271 -0
  24. package/src/components/layout/AppNavigation.tsx +313 -0
  25. package/src/components/layout/AppSidebar.tsx +229 -0
  26. package/src/components/patterns/index.ts +14 -0
  27. package/src/components/patterns/p-alert-5.tsx +19 -0
  28. package/src/components/patterns/p-autocomplete-5.tsx +89 -0
  29. package/src/components/patterns/p-breadcrumb-1.tsx +28 -0
  30. package/src/components/patterns/p-button-42.tsx +37 -0
  31. package/src/components/patterns/p-button-51.tsx +14 -0
  32. package/src/components/patterns/p-button-6.tsx +5 -0
  33. package/src/components/patterns/p-calendar-1.tsx +18 -0
  34. package/src/components/patterns/p-card-1.tsx +33 -0
  35. package/src/components/patterns/p-card-2.tsx +26 -0
  36. package/src/components/patterns/p-card-5.tsx +31 -0
  37. package/src/components/patterns/p-collapsible-7.tsx +121 -0
  38. package/src/components/patterns/p-command-6.tsx +113 -0
  39. package/src/components/patterns/p-dialog-1.tsx +56 -0
  40. package/src/components/patterns/p-dropdown-menu-1.tsx +38 -0
  41. package/src/components/patterns/p-dropdown-menu-11.tsx +122 -0
  42. package/src/components/patterns/p-dropdown-menu-14.tsx +165 -0
  43. package/src/components/patterns/p-dropdown-menu-9.tsx +108 -0
  44. package/src/components/patterns/p-empty-2.tsx +34 -0
  45. package/src/components/patterns/p-file-upload-1.tsx +72 -0
  46. package/src/components/patterns/p-filters-1.tsx +666 -0
  47. package/src/components/patterns/p-frame-2.tsx +26 -0
  48. package/src/components/patterns/p-tabs-2.tsx +129 -0
  49. package/src/components/reui/alert.tsx +92 -0
  50. package/src/components/reui/autocomplete.tsx +343 -0
  51. package/src/components/reui/badge.tsx +87 -0
  52. package/src/components/reui/data-grid/data-grid-column-filter.tsx +165 -0
  53. package/src/components/reui/data-grid/data-grid-column-header.tsx +339 -0
  54. package/src/components/reui/data-grid/data-grid-column-visibility.tsx +55 -0
  55. package/src/components/reui/data-grid/data-grid-pagination.tsx +224 -0
  56. package/src/components/reui/data-grid/data-grid-table-dnd-rows.tsx +260 -0
  57. package/src/components/reui/data-grid/data-grid-table-dnd.tsx +253 -0
  58. package/src/components/reui/data-grid/data-grid-table.tsx +639 -0
  59. package/src/components/reui/data-grid/data-grid.tsx +209 -0
  60. package/src/components/reui/date-selector.tsx +1330 -0
  61. package/src/components/reui/filters.tsx +1869 -0
  62. package/src/components/reui/frame.tsx +134 -0
  63. package/src/components/reui/index.ts +17 -0
  64. package/src/components/reui/timeline.tsx +219 -0
  65. package/src/components/search/Autocomplete.tsx +183 -0
  66. package/src/components/search/AutocompleteClient.tsx +293 -0
  67. package/src/components/search/GlobalSearch.tsx +187 -0
  68. package/src/components/section-drawer/deal-drawer-content.tsx +891 -0
  69. package/src/components/section-drawer/index.ts +19 -0
  70. package/src/components/section-drawer/section-drawer.css +665 -0
  71. package/src/components/section-drawer/section-drawer.tsx +467 -0
  72. package/src/components/sectioned-list-board/README.md +78 -0
  73. package/src/components/sectioned-list-board/board-card-content.tsx +340 -0
  74. package/src/components/sectioned-list-board/date-range-filter.tsx +249 -0
  75. package/src/components/sectioned-list-board/index.ts +19 -0
  76. package/src/components/sectioned-list-board/sectioned-list-board.css +564 -0
  77. package/src/components/sectioned-list-board/sectioned-list-board.tsx +731 -0
  78. package/src/components/sectioned-list-board/sortable-card.tsx +314 -0
  79. package/src/components/sectioned-list-board/sortable-section.tsx +319 -0
  80. package/src/components/sectioned-list-board/types.ts +216 -0
  81. package/src/components/sectioned-list-table/README.md +80 -0
  82. package/src/components/sectioned-list-table/index.ts +14 -0
  83. package/src/components/sectioned-list-table/sectioned-list-table.css +534 -0
  84. package/src/components/sectioned-list-table/sectioned-list-table.tsx +740 -0
  85. package/src/components/sectioned-list-table/sortable-column-header.tsx +120 -0
  86. package/src/components/sectioned-list-table/sortable-row.tsx +420 -0
  87. package/src/components/sectioned-list-table/sortable-section.tsx +251 -0
  88. package/src/components/sectioned-list-table/table-cell-content.tsx +129 -0
  89. package/src/components/sectioned-list-table/types.ts +120 -0
  90. package/src/components/sectioned-list-table/use-column-preferences.ts +103 -0
  91. package/src/components/ui/actions-dropdown.tsx +109 -0
  92. package/src/components/ui/assignee-selector.tsx +209 -0
  93. package/src/components/ui/avatar.tsx +107 -0
  94. package/src/components/ui/breadcrumb.tsx +109 -0
  95. package/src/components/ui/button-group.tsx +83 -0
  96. package/src/components/ui/button.tsx +64 -0
  97. package/src/components/ui/calendar.tsx +220 -0
  98. package/src/components/ui/card.tsx +92 -0
  99. package/src/components/ui/chart.tsx +376 -0
  100. package/src/components/ui/checkbox.tsx +30 -0
  101. package/src/components/ui/collapsible.tsx +33 -0
  102. package/src/components/ui/command.tsx +182 -0
  103. package/src/components/ui/context-menu.tsx +250 -0
  104. package/src/components/ui/create-button-group.tsx +128 -0
  105. package/src/components/ui/dialog.tsx +156 -0
  106. package/src/components/ui/drawer.tsx +133 -0
  107. package/src/components/ui/dropdown-menu.tsx +255 -0
  108. package/src/components/ui/empty.tsx +104 -0
  109. package/src/components/ui/field.tsx +248 -0
  110. package/src/components/ui/form.tsx +165 -0
  111. package/src/components/ui/index.ts +37 -0
  112. package/src/components/ui/input-group.tsx +168 -0
  113. package/src/components/ui/input.tsx +21 -0
  114. package/src/components/ui/kbd.tsx +28 -0
  115. package/src/components/ui/label.tsx +22 -0
  116. package/src/components/ui/navigation-menu.tsx +168 -0
  117. package/src/components/ui/page-header.tsx +80 -0
  118. package/src/components/ui/popover.tsx +87 -0
  119. package/src/components/ui/scroll-area.tsx +56 -0
  120. package/src/components/ui/select.tsx +190 -0
  121. package/src/components/ui/separator.tsx +26 -0
  122. package/src/components/ui/sheet.tsx +141 -0
  123. package/src/components/ui/sidebar.tsx +726 -0
  124. package/src/components/ui/skeleton.tsx +13 -0
  125. package/src/components/ui/sonner.tsx +38 -0
  126. package/src/components/ui/switch.tsx +33 -0
  127. package/src/components/ui/tabs.tsx +91 -0
  128. package/src/components/ui/textarea.tsx +18 -0
  129. package/src/components/ui/toggle-group.tsx +83 -0
  130. package/src/components/ui/toggle.tsx +45 -0
  131. package/src/components/ui/tooltip.tsx +57 -0
  132. package/src/hooks/use-copy-to-clipboard.ts +37 -0
  133. package/src/hooks/use-file-upload.ts +415 -0
  134. package/src/hooks/use-mobile.ts +19 -0
  135. package/src/index.ts +95 -0
  136. package/src/lib/utils.ts +6 -0
  137. package/src/styles.css +1859 -0
  138. package/src/urls.ts +83 -0
  139. package/src/vite.d.ts +22 -0
  140. package/src/vite.js +241 -0
  141. package/tsconfig.base.json +18 -0
  142. package/tsconfig.json +24 -0
@@ -0,0 +1,129 @@
1
+ import { Button } from "@/components/ui/button"
2
+ import {
3
+ Card,
4
+ CardContent,
5
+ CardDescription,
6
+ CardFooter,
7
+ CardHeader,
8
+ CardTitle,
9
+ } from "@/components/ui/card"
10
+ import { Input } from "@/components/ui/input"
11
+ import { Label } from "@/components/ui/label"
12
+ import {
13
+ Tabs,
14
+ TabsContent,
15
+ TabsList,
16
+ TabsTrigger,
17
+ } from "@/components/ui/tabs"
18
+
19
+ export function Pattern() {
20
+ return (
21
+ <div className="flex w-full max-w-xs flex-col gap-6">
22
+ <Tabs defaultValue="account">
23
+ <TabsList variant="line" className="mb-3.5 w-full">
24
+ <TabsTrigger value="account">Account</TabsTrigger>
25
+ <TabsTrigger value="password">Password</TabsTrigger>
26
+ <TabsTrigger value="settings">Settings</TabsTrigger>
27
+ </TabsList>
28
+ <TabsContent value="account">
29
+ <Card>
30
+ <CardHeader className="pb-3">
31
+ <CardTitle className="text-base">Account</CardTitle>
32
+ <CardDescription className="text-sm">
33
+ Update your account information.
34
+ </CardDescription>
35
+ </CardHeader>
36
+ <CardContent className="space-y-4">
37
+ <div className="space-y-2">
38
+ <Label htmlFor="underline-name" className="text-sm">
39
+ Name
40
+ </Label>
41
+ <Input
42
+ id="underline-name"
43
+ defaultValue="Alex Chen"
44
+ className="h-9"
45
+ />
46
+ </div>
47
+ <div className="space-y-2">
48
+ <Label htmlFor="underline-email" className="text-sm">
49
+ Email
50
+ </Label>
51
+ <Input
52
+ id="underline-email"
53
+ type="email"
54
+ defaultValue="alex.chen@example.com"
55
+ className="h-9"
56
+ />
57
+ </div>
58
+ </CardContent>
59
+ <CardFooter className="pt-3">
60
+ <Button size="sm">Save changes</Button>
61
+ </CardFooter>
62
+ </Card>
63
+ </TabsContent>
64
+ <TabsContent value="password">
65
+ <Card>
66
+ <CardHeader className="pb-3">
67
+ <CardTitle className="text-base">Password</CardTitle>
68
+ <CardDescription className="text-sm">
69
+ Change your password here.
70
+ </CardDescription>
71
+ </CardHeader>
72
+ <CardContent className="space-y-4">
73
+ <div className="space-y-2">
74
+ <Label htmlFor="underline-current" className="text-sm">
75
+ Current password
76
+ </Label>
77
+ <Input id="underline-current" type="password" className="h-9" />
78
+ </div>
79
+ <div className="space-y-2">
80
+ <Label htmlFor="underline-new" className="text-sm">
81
+ New password
82
+ </Label>
83
+ <Input id="underline-new" type="password" className="h-9" />
84
+ </div>
85
+ </CardContent>
86
+ <CardFooter className="pt-3">
87
+ <Button size="sm">Update password</Button>
88
+ </CardFooter>
89
+ </Card>
90
+ </TabsContent>
91
+ <TabsContent value="settings">
92
+ <Card>
93
+ <CardHeader className="pb-3">
94
+ <CardTitle className="text-base">Settings</CardTitle>
95
+ <CardDescription className="text-sm">
96
+ Manage your preferences.
97
+ </CardDescription>
98
+ </CardHeader>
99
+ <CardContent className="space-y-4">
100
+ <div className="space-y-2">
101
+ <Label htmlFor="underline-theme" className="text-sm">
102
+ Theme
103
+ </Label>
104
+ <Input
105
+ id="underline-theme"
106
+ defaultValue="Light"
107
+ className="h-9"
108
+ />
109
+ </div>
110
+ <div className="space-y-2">
111
+ <Label htmlFor="underline-language" className="text-sm">
112
+ Language
113
+ </Label>
114
+ <Input
115
+ id="underline-language"
116
+ defaultValue="English"
117
+ className="h-9"
118
+ />
119
+ </div>
120
+ </CardContent>
121
+ <CardFooter className="pt-3">
122
+ <Button size="sm">Save settings</Button>
123
+ </CardFooter>
124
+ </Card>
125
+ </TabsContent>
126
+ </Tabs>
127
+ </div>
128
+ )
129
+ }
@@ -0,0 +1,92 @@
1
+ import { cva, type VariantProps } from "class-variance-authority"
2
+
3
+ import { cn } from "@/lib/utils"
4
+
5
+ const alertVariants = cva(
6
+ [
7
+ "relative w-full text-sm border has-[>svg]:grid-cols-[calc(var(--spacing)*3)_1fr] grid-cols-[0_1fr] grid gap-y-0.5 items-center [&>svg:not([class*=size-])]:size-4",
8
+ "has-[>[data-slot=alert-title]+[data-slot=alert-description]]:[&_[data-slot=alert-action]]:sm:row-end-3",
9
+ "has-[>[data-slot=alert-title]+[data-slot=alert-description]]:items-start",
10
+ "has-[>[data-slot=alert-title]+[data-slot=alert-description]]:[&_svg]:translate-y-0.5",
11
+ "rounded-lg",
12
+ "px-3",
13
+ "py-2.5",
14
+ "has-[>svg]:gap-x-2.5",
15
+ ],
16
+ {
17
+ variants: {
18
+ variant: {
19
+ default: "bg-card text-card-foreground",
20
+ destructive:
21
+ "border-destructive/30 bg-destructive/4 [&>svg]:text-destructive",
22
+ info: "border-info/30 bg-info/4 [&>svg]:text-info",
23
+ success: "border-success/30 bg-success/4 [&>svg]:text-success",
24
+ warning: "border-warning/30 bg-warning/4 [&>svg]:text-warning",
25
+ invert:
26
+ "border-invert bg-invert text-invert-foreground [&_[data-slot=alert-description]]:text-invert-foreground/70",
27
+ },
28
+ },
29
+ defaultVariants: {
30
+ variant: "default",
31
+ },
32
+ }
33
+ )
34
+
35
+ function Alert({
36
+ className,
37
+ variant,
38
+ ...props
39
+ }: React.ComponentProps<"div"> & VariantProps<typeof alertVariants>) {
40
+ return (
41
+ <div
42
+ data-slot="alert"
43
+ role="alert"
44
+ className={cn(alertVariants({ variant }), className)}
45
+ {...props}
46
+ />
47
+ )
48
+ }
49
+
50
+ function AlertTitle({ className, ...props }: React.ComponentProps<"div">) {
51
+ return (
52
+ <div
53
+ data-slot="alert-title"
54
+ className={cn(
55
+ "col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight",
56
+ className
57
+ )}
58
+ {...props}
59
+ />
60
+ )
61
+ }
62
+
63
+ function AlertDescription({
64
+ className,
65
+ ...props
66
+ }: React.ComponentProps<"div">) {
67
+ return (
68
+ <div
69
+ data-slot="alert-description"
70
+ className={cn(
71
+ "text-muted-foreground col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed",
72
+ className
73
+ )}
74
+ {...props}
75
+ />
76
+ )
77
+ }
78
+
79
+ function AlertAction({ className, ...props }: React.ComponentProps<"div">) {
80
+ return (
81
+ <div
82
+ data-slot="alert-action"
83
+ className={cn(
84
+ "flex gap-1.5 max-sm:col-start-2 max-sm:mt-2 max-sm:justify-start sm:col-start-3 sm:row-start-1 sm:justify-end sm:self-center",
85
+ className
86
+ )}
87
+ {...props}
88
+ />
89
+ )
90
+ }
91
+
92
+ export { Alert, AlertTitle, AlertDescription, AlertAction }
@@ -0,0 +1,343 @@
1
+ "use client"
2
+
3
+ import { Autocomplete as AutocompletePrimitive } from "@base-ui/react/autocomplete"
4
+ import { cva, type VariantProps } from "class-variance-authority"
5
+
6
+ import { cn } from "../../lib/utils"
7
+ import { ScrollArea } from "../ui/scroll-area"
8
+ import { XIcon, ChevronsUpDownIcon } from "lucide-react"
9
+
10
+ const inputVariants = cva(
11
+ "outline-none flex w-full text-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 [[readonly]]:bg-muted/80 [[readonly]]:cursor-not-allowed border border-input focus-visible:border-ring aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-lg bg-transparent dark:bg-input/30 text-sm transition-colors focus-visible:ring-ring/50 focus-visible:ring-3 aria-invalid:ring-3",
12
+ {
13
+ variants: {
14
+ size: {
15
+ sm: "h-7 px-2 [&~[data-slot=autocomplete-clear]]:end-1.5 [&~[data-slot=autocomplete-trigger]]:end-1.5",
16
+ default:
17
+ "h-8 px-2.5 [&~[data-slot=autocomplete-clear]]:end-1.75 [&~[data-slot=autocomplete-trigger]]:end-1.75",
18
+ lg: "h-9 px-2.5 [&~[data-slot=autocomplete-clear]]:end-2 [&~[data-slot=autocomplete-trigger]]:end-2",
19
+ },
20
+ },
21
+ defaultVariants: {
22
+ size: "default",
23
+ },
24
+ }
25
+ )
26
+
27
+ const Autocomplete = AutocompletePrimitive.Root
28
+
29
+ function AutocompleteValue({ ...props }: AutocompletePrimitive.Value.Props) {
30
+ return (
31
+ <AutocompletePrimitive.Value data-slot="autocomplete-value" {...props} />
32
+ )
33
+ }
34
+
35
+ function AutocompleteInput({
36
+ className,
37
+ size = "default",
38
+ showClear = false,
39
+ showTrigger = false,
40
+ ...props
41
+ }: Omit<AutocompletePrimitive.Input.Props, "size"> &
42
+ VariantProps<typeof inputVariants> & {
43
+ showClear?: boolean
44
+ showTrigger?: boolean
45
+ }) {
46
+ return (
47
+ <div className="relative w-full">
48
+ <AutocompletePrimitive.Input
49
+ data-slot="autocomplete-input"
50
+ data-size={size}
51
+ className={cn(inputVariants({ size }), className)}
52
+ {...props}
53
+ />
54
+ {showTrigger && <AutocompleteTrigger />}
55
+ {showClear && <AutocompleteClear />}
56
+ </div>
57
+ )
58
+ }
59
+
60
+ function AutocompleteStatus({
61
+ className,
62
+ ...props
63
+ }: AutocompletePrimitive.Status.Props) {
64
+ return (
65
+ <AutocompletePrimitive.Status
66
+ data-slot="autocomplete-status"
67
+ className={cn(
68
+ "text-muted-foreground px-2 py-1.5 text-sm empty:m-0 empty:p-0",
69
+ className
70
+ )}
71
+ {...props}
72
+ />
73
+ )
74
+ }
75
+
76
+ function AutocompletePortal({ ...props }: AutocompletePrimitive.Portal.Props) {
77
+ return (
78
+ <AutocompletePrimitive.Portal data-slot="autocomplete-portal" {...props} />
79
+ )
80
+ }
81
+
82
+ function AutocompleteBackdrop({
83
+ ...props
84
+ }: AutocompletePrimitive.Backdrop.Props) {
85
+ return (
86
+ <AutocompletePrimitive.Backdrop
87
+ data-slot="autocomplete-backdrop"
88
+ {...props}
89
+ />
90
+ )
91
+ }
92
+
93
+ function AutocompletePositioner({
94
+ className,
95
+ ...props
96
+ }: AutocompletePrimitive.Positioner.Props) {
97
+ return (
98
+ <AutocompletePrimitive.Positioner
99
+ data-slot="autocomplete-positioner"
100
+ className={cn("z-50 outline-none", className)}
101
+ {...props}
102
+ />
103
+ )
104
+ }
105
+
106
+ function AutocompleteList({
107
+ className,
108
+ scrollAreaClassName,
109
+ ...props
110
+ }: AutocompletePrimitive.List.Props & {
111
+ scrollAreaClassName?: string
112
+ scrollFade?: boolean
113
+ scrollbarGutter?: boolean
114
+ }) {
115
+ return (
116
+ <ScrollArea
117
+ className={cn(
118
+ "size-full min-h-0 **:data-[slot=scroll-area-viewport]:h-full **:data-[slot=scroll-area-viewport]:overscroll-contain",
119
+ scrollAreaClassName
120
+ )}
121
+ >
122
+ <AutocompletePrimitive.List
123
+ data-slot="autocomplete-list"
124
+ className={cn(
125
+ "not-empty:px-1 not-empty:py-1 not-empty:scroll-py-1 in-data-has-overflow-y:me-3",
126
+ className
127
+ )}
128
+ {...props}
129
+ />
130
+ </ScrollArea>
131
+ )
132
+ }
133
+
134
+ function AutocompleteCollection({
135
+ ...props
136
+ }: React.ComponentProps<typeof AutocompletePrimitive.Collection>) {
137
+ return (
138
+ <AutocompletePrimitive.Collection
139
+ data-slot="autocomplete-collection"
140
+ {...props}
141
+ />
142
+ )
143
+ }
144
+
145
+ function AutocompleteRow({
146
+ className,
147
+ ...props
148
+ }: React.ComponentProps<typeof AutocompletePrimitive.Row>) {
149
+ return (
150
+ <AutocompletePrimitive.Row
151
+ data-slot="autocomplete-row"
152
+ className={cn("flex items-center gap-2", className)}
153
+ {...props}
154
+ />
155
+ )
156
+ }
157
+
158
+ function AutocompleteItem({
159
+ className,
160
+ ...props
161
+ }: React.ComponentProps<typeof AutocompletePrimitive.Item>) {
162
+ return (
163
+ <AutocompletePrimitive.Item
164
+ data-slot="autocomplete-item"
165
+ className={cn(
166
+ "text-foreground data-highlighted:text-foreground data-highlighted:before:bg-accent gap-1.5 rounded-md px-1.5 py-1 text-sm data-highlighted:before:rounded-sm [&_svg:not([class*='size-'])]:size-4 relative flex cursor-default items-center outline-hidden transition-colors select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-highlighted:relative data-highlighted:z-0 data-highlighted:before:absolute data-highlighted:before:inset-x-0 data-highlighted:before:inset-y-0 data-highlighted:before:z-[-1] [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([role=img]):not([class*=text-])]:opacity-60",
167
+ className
168
+ )}
169
+ {...props}
170
+ />
171
+ )
172
+ }
173
+
174
+ export interface AutocompleteContentProps extends React.ComponentProps<
175
+ typeof AutocompletePrimitive.Popup
176
+ > {
177
+ align?: AutocompletePrimitive.Positioner.Props["align"]
178
+ sideOffset?: AutocompletePrimitive.Positioner.Props["sideOffset"]
179
+ alignOffset?: AutocompletePrimitive.Positioner.Props["alignOffset"]
180
+ side?: AutocompletePrimitive.Positioner.Props["side"]
181
+ anchor?: AutocompletePrimitive.Positioner.Props["anchor"]
182
+ showBackdrop?: boolean
183
+ }
184
+
185
+ function AutocompleteContent({
186
+ className,
187
+ children,
188
+ showBackdrop = false,
189
+ align = "start",
190
+ sideOffset = 4,
191
+ alignOffset = 0,
192
+ side = "bottom",
193
+ anchor,
194
+ ...props
195
+ }: AutocompleteContentProps) {
196
+ return (
197
+ <AutocompletePortal>
198
+ {showBackdrop && <AutocompleteBackdrop />}
199
+ <AutocompletePositioner
200
+ align={align}
201
+ sideOffset={sideOffset}
202
+ alignOffset={alignOffset}
203
+ side={side}
204
+ anchor={anchor}
205
+ >
206
+ <div className="relative flex max-h-full">
207
+ <AutocompletePrimitive.Popup
208
+ data-slot="autocomplete-popup"
209
+ className={cn(
210
+ "bg-popover text-popover-foreground rounded-lg shadow-md ring-foreground/10 flex max-h-[min(var(--available-height),24rem)] w-(--anchor-width) max-w-(--available-width) origin-(--transform-origin) scroll-pt-2 scroll-pb-2 flex-col overscroll-contain py-0.5 ring-1 transition-[scale,opacity] has-data-starting-style:scale-98 has-data-starting-style:opacity-0 has-data-[side=none]:scale-100 has-data-[side=none]:transition-none",
211
+ className
212
+ )}
213
+ {...props}
214
+ >
215
+ {children}
216
+ </AutocompletePrimitive.Popup>
217
+ </div>
218
+ </AutocompletePositioner>
219
+ </AutocompletePortal>
220
+ )
221
+ }
222
+
223
+ function AutocompleteGroup({
224
+ ...props
225
+ }: React.ComponentProps<typeof AutocompletePrimitive.Group>) {
226
+ return (
227
+ <AutocompletePrimitive.Group data-slot="autocomplete-group" {...props} />
228
+ )
229
+ }
230
+
231
+ function AutocompleteGroupLabel({
232
+ className,
233
+ ...props
234
+ }: React.ComponentProps<typeof AutocompletePrimitive.GroupLabel>) {
235
+ return (
236
+ <AutocompletePrimitive.GroupLabel
237
+ data-slot="autocomplete-group-label"
238
+ className={cn(
239
+ "text-muted-foreground px-1.5 py-1 text-xs font-medium",
240
+ className
241
+ )}
242
+ {...props}
243
+ />
244
+ )
245
+ }
246
+
247
+ function AutocompleteEmpty({
248
+ className,
249
+ ...props
250
+ }: React.ComponentProps<typeof AutocompletePrimitive.Empty>) {
251
+ return (
252
+ <AutocompletePrimitive.Empty
253
+ data-slot="autocomplete-empty"
254
+ className={cn(
255
+ "text-muted-foreground px-2 py-1.5 text-sm text-center empty:m-0 empty:p-0",
256
+ className
257
+ )}
258
+ {...props}
259
+ />
260
+ )
261
+ }
262
+
263
+ function AutocompleteClear({
264
+ className,
265
+ ...props
266
+ }: React.ComponentProps<typeof AutocompletePrimitive.Clear>) {
267
+ return (
268
+ <AutocompletePrimitive.Clear
269
+ data-slot="autocomplete-clear"
270
+ className={cn(
271
+ "ring-offset-background focus:ring-ring absolute top-1/2 -translate-y-1/2 cursor-pointer opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-none disabled:pointer-events-none data-disabled:pointer-events-none",
272
+ className
273
+ )}
274
+ {...props}
275
+ >
276
+ <XIcon className="size-4" />
277
+ </AutocompletePrimitive.Clear>
278
+ )
279
+ }
280
+
281
+ function AutocompleteTrigger({
282
+ className,
283
+ ...props
284
+ }: React.ComponentProps<typeof AutocompletePrimitive.Trigger>) {
285
+ return (
286
+ <AutocompletePrimitive.Trigger
287
+ data-slot="autocomplete-trigger"
288
+ className={cn(
289
+ "focus:ring-ring ring-offset-background absolute top-1/2 -translate-y-1/2 cursor-pointer focus:ring-2 focus:ring-offset-2 focus:outline-none disabled:pointer-events-none has-[+[data-slot=autocomplete-clear]]:hidden data-disabled:pointer-events-none",
290
+ className
291
+ )}
292
+ {...props}
293
+ >
294
+ <ChevronsUpDownIcon className="size-4 opacity-70" />
295
+ </AutocompletePrimitive.Trigger>
296
+ )
297
+ }
298
+
299
+ function AutocompleteArrow({
300
+ ...props
301
+ }: React.ComponentProps<typeof AutocompletePrimitive.Arrow>) {
302
+ return (
303
+ <AutocompletePrimitive.Arrow data-slot="autocomplete-arrow" {...props} />
304
+ )
305
+ }
306
+
307
+ function AutocompleteSeparator({
308
+ className,
309
+ ...props
310
+ }: React.ComponentProps<typeof AutocompletePrimitive.Separator>) {
311
+ return (
312
+ <AutocompletePrimitive.Separator
313
+ data-slot="autocomplete-separator"
314
+ className={cn(
315
+ "bg-border my-1.5 h-px",
316
+ className
317
+ )}
318
+ {...props}
319
+ />
320
+ )
321
+ }
322
+
323
+ export {
324
+ Autocomplete,
325
+ AutocompleteValue,
326
+ AutocompleteTrigger,
327
+ AutocompleteInput,
328
+ AutocompleteStatus,
329
+ AutocompletePortal,
330
+ AutocompleteBackdrop,
331
+ AutocompletePositioner,
332
+ AutocompleteContent,
333
+ AutocompleteList,
334
+ AutocompleteCollection,
335
+ AutocompleteRow,
336
+ AutocompleteItem,
337
+ AutocompleteGroup,
338
+ AutocompleteGroupLabel,
339
+ AutocompleteEmpty,
340
+ AutocompleteClear,
341
+ AutocompleteArrow,
342
+ AutocompleteSeparator,
343
+ }
@@ -0,0 +1,87 @@
1
+ import { cva, type VariantProps } from "class-variance-authority"
2
+ import { Slot } from "radix-ui"
3
+
4
+ import { cn } from "@/lib/utils"
5
+
6
+ const badgeVariants = cva(
7
+ "rounded-sm relative inline-flex shrink-0 items-center justify-center w-fit border border-transparent font-medium whitespace-nowrap outline-none transition-shadow focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=size-])]:size-3",
8
+ {
9
+ variants: {
10
+ variant: {
11
+ default: "bg-primary text-primary-foreground",
12
+ outline: "border-border bg-transparent dark:bg-input/32",
13
+ secondary: "bg-secondary text-secondary-foreground",
14
+ info: "bg-info text-white",
15
+ success: "bg-success text-white",
16
+ warning: "bg-warning text-white",
17
+ destructive: "bg-destructive text-white",
18
+ focus: "bg-focus text-focus-foreground",
19
+ invert: "bg-invert text-invert-foreground",
20
+ "primary-light":
21
+ "bg-primary/10 border-none text-primary dark:bg-primary/20",
22
+ "warning-light":
23
+ "bg-warning/10 border-none text-warning-foreground dark:bg-warning/20",
24
+ "success-light":
25
+ "bg-success/10 border-none text-success-foreground dark:bg-success/20",
26
+ "info-light":
27
+ "bg-info/10 border-none text-info-foreground dark:bg-info/20",
28
+ "destructive-light":
29
+ "bg-destructive/10 border-none text-destructive-foreground dark:bg-destructive/20",
30
+ "invert-light":
31
+ "bg-invert/10 border-none text-foreground dark:bg-invert/20",
32
+ "focus-light":
33
+ "bg-focus/10 border-none text-focus-foreground dark:bg-focus/20",
34
+ "primary-outline":
35
+ "bg-background border-border text-primary dark:bg-input/30",
36
+ "warning-outline":
37
+ "bg-background border-border text-warning-foreground dark:bg-input/30",
38
+ "success-outline":
39
+ "bg-background border-border text-success-foreground dark:bg-input/30",
40
+ "info-outline":
41
+ "bg-background border-border text-info-foreground dark:bg-input/30",
42
+ "destructive-outline":
43
+ "bg-background border-border text-destructive-foreground dark:bg-input/30",
44
+ "invert-outline":
45
+ "bg-background border-border text-invert-foreground dark:bg-input/30",
46
+ "focus-outline":
47
+ "bg-background border-border text-focus-foreground dark:bg-input/30",
48
+ },
49
+ size: {
50
+ xs: "px-1 py-0.25 text-[0.6rem] leading-none h-4 min-w-4 gap-1",
51
+ sm: "px-1 py-0.25 text-[0.625rem] leading-none h-4.5 min-w-4.5 gap-1",
52
+ default: "px-1.25 py-0.5 text-xs h-5 min-w-5 gap-1",
53
+ lg: "px-1.5 py-0.5 text-xs h-5.5 min-w-5.5 gap-1",
54
+ xl: "px-2 py-0.75 text-sm h-6 min-w-6 gap-1.5",
55
+ },
56
+ },
57
+ defaultVariants: {
58
+ variant: "default",
59
+ size: "default",
60
+ },
61
+ }
62
+ )
63
+
64
+ interface BadgeProps
65
+ extends React.ComponentProps<"span">, VariantProps<typeof badgeVariants> {
66
+ asChild?: boolean
67
+ }
68
+
69
+ function Badge({
70
+ className,
71
+ variant,
72
+ size,
73
+ asChild = false,
74
+ ...props
75
+ }: BadgeProps) {
76
+ const Comp = asChild ? Slot.Root : "span"
77
+
78
+ return (
79
+ <Comp
80
+ data-slot="badge"
81
+ className={cn(badgeVariants({ variant, size, className }))}
82
+ {...props}
83
+ />
84
+ )
85
+ }
86
+
87
+ export { Badge, badgeVariants, type BadgeProps }