arcway 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 (274) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +711 -0
  3. package/client/env.js +55 -0
  4. package/client/fetcher.js +50 -0
  5. package/client/graphql.js +35 -0
  6. package/client/head.js +140 -0
  7. package/client/hooks/use-api.js +80 -0
  8. package/client/hooks/use-debounce.js +12 -0
  9. package/client/hooks/use-form.js +86 -0
  10. package/client/hooks/use-graphql.js +30 -0
  11. package/client/hooks/use-interval.js +12 -0
  12. package/client/hooks/use-mutation.js +27 -0
  13. package/client/hooks/use-query.js +45 -0
  14. package/client/hooks/web/use-click-outside.js +22 -0
  15. package/client/hooks/web/use-local-storage.js +42 -0
  16. package/client/index.js +62 -0
  17. package/client/page-loader.js +155 -0
  18. package/client/provider.js +53 -0
  19. package/client/query.js +13 -0
  20. package/client/router.jsx +303 -0
  21. package/client/ui/accordion.jsx +65 -0
  22. package/client/ui/accordion.stories.jsx +48 -0
  23. package/client/ui/alert-dialog.jsx +122 -0
  24. package/client/ui/alert-dialog.stories.jsx +44 -0
  25. package/client/ui/alert.jsx +52 -0
  26. package/client/ui/alert.stories.jsx +31 -0
  27. package/client/ui/app-shell.jsx +39 -0
  28. package/client/ui/app-shell.stories.jsx +51 -0
  29. package/client/ui/aspect-ratio.jsx +6 -0
  30. package/client/ui/aspect-ratio.stories.jsx +69 -0
  31. package/client/ui/avatar.jsx +78 -0
  32. package/client/ui/avatar.stories.jsx +62 -0
  33. package/client/ui/badge.jsx +34 -0
  34. package/client/ui/badge.stories.js +32 -0
  35. package/client/ui/breadcrumb.jsx +86 -0
  36. package/client/ui/breadcrumb.stories.jsx +43 -0
  37. package/client/ui/button-group.jsx +58 -0
  38. package/client/ui/button-group.stories.jsx +67 -0
  39. package/client/ui/button.jsx +46 -0
  40. package/client/ui/button.stories.js +72 -0
  41. package/client/ui/calendar.jsx +172 -0
  42. package/client/ui/card.jsx +57 -0
  43. package/client/ui/card.stories.jsx +33 -0
  44. package/client/ui/carousel.jsx +167 -0
  45. package/client/ui/chart.jsx +244 -0
  46. package/client/ui/checkbox.jsx +24 -0
  47. package/client/ui/checkbox.stories.js +33 -0
  48. package/client/ui/collapsible.jsx +12 -0
  49. package/client/ui/collapsible.stories.jsx +42 -0
  50. package/client/ui/combobox.jsx +223 -0
  51. package/client/ui/command.jsx +128 -0
  52. package/client/ui/context-menu.jsx +170 -0
  53. package/client/ui/context-menu.stories.jsx +35 -0
  54. package/client/ui/dialog.jsx +109 -0
  55. package/client/ui/dialog.stories.jsx +37 -0
  56. package/client/ui/direction.jsx +9 -0
  57. package/client/ui/drawer.jsx +87 -0
  58. package/client/ui/dropdown-menu.jsx +172 -0
  59. package/client/ui/dropdown-menu.stories.jsx +34 -0
  60. package/client/ui/empty.jsx +76 -0
  61. package/client/ui/empty.stories.jsx +64 -0
  62. package/client/ui/field.jsx +174 -0
  63. package/client/ui/field.stories.jsx +118 -0
  64. package/client/ui/form.jsx +17 -0
  65. package/client/ui/hooks/use-mobile.js +16 -0
  66. package/client/ui/hover-card.jsx +26 -0
  67. package/client/ui/hover-card.stories.jsx +28 -0
  68. package/client/ui/index.js +649 -0
  69. package/client/ui/input-group.jsx +116 -0
  70. package/client/ui/input-group.stories.jsx +65 -0
  71. package/client/ui/input-otp.jsx +62 -0
  72. package/client/ui/input.jsx +16 -0
  73. package/client/ui/input.stories.js +27 -0
  74. package/client/ui/item.jsx +155 -0
  75. package/client/ui/item.stories.jsx +118 -0
  76. package/client/ui/kbd.jsx +24 -0
  77. package/client/ui/kbd.stories.jsx +32 -0
  78. package/client/ui/label.jsx +16 -0
  79. package/client/ui/label.stories.js +25 -0
  80. package/client/ui/lib/utils.js +6 -0
  81. package/client/ui/main-content.jsx +30 -0
  82. package/client/ui/menubar.jsx +189 -0
  83. package/client/ui/menubar.stories.jsx +43 -0
  84. package/client/ui/native-select.jsx +34 -0
  85. package/client/ui/native-select.stories.jsx +67 -0
  86. package/client/ui/navigation-menu.jsx +120 -0
  87. package/client/ui/navigation-menu.stories.jsx +45 -0
  88. package/client/ui/pagination.jsx +92 -0
  89. package/client/ui/pagination.stories.jsx +52 -0
  90. package/client/ui/panel.jsx +66 -0
  91. package/client/ui/popover.jsx +54 -0
  92. package/client/ui/popover.stories.jsx +27 -0
  93. package/client/ui/progress.jsx +19 -0
  94. package/client/ui/progress.stories.js +34 -0
  95. package/client/ui/radio-group.jsx +33 -0
  96. package/client/ui/radio-group.stories.jsx +49 -0
  97. package/client/ui/resizable.jsx +33 -0
  98. package/client/ui/scroll-area.jsx +41 -0
  99. package/client/ui/scroll-area.stories.jsx +43 -0
  100. package/client/ui/select.jsx +145 -0
  101. package/client/ui/select.stories.jsx +80 -0
  102. package/client/ui/separator.jsx +18 -0
  103. package/client/ui/separator.stories.jsx +37 -0
  104. package/client/ui/sheet.jsx +95 -0
  105. package/client/ui/sheet.stories.jsx +56 -0
  106. package/client/ui/sidebar.jsx +544 -0
  107. package/client/ui/skeleton.jsx +8 -0
  108. package/client/ui/skeleton.stories.js +23 -0
  109. package/client/ui/slider.jsx +41 -0
  110. package/client/ui/slider.stories.js +31 -0
  111. package/client/ui/sonner.jsx +37 -0
  112. package/client/ui/spinner.jsx +14 -0
  113. package/client/ui/spinner.stories.js +16 -0
  114. package/client/ui/style-mira.css +1316 -0
  115. package/client/ui/switch.jsx +22 -0
  116. package/client/ui/switch.stories.js +44 -0
  117. package/client/ui/table.jsx +33 -0
  118. package/client/ui/table.stories.jsx +42 -0
  119. package/client/ui/tabs.jsx +63 -0
  120. package/client/ui/tabs.stories.jsx +45 -0
  121. package/client/ui/textarea.jsx +15 -0
  122. package/client/ui/textarea.stories.js +33 -0
  123. package/client/ui/theme.css +459 -0
  124. package/client/ui/toggle-group.jsx +62 -0
  125. package/client/ui/toggle-group.stories.jsx +68 -0
  126. package/client/ui/toggle.jsx +34 -0
  127. package/client/ui/toggle.stories.js +46 -0
  128. package/client/ui/tooltip.jsx +37 -0
  129. package/client/ui/tooltip.stories.jsx +32 -0
  130. package/client/ui/use-transition.js +35 -0
  131. package/client/ws.js +132 -0
  132. package/package.json +134 -0
  133. package/server/bin/cli.js +42 -0
  134. package/server/bin/commands/build.js +23 -0
  135. package/server/bin/commands/dev.js +57 -0
  136. package/server/bin/commands/docs.js +30 -0
  137. package/server/bin/commands/graphql-schema.js +32 -0
  138. package/server/bin/commands/lint.js +35 -0
  139. package/server/bin/commands/mcp.js +26 -0
  140. package/server/bin/commands/migrate.js +82 -0
  141. package/server/bin/commands/schema.js +41 -0
  142. package/server/bin/commands/seed.js +36 -0
  143. package/server/bin/commands/start.js +31 -0
  144. package/server/bin/commands/test.js +20 -0
  145. package/server/bin/solo.js +4 -0
  146. package/server/boot/index.js +150 -0
  147. package/server/boot.js +2 -0
  148. package/server/build.js +23 -0
  149. package/server/cache/drivers/memory.js +23 -0
  150. package/server/cache/drivers/redis.js +28 -0
  151. package/server/cache/index.js +69 -0
  152. package/server/config/loader.js +89 -0
  153. package/server/config/modules/api.js +17 -0
  154. package/server/config/modules/build.js +9 -0
  155. package/server/config/modules/cache.js +10 -0
  156. package/server/config/modules/database.js +29 -0
  157. package/server/config/modules/events.js +15 -0
  158. package/server/config/modules/files.js +15 -0
  159. package/server/config/modules/jobs.js +20 -0
  160. package/server/config/modules/logger.js +9 -0
  161. package/server/config/modules/mail.js +11 -0
  162. package/server/config/modules/mcp.js +9 -0
  163. package/server/config/modules/pages.js +20 -0
  164. package/server/config/modules/queue.js +10 -0
  165. package/server/config/modules/redis.js +9 -0
  166. package/server/config/modules/server.js +30 -0
  167. package/server/config/modules/session.js +9 -0
  168. package/server/config/modules/websocket.js +11 -0
  169. package/server/constants.js +67 -0
  170. package/server/context.js +15 -0
  171. package/server/db/index.js +87 -0
  172. package/server/db/schema/drivers/mysql.js +28 -0
  173. package/server/db/schema/drivers/pg.js +34 -0
  174. package/server/db/schema/drivers/sqlite.js +22 -0
  175. package/server/db/schema/index.js +78 -0
  176. package/server/db/seeds.js +22 -0
  177. package/server/discovery.js +67 -0
  178. package/server/docs/openapi.js +153 -0
  179. package/server/env.js +17 -0
  180. package/server/events/drivers/memory.js +45 -0
  181. package/server/events/drivers/redis.js +64 -0
  182. package/server/events/handler.js +67 -0
  183. package/server/events/index.js +35 -0
  184. package/server/events/pattern.js +5 -0
  185. package/server/files/drivers/local.js +83 -0
  186. package/server/files/drivers/s3.js +113 -0
  187. package/server/files/index.js +57 -0
  188. package/server/filewatcher/index.js +156 -0
  189. package/server/glob.js +6 -0
  190. package/server/graphql/discovery.js +70 -0
  191. package/server/graphql/handler.js +41 -0
  192. package/server/graphql/index.js +13 -0
  193. package/server/graphql/loaders.js +19 -0
  194. package/server/graphql/merge.js +48 -0
  195. package/server/graphql/subscriptions.js +43 -0
  196. package/server/health.js +34 -0
  197. package/server/helpers.js +9 -0
  198. package/server/index.js +55 -0
  199. package/server/internals.js +139 -0
  200. package/server/jobs/cron.js +10 -0
  201. package/server/jobs/drivers/knex-queue.js +207 -0
  202. package/server/jobs/drivers/lease.js +148 -0
  203. package/server/jobs/drivers/memory-queue.js +134 -0
  204. package/server/jobs/queue.js +27 -0
  205. package/server/jobs/runner.js +197 -0
  206. package/server/jobs/throughput.js +63 -0
  207. package/server/lib/vault/encrypt.js +40 -0
  208. package/server/lib/vault/ids.js +9 -0
  209. package/server/lib/vault/index.js +14 -0
  210. package/server/lib/vault/jwt.js +55 -0
  211. package/server/lib/vault/password.js +10 -0
  212. package/server/lint/boundaries.js +77 -0
  213. package/server/logger/index.js +130 -0
  214. package/server/mail/drivers/console.js +31 -0
  215. package/server/mail/drivers/smtp.js +34 -0
  216. package/server/mail/imap.js +105 -0
  217. package/server/mail/inbound-store.js +58 -0
  218. package/server/mail/inbound.js +79 -0
  219. package/server/mail/index.js +112 -0
  220. package/server/mcp/debug-api.js +137 -0
  221. package/server/mcp/helpers.js +30 -0
  222. package/server/mcp/index.js +77 -0
  223. package/server/mcp/runtime.js +7 -0
  224. package/server/mcp/server.js +19 -0
  225. package/server/mcp/tools/debugging.js +133 -0
  226. package/server/mcp/tools/introspection.js +87 -0
  227. package/server/middlewares/cors.js +30 -0
  228. package/server/middlewares/index.js +3 -0
  229. package/server/middlewares/require-session.js +15 -0
  230. package/server/module-loader.js +9 -0
  231. package/server/pages/build-client.js +187 -0
  232. package/server/pages/build-css.js +47 -0
  233. package/server/pages/build-manifest.js +55 -0
  234. package/server/pages/build-plugins.js +75 -0
  235. package/server/pages/build-server.js +115 -0
  236. package/server/pages/build.js +116 -0
  237. package/server/pages/discovery.js +120 -0
  238. package/server/pages/fonts.js +128 -0
  239. package/server/pages/handler.js +276 -0
  240. package/server/pages/hmr.js +176 -0
  241. package/server/pages/pages-router.js +78 -0
  242. package/server/pages/ssr.js +276 -0
  243. package/server/pages/static.js +92 -0
  244. package/server/pages/watcher.js +90 -0
  245. package/server/queue/drivers/knex.js +67 -0
  246. package/server/queue/drivers/redis.js +91 -0
  247. package/server/queue/index.js +61 -0
  248. package/server/rate-limit/consume.js +21 -0
  249. package/server/rate-limit/drivers/memory.js +24 -0
  250. package/server/rate-limit/drivers/redis.js +32 -0
  251. package/server/rate-limit/index.js +33 -0
  252. package/server/redis/index.js +67 -0
  253. package/server/ring-buffer.js +44 -0
  254. package/server/route.js +4 -0
  255. package/server/router/api-router.js +317 -0
  256. package/server/router/cors.js +31 -0
  257. package/server/router/middleware.js +91 -0
  258. package/server/router/routes.js +132 -0
  259. package/server/server.js +35 -0
  260. package/server/session/helpers.js +21 -0
  261. package/server/session/index.js +89 -0
  262. package/server/static/index.js +36 -0
  263. package/server/system-jobs/index.js +50 -0
  264. package/server/system-routes/index.js +84 -0
  265. package/server/testing/index.js +263 -0
  266. package/server/validation.js +41 -0
  267. package/server/watcher.js +34 -0
  268. package/server/web-server.js +231 -0
  269. package/server/ws/discovery.js +54 -0
  270. package/server/ws/index.js +14 -0
  271. package/server/ws/realtime.js +318 -0
  272. package/server/ws/registry.js +17 -0
  273. package/server/ws/server.js +152 -0
  274. package/server/ws/ws-router.js +335 -0
