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,86 @@
1
+ import React from 'react';
2
+ import { Slot } from 'radix-ui';
3
+ import { cn } from './lib/utils.js';
4
+ import { ChevronRightIcon, MoreHorizontalIcon } from 'lucide-react';
5
+ function Breadcrumb({ className, ...props }) {
6
+ return (
7
+ <nav
8
+ aria-label="breadcrumb"
9
+ data-slot="breadcrumb"
10
+ className={cn('cn-breadcrumb', className)}
11
+ {...props}
12
+ />
13
+ );
14
+ }
15
+ function BreadcrumbList({ className, ...props }) {
16
+ return (
17
+ <ol
18
+ data-slot="breadcrumb-list"
19
+ className={cn('cn-breadcrumb-list flex flex-wrap items-center wrap-break-word', className)}
20
+ {...props}
21
+ />
22
+ );
23
+ }
24
+ function BreadcrumbItem({ className, ...props }) {
25
+ return (
26
+ <li
27
+ data-slot="breadcrumb-item"
28
+ className={cn('cn-breadcrumb-item inline-flex items-center', className)}
29
+ {...props}
30
+ />
31
+ );
32
+ }
33
+ function BreadcrumbLink({ asChild, className, ...props }) {
34
+ const Comp = asChild ? Slot.Root : 'a';
35
+ return (
36
+ <Comp data-slot="breadcrumb-link" className={cn('cn-breadcrumb-link', className)} {...props} />
37
+ );
38
+ }
39
+ function BreadcrumbPage({ className, ...props }) {
40
+ return (
41
+ <span
42
+ data-slot="breadcrumb-page"
43
+ role="link"
44
+ aria-disabled="true"
45
+ aria-current="page"
46
+ className={cn('cn-breadcrumb-page', className)}
47
+ {...props}
48
+ />
49
+ );
50
+ }
51
+ function BreadcrumbSeparator({ children, className, ...props }) {
52
+ return (
53
+ <li
54
+ data-slot="breadcrumb-separator"
55
+ role="presentation"
56
+ aria-hidden="true"
57
+ className={cn('cn-breadcrumb-separator', className)}
58
+ {...props}
59
+ >
60
+ {children ?? <ChevronRightIcon className="cn-rtl-flip" />}
61
+ </li>
62
+ );
63
+ }
64
+ function BreadcrumbEllipsis({ className, ...props }) {
65
+ return (
66
+ <span
67
+ data-slot="breadcrumb-ellipsis"
68
+ role="presentation"
69
+ aria-hidden="true"
70
+ className={cn('cn-breadcrumb-ellipsis flex items-center justify-center', className)}
71
+ {...props}
72
+ >
73
+ <MoreHorizontalIcon />
74
+ <span className="sr-only">More</span>
75
+ </span>
76
+ );
77
+ }
78
+ export {
79
+ Breadcrumb,
80
+ BreadcrumbEllipsis,
81
+ BreadcrumbItem,
82
+ BreadcrumbLink,
83
+ BreadcrumbList,
84
+ BreadcrumbPage,
85
+ BreadcrumbSeparator,
86
+ };
@@ -0,0 +1,43 @@
1
+ import React from 'react';
2
+ import { expect, within } from 'storybook/test';
3
+ import {
4
+ Breadcrumb,
5
+ BreadcrumbList,
6
+ BreadcrumbItem,
7
+ BreadcrumbLink,
8
+ BreadcrumbSeparator,
9
+ BreadcrumbPage,
10
+ } from './breadcrumb.jsx';
11
+ const meta = {
12
+ title: 'UI/Breadcrumb',
13
+ component: Breadcrumb,
14
+ };
15
+ var stdin_default = meta;
16
+ const Default = {
17
+ render: () => (
18
+ <Breadcrumb>
19
+ <BreadcrumbList>
20
+ <BreadcrumbItem>
21
+ <BreadcrumbLink href="#">Home</BreadcrumbLink>
22
+ </BreadcrumbItem>
23
+ <BreadcrumbSeparator />
24
+ <BreadcrumbItem>
25
+ <BreadcrumbLink href="#">Products</BreadcrumbLink>
26
+ </BreadcrumbItem>
27
+ <BreadcrumbSeparator />
28
+ <BreadcrumbItem>
29
+ <BreadcrumbPage>Current Page</BreadcrumbPage>
30
+ </BreadcrumbItem>
31
+ </BreadcrumbList>
32
+ </Breadcrumb>
33
+ ),
34
+ play: async ({ canvasElement }) => {
35
+ const canvas = within(canvasElement);
36
+ await expect(canvas.getByText('Home')).toBeInTheDocument();
37
+ await expect(canvas.getByText('Products')).toBeInTheDocument();
38
+ const current = canvas.getByText('Current Page');
39
+ await expect(current).toBeInTheDocument();
40
+ await expect(current).toHaveAttribute('aria-current', 'page');
41
+ },
42
+ };
43
+ export { Default, stdin_default as default };
@@ -0,0 +1,58 @@
1
+ import React from 'react';
2
+ import { cva } from 'class-variance-authority';
3
+ import { Slot } from 'radix-ui';
4
+ import { cn } from './lib/utils.js';
5
+ import { Separator } from './separator.jsx';
6
+ const buttonGroupVariants = cva(
7
+ "cn-button-group flex w-fit items-stretch *:focus-visible:z-10 *:focus-visible:relative [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1 ",
8
+ {
9
+ variants: {
10
+ orientation: {
11
+ horizontal:
12
+ 'cn-button-group-orientation-horizontal [&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none',
13
+ vertical:
14
+ 'cn-button-group-orientation-vertical flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none',
15
+ },
16
+ },
17
+ defaultVariants: {
18
+ orientation: 'horizontal',
19
+ },
20
+ },
21
+ );
22
+ function ButtonGroup({ className, orientation, ...props }) {
23
+ return (
24
+ <div
25
+ role="group"
26
+ data-slot="button-group"
27
+ data-orientation={orientation}
28
+ className={cn(buttonGroupVariants({ orientation }), className)}
29
+ {...props}
30
+ />
31
+ );
32
+ }
33
+ function ButtonGroupText({ className, asChild = false, ...props }) {
34
+ const Comp = asChild ? Slot.Root : 'div';
35
+ return (
36
+ <Comp
37
+ className={cn(
38
+ 'cn-button-group-text flex items-center [&_svg]:pointer-events-none',
39
+ className,
40
+ )}
41
+ {...props}
42
+ />
43
+ );
44
+ }
45
+ function ButtonGroupSeparator({ className, orientation = 'vertical', ...props }) {
46
+ return (
47
+ <Separator
48
+ data-slot="button-group-separator"
49
+ orientation={orientation}
50
+ className={cn(
51
+ 'cn-button-group-separator relative self-stretch data-horizontal:mx-px data-horizontal:w-auto data-vertical:my-px data-vertical:h-auto',
52
+ className,
53
+ )}
54
+ {...props}
55
+ />
56
+ );
57
+ }
58
+ export { ButtonGroup, ButtonGroupSeparator, ButtonGroupText, buttonGroupVariants };
@@ -0,0 +1,67 @@
1
+ import React from 'react';
2
+ import { expect, within } from 'storybook/test';
3
+ import { ButtonGroup, ButtonGroupText, ButtonGroupSeparator } from './button-group.jsx';
4
+ import { Button } from './button.jsx';
5
+ const meta = {
6
+ title: 'UI/ButtonGroup',
7
+ component: ButtonGroup,
8
+ };
9
+ var stdin_default = meta;
10
+ const Horizontal = {
11
+ render: () => (
12
+ <ButtonGroup orientation="horizontal">
13
+ <Button variant="outline">Left</Button>
14
+ <Button variant="outline">Center</Button>
15
+ <Button variant="outline">Right</Button>
16
+ </ButtonGroup>
17
+ ),
18
+ play: async ({ canvasElement }) => {
19
+ const canvas = within(canvasElement);
20
+ const group = canvas.getByRole('group');
21
+ await expect(group).toBeInTheDocument();
22
+ await expect(group.dataset.slot).toBe('button-group');
23
+ await expect(group.dataset.orientation).toBe('horizontal');
24
+ const buttons = canvas.getAllByRole('button');
25
+ await expect(buttons).toHaveLength(3);
26
+ },
27
+ };
28
+ const Vertical = {
29
+ render: () => (
30
+ <ButtonGroup orientation="vertical">
31
+ <Button variant="outline">Top</Button>
32
+ <Button variant="outline">Middle</Button>
33
+ <Button variant="outline">Bottom</Button>
34
+ </ButtonGroup>
35
+ ),
36
+ play: async ({ canvasElement }) => {
37
+ const canvas = within(canvasElement);
38
+ const group = canvas.getByRole('group');
39
+ await expect(group.dataset.orientation).toBe('vertical');
40
+ },
41
+ };
42
+ const WithSeparator = {
43
+ render: () => (
44
+ <ButtonGroup orientation="horizontal">
45
+ <Button variant="outline">Save</Button>
46
+ <ButtonGroupSeparator />
47
+ <Button variant="outline">Cancel</Button>
48
+ </ButtonGroup>
49
+ ),
50
+ play: async ({ canvasElement }) => {
51
+ const sep = canvasElement.querySelector('[data-slot="button-group-separator"]');
52
+ await expect(sep).toBeInTheDocument();
53
+ },
54
+ };
55
+ const WithText = {
56
+ render: () => (
57
+ <ButtonGroup orientation="horizontal">
58
+ <ButtonGroupText>Label:</ButtonGroupText>
59
+ <Button variant="outline">Action</Button>
60
+ </ButtonGroup>
61
+ ),
62
+ play: async ({ canvasElement }) => {
63
+ const canvas = within(canvasElement);
64
+ await expect(canvas.getByText('Label:')).toBeInTheDocument();
65
+ },
66
+ };
67
+ export { Horizontal, Vertical, WithSeparator, WithText, stdin_default as default };
@@ -0,0 +1,46 @@
1
+ import React from 'react';
2
+ import { cva } from 'class-variance-authority';
3
+ import { Slot } from 'radix-ui';
4
+ import { cn } from './lib/utils.js';
5
+ const buttonVariants = cva(
6
+ 'cn-button inline-flex items-center justify-center whitespace-nowrap transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none group/button select-none',
7
+ {
8
+ variants: {
9
+ variant: {
10
+ default: 'cn-button-variant-default',
11
+ outline: 'cn-button-variant-outline',
12
+ secondary: 'cn-button-variant-secondary',
13
+ ghost: 'cn-button-variant-ghost',
14
+ destructive: 'cn-button-variant-destructive',
15
+ link: 'cn-button-variant-link',
16
+ },
17
+ size: {
18
+ default: 'cn-button-size-default',
19
+ xs: 'cn-button-size-xs',
20
+ sm: 'cn-button-size-sm',
21
+ lg: 'cn-button-size-lg',
22
+ icon: 'cn-button-size-icon',
23
+ 'icon-xs': 'cn-button-size-icon-xs',
24
+ 'icon-sm': 'cn-button-size-icon-sm',
25
+ 'icon-lg': 'cn-button-size-icon-lg',
26
+ },
27
+ },
28
+ defaultVariants: {
29
+ variant: 'default',
30
+ size: 'default',
31
+ },
32
+ },
33
+ );
34
+ function Button({ className, variant = 'default', size = 'default', asChild = false, ...props }) {
35
+ const Comp = asChild ? Slot.Root : 'button';
36
+ return (
37
+ <Comp
38
+ data-slot="button"
39
+ data-variant={variant}
40
+ data-size={size}
41
+ className={cn(buttonVariants({ variant, size, className }))}
42
+ {...props}
43
+ />
44
+ );
45
+ }
46
+ export { Button, buttonVariants };
@@ -0,0 +1,72 @@
1
+ import { expect, within } from 'storybook/test';
2
+ import { Button } from './button.jsx';
3
+ const meta = {
4
+ title: 'UI/Button',
5
+ component: Button,
6
+ argTypes: {
7
+ variant: {
8
+ control: 'select',
9
+ options: ['default', 'outline', 'secondary', 'ghost', 'destructive', 'link'],
10
+ },
11
+ size: {
12
+ control: 'select',
13
+ options: ['default', 'xs', 'sm', 'lg', 'icon'],
14
+ },
15
+ },
16
+ };
17
+ var stdin_default = meta;
18
+ const Default = {
19
+ args: { children: 'Button' },
20
+ play: async ({ canvasElement }) => {
21
+ const canvas = within(canvasElement);
22
+ const btn = canvas.getByRole('button', { name: 'Button' });
23
+ await expect(btn).toBeInTheDocument();
24
+ await expect(btn.dataset.slot).toBe('button');
25
+ },
26
+ };
27
+ const Outline = {
28
+ args: { children: 'Outline', variant: 'outline' },
29
+ play: async ({ canvasElement }) => {
30
+ const canvas = within(canvasElement);
31
+ const btn = canvas.getByRole('button', { name: 'Outline' });
32
+ await expect(btn.dataset.variant).toBe('outline');
33
+ },
34
+ };
35
+ const Secondary = {
36
+ args: { children: 'Secondary', variant: 'secondary' },
37
+ };
38
+ const Ghost = {
39
+ args: { children: 'Ghost', variant: 'ghost' },
40
+ };
41
+ const Destructive = {
42
+ args: { children: 'Destructive', variant: 'destructive' },
43
+ };
44
+ const Link = {
45
+ args: { children: 'Link', variant: 'link' },
46
+ };
47
+ const Small = {
48
+ args: { children: 'Small', size: 'sm' },
49
+ };
50
+ const Large = {
51
+ args: { children: 'Large', size: 'lg' },
52
+ };
53
+ const Disabled = {
54
+ args: { children: 'Disabled', disabled: true },
55
+ play: async ({ canvasElement }) => {
56
+ const canvas = within(canvasElement);
57
+ const btn = canvas.getByRole('button', { name: 'Disabled' });
58
+ await expect(btn).toBeDisabled();
59
+ },
60
+ };
61
+ export {
62
+ Default,
63
+ Destructive,
64
+ Disabled,
65
+ Ghost,
66
+ Large,
67
+ Link,
68
+ Outline,
69
+ Secondary,
70
+ Small,
71
+ stdin_default as default,
72
+ };
@@ -0,0 +1,172 @@
1
+ import * as React from 'react';
2
+ import { DayPicker, getDefaultClassNames } from 'react-day-picker';
3
+ import { cn } from './lib/utils.js';
4
+ import { Button, buttonVariants } from './button.jsx';
5
+ import { ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon } from 'lucide-react';
6
+ function Calendar({
7
+ className,
8
+ classNames,
9
+ showOutsideDays = true,
10
+ captionLayout = 'label',
11
+ buttonVariant = 'ghost',
12
+ locale,
13
+ formatters,
14
+ components,
15
+ ...props
16
+ }) {
17
+ const defaultClassNames = getDefaultClassNames();
18
+ return (
19
+ <DayPicker
20
+ showOutsideDays={showOutsideDays}
21
+ className={cn(
22
+ 'cn-calendar bg-background group/calendar in-data-[slot=card-content]:bg-transparent in-data-[slot=popover-content]:bg-transparent',
23
+ String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
24
+ String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
25
+ className,
26
+ )}
27
+ captionLayout={captionLayout}
28
+ locale={locale}
29
+ formatters={{
30
+ formatMonthDropdown: (date) => date.toLocaleString(locale?.code, { month: 'short' }),
31
+ ...formatters,
32
+ }}
33
+ classNames={{
34
+ root: cn('w-fit', defaultClassNames.root),
35
+ months: cn('flex gap-4 flex-col md:flex-row relative', defaultClassNames.months),
36
+ month: cn('flex flex-col w-full gap-4', defaultClassNames.month),
37
+ nav: cn(
38
+ 'flex items-center gap-1 w-full absolute top-0 inset-x-0 justify-between',
39
+ defaultClassNames.nav,
40
+ ),
41
+ button_previous: cn(
42
+ buttonVariants({ variant: buttonVariant }),
43
+ 'size-(--cell-size) aria-disabled:opacity-50 p-0 select-none',
44
+ defaultClassNames.button_previous,
45
+ ),
46
+ button_next: cn(
47
+ buttonVariants({ variant: buttonVariant }),
48
+ 'size-(--cell-size) aria-disabled:opacity-50 p-0 select-none',
49
+ defaultClassNames.button_next,
50
+ ),
51
+ month_caption: cn(
52
+ 'flex items-center justify-center h-(--cell-size) w-full px-(--cell-size)',
53
+ defaultClassNames.month_caption,
54
+ ),
55
+ dropdowns: cn(
56
+ 'w-full flex items-center text-sm font-medium justify-center h-(--cell-size) gap-1.5',
57
+ defaultClassNames.dropdowns,
58
+ ),
59
+ dropdown_root: cn(
60
+ 'relative cn-calendar-dropdown-root rounded-(--cell-radius)',
61
+ defaultClassNames.dropdown_root,
62
+ ),
63
+ dropdown: cn('absolute bg-popover inset-0 opacity-0', defaultClassNames.dropdown),
64
+ caption_label: cn(
65
+ 'select-none font-medium',
66
+ captionLayout === 'label'
67
+ ? 'text-sm'
68
+ : 'cn-calendar-caption-label rounded-(--cell-radius) flex items-center gap-1 text-sm [&>svg]:text-muted-foreground [&>svg]:size-3.5',
69
+ defaultClassNames.caption_label,
70
+ ),
71
+ table: 'w-full border-collapse',
72
+ weekdays: cn('flex', defaultClassNames.weekdays),
73
+ weekday: cn(
74
+ 'text-muted-foreground rounded-(--cell-radius) flex-1 font-normal text-[0.8rem] select-none',
75
+ defaultClassNames.weekday,
76
+ ),
77
+ week: cn('flex w-full mt-2', defaultClassNames.week),
78
+ week_number_header: cn('select-none w-(--cell-size)', defaultClassNames.week_number_header),
79
+ week_number: cn(
80
+ 'text-[0.8rem] select-none text-muted-foreground',
81
+ defaultClassNames.week_number,
82
+ ),
83
+ day: cn(
84
+ 'relative w-full rounded-(--cell-radius) h-full p-0 text-center [&:last-child[data-selected=true]_button]:rounded-r-(--cell-radius) group/day aspect-square select-none',
85
+ props.showWeekNumber
86
+ ? '[&:nth-child(2)[data-selected=true]_button]:rounded-l-(--cell-radius)'
87
+ : '[&:first-child[data-selected=true]_button]:rounded-l-(--cell-radius)',
88
+ defaultClassNames.day,
89
+ ),
90
+ range_start: cn(
91
+ 'rounded-l-(--cell-radius) bg-muted relative after:bg-muted after:absolute after:inset-y-0 after:w-4 after:right-0 z-0 isolate',
92
+ defaultClassNames.range_start,
93
+ ),
94
+ range_middle: cn('rounded-none', defaultClassNames.range_middle),
95
+ range_end: cn(
96
+ 'rounded-r-(--cell-radius) bg-muted relative after:bg-muted after:absolute after:inset-y-0 after:w-4 after:left-0 z-0 isolate',
97
+ defaultClassNames.range_end,
98
+ ),
99
+ today: cn(
100
+ 'bg-muted text-foreground rounded-(--cell-radius) data-[selected=true]:rounded-none',
101
+ defaultClassNames.today,
102
+ ),
103
+ outside: cn(
104
+ 'text-muted-foreground aria-selected:text-muted-foreground',
105
+ defaultClassNames.outside,
106
+ ),
107
+ disabled: cn('text-muted-foreground opacity-50', defaultClassNames.disabled),
108
+ hidden: cn('invisible', defaultClassNames.hidden),
109
+ ...classNames,
110
+ }}
111
+ components={{
112
+ Root: ({ className: className2, rootRef, ...props2 }) => {
113
+ return <div data-slot="calendar" ref={rootRef} className={cn(className2)} {...props2} />;
114
+ },
115
+ Chevron: ({ className: className2, orientation, ...props2 }) => {
116
+ if (orientation === 'left') {
117
+ return <ChevronLeftIcon className={cn('cn-rtl-flip size-4', className2)} {...props2} />;
118
+ }
119
+ if (orientation === 'right') {
120
+ return (
121
+ <ChevronRightIcon className={cn('cn-rtl-flip size-4', className2)} {...props2} />
122
+ );
123
+ }
124
+ return <ChevronDownIcon className={cn('size-4', className2)} {...props2} />;
125
+ },
126
+ DayButton: ({ ...props2 }) => <CalendarDayButton locale={locale} {...props2} />,
127
+ WeekNumber: ({ children, ...props2 }) => {
128
+ return (
129
+ <td {...props2}>
130
+ <div className="flex size-(--cell-size) items-center justify-center text-center">
131
+ {children}
132
+ </div>
133
+ </td>
134
+ );
135
+ },
136
+ ...components,
137
+ }}
138
+ {...props}
139
+ />
140
+ );
141
+ }
142
+ function CalendarDayButton({ className, day, modifiers, locale, ...props }) {
143
+ const defaultClassNames = getDefaultClassNames();
144
+ const ref = React.useRef(null);
145
+ React.useEffect(() => {
146
+ if (modifiers.focused) ref.current?.focus();
147
+ }, [modifiers.focused]);
148
+ return (
149
+ <Button
150
+ ref={ref}
151
+ variant="ghost"
152
+ size="icon"
153
+ data-day={day.date.toLocaleDateString(locale?.code)}
154
+ data-selected-single={
155
+ modifiers.selected &&
156
+ !modifiers.range_start &&
157
+ !modifiers.range_end &&
158
+ !modifiers.range_middle
159
+ }
160
+ data-range-start={modifiers.range_start}
161
+ data-range-end={modifiers.range_end}
162
+ data-range-middle={modifiers.range_middle}
163
+ className={cn(
164
+ 'cn-calendar-day-button data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground data-[range-middle=true]:bg-muted data-[range-middle=true]:text-foreground data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-ring/50 dark:hover:text-foreground relative isolate z-10 flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 border-0 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-[3px] data-[range-end=true]:rounded-(--cell-radius) data-[range-end=true]:rounded-r-(--cell-radius) data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-(--cell-radius) data-[range-start=true]:rounded-l-(--cell-radius) [&>span]:text-xs [&>span]:opacity-70',
165
+ defaultClassNames.day,
166
+ className,
167
+ )}
168
+ {...props}
169
+ />
170
+ );
171
+ }
172
+ export { Calendar, CalendarDayButton };
@@ -0,0 +1,57 @@
1
+ import React from 'react';
2
+ import { cn } from './lib/utils.js';
3
+ function Card({ className, size = 'default', ...props }) {
4
+ return (
5
+ <div
6
+ data-slot="card"
7
+ data-size={size}
8
+ className={cn('cn-card group/card flex flex-col', className)}
9
+ {...props}
10
+ />
11
+ );
12
+ }
13
+ function CardHeader({ className, ...props }) {
14
+ return (
15
+ <div
16
+ data-slot="card-header"
17
+ className={cn(
18
+ 'cn-card-header group/card-header @container/card-header grid auto-rows-min items-start has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto]',
19
+ className,
20
+ )}
21
+ {...props}
22
+ />
23
+ );
24
+ }
25
+ function CardTitle({ className, ...props }) {
26
+ return <div data-slot="card-title" className={cn('cn-card-title', className)} {...props} />;
27
+ }
28
+ function CardDescription({ className, ...props }) {
29
+ return (
30
+ <div data-slot="card-description" className={cn('cn-card-description', className)} {...props} />
31
+ );
32
+ }
33
+ function CardAction({ className, ...props }) {
34
+ return (
35
+ <div
36
+ data-slot="card-action"
37
+ className={cn(
38
+ 'cn-card-action col-start-2 row-span-2 row-start-1 self-start justify-self-end',
39
+ className,
40
+ )}
41
+ {...props}
42
+ />
43
+ );
44
+ }
45
+ function CardContent({ className, ...props }) {
46
+ return <div data-slot="card-content" className={cn('cn-card-content', className)} {...props} />;
47
+ }
48
+ function CardFooter({ className, ...props }) {
49
+ return (
50
+ <div
51
+ data-slot="card-footer"
52
+ className={cn('cn-card-footer flex items-center', className)}
53
+ {...props}
54
+ />
55
+ );
56
+ }
57
+ export { Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle };
@@ -0,0 +1,33 @@
1
+ import React from 'react';
2
+ import { expect, within } from 'storybook/test';
3
+ import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from './card.jsx';
4
+ import { Button } from './button.jsx';
5
+ const meta = {
6
+ title: 'UI/Card',
7
+ component: Card,
8
+ };
9
+ var stdin_default = meta;
10
+ const Default = {
11
+ render: () => (
12
+ <Card className="w-80">
13
+ <CardHeader>
14
+ <CardTitle>Card Title</CardTitle>
15
+ <CardDescription>Card description text.</CardDescription>
16
+ </CardHeader>
17
+ <CardContent>
18
+ <p>Card body content goes here.</p>
19
+ </CardContent>
20
+ <CardFooter>
21
+ <Button>Action</Button>
22
+ </CardFooter>
23
+ </Card>
24
+ ),
25
+ play: async ({ canvasElement }) => {
26
+ const canvas = within(canvasElement);
27
+ const card = canvasElement.querySelector('[data-slot="card"]');
28
+ await expect(card).toBeInTheDocument();
29
+ await expect(canvas.getByText('Card Title')).toBeInTheDocument();
30
+ await expect(canvas.getByText('Card description text.')).toBeInTheDocument();
31
+ },
32
+ };
33
+ export { Default, stdin_default as default };