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,66 @@
1
+ import React from 'react';
2
+ import { useAppShell } from './app-shell.jsx';
3
+ function PanelHeader({ children }) {
4
+ return (
5
+ <header
6
+ data-panel-header
7
+ className="flex h-14 shrink-0 items-center border-b border-panel-border px-4"
8
+ >
9
+ {children}
10
+ </header>
11
+ );
12
+ }
13
+ function PanelBody({ children }) {
14
+ return (
15
+ <div data-panel-body className="flex-1 overflow-y-auto">
16
+ {children}
17
+ </div>
18
+ );
19
+ }
20
+ function PanelTrigger({ children }) {
21
+ const { togglePanel } = useAppShell();
22
+ return (
23
+ <button
24
+ data-panel-trigger
25
+ type="button"
26
+ onClick={togglePanel}
27
+ className="inline-flex items-center justify-center rounded-md p-2 text-foreground hover:bg-muted"
28
+ aria-label="Toggle panel"
29
+ >
30
+ {children || (
31
+ <svg
32
+ xmlns="http://www.w3.org/2000/svg"
33
+ width="20"
34
+ height="20"
35
+ viewBox="0 0 24 24"
36
+ fill="none"
37
+ stroke="currentColor"
38
+ strokeWidth="2"
39
+ strokeLinecap="round"
40
+ strokeLinejoin="round"
41
+ >
42
+ <rect width="18" height="18" x="3" y="3" rx="2" />
43
+ <path d="M15 3v18" />
44
+ </svg>
45
+ )}
46
+ </button>
47
+ );
48
+ }
49
+ function PanelRoot({ children, width = 'w-80' }) {
50
+ const { panelOpen } = useAppShell();
51
+ if (!panelOpen) return null;
52
+ return (
53
+ <aside
54
+ data-panel
55
+ className={`@container/panel flex shrink-0 flex-col overflow-hidden border-l border-panel-border bg-panel text-panel-foreground ${width}`}
56
+ >
57
+ {children}
58
+ </aside>
59
+ );
60
+ }
61
+ const Panel = Object.assign(PanelRoot, {
62
+ Header: PanelHeader,
63
+ Body: PanelBody,
64
+ Trigger: PanelTrigger,
65
+ });
66
+ export { Panel };
@@ -0,0 +1,54 @@
1
+ import React from 'react';
2
+ import { Popover as PopoverPrimitive } from 'radix-ui';
3
+ import { cn } from './lib/utils.js';
4
+ function Popover({ ...props }) {
5
+ return <PopoverPrimitive.Root data-slot="popover" {...props} />;
6
+ }
7
+ function PopoverTrigger({ ...props }) {
8
+ return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />;
9
+ }
10
+ function PopoverContent({ className, align = 'center', sideOffset = 4, ...props }) {
11
+ return (
12
+ <PopoverPrimitive.Portal>
13
+ <PopoverPrimitive.Content
14
+ data-slot="popover-content"
15
+ align={align}
16
+ sideOffset={sideOffset}
17
+ className={cn(
18
+ 'cn-popover-content z-50 w-72 origin-(--radix-popover-content-transform-origin) outline-hidden',
19
+ className,
20
+ )}
21
+ {...props}
22
+ />
23
+ </PopoverPrimitive.Portal>
24
+ );
25
+ }
26
+ function PopoverAnchor({ ...props }) {
27
+ return <PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} />;
28
+ }
29
+ function PopoverHeader({ className, ...props }) {
30
+ return (
31
+ <div data-slot="popover-header" className={cn('cn-popover-header', className)} {...props} />
32
+ );
33
+ }
34
+ function PopoverTitle({ className, ...props }) {
35
+ return <div data-slot="popover-title" className={cn('cn-popover-title', className)} {...props} />;
36
+ }
37
+ function PopoverDescription({ className, ...props }) {
38
+ return (
39
+ <p
40
+ data-slot="popover-description"
41
+ className={cn('cn-popover-description', className)}
42
+ {...props}
43
+ />
44
+ );
45
+ }
46
+ export {
47
+ Popover,
48
+ PopoverAnchor,
49
+ PopoverContent,
50
+ PopoverDescription,
51
+ PopoverHeader,
52
+ PopoverTitle,
53
+ PopoverTrigger,
54
+ };
@@ -0,0 +1,27 @@
1
+ import React from 'react';
2
+ import { expect, within } from 'storybook/test';
3
+ import { Popover, PopoverTrigger, PopoverContent } from './popover.jsx';
4
+ import { Button } from './button.jsx';
5
+ const meta = {
6
+ title: 'UI/Popover',
7
+ component: Popover,
8
+ };
9
+ var stdin_default = meta;
10
+ const Default = {
11
+ render: () => (
12
+ <Popover>
13
+ <PopoverTrigger asChild>
14
+ <Button>Open Popover</Button>
15
+ </PopoverTrigger>
16
+ <PopoverContent>
17
+ <p>Popover content goes here.</p>
18
+ </PopoverContent>
19
+ </Popover>
20
+ ),
21
+ play: async ({ canvasElement }) => {
22
+ const canvas = within(canvasElement);
23
+ const trigger = canvas.getByRole('button', { name: 'Open Popover' });
24
+ await expect(trigger).toBeInTheDocument();
25
+ },
26
+ };
27
+ export { Default, stdin_default as default };
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ import { Progress as ProgressPrimitive } from 'radix-ui';
3
+ import { cn } from './lib/utils.js';
4
+ function Progress({ className, value, ...props }) {
5
+ return (
6
+ <ProgressPrimitive.Root
7
+ data-slot="progress"
8
+ className={cn('cn-progress relative flex w-full items-center overflow-x-hidden', className)}
9
+ {...props}
10
+ >
11
+ <ProgressPrimitive.Indicator
12
+ data-slot="progress-indicator"
13
+ className="cn-progress-indicator size-full flex-1 transition-all"
14
+ style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
15
+ />
16
+ </ProgressPrimitive.Root>
17
+ );
18
+ }
19
+ export { Progress };
@@ -0,0 +1,34 @@
1
+ import { expect } from 'storybook/test';
2
+ import { Progress } from './progress.jsx';
3
+ const meta = {
4
+ title: 'UI/Progress',
5
+ component: Progress,
6
+ argTypes: {
7
+ value: { control: { type: 'range', min: 0, max: 100 } },
8
+ },
9
+ };
10
+ var stdin_default = meta;
11
+ const Default = {
12
+ args: { value: 50 },
13
+ play: async ({ canvasElement }) => {
14
+ const el = canvasElement.querySelector('[data-slot="progress"]');
15
+ await expect(el).toBeInTheDocument();
16
+ const indicator = canvasElement.querySelector('[data-slot="progress-indicator"]');
17
+ await expect(indicator).toBeInTheDocument();
18
+ },
19
+ };
20
+ const Empty = {
21
+ args: { value: 0 },
22
+ play: async ({ canvasElement }) => {
23
+ const indicator = canvasElement.querySelector('[data-slot="progress-indicator"]');
24
+ await expect(indicator.style.transform).toBe('translateX(-100%)');
25
+ },
26
+ };
27
+ const Full = {
28
+ args: { value: 100 },
29
+ play: async ({ canvasElement }) => {
30
+ const indicator = canvasElement.querySelector('[data-slot="progress-indicator"]');
31
+ await expect(indicator.style.transform).toBe('translateX(0%)');
32
+ },
33
+ };
34
+ export { Default, Empty, Full, stdin_default as default };
@@ -0,0 +1,33 @@
1
+ import React from 'react';
2
+ import { RadioGroup as RadioGroupPrimitive } from 'radix-ui';
3
+ import { cn } from './lib/utils.js';
4
+ import { CircleIcon } from 'lucide-react';
5
+ function RadioGroup({ className, ...props }) {
6
+ return (
7
+ <RadioGroupPrimitive.Root
8
+ data-slot="radio-group"
9
+ className={cn('cn-radio-group w-full', className)}
10
+ {...props}
11
+ />
12
+ );
13
+ }
14
+ function RadioGroupItem({ className, ...props }) {
15
+ return (
16
+ <RadioGroupPrimitive.Item
17
+ data-slot="radio-group-item"
18
+ className={cn(
19
+ 'cn-radio-group-item group/radio-group-item peer relative aspect-square shrink-0 border outline-none after:absolute after:-inset-x-3 after:-inset-y-2 disabled:cursor-not-allowed disabled:opacity-50',
20
+ className,
21
+ )}
22
+ {...props}
23
+ >
24
+ <RadioGroupPrimitive.Indicator
25
+ data-slot="radio-group-indicator"
26
+ className="cn-radio-group-indicator"
27
+ >
28
+ <CircleIcon className="cn-radio-group-indicator-icon" />
29
+ </RadioGroupPrimitive.Indicator>
30
+ </RadioGroupPrimitive.Item>
31
+ );
32
+ }
33
+ export { RadioGroup, RadioGroupItem };
@@ -0,0 +1,49 @@
1
+ import React from 'react';
2
+ import { expect, within } from 'storybook/test';
3
+ import { RadioGroup, RadioGroupItem } from './radio-group.jsx';
4
+ import { Label } from './label.jsx';
5
+ const meta = {
6
+ title: 'UI/RadioGroup',
7
+ component: RadioGroup,
8
+ };
9
+ var stdin_default = meta;
10
+ const Default = {
11
+ render: (args) => (
12
+ <RadioGroup defaultValue="option-1" {...args}>
13
+ <div className="flex items-center gap-2">
14
+ <RadioGroupItem value="option-1" id="option-1" />
15
+ <Label htmlFor="option-1">Option 1</Label>
16
+ </div>
17
+ <div className="flex items-center gap-2">
18
+ <RadioGroupItem value="option-2" id="option-2" />
19
+ <Label htmlFor="option-2">Option 2</Label>
20
+ </div>
21
+ <div className="flex items-center gap-2">
22
+ <RadioGroupItem value="option-3" id="option-3" />
23
+ <Label htmlFor="option-3">Option 3</Label>
24
+ </div>
25
+ </RadioGroup>
26
+ ),
27
+ play: async ({ canvasElement }) => {
28
+ const canvas = within(canvasElement);
29
+ const radios = canvas.getAllByRole('radio');
30
+ await expect(radios).toHaveLength(3);
31
+ await expect(radios[0]).toBeChecked();
32
+ await expect(radios[1]).not.toBeChecked();
33
+ },
34
+ };
35
+ const Disabled = {
36
+ render: () => (
37
+ <RadioGroup disabled defaultValue="option-1">
38
+ <div className="flex items-center gap-2">
39
+ <RadioGroupItem value="option-1" id="d-1" />
40
+ <Label htmlFor="d-1">Disabled</Label>
41
+ </div>
42
+ </RadioGroup>
43
+ ),
44
+ play: async ({ canvasElement }) => {
45
+ const canvas = within(canvasElement);
46
+ await expect(canvas.getByRole('radio')).toBeDisabled();
47
+ },
48
+ };
49
+ export { Default, Disabled, stdin_default as default };
@@ -0,0 +1,33 @@
1
+ import React from 'react';
2
+ import * as ResizablePrimitive from 'react-resizable-panels';
3
+ import { cn } from './lib/utils.js';
4
+ function ResizablePanelGroup({ className, ...props }) {
5
+ return (
6
+ <ResizablePrimitive.Group
7
+ data-slot="resizable-panel-group"
8
+ className={cn(
9
+ 'cn-resizable-panel-group flex h-full w-full aria-[orientation=vertical]:flex-col',
10
+ className,
11
+ )}
12
+ {...props}
13
+ />
14
+ );
15
+ }
16
+ function ResizablePanel({ ...props }) {
17
+ return <ResizablePrimitive.Panel data-slot="resizable-panel" {...props} />;
18
+ }
19
+ function ResizableHandle({ withHandle, className, ...props }) {
20
+ return (
21
+ <ResizablePrimitive.Separator
22
+ data-slot="resizable-handle"
23
+ className={cn(
24
+ 'cn-resizable-handle bg-border focus-visible:ring-ring ring-offset-background relative flex w-px items-center justify-center after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:ring-1 focus-visible:outline-hidden aria-[orientation=horizontal]:h-px aria-[orientation=horizontal]:w-full aria-[orientation=horizontal]:after:left-0 aria-[orientation=horizontal]:after:h-1 aria-[orientation=horizontal]:after:w-full aria-[orientation=horizontal]:after:translate-x-0 aria-[orientation=horizontal]:after:-translate-y-1/2 [&[aria-orientation=horizontal]>div]:rotate-90',
25
+ className,
26
+ )}
27
+ {...props}
28
+ >
29
+ {withHandle && <div className="cn-resizable-handle-icon z-10 flex shrink-0" />}
30
+ </ResizablePrimitive.Separator>
31
+ );
32
+ }
33
+ export { ResizableHandle, ResizablePanel, ResizablePanelGroup };
@@ -0,0 +1,41 @@
1
+ import React from 'react';
2
+ import { ScrollArea as ScrollAreaPrimitive } from 'radix-ui';
3
+ import { cn } from './lib/utils.js';
4
+ function ScrollArea({ className, children, ...props }) {
5
+ return (
6
+ <ScrollAreaPrimitive.Root
7
+ data-slot="scroll-area"
8
+ className={cn('cn-scroll-area relative', className)}
9
+ {...props}
10
+ >
11
+ <ScrollAreaPrimitive.Viewport
12
+ data-slot="scroll-area-viewport"
13
+ className="cn-scroll-area-viewport focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1"
14
+ >
15
+ {children}
16
+ </ScrollAreaPrimitive.Viewport>
17
+ <ScrollBar />
18
+ <ScrollAreaPrimitive.Corner />
19
+ </ScrollAreaPrimitive.Root>
20
+ );
21
+ }
22
+ function ScrollBar({ className, orientation = 'vertical', ...props }) {
23
+ return (
24
+ <ScrollAreaPrimitive.ScrollAreaScrollbar
25
+ data-slot="scroll-area-scrollbar"
26
+ data-orientation={orientation}
27
+ orientation={orientation}
28
+ className={cn(
29
+ 'cn-scroll-area-scrollbar flex touch-none p-px transition-colors select-none',
30
+ className,
31
+ )}
32
+ {...props}
33
+ >
34
+ <ScrollAreaPrimitive.ScrollAreaThumb
35
+ data-slot="scroll-area-thumb"
36
+ className="cn-scroll-area-thumb bg-border relative flex-1"
37
+ />
38
+ </ScrollAreaPrimitive.ScrollAreaScrollbar>
39
+ );
40
+ }
41
+ export { ScrollArea, ScrollBar };
@@ -0,0 +1,43 @@
1
+ import React from 'react';
2
+ import { expect, within } from 'storybook/test';
3
+ import { ScrollArea, ScrollBar } from './scroll-area.jsx';
4
+ const meta = {
5
+ title: 'UI/ScrollArea',
6
+ component: ScrollArea,
7
+ };
8
+ var stdin_default = meta;
9
+ const Vertical = {
10
+ render: () => (
11
+ <ScrollArea style={{ height: 200, width: 300 }}>
12
+ <div style={{ padding: '1rem' }}>
13
+ {Array.from({ length: 20 }, (_, i) => (
14
+ <p key={i}>Scrollable item {i + 1}</p>
15
+ ))}
16
+ </div>
17
+ </ScrollArea>
18
+ ),
19
+ play: async ({ canvasElement }) => {
20
+ const canvas = within(canvasElement);
21
+ await expect(canvas.getByText('Scrollable item 1')).toBeInTheDocument();
22
+ await expect(canvas.getByText('Scrollable item 20')).toBeInTheDocument();
23
+ },
24
+ };
25
+ const Horizontal = {
26
+ render: () => (
27
+ <ScrollArea style={{ width: 300 }}>
28
+ <div style={{ display: 'flex', gap: '1rem', padding: '1rem', width: '800px' }}>
29
+ {Array.from({ length: 10 }, (_, i) => (
30
+ <div key={i} style={{ minWidth: 100, padding: '1rem', border: '1px solid gray' }}>
31
+ Item {i + 1}
32
+ </div>
33
+ ))}
34
+ </div>
35
+ <ScrollBar orientation="horizontal" />
36
+ </ScrollArea>
37
+ ),
38
+ play: async ({ canvasElement }) => {
39
+ const canvas = within(canvasElement);
40
+ await expect(canvas.getByText('Item 1')).toBeInTheDocument();
41
+ },
42
+ };
43
+ export { Horizontal, Vertical, stdin_default as default };
@@ -0,0 +1,145 @@
1
+ import React from 'react';
2
+ import { Select as SelectPrimitive } from 'radix-ui';
3
+ import { cn } from './lib/utils.js';
4
+ import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from 'lucide-react';
5
+ function Select({ ...props }) {
6
+ return <SelectPrimitive.Root data-slot="select" {...props} />;
7
+ }
8
+ function SelectGroup({ className, ...props }) {
9
+ return (
10
+ <SelectPrimitive.Group
11
+ data-slot="select-group"
12
+ className={cn('cn-select-group', className)}
13
+ {...props}
14
+ />
15
+ );
16
+ }
17
+ function SelectValue({ ...props }) {
18
+ return <SelectPrimitive.Value data-slot="select-value" {...props} />;
19
+ }
20
+ function SelectTrigger({ className, size = 'default', children, ...props }) {
21
+ return (
22
+ <SelectPrimitive.Trigger
23
+ data-slot="select-trigger"
24
+ data-size={size}
25
+ className={cn(
26
+ 'cn-select-trigger flex w-fit items-center justify-between whitespace-nowrap outline-none disabled:cursor-not-allowed disabled:opacity-50 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center [&_svg]:pointer-events-none [&_svg]:shrink-0',
27
+ className,
28
+ )}
29
+ {...props}
30
+ >
31
+ {children}
32
+ <SelectPrimitive.Icon asChild>
33
+ <ChevronDownIcon className="cn-select-trigger-icon pointer-events-none" />
34
+ </SelectPrimitive.Icon>
35
+ </SelectPrimitive.Trigger>
36
+ );
37
+ }
38
+ function SelectContent({
39
+ className,
40
+ children,
41
+ position = 'item-aligned',
42
+ align = 'center',
43
+ ...props
44
+ }) {
45
+ return (
46
+ <SelectPrimitive.Portal>
47
+ <SelectPrimitive.Content
48
+ data-slot="select-content"
49
+ data-align-trigger={position === 'item-aligned'}
50
+ className={cn(
51
+ 'cn-select-content cn-menu-target relative z-50 max-h-(--radix-select-content-available-height) origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto data-[align-trigger=true]:animate-none',
52
+ position === 'popper' &&
53
+ 'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
54
+ className,
55
+ )}
56
+ position={position}
57
+ align={align}
58
+ {...props}
59
+ >
60
+ <SelectScrollUpButton />
61
+ <SelectPrimitive.Viewport
62
+ data-position={position}
63
+ className={cn(
64
+ 'cn-select-viewport data-[position=popper]:h-(--radix-select-trigger-height) data-[position=popper]:w-full data-[position=popper]:min-w-(--radix-select-trigger-width)',
65
+ position === 'popper' && '',
66
+ )}
67
+ >
68
+ {children}
69
+ </SelectPrimitive.Viewport>
70
+ <SelectScrollDownButton />
71
+ </SelectPrimitive.Content>
72
+ </SelectPrimitive.Portal>
73
+ );
74
+ }
75
+ function SelectLabel({ className, ...props }) {
76
+ return (
77
+ <SelectPrimitive.Label
78
+ data-slot="select-label"
79
+ className={cn('cn-select-label', className)}
80
+ {...props}
81
+ />
82
+ );
83
+ }
84
+ function SelectItem({ className, children, ...props }) {
85
+ return (
86
+ <SelectPrimitive.Item
87
+ data-slot="select-item"
88
+ className={cn(
89
+ 'cn-select-item relative flex w-full cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0',
90
+ className,
91
+ )}
92
+ {...props}
93
+ >
94
+ <span className="cn-select-item-indicator">
95
+ <SelectPrimitive.ItemIndicator>
96
+ <CheckIcon className="cn-select-item-indicator-icon pointer-events-none" />
97
+ </SelectPrimitive.ItemIndicator>
98
+ </span>
99
+ <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
100
+ </SelectPrimitive.Item>
101
+ );
102
+ }
103
+ function SelectSeparator({ className, ...props }) {
104
+ return (
105
+ <SelectPrimitive.Separator
106
+ data-slot="select-separator"
107
+ className={cn('cn-select-separator pointer-events-none', className)}
108
+ {...props}
109
+ />
110
+ );
111
+ }
112
+ function SelectScrollUpButton({ className, ...props }) {
113
+ return (
114
+ <SelectPrimitive.ScrollUpButton
115
+ data-slot="select-scroll-up-button"
116
+ className={cn('cn-select-scroll-up-button', className)}
117
+ {...props}
118
+ >
119
+ <ChevronUpIcon />
120
+ </SelectPrimitive.ScrollUpButton>
121
+ );
122
+ }
123
+ function SelectScrollDownButton({ className, ...props }) {
124
+ return (
125
+ <SelectPrimitive.ScrollDownButton
126
+ data-slot="select-scroll-down-button"
127
+ className={cn('cn-select-scroll-down-button', className)}
128
+ {...props}
129
+ >
130
+ <ChevronDownIcon />
131
+ </SelectPrimitive.ScrollDownButton>
132
+ );
133
+ }
134
+ export {
135
+ Select,
136
+ SelectContent,
137
+ SelectGroup,
138
+ SelectItem,
139
+ SelectLabel,
140
+ SelectScrollDownButton,
141
+ SelectScrollUpButton,
142
+ SelectSeparator,
143
+ SelectTrigger,
144
+ SelectValue,
145
+ };
@@ -0,0 +1,80 @@
1
+ import React from 'react';
2
+ import { expect, within } from 'storybook/test';
3
+ import {
4
+ Select,
5
+ SelectContent,
6
+ SelectItem,
7
+ SelectTrigger,
8
+ SelectValue,
9
+ SelectGroup,
10
+ SelectLabel,
11
+ } from './select.jsx';
12
+ const meta = {
13
+ title: 'UI/Select',
14
+ component: Select,
15
+ };
16
+ var stdin_default = meta;
17
+ const Default = {
18
+ render: () => (
19
+ <Select>
20
+ <SelectTrigger className="w-[200px]">
21
+ <SelectValue placeholder="Pick a fruit" />
22
+ </SelectTrigger>
23
+ <SelectContent>
24
+ <SelectItem value="apple">Apple</SelectItem>
25
+ <SelectItem value="banana">Banana</SelectItem>
26
+ <SelectItem value="cherry">Cherry</SelectItem>
27
+ </SelectContent>
28
+ </Select>
29
+ ),
30
+ play: async ({ canvasElement }) => {
31
+ const canvas = within(canvasElement);
32
+ const trigger = canvas.getByRole('combobox');
33
+ await expect(trigger).toBeInTheDocument();
34
+ await expect(trigger.dataset.slot).toBe('select-trigger');
35
+ },
36
+ };
37
+ const WithGroups = {
38
+ render: () => (
39
+ <Select>
40
+ <SelectTrigger className="w-[200px]">
41
+ <SelectValue placeholder="Select food" />
42
+ </SelectTrigger>
43
+ <SelectContent>
44
+ <SelectGroup>
45
+ <SelectLabel>Fruits</SelectLabel>
46
+ <SelectItem value="apple">Apple</SelectItem>
47
+ <SelectItem value="banana">Banana</SelectItem>
48
+ </SelectGroup>
49
+ <SelectGroup>
50
+ <SelectLabel>Vegetables</SelectLabel>
51
+ <SelectItem value="carrot">Carrot</SelectItem>
52
+ <SelectItem value="potato">Potato</SelectItem>
53
+ </SelectGroup>
54
+ </SelectContent>
55
+ </Select>
56
+ ),
57
+ play: async ({ canvasElement }) => {
58
+ const canvas = within(canvasElement);
59
+ await expect(canvas.getByRole('combobox')).toBeInTheDocument();
60
+ },
61
+ };
62
+ const SmallSize = {
63
+ render: () => (
64
+ <Select>
65
+ <SelectTrigger size="sm" className="w-[200px]">
66
+ <SelectValue placeholder="Small select" />
67
+ </SelectTrigger>
68
+ <SelectContent>
69
+ <SelectItem value="a">Item A</SelectItem>
70
+ <SelectItem value="b">Item B</SelectItem>
71
+ </SelectContent>
72
+ </Select>
73
+ ),
74
+ play: async ({ canvasElement }) => {
75
+ const canvas = within(canvasElement);
76
+ const trigger = canvas.getByRole('combobox');
77
+ await expect(trigger.dataset.size).toBe('sm');
78
+ },
79
+ };
80
+ export { Default, SmallSize, WithGroups, stdin_default as default };
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ import { Separator as SeparatorPrimitive } from 'radix-ui';
3
+ import { cn } from './lib/utils.js';
4
+ function Separator({ className, orientation = 'horizontal', decorative = true, ...props }) {
5
+ return (
6
+ <SeparatorPrimitive.Root
7
+ data-slot="separator"
8
+ decorative={decorative}
9
+ orientation={orientation}
10
+ className={cn(
11
+ 'bg-border shrink-0 data-horizontal:h-px data-horizontal:w-full data-vertical:w-px data-vertical:self-stretch',
12
+ className,
13
+ )}
14
+ {...props}
15
+ />
16
+ );
17
+ }
18
+ export { Separator };