@@ -0,0 +1,544 @@
1
+ import * as React from 'react';
2
+ import { cva } from 'class-variance-authority';
3
+ import { Slot } from 'radix-ui';
4
+ import { useIsMobile } from './hooks/use-mobile.js';
5
+ import { cn } from './lib/utils.js';
6
+ import { Button } from './button.jsx';
7
+ import { Input } from './input.jsx';
8
+ import { Separator } from './separator.jsx';
9
+ import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from './sheet.jsx';
10
+ import { Skeleton } from './skeleton.jsx';
11
+ import { Tooltip, TooltipContent, TooltipTrigger } from './tooltip.jsx';
12
+ import { PanelLeftIcon } from 'lucide-react';
13
+ const SIDEBAR_COOKIE_NAME = 'sidebar_state';
14
+ const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
15
+ const SIDEBAR_WIDTH = '16rem';
16
+ const SIDEBAR_WIDTH_MOBILE = '18rem';
17
+ const SIDEBAR_WIDTH_ICON = '3rem';
18
+ const SIDEBAR_KEYBOARD_SHORTCUT = 'b';
19
+ const SidebarContext = React.createContext(null);
20
+ function useSidebar() {
21
+ const context = React.useContext(SidebarContext);
22
+ if (!context) {
23
+ throw new Error('useSidebar must be used within a SidebarProvider.');
24
+ }
25
+ return context;
26
+ }
27
+ function SidebarProvider({
28
+ defaultOpen = true,
29
+ open: openProp,
30
+ onOpenChange: setOpenProp,
31
+ className,
32
+ style,
33
+ children,
34
+ ...props
35
+ }) {
36
+ const isMobile = useIsMobile();
37
+ const [openMobile, setOpenMobile] = React.useState(false);
38
+ const [_open, _setOpen] = React.useState(defaultOpen);
39
+ const open = openProp ?? _open;
40
+ const setOpen = React.useCallback(
41
+ (value) => {
42
+ const openState = typeof value === 'function' ? value(open) : value;
43
+ if (setOpenProp) {
44
+ setOpenProp(openState);
45
+ } else {
46
+ _setOpen(openState);
47
+ }
48
+ document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
49
+ },
50
+ [setOpenProp, open],
51
+ );
52
+ const toggleSidebar = React.useCallback(() => {
53
+ return isMobile ? setOpenMobile((open2) => !open2) : setOpen((open2) => !open2);
54
+ }, [isMobile, setOpen, setOpenMobile]);
55
+ React.useEffect(() => {
56
+ const handleKeyDown = (event) => {
57
+ if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
58
+ event.preventDefault();
59
+ toggleSidebar();
60
+ }
61
+ };
62
+ window.addEventListener('keydown', handleKeyDown);
63
+ return () => window.removeEventListener('keydown', handleKeyDown);
64
+ }, [toggleSidebar]);
65
+ const state = open ? 'expanded' : 'collapsed';
66
+ const contextValue = React.useMemo(
67
+ () => ({
68
+ state,
69
+ open,
70
+ setOpen,
71
+ isMobile,
72
+ openMobile,
73
+ setOpenMobile,
74
+ toggleSidebar,
75
+ }),
76
+ [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar],
77
+ );
78
+ return (
79
+ <SidebarContext.Provider value={contextValue}>
80
+ <div
81
+ data-slot="sidebar-wrapper"
82
+ style={{
83
+ '--sidebar-width': SIDEBAR_WIDTH,
84
+ '--sidebar-width-icon': SIDEBAR_WIDTH_ICON,
85
+ ...style,
86
+ }}
87
+ className={cn(
88
+ 'group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full',
89
+ className,
90
+ )}
91
+ {...props}
92
+ >
93
+ {children}
94
+ </div>
95
+ </SidebarContext.Provider>
96
+ );
97
+ }
98
+ function Sidebar({
99
+ side = 'left',
100
+ variant = 'sidebar',
101
+ collapsible = 'offcanvas',
102
+ className,
103
+ children,
104
+ dir,
105
+ ...props
106
+ }) {
107
+ const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
108
+ if (collapsible === 'none') {
109
+ return (
110
+ <div
111
+ data-slot="sidebar"
112
+ className={cn(
113
+ 'bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col',
114
+ className,
115
+ )}
116
+ {...props}
117
+ >
118
+ {children}
119
+ </div>
120
+ );
121
+ }
122
+ if (isMobile) {
123
+ return (
124
+ <Sheet open={openMobile} onOpenChange={setOpenMobile} {...props}>
125
+ <SheetContent
126
+ dir={dir}
127
+ data-sidebar="sidebar"
128
+ data-slot="sidebar"
129
+ data-mobile="true"
130
+ className="bg-sidebar text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden"
131
+ style={{
132
+ '--sidebar-width': SIDEBAR_WIDTH_MOBILE,
133
+ }}
134
+ side={side}
135
+ >
136
+ <SheetHeader className="sr-only">
137
+ <SheetTitle>Sidebar</SheetTitle>
138
+ <SheetDescription>Displays the mobile sidebar.</SheetDescription>
139
+ </SheetHeader>
140
+ <div className="flex h-full w-full flex-col">{children}</div>
141
+ </SheetContent>
142
+ </Sheet>
143
+ );
144
+ }
145
+ return (
146
+ <div
147
+ className="group peer text-sidebar-foreground hidden md:block"
148
+ data-state={state}
149
+ data-collapsible={state === 'collapsed' ? collapsible : ''}
150
+ data-variant={variant}
151
+ data-side={side}
152
+ data-slot="sidebar"
153
+ >
154
+ {/* This is what handles the sidebar gap on desktop */}
155
+ <div
156
+ data-slot="sidebar-gap"
157
+ className={cn(
158
+ 'cn-sidebar-gap relative w-(--sidebar-width) bg-transparent',
159
+ 'group-data-[collapsible=offcanvas]:w-0',
160
+ 'group-data-[side=right]:rotate-180',
161
+ variant === 'floating' || variant === 'inset'
162
+ ? 'group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]'
163
+ : 'group-data-[collapsible=icon]:w-(--sidebar-width-icon)',
164
+ )}
165
+ />
166
+ <div
167
+ data-slot="sidebar-container"
168
+ data-side={side}
169
+ className={cn(
170
+ 'fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear data-[side=left]:left-0 data-[side=left]:group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)] data-[side=right]:right-0 data-[side=right]:group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)] md:flex',
171
+ // Adjust the padding for floating and inset variants.
172
+ variant === 'floating' || variant === 'inset'
173
+ ? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]'
174
+ : 'group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l',
175
+ className,
176
+ )}
177
+ {...props}
178
+ >
179
+ <div
180
+ data-sidebar="sidebar"
181
+ data-slot="sidebar-inner"
182
+ className="cn-sidebar-inner flex size-full flex-col"
183
+ >
184
+ {children}
185
+ </div>
186
+ </div>
187
+ </div>
188
+ );
189
+ }
190
+ function SidebarTrigger({ className, onClick, ...props }) {
191
+ const { toggleSidebar } = useSidebar();
192
+ return (
193
+ <Button
194
+ data-sidebar="trigger"
195
+ data-slot="sidebar-trigger"
196
+ variant="ghost"
197
+ size="icon-sm"
198
+ className={cn('cn-sidebar-trigger', className)}
199
+ onClick={(event) => {
200
+ onClick?.(event);
201
+ toggleSidebar();
202
+ }}
203
+ {...props}
204
+ >
205
+ <PanelLeftIcon className="cn-rtl-flip" />
206
+ <span className="sr-only">Toggle Sidebar</span>
207
+ </Button>
208
+ );
209
+ }
210
+ function SidebarRail({ className, ...props }) {
211
+ const { toggleSidebar } = useSidebar();
212
+ return (
213
+ <button
214
+ data-sidebar="rail"
215
+ data-slot="sidebar-rail"
216
+ aria-label="Toggle Sidebar"
217
+ tabIndex={-1}
218
+ onClick={toggleSidebar}
219
+ title="Toggle Sidebar"
220
+ className={cn(
221
+ 'cn-sidebar-rail absolute inset-y-0 z-20 hidden w-4 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:start-1/2 after:w-[2px] sm:flex ltr:-translate-x-1/2 rtl:-translate-x-1/2',
222
+ 'in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize',
223
+ '[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize',
224
+ 'hover:group-data-[collapsible=offcanvas]:bg-sidebar group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full',
225
+ '[[data-side=left][data-collapsible=offcanvas]_&]:-right-2',
226
+ '[[data-side=right][data-collapsible=offcanvas]_&]:-left-2',
227
+ className,
228
+ )}
229
+ {...props}
230
+ />
231
+ );
232
+ }
233
+ function SidebarInset({ className, ...props }) {
234
+ return (
235
+ <main
236
+ data-slot="sidebar-inset"
237
+ className={cn('cn-sidebar-inset relative flex w-full flex-1 flex-col', className)}
238
+ {...props}
239
+ />
240
+ );
241
+ }
242
+ function SidebarInput({ className, ...props }) {
243
+ return (
244
+ <Input
245
+ data-slot="sidebar-input"
246
+ data-sidebar="input"
247
+ className={cn('cn-sidebar-input', className)}
248
+ {...props}
249
+ />
250
+ );
251
+ }
252
+ function SidebarHeader({ className, ...props }) {
253
+ return (
254
+ <div
255
+ data-slot="sidebar-header"
256
+ data-sidebar="header"
257
+ className={cn('cn-sidebar-header flex flex-col', className)}
258
+ {...props}
259
+ />
260
+ );
261
+ }
262
+ function SidebarFooter({ className, ...props }) {
263
+ return (
264
+ <div
265
+ data-slot="sidebar-footer"
266
+ data-sidebar="footer"
267
+ className={cn('cn-sidebar-footer flex flex-col', className)}
268
+ {...props}
269
+ />
270
+ );
271
+ }
272
+ function SidebarSeparator({ className, ...props }) {
273
+ return (
274
+ <Separator
275
+ data-slot="sidebar-separator"
276
+ data-sidebar="separator"
277
+ className={cn('cn-sidebar-separator w-auto', className)}
278
+ {...props}
279
+ />
280
+ );
281
+ }
282
+ function SidebarContent({ className, ...props }) {
283
+ return (
284
+ <div
285
+ data-slot="sidebar-content"
286
+ data-sidebar="content"
287
+ className={cn(
288
+ 'cn-sidebar-content flex min-h-0 flex-1 flex-col overflow-auto group-data-[collapsible=icon]:overflow-hidden',
289
+ className,
290
+ )}
291
+ {...props}
292
+ />
293
+ );
294
+ }
295
+ function SidebarGroup({ className, ...props }) {
296
+ return (
297
+ <div
298
+ data-slot="sidebar-group"
299
+ data-sidebar="group"
300
+ className={cn('cn-sidebar-group relative flex w-full min-w-0 flex-col', className)}
301
+ {...props}
302
+ />
303
+ );
304
+ }
305
+ function SidebarGroupLabel({ className, asChild = false, ...props }) {
306
+ const Comp = asChild ? Slot.Root : 'div';
307
+ return (
308
+ <Comp
309
+ data-slot="sidebar-group-label"
310
+ data-sidebar="group-label"
311
+ className={cn(
312
+ 'cn-sidebar-group-label flex shrink-0 items-center outline-hidden [&>svg]:shrink-0',
313
+ className,
314
+ )}
315
+ {...props}
316
+ />
317
+ );
318
+ }
319
+ function SidebarGroupAction({ className, asChild = false, ...props }) {
320
+ const Comp = asChild ? Slot.Root : 'button';
321
+ return (
322
+ <Comp
323
+ data-slot="sidebar-group-action"
324
+ data-sidebar="group-action"
325
+ className={cn(
326
+ 'cn-sidebar-group-action flex aspect-square items-center justify-center outline-hidden transition-transform group-data-[collapsible=icon]:hidden after:absolute after:-inset-2 md:after:hidden [&>svg]:shrink-0',
327
+ className,
328
+ )}
329
+ {...props}
330
+ />
331
+ );
332
+ }
333
+ function SidebarGroupContent({ className, ...props }) {
334
+ return (
335
+ <div
336
+ data-slot="sidebar-group-content"
337
+ data-sidebar="group-content"
338
+ className={cn('cn-sidebar-group-content w-full', className)}
339
+ {...props}
340
+ />
341
+ );
342
+ }
343
+ function SidebarMenu({ className, ...props }) {
344
+ return (
345
+ <ul
346
+ data-slot="sidebar-menu"
347
+ data-sidebar="menu"
348
+ className={cn('cn-sidebar-menu flex w-full min-w-0 flex-col', className)}
349
+ {...props}
350
+ />
351
+ );
352
+ }
353
+ function SidebarMenuItem({ className, ...props }) {
354
+ return (
355
+ <li
356
+ data-slot="sidebar-menu-item"
357
+ data-sidebar="menu-item"
358
+ className={cn('group/menu-item relative', className)}
359
+ {...props}
360
+ />
361
+ );
362
+ }
363
+ const sidebarMenuButtonVariants = cva(
364
+ 'cn-sidebar-menu-button peer/menu-button flex w-full items-center overflow-hidden outline-hidden group/menu-button disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&_svg]:size-4 [&_svg]:shrink-0',
365
+ {
366
+ variants: {
367
+ variant: {
368
+ default: 'cn-sidebar-menu-button-variant-default ',
369
+ outline: 'cn-sidebar-menu-button-variant-outline',
370
+ },
371
+ size: {
372
+ default: 'cn-sidebar-menu-button-size-default',
373
+ sm: 'cn-sidebar-menu-button-size-sm',
374
+ lg: 'cn-sidebar-menu-button-size-lg',
375
+ },
376
+ },
377
+ defaultVariants: {
378
+ variant: 'default',
379
+ size: 'default',
380
+ },
381
+ },
382
+ );
383
+ function SidebarMenuButton({
384
+ asChild = false,
385
+ isActive = false,
386
+ variant = 'default',
387
+ size = 'default',
388
+ tooltip,
389
+ className,
390
+ ...props
391
+ }) {
392
+ const Comp = asChild ? Slot.Root : 'button';
393
+ const { isMobile, state } = useSidebar();
394
+ const button = (
395
+ <Comp
396
+ data-slot="sidebar-menu-button"
397
+ data-sidebar="menu-button"
398
+ data-size={size}
399
+ data-active={isActive}
400
+ className={cn(sidebarMenuButtonVariants({ variant, size }), className)}
401
+ {...props}
402
+ />
403
+ );
404
+ if (!tooltip) {
405
+ return button;
406
+ }
407
+ if (typeof tooltip === 'string') {
408
+ tooltip = {
409
+ children: tooltip,
410
+ };
411
+ }
412
+ return (
413
+ <Tooltip>
414
+ <TooltipTrigger asChild>{button}</TooltipTrigger>
415
+ <TooltipContent
416
+ side="right"
417
+ align="center"
418
+ hidden={state !== 'collapsed' || isMobile}
419
+ {...tooltip}
420
+ />
421
+ </Tooltip>
422
+ );
423
+ }
424
+ function SidebarMenuAction({ className, asChild = false, showOnHover = false, ...props }) {
425
+ const Comp = asChild ? Slot.Root : 'button';
426
+ return (
427
+ <Comp
428
+ data-slot="sidebar-menu-action"
429
+ data-sidebar="menu-action"
430
+ className={cn(
431
+ 'cn-sidebar-menu-action flex items-center justify-center outline-hidden transition-transform group-data-[collapsible=icon]:hidden after:absolute after:-inset-2 md:after:hidden [&>svg]:shrink-0',
432
+ showOnHover &&
433
+ 'peer-data-active/menu-button:text-sidebar-accent-foreground group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 aria-expanded:opacity-100 md:opacity-0',
434
+ className,
435
+ )}
436
+ {...props}
437
+ />
438
+ );
439
+ }
440
+ function SidebarMenuBadge({ className, ...props }) {
441
+ return (
442
+ <div
443
+ data-slot="sidebar-menu-badge"
444
+ data-sidebar="menu-badge"
445
+ className={cn(
446
+ 'cn-sidebar-menu-badge flex items-center justify-center tabular-nums select-none group-data-[collapsible=icon]:hidden',
447
+ className,
448
+ )}
449
+ {...props}
450
+ />
451
+ );
452
+ }
453
+ function SidebarMenuSkeleton({ className, showIcon = false, ...props }) {
454
+ const [width] = React.useState(() => {
455
+ return `${Math.floor(Math.random() * 40) + 50}%`;
456
+ });
457
+ return (
458
+ <div
459
+ data-slot="sidebar-menu-skeleton"
460
+ data-sidebar="menu-skeleton"
461
+ className={cn('cn-sidebar-menu-skeleton flex items-center', className)}
462
+ {...props}
463
+ >
464
+ {showIcon && (
465
+ <Skeleton className="cn-sidebar-menu-skeleton-icon" data-sidebar="menu-skeleton-icon" />
466
+ )}
467
+ <Skeleton
468
+ className="cn-sidebar-menu-skeleton-text max-w-(--skeleton-width) flex-1"
469
+ data-sidebar="menu-skeleton-text"
470
+ style={{
471
+ '--skeleton-width': width,
472
+ }}
473
+ />
474
+ </div>
475
+ );
476
+ }
477
+ function SidebarMenuSub({ className, ...props }) {
478
+ return (
479
+ <ul
480
+ data-slot="sidebar-menu-sub"
481
+ data-sidebar="menu-sub"
482
+ className={cn('cn-sidebar-menu-sub flex min-w-0 flex-col', className)}
483
+ {...props}
484
+ />
485
+ );
486
+ }
487
+ function SidebarMenuSubItem({ className, ...props }) {
488
+ return (
489
+ <li
490
+ data-slot="sidebar-menu-sub-item"
491
+ data-sidebar="menu-sub-item"
492
+ className={cn('group/menu-sub-item relative', className)}
493
+ {...props}
494
+ />
495
+ );
496
+ }
497
+ function SidebarMenuSubButton({
498
+ asChild = false,
499
+ size = 'md',
500
+ isActive = false,
501
+ className,
502
+ ...props
503
+ }) {
504
+ const Comp = asChild ? Slot.Root : 'a';
505
+ return (
506
+ <Comp
507
+ data-slot="sidebar-menu-sub-button"
508
+ data-sidebar="menu-sub-button"
509
+ data-size={size}
510
+ data-active={isActive}
511
+ className={cn(
512
+ 'cn-sidebar-menu-sub-button flex min-w-0 -translate-x-px items-center overflow-hidden outline-hidden group-data-[collapsible=icon]:hidden disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:shrink-0',
513
+ className,
514
+ )}
515
+ {...props}
516
+ />
517
+ );
518
+ }
519
+ export {
520
+ Sidebar,
521
+ SidebarContent,
522
+ SidebarFooter,
523
+ SidebarGroup,
524
+ SidebarGroupAction,
525
+ SidebarGroupContent,
526
+ SidebarGroupLabel,
527
+ SidebarHeader,
528
+ SidebarInput,
529
+ SidebarInset,
530
+ SidebarMenu,
531
+ SidebarMenuAction,
532
+ SidebarMenuBadge,
533
+ SidebarMenuButton,
534
+ SidebarMenuItem,
535
+ SidebarMenuSkeleton,
536
+ SidebarMenuSub,
537
+ SidebarMenuSubButton,
538
+ SidebarMenuSubItem,
539
+ SidebarProvider,
540
+ SidebarRail,
541
+ SidebarSeparator,
542
+ SidebarTrigger,
543
+ useSidebar,
544
+ };
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import { cn } from './lib/utils.js';
3
+ function Skeleton({ className, ...props }) {
4
+ return (
5
+ <div data-slot="skeleton" className={cn('cn-skeleton animate-pulse', className)} {...props} />
6
+ );
7
+ }
8
+ export { Skeleton };
@@ -0,0 +1,23 @@
1
+ import { expect } from 'storybook/test';
2
+ import { Skeleton } from './skeleton.jsx';
3
+ const meta = {
4
+ title: 'UI/Skeleton',
5
+ component: Skeleton,
6
+ };
7
+ var stdin_default = meta;
8
+ const Default = {
9
+ args: { style: { width: 200, height: 20 } },
10
+ play: async ({ canvasElement }) => {
11
+ const el = canvasElement.querySelector('[data-slot="skeleton"]');
12
+ await expect(el).toBeInTheDocument();
13
+ await expect(el.className).toContain('animate-pulse');
14
+ },
15
+ };
16
+ const Circle = {
17
+ args: { style: { width: 48, height: 48, borderRadius: '50%' } },
18
+ play: async ({ canvasElement }) => {
19
+ const el = canvasElement.querySelector('[data-slot="skeleton"]');
20
+ await expect(el).toBeInTheDocument();
21
+ },
22
+ };
23
+ export { Circle, Default, stdin_default as default };
@@ -0,0 +1,41 @@
1
+ import * as React from 'react';
2
+ import { Slider as SliderPrimitive } from 'radix-ui';
3
+ import { cn } from './lib/utils.js';
4
+ function Slider({ className, defaultValue, value, min = 0, max = 100, ...props }) {
5
+ const _values = React.useMemo(
6
+ () => (Array.isArray(value) ? value : Array.isArray(defaultValue) ? defaultValue : [min, max]),
7
+ [value, defaultValue, min, max],
8
+ );
9
+ return (
10
+ <SliderPrimitive.Root
11
+ data-slot="slider"
12
+ defaultValue={defaultValue}
13
+ value={value}
14
+ min={min}
15
+ max={max}
16
+ className={cn(
17
+ 'cn-slider relative flex w-full touch-none items-center select-none data-disabled:opacity-50 data-vertical:h-full data-vertical:w-auto data-vertical:flex-col',
18
+ className,
19
+ )}
20
+ {...props}
21
+ >
22
+ <SliderPrimitive.Track
23
+ data-slot="slider-track"
24
+ className="cn-slider-track relative grow overflow-hidden data-horizontal:w-full data-vertical:h-full"
25
+ >
26
+ <SliderPrimitive.Range
27
+ data-slot="slider-range"
28
+ className="cn-slider-range absolute select-none data-horizontal:h-full data-vertical:w-full"
29
+ />
30
+ </SliderPrimitive.Track>
31
+ {Array.from({ length: _values.length }, (_, index) => (
32
+ <SliderPrimitive.Thumb
33
+ data-slot="slider-thumb"
34
+ key={index}
35
+ className="cn-slider-thumb block shrink-0 select-none disabled:pointer-events-none disabled:opacity-50"
36
+ />
37
+ ))}
38
+ </SliderPrimitive.Root>
39
+ );
40
+ }
41
+ export { Slider };
@@ -0,0 +1,31 @@
1
+ import { expect } from 'storybook/test';
2
+ import { Slider } from './slider.jsx';
3
+ const meta = {
4
+ title: 'UI/Slider',
5
+ component: Slider,
6
+ };
7
+ var stdin_default = meta;
8
+ const Default = {
9
+ args: { defaultValue: [50], min: 0, max: 100 },
10
+ play: async ({ canvasElement }) => {
11
+ const el = canvasElement.querySelector('[data-slot="slider"]');
12
+ await expect(el).toBeInTheDocument();
13
+ const thumb = canvasElement.querySelector('[data-slot="slider-thumb"]');
14
+ await expect(thumb).toBeInTheDocument();
15
+ },
16
+ };
17
+ const Range = {
18
+ args: { defaultValue: [25, 75], min: 0, max: 100 },
19
+ play: async ({ canvasElement }) => {
20
+ const thumbs = canvasElement.querySelectorAll('[data-slot="slider-thumb"]');
21
+ await expect(thumbs.length).toBe(2);
22
+ },
23
+ };
24
+ const Disabled = {
25
+ args: { defaultValue: [50], disabled: true },
26
+ play: async ({ canvasElement }) => {
27
+ const el = canvasElement.querySelector('[data-slot="slider"]');
28
+ await expect(el.getAttribute('data-disabled')).toBeDefined();
29
+ },
30
+ };
31
+ export { Default, Disabled, Range, stdin_default as default };
@@ -0,0 +1,37 @@
1
+ import React from 'react';
2
+ import { Toaster as Sonner } from 'sonner';
3
+ import {
4
+ CircleCheckIcon,
5
+ InfoIcon,
6
+ Loader2Icon,
7
+ OctagonXIcon,
8
+ TriangleAlertIcon,
9
+ } from 'lucide-react';
10
+ function Toaster({ theme = 'system', ...props }) {
11
+ return (
12
+ <Sonner
13
+ theme={theme}
14
+ className="toaster group"
15
+ icons={{
16
+ success: <CircleCheckIcon className="size-4" />,
17
+ info: <InfoIcon className="size-4" />,
18
+ warning: <TriangleAlertIcon className="size-4" />,
19
+ error: <OctagonXIcon className="size-4" />,
20
+ loading: <Loader2Icon className="size-4 animate-spin" />,
21
+ }}
22
+ style={{
23
+ '--normal-bg': 'var(--popover)',
24
+ '--normal-text': 'var(--popover-foreground)',
25
+ '--normal-border': 'var(--border)',
26
+ '--border-radius': 'var(--radius)',
27
+ }}
28
+ toastOptions={{
29
+ classNames: {
30
+ toast: 'cn-toast',
31
+ },
32
+ }}
33
+ {...props}
34
+ />
35
+ );
36
+ }
37
+ export { Toaster };
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import { cn } from './lib/utils.js';
3
+ import { Loader2Icon } from 'lucide-react';
4
+ function Spinner({ className, ...props }) {
5
+ return (
6
+ <Loader2Icon
7
+ role="status"
8
+ aria-label="Loading"
9
+ className={cn('size-4 animate-spin', className)}
10
+ {...props}
11
+ />
12
+ );
13
+ }
14
+ export { Spinner };