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.
- package/LICENSE +21 -0
- package/README.md +711 -0
- package/client/env.js +55 -0
- package/client/fetcher.js +50 -0
- package/client/graphql.js +35 -0
- package/client/head.js +140 -0
- package/client/hooks/use-api.js +80 -0
- package/client/hooks/use-debounce.js +12 -0
- package/client/hooks/use-form.js +86 -0
- package/client/hooks/use-graphql.js +30 -0
- package/client/hooks/use-interval.js +12 -0
- package/client/hooks/use-mutation.js +27 -0
- package/client/hooks/use-query.js +45 -0
- package/client/hooks/web/use-click-outside.js +22 -0
- package/client/hooks/web/use-local-storage.js +42 -0
- package/client/index.js +62 -0
- package/client/page-loader.js +155 -0
- package/client/provider.js +53 -0
- package/client/query.js +13 -0
- package/client/router.jsx +303 -0
- package/client/ui/accordion.jsx +65 -0
- package/client/ui/accordion.stories.jsx +48 -0
- package/client/ui/alert-dialog.jsx +122 -0
- package/client/ui/alert-dialog.stories.jsx +44 -0
- package/client/ui/alert.jsx +52 -0
- package/client/ui/alert.stories.jsx +31 -0
- package/client/ui/app-shell.jsx +39 -0
- package/client/ui/app-shell.stories.jsx +51 -0
- package/client/ui/aspect-ratio.jsx +6 -0
- package/client/ui/aspect-ratio.stories.jsx +69 -0
- package/client/ui/avatar.jsx +78 -0
- package/client/ui/avatar.stories.jsx +62 -0
- package/client/ui/badge.jsx +34 -0
- package/client/ui/badge.stories.js +32 -0
- package/client/ui/breadcrumb.jsx +86 -0
- package/client/ui/breadcrumb.stories.jsx +43 -0
- package/client/ui/button-group.jsx +58 -0
- package/client/ui/button-group.stories.jsx +67 -0
- package/client/ui/button.jsx +46 -0
- package/client/ui/button.stories.js +72 -0
- package/client/ui/calendar.jsx +172 -0
- package/client/ui/card.jsx +57 -0
- package/client/ui/card.stories.jsx +33 -0
- package/client/ui/carousel.jsx +167 -0
- package/client/ui/chart.jsx +244 -0
- package/client/ui/checkbox.jsx +24 -0
- package/client/ui/checkbox.stories.js +33 -0
- package/client/ui/collapsible.jsx +12 -0
- package/client/ui/collapsible.stories.jsx +42 -0
- package/client/ui/combobox.jsx +223 -0
- package/client/ui/command.jsx +128 -0
- package/client/ui/context-menu.jsx +170 -0
- package/client/ui/context-menu.stories.jsx +35 -0
- package/client/ui/dialog.jsx +109 -0
- package/client/ui/dialog.stories.jsx +37 -0
- package/client/ui/direction.jsx +9 -0
- package/client/ui/drawer.jsx +87 -0
- package/client/ui/dropdown-menu.jsx +172 -0
- package/client/ui/dropdown-menu.stories.jsx +34 -0
- package/client/ui/empty.jsx +76 -0
- package/client/ui/empty.stories.jsx +64 -0
- package/client/ui/field.jsx +174 -0
- package/client/ui/field.stories.jsx +118 -0
- package/client/ui/form.jsx +17 -0
- package/client/ui/hooks/use-mobile.js +16 -0
- package/client/ui/hover-card.jsx +26 -0
- package/client/ui/hover-card.stories.jsx +28 -0
- package/client/ui/index.js +649 -0
- package/client/ui/input-group.jsx +116 -0
- package/client/ui/input-group.stories.jsx +65 -0
- package/client/ui/input-otp.jsx +62 -0
- package/client/ui/input.jsx +16 -0
- package/client/ui/input.stories.js +27 -0
- package/client/ui/item.jsx +155 -0
- package/client/ui/item.stories.jsx +118 -0
- package/client/ui/kbd.jsx +24 -0
- package/client/ui/kbd.stories.jsx +32 -0
- package/client/ui/label.jsx +16 -0
- package/client/ui/label.stories.js +25 -0
- package/client/ui/lib/utils.js +6 -0
- package/client/ui/main-content.jsx +30 -0
- package/client/ui/menubar.jsx +189 -0
- package/client/ui/menubar.stories.jsx +43 -0
- package/client/ui/native-select.jsx +34 -0
- package/client/ui/native-select.stories.jsx +67 -0
- package/client/ui/navigation-menu.jsx +120 -0
- package/client/ui/navigation-menu.stories.jsx +45 -0
- package/client/ui/pagination.jsx +92 -0
- package/client/ui/pagination.stories.jsx +52 -0
- package/client/ui/panel.jsx +66 -0
- package/client/ui/popover.jsx +54 -0
- package/client/ui/popover.stories.jsx +27 -0
- package/client/ui/progress.jsx +19 -0
- package/client/ui/progress.stories.js +34 -0
- package/client/ui/radio-group.jsx +33 -0
- package/client/ui/radio-group.stories.jsx +49 -0
- package/client/ui/resizable.jsx +33 -0
- package/client/ui/scroll-area.jsx +41 -0
- package/client/ui/scroll-area.stories.jsx +43 -0
- package/client/ui/select.jsx +145 -0
- package/client/ui/select.stories.jsx +80 -0
- package/client/ui/separator.jsx +18 -0
- package/client/ui/separator.stories.jsx +37 -0
- package/client/ui/sheet.jsx +95 -0
- package/client/ui/sheet.stories.jsx +56 -0
- package/client/ui/sidebar.jsx +544 -0
- package/client/ui/skeleton.jsx +8 -0
- package/client/ui/skeleton.stories.js +23 -0
- package/client/ui/slider.jsx +41 -0
- package/client/ui/slider.stories.js +31 -0
- package/client/ui/sonner.jsx +37 -0
- package/client/ui/spinner.jsx +14 -0
- package/client/ui/spinner.stories.js +16 -0
- package/client/ui/style-mira.css +1316 -0
- package/client/ui/switch.jsx +22 -0
- package/client/ui/switch.stories.js +44 -0
- package/client/ui/table.jsx +33 -0
- package/client/ui/table.stories.jsx +42 -0
- package/client/ui/tabs.jsx +63 -0
- package/client/ui/tabs.stories.jsx +45 -0
- package/client/ui/textarea.jsx +15 -0
- package/client/ui/textarea.stories.js +33 -0
- package/client/ui/theme.css +459 -0
- package/client/ui/toggle-group.jsx +62 -0
- package/client/ui/toggle-group.stories.jsx +68 -0
- package/client/ui/toggle.jsx +34 -0
- package/client/ui/toggle.stories.js +46 -0
- package/client/ui/tooltip.jsx +37 -0
- package/client/ui/tooltip.stories.jsx +32 -0
- package/client/ui/use-transition.js +35 -0
- package/client/ws.js +132 -0
- package/package.json +134 -0
- package/server/bin/cli.js +42 -0
- package/server/bin/commands/build.js +23 -0
- package/server/bin/commands/dev.js +57 -0
- package/server/bin/commands/docs.js +30 -0
- package/server/bin/commands/graphql-schema.js +32 -0
- package/server/bin/commands/lint.js +35 -0
- package/server/bin/commands/mcp.js +26 -0
- package/server/bin/commands/migrate.js +82 -0
- package/server/bin/commands/schema.js +41 -0
- package/server/bin/commands/seed.js +36 -0
- package/server/bin/commands/start.js +31 -0
- package/server/bin/commands/test.js +20 -0
- package/server/bin/solo.js +4 -0
- package/server/boot/index.js +150 -0
- package/server/boot.js +2 -0
- package/server/build.js +23 -0
- package/server/cache/drivers/memory.js +23 -0
- package/server/cache/drivers/redis.js +28 -0
- package/server/cache/index.js +69 -0
- package/server/config/loader.js +89 -0
- package/server/config/modules/api.js +17 -0
- package/server/config/modules/build.js +9 -0
- package/server/config/modules/cache.js +10 -0
- package/server/config/modules/database.js +29 -0
- package/server/config/modules/events.js +15 -0
- package/server/config/modules/files.js +15 -0
- package/server/config/modules/jobs.js +20 -0
- package/server/config/modules/logger.js +9 -0
- package/server/config/modules/mail.js +11 -0
- package/server/config/modules/mcp.js +9 -0
- package/server/config/modules/pages.js +20 -0
- package/server/config/modules/queue.js +10 -0
- package/server/config/modules/redis.js +9 -0
- package/server/config/modules/server.js +30 -0
- package/server/config/modules/session.js +9 -0
- package/server/config/modules/websocket.js +11 -0
- package/server/constants.js +67 -0
- package/server/context.js +15 -0
- package/server/db/index.js +87 -0
- package/server/db/schema/drivers/mysql.js +28 -0
- package/server/db/schema/drivers/pg.js +34 -0
- package/server/db/schema/drivers/sqlite.js +22 -0
- package/server/db/schema/index.js +78 -0
- package/server/db/seeds.js +22 -0
- package/server/discovery.js +67 -0
- package/server/docs/openapi.js +153 -0
- package/server/env.js +17 -0
- package/server/events/drivers/memory.js +45 -0
- package/server/events/drivers/redis.js +64 -0
- package/server/events/handler.js +67 -0
- package/server/events/index.js +35 -0
- package/server/events/pattern.js +5 -0
- package/server/files/drivers/local.js +83 -0
- package/server/files/drivers/s3.js +113 -0
- package/server/files/index.js +57 -0
- package/server/filewatcher/index.js +156 -0
- package/server/glob.js +6 -0
- package/server/graphql/discovery.js +70 -0
- package/server/graphql/handler.js +41 -0
- package/server/graphql/index.js +13 -0
- package/server/graphql/loaders.js +19 -0
- package/server/graphql/merge.js +48 -0
- package/server/graphql/subscriptions.js +43 -0
- package/server/health.js +34 -0
- package/server/helpers.js +9 -0
- package/server/index.js +55 -0
- package/server/internals.js +139 -0
- package/server/jobs/cron.js +10 -0
- package/server/jobs/drivers/knex-queue.js +207 -0
- package/server/jobs/drivers/lease.js +148 -0
- package/server/jobs/drivers/memory-queue.js +134 -0
- package/server/jobs/queue.js +27 -0
- package/server/jobs/runner.js +197 -0
- package/server/jobs/throughput.js +63 -0
- package/server/lib/vault/encrypt.js +40 -0
- package/server/lib/vault/ids.js +9 -0
- package/server/lib/vault/index.js +14 -0
- package/server/lib/vault/jwt.js +55 -0
- package/server/lib/vault/password.js +10 -0
- package/server/lint/boundaries.js +77 -0
- package/server/logger/index.js +130 -0
- package/server/mail/drivers/console.js +31 -0
- package/server/mail/drivers/smtp.js +34 -0
- package/server/mail/imap.js +105 -0
- package/server/mail/inbound-store.js +58 -0
- package/server/mail/inbound.js +79 -0
- package/server/mail/index.js +112 -0
- package/server/mcp/debug-api.js +137 -0
- package/server/mcp/helpers.js +30 -0
- package/server/mcp/index.js +77 -0
- package/server/mcp/runtime.js +7 -0
- package/server/mcp/server.js +19 -0
- package/server/mcp/tools/debugging.js +133 -0
- package/server/mcp/tools/introspection.js +87 -0
- package/server/middlewares/cors.js +30 -0
- package/server/middlewares/index.js +3 -0
- package/server/middlewares/require-session.js +15 -0
- package/server/module-loader.js +9 -0
- package/server/pages/build-client.js +187 -0
- package/server/pages/build-css.js +47 -0
- package/server/pages/build-manifest.js +55 -0
- package/server/pages/build-plugins.js +75 -0
- package/server/pages/build-server.js +115 -0
- package/server/pages/build.js +116 -0
- package/server/pages/discovery.js +120 -0
- package/server/pages/fonts.js +128 -0
- package/server/pages/handler.js +276 -0
- package/server/pages/hmr.js +176 -0
- package/server/pages/pages-router.js +78 -0
- package/server/pages/ssr.js +276 -0
- package/server/pages/static.js +92 -0
- package/server/pages/watcher.js +90 -0
- package/server/queue/drivers/knex.js +67 -0
- package/server/queue/drivers/redis.js +91 -0
- package/server/queue/index.js +61 -0
- package/server/rate-limit/consume.js +21 -0
- package/server/rate-limit/drivers/memory.js +24 -0
- package/server/rate-limit/drivers/redis.js +32 -0
- package/server/rate-limit/index.js +33 -0
- package/server/redis/index.js +67 -0
- package/server/ring-buffer.js +44 -0
- package/server/route.js +4 -0
- package/server/router/api-router.js +317 -0
- package/server/router/cors.js +31 -0
- package/server/router/middleware.js +91 -0
- package/server/router/routes.js +132 -0
- package/server/server.js +35 -0
- package/server/session/helpers.js +21 -0
- package/server/session/index.js +89 -0
- package/server/static/index.js +36 -0
- package/server/system-jobs/index.js +50 -0
- package/server/system-routes/index.js +84 -0
- package/server/testing/index.js +263 -0
- package/server/validation.js +41 -0
- package/server/watcher.js +34 -0
- package/server/web-server.js +231 -0
- package/server/ws/discovery.js +54 -0
- package/server/ws/index.js +14 -0
- package/server/ws/realtime.js +318 -0
- package/server/ws/registry.js +17 -0
- package/server/ws/server.js +152 -0
- 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 };
|