appos 0.4.3-0 → 0.5.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/dist/exports/api/index.d.mts +3 -3
- package/dist/exports/api/index.mjs +34 -9
- package/dist/exports/api/workflows/index.d.mts +2 -2
- package/dist/exports/api/workflows/index.mjs +2 -2
- package/dist/exports/{auth-By0xx0MI.d.mts → auth-BCOIpGDO.d.mts} +325 -214
- package/dist/exports/cli/index.d.mts +105 -106
- package/dist/exports/cli/index.mjs +87 -13
- package/dist/exports/{constants-BePPc_yF.mjs → constants-BicCnEiJ.mjs} +7 -1
- package/dist/exports/{index-Bpo5QE7k.d.mts → index-CiuTp085.d.mts} +580 -614
- package/dist/exports/{openapi-crG3j4xx.mjs → openapi-uisUTLq7.mjs} +45 -102
- package/dist/exports/{send-email-Bgcdjy-e.mjs → send-email-CXxlkfFL.mjs} +1 -1
- package/dist/exports/{server-BlNxgHUc.mjs → server-CA4aI0U6.mjs} +6 -2
- package/dist/exports/storybook/index.d.ts +40 -0
- package/dist/exports/storybook/index.js +43 -0
- package/dist/exports/tests/api.d.mts +2 -2
- package/dist/exports/tests/api.mjs +3 -3
- package/dist/exports/vite/index.d.mts +19 -3
- package/dist/exports/vite/index.mjs +82 -6
- package/dist/exports/web/index.d.ts +2247 -700
- package/dist/exports/web/index.js +2445 -754
- package/dist/exports/web/routes.d.mts +41 -43
- package/dist/exports/web/ssr.d.mts +2 -2
- package/package.json +48 -31
- package/src/storybook/.storybook/main.ts +119 -0
- package/src/storybook/.storybook/manager.ts +75 -0
- package/src/storybook/.storybook/preview.tsx +76 -0
- package/src/storybook/components/ColorGrid.tsx +324 -0
- package/src/storybook/components/IconGallery.tsx +268 -0
- package/src/storybook/components/SpacingScale.tsx +236 -0
- package/src/storybook/components/TypographyScale.tsx +277 -0
- package/src/storybook/components/index.ts +3 -0
- package/src/storybook/docs/Introduction.mdx +29 -0
- package/src/storybook/docs/foundations/Colors.mdx +27 -0
- package/src/storybook/docs/foundations/Icons.mdx +26 -0
- package/src/storybook/docs/foundations/Spacing.mdx +23 -0
- package/src/storybook/docs/foundations/Typography.mdx +39 -0
- package/src/storybook/index.ts +147 -0
- package/src/storybook/shims/void-elements.js +18 -0
- package/src/web/client/auth-paths.ts +148 -0
- package/src/web/client/auth.ts +218 -0
- package/src/web/client/i18n.d.ts +9 -0
- package/src/web/client/i18n.ts +127 -0
- package/src/web/client/react-router.ts +84 -0
- package/src/web/hooks/index.ts +1 -0
- package/src/web/hooks/use-mobile.ts +19 -0
- package/src/web/index.ts +42 -0
- package/src/web/lib/colors.ts +220 -0
- package/src/web/lib/utils.ts +52 -0
- package/src/web/routes/auth/_layout.tsx +5 -11
- package/src/web/routes.ts +101 -0
- package/src/web/server/context.ts +14 -0
- package/src/web/server/render.ts +11 -0
- package/src/web/ssr.ts +17 -0
- package/src/web/ui/accordion.stories.tsx +183 -0
- package/src/web/ui/accordion.tsx +134 -0
- package/src/web/ui/alert-dialog.stories.tsx +215 -0
- package/src/web/ui/alert-dialog.tsx +328 -0
- package/src/web/ui/alert.stories.tsx +224 -0
- package/src/web/ui/alert.tsx +136 -0
- package/src/web/ui/animated-check.stories.tsx +200 -0
- package/src/web/ui/animated-check.tsx +98 -0
- package/src/web/ui/aspect-ratio.stories.tsx +204 -0
- package/src/web/ui/aspect-ratio.tsx +36 -0
- package/src/web/ui/auth/__mocks__/auth-context.tsx +273 -0
- package/src/web/ui/auth/auth-card.stories.tsx +295 -0
- package/src/web/ui/auth/auth-card.tsx +124 -0
- package/src/web/ui/auth/auth-layout.stories.tsx +330 -0
- package/src/web/ui/auth/auth-layout.tsx +269 -0
- package/src/web/ui/auth/captcha-widget.stories.tsx +200 -0
- package/src/web/ui/auth/captcha-widget.tsx +197 -0
- package/src/web/ui/auth/context.tsx +87 -0
- package/src/web/ui/auth/email-input.stories.tsx +167 -0
- package/src/web/ui/auth/email-input.tsx +84 -0
- package/src/web/ui/auth/forms/email-otp-form.tsx +377 -0
- package/src/web/ui/auth/forms/forgot-password-form.tsx +240 -0
- package/src/web/ui/auth/forms/index.ts +40 -0
- package/src/web/ui/auth/forms/login-form.tsx +486 -0
- package/src/web/ui/auth/forms/phone-otp-form.tsx +388 -0
- package/src/web/ui/auth/forms/reset-password-form.tsx +331 -0
- package/src/web/ui/auth/forms/signup-form.tsx +499 -0
- package/src/web/ui/auth/forms/two-factor-form.tsx +410 -0
- package/src/web/ui/auth/forms/verify-email-form.tsx +373 -0
- package/src/web/ui/auth/hooks.ts +266 -0
- package/src/web/ui/auth/index.ts +31 -0
- package/src/web/ui/auth/magic-link-form.tsx +191 -0
- package/src/web/ui/auth/otp-input.stories.tsx +199 -0
- package/src/web/ui/auth/otp-input.tsx +157 -0
- package/src/web/ui/auth/passkey-button.stories.tsx +115 -0
- package/src/web/ui/auth/passkey-button.tsx +113 -0
- package/src/web/ui/auth/passkey-register-button.stories.tsx +109 -0
- package/src/web/ui/auth/passkey-register-button.tsx +106 -0
- package/src/web/ui/auth/password-input.stories.tsx +287 -0
- package/src/web/ui/auth/password-input.tsx +306 -0
- package/src/web/ui/auth/phone-input.stories.tsx +160 -0
- package/src/web/ui/auth/phone-input.tsx +89 -0
- package/src/web/ui/auth/social-buttons.stories.tsx +217 -0
- package/src/web/ui/auth/social-buttons.tsx +196 -0
- package/src/web/ui/auth/sso-button.stories.tsx +160 -0
- package/src/web/ui/auth/sso-button.tsx +108 -0
- package/src/web/ui/auth/trust-signals.stories.tsx +208 -0
- package/src/web/ui/auth/trust-signals.tsx +260 -0
- package/src/web/ui/avatar.stories.tsx +302 -0
- package/src/web/ui/avatar.tsx +189 -0
- package/src/web/ui/badge.stories.tsx +225 -0
- package/src/web/ui/badge.tsx +66 -0
- package/src/web/ui/brand.stories.tsx +266 -0
- package/src/web/ui/brand.tsx +162 -0
- package/src/web/ui/breadcrumb.stories.tsx +271 -0
- package/src/web/ui/breadcrumb.tsx +214 -0
- package/src/web/ui/button-group.stories.tsx +251 -0
- package/src/web/ui/button-group.tsx +87 -0
- package/src/web/ui/button.stories.tsx +264 -0
- package/src/web/ui/button.tsx +120 -0
- package/src/web/ui/calendar.stories.tsx +235 -0
- package/src/web/ui/calendar.tsx +221 -0
- package/src/web/ui/card.stories.tsx +262 -0
- package/src/web/ui/card.tsx +199 -0
- package/src/web/ui/carousel.stories.tsx +244 -0
- package/src/web/ui/carousel.tsx +241 -0
- package/src/web/ui/chart.stories.tsx +833 -0
- package/src/web/ui/chart.tsx +390 -0
- package/src/web/ui/checkbox.stories.tsx +208 -0
- package/src/web/ui/checkbox.tsx +39 -0
- package/src/web/ui/collapsible.stories.tsx +239 -0
- package/src/web/ui/collapsible.tsx +21 -0
- package/src/web/ui/command.stories.tsx +291 -0
- package/src/web/ui/command.tsx +189 -0
- package/src/web/ui/context-menu.stories.tsx +255 -0
- package/src/web/ui/context-menu.tsx +263 -0
- package/src/web/ui/dialog.stories.tsx +263 -0
- package/src/web/ui/dialog.tsx +273 -0
- package/src/web/ui/drawer.stories.tsx +299 -0
- package/src/web/ui/drawer.tsx +130 -0
- package/src/web/ui/dropdown-menu.stories.tsx +320 -0
- package/src/web/ui/dropdown-menu.tsx +263 -0
- package/src/web/ui/empty.stories.tsx +204 -0
- package/src/web/ui/empty.tsx +101 -0
- package/src/web/ui/error-page.stories.tsx +181 -0
- package/src/web/ui/error-page.tsx +136 -0
- package/src/web/ui/field.stories.tsx +364 -0
- package/src/web/ui/field.tsx +252 -0
- package/src/web/ui/globals.css +3 -0
- package/src/web/ui/hover-card.stories.tsx +261 -0
- package/src/web/ui/hover-card.tsx +50 -0
- package/src/web/ui/index.ts +55 -0
- package/src/web/ui/input-group.stories.tsx +290 -0
- package/src/web/ui/input-group.tsx +157 -0
- package/src/web/ui/input-otp.stories.tsx +235 -0
- package/src/web/ui/input-otp.tsx +86 -0
- package/src/web/ui/input.stories.tsx +205 -0
- package/src/web/ui/input.tsx +30 -0
- package/src/web/ui/item.stories.tsx +348 -0
- package/src/web/ui/item.tsx +200 -0
- package/src/web/ui/kbd.stories.tsx +236 -0
- package/src/web/ui/kbd.tsx +27 -0
- package/src/web/ui/label.stories.tsx +180 -0
- package/src/web/ui/label.tsx +32 -0
- package/src/web/ui/locales/en/ui.json +13 -30
- package/src/web/ui/locales/zh-CN/ui.json +17 -34
- package/src/web/ui/locales/zh-TW/ui.json +17 -34
- package/src/web/ui/menubar.stories.tsx +385 -0
- package/src/web/ui/menubar.tsx +273 -0
- package/src/web/ui/navigation-menu.stories.tsx +361 -0
- package/src/web/ui/navigation-menu.tsx +168 -0
- package/src/web/ui/pagination.stories.tsx +312 -0
- package/src/web/ui/pagination.tsx +221 -0
- package/src/web/ui/popover.stories.tsx +315 -0
- package/src/web/ui/popover.tsx +89 -0
- package/src/web/ui/progress.stories.tsx +239 -0
- package/src/web/ui/progress.tsx +128 -0
- package/src/web/ui/radio-group.stories.tsx +315 -0
- package/src/web/ui/radio-group.tsx +38 -0
- package/src/web/ui/resizable.stories.tsx +304 -0
- package/src/web/ui/resizable.tsx +53 -0
- package/src/web/ui/scroll-area.stories.tsx +276 -0
- package/src/web/ui/scroll-area.tsx +53 -0
- package/src/web/ui/select.stories.tsx +314 -0
- package/src/web/ui/select.tsx +312 -0
- package/src/web/ui/separator.stories.tsx +246 -0
- package/src/web/ui/separator.tsx +36 -0
- package/src/web/ui/sheet.stories.tsx +417 -0
- package/src/web/ui/sheet.tsx +133 -0
- package/src/web/ui/sidebar.stories.tsx +402 -0
- package/src/web/ui/sidebar.tsx +723 -0
- package/src/web/ui/skeleton.stories.tsx +235 -0
- package/src/web/ui/skeleton.tsx +26 -0
- package/src/web/ui/slider.stories.tsx +294 -0
- package/src/web/ui/slider.tsx +75 -0
- package/src/web/ui/sonner.stories.tsx +279 -0
- package/src/web/ui/sonner.tsx +46 -0
- package/src/web/ui/spinner.stories.tsx +204 -0
- package/src/web/ui/spinner.tsx +28 -0
- package/src/web/ui/switch.stories.tsx +285 -0
- package/src/web/ui/switch.tsx +43 -0
- package/src/web/ui/table.stories.tsx +362 -0
- package/src/web/ui/table.tsx +115 -0
- package/src/web/ui/tabs.stories.tsx +401 -0
- package/src/web/ui/tabs.tsx +136 -0
- package/src/web/ui/textarea.stories.tsx +272 -0
- package/src/web/ui/textarea.tsx +28 -0
- package/src/web/ui/toggle-group.stories.tsx +334 -0
- package/src/web/ui/toggle-group.tsx +88 -0
- package/src/web/ui/toggle.stories.tsx +264 -0
- package/src/web/ui/toggle.tsx +57 -0
- package/src/web/ui/tooltip.stories.tsx +342 -0
- package/src/web/ui/tooltip.tsx +116 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { IconChevronDown, IconPlus } from "@tabler/icons-react";
|
|
3
|
+
import {
|
|
4
|
+
Button,
|
|
5
|
+
Collapsible,
|
|
6
|
+
CollapsibleContent,
|
|
7
|
+
CollapsibleTrigger,
|
|
8
|
+
} from "appos/web";
|
|
9
|
+
import { useState } from "react";
|
|
10
|
+
import { expect, userEvent, within } from "storybook/test";
|
|
11
|
+
|
|
12
|
+
const meta = {
|
|
13
|
+
title: "Base/Collapsible",
|
|
14
|
+
component: Collapsible,
|
|
15
|
+
tags: ["autodocs"],
|
|
16
|
+
parameters: {
|
|
17
|
+
layout: "centered",
|
|
18
|
+
docs: {
|
|
19
|
+
description: {
|
|
20
|
+
component:
|
|
21
|
+
"An interactive component that expands/collapses content. Built on Base UI's Collapsible primitive for accessible toggle functionality.",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
} satisfies Meta<typeof Collapsible>;
|
|
26
|
+
|
|
27
|
+
export default meta;
|
|
28
|
+
type Story = StoryObj<typeof meta>;
|
|
29
|
+
|
|
30
|
+
export const Default: Story = {
|
|
31
|
+
render: () => (
|
|
32
|
+
<Collapsible className="w-80 space-y-2">
|
|
33
|
+
<div className="flex items-center justify-between">
|
|
34
|
+
<h4 className="text-sm font-semibold">
|
|
35
|
+
@shadcn starred 3 repositories
|
|
36
|
+
</h4>
|
|
37
|
+
<CollapsibleTrigger render={<Button variant="ghost" size="icon-sm" />}>
|
|
38
|
+
<IconChevronDown className="size-4" />
|
|
39
|
+
<span className="sr-only">Toggle</span>
|
|
40
|
+
</CollapsibleTrigger>
|
|
41
|
+
</div>
|
|
42
|
+
<div className="rounded-md border px-4 py-2 text-sm">
|
|
43
|
+
@radix-ui/primitives
|
|
44
|
+
</div>
|
|
45
|
+
<CollapsibleContent className="space-y-2">
|
|
46
|
+
<div className="rounded-md border px-4 py-2 text-sm">
|
|
47
|
+
@radix-ui/colors
|
|
48
|
+
</div>
|
|
49
|
+
<div className="rounded-md border px-4 py-2 text-sm">
|
|
50
|
+
@stitches/react
|
|
51
|
+
</div>
|
|
52
|
+
</CollapsibleContent>
|
|
53
|
+
</Collapsible>
|
|
54
|
+
),
|
|
55
|
+
parameters: {
|
|
56
|
+
docs: {
|
|
57
|
+
description: {
|
|
58
|
+
story:
|
|
59
|
+
"Default collapsible showing additional items when expanded. Click the chevron button to toggle.",
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
play: async ({ canvasElement }) => {
|
|
64
|
+
const canvas = within(canvasElement);
|
|
65
|
+
const trigger = canvas.getByRole("button");
|
|
66
|
+
await userEvent.click(trigger);
|
|
67
|
+
await expect(canvas.getByText("@radix-ui/colors")).toBeVisible();
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export const DefaultOpen: Story = {
|
|
72
|
+
render: () => (
|
|
73
|
+
<Collapsible defaultOpen className="w-80 space-y-2">
|
|
74
|
+
<div className="flex items-center justify-between">
|
|
75
|
+
<h4 className="text-sm font-semibold">Details</h4>
|
|
76
|
+
<CollapsibleTrigger render={<Button variant="ghost" size="icon-sm" />}>
|
|
77
|
+
<IconChevronDown className="size-4" />
|
|
78
|
+
<span className="sr-only">Toggle</span>
|
|
79
|
+
</CollapsibleTrigger>
|
|
80
|
+
</div>
|
|
81
|
+
<CollapsibleContent>
|
|
82
|
+
<div className="rounded-md border p-4 text-sm">
|
|
83
|
+
This content is visible by default. Click the button to collapse.
|
|
84
|
+
</div>
|
|
85
|
+
</CollapsibleContent>
|
|
86
|
+
</Collapsible>
|
|
87
|
+
),
|
|
88
|
+
parameters: {
|
|
89
|
+
docs: {
|
|
90
|
+
description: {
|
|
91
|
+
story:
|
|
92
|
+
"Collapsible that starts in the open state. Use defaultOpen prop for initial expanded state.",
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export const Controlled: Story = {
|
|
99
|
+
render: () => {
|
|
100
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
101
|
+
return (
|
|
102
|
+
<div className="space-y-4">
|
|
103
|
+
<Collapsible
|
|
104
|
+
open={isOpen}
|
|
105
|
+
onOpenChange={setIsOpen}
|
|
106
|
+
className="w-80 space-y-2"
|
|
107
|
+
>
|
|
108
|
+
<div className="flex items-center justify-between">
|
|
109
|
+
<h4 className="text-sm font-semibold">
|
|
110
|
+
{isOpen ? "Expanded" : "Collapsed"}
|
|
111
|
+
</h4>
|
|
112
|
+
<CollapsibleTrigger
|
|
113
|
+
render={<Button variant="ghost" size="icon-sm" />}
|
|
114
|
+
>
|
|
115
|
+
<IconChevronDown
|
|
116
|
+
className={`size-4 transition-transform ${isOpen ? "rotate-180" : ""}`}
|
|
117
|
+
/>
|
|
118
|
+
<span className="sr-only">Toggle</span>
|
|
119
|
+
</CollapsibleTrigger>
|
|
120
|
+
</div>
|
|
121
|
+
<CollapsibleContent>
|
|
122
|
+
<div className="rounded-md border p-4 text-sm">
|
|
123
|
+
Controlled collapsible content with animated icon rotation.
|
|
124
|
+
</div>
|
|
125
|
+
</CollapsibleContent>
|
|
126
|
+
</Collapsible>
|
|
127
|
+
<Button variant="outline" size="sm" onClick={() => setIsOpen(!isOpen)}>
|
|
128
|
+
Toggle from outside
|
|
129
|
+
</Button>
|
|
130
|
+
</div>
|
|
131
|
+
);
|
|
132
|
+
},
|
|
133
|
+
parameters: {
|
|
134
|
+
docs: {
|
|
135
|
+
description: {
|
|
136
|
+
story:
|
|
137
|
+
"Controlled collapsible with external toggle button. Use open and onOpenChange for controlled state.",
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
export const Disabled: Story = {
|
|
144
|
+
render: () => (
|
|
145
|
+
<Collapsible disabled className="w-80 space-y-2">
|
|
146
|
+
<div className="flex items-center justify-between">
|
|
147
|
+
<h4 className="text-muted-foreground text-sm font-semibold">
|
|
148
|
+
Disabled Section
|
|
149
|
+
</h4>
|
|
150
|
+
<CollapsibleTrigger
|
|
151
|
+
render={<Button variant="ghost" size="icon-sm" disabled />}
|
|
152
|
+
>
|
|
153
|
+
<IconChevronDown className="size-4" />
|
|
154
|
+
<span className="sr-only">Toggle</span>
|
|
155
|
+
</CollapsibleTrigger>
|
|
156
|
+
</div>
|
|
157
|
+
<div className="text-muted-foreground rounded-md border px-4 py-2 text-sm opacity-50">
|
|
158
|
+
Content preview
|
|
159
|
+
</div>
|
|
160
|
+
</Collapsible>
|
|
161
|
+
),
|
|
162
|
+
parameters: {
|
|
163
|
+
docs: {
|
|
164
|
+
description: {
|
|
165
|
+
story:
|
|
166
|
+
"Disabled collapsible that cannot be toggled. Use disabled prop on Collapsible.",
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
export const WithTextTrigger: Story = {
|
|
173
|
+
render: () => (
|
|
174
|
+
<Collapsible className="w-80 space-y-2">
|
|
175
|
+
<CollapsibleTrigger
|
|
176
|
+
render={<Button variant="ghost" className="w-full justify-between" />}
|
|
177
|
+
>
|
|
178
|
+
Show more options
|
|
179
|
+
<IconPlus className="size-4" />
|
|
180
|
+
</CollapsibleTrigger>
|
|
181
|
+
<CollapsibleContent className="space-y-2">
|
|
182
|
+
<div className="rounded-md border p-4 text-sm">
|
|
183
|
+
Additional options and settings can be placed here.
|
|
184
|
+
</div>
|
|
185
|
+
</CollapsibleContent>
|
|
186
|
+
</Collapsible>
|
|
187
|
+
),
|
|
188
|
+
parameters: {
|
|
189
|
+
docs: {
|
|
190
|
+
description: {
|
|
191
|
+
story: "Collapsible with a full-width text button as the trigger.",
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
export const NestedContent: Story = {
|
|
198
|
+
render: () => (
|
|
199
|
+
<Collapsible className="w-80 space-y-2">
|
|
200
|
+
<div className="flex items-center justify-between">
|
|
201
|
+
<h4 className="text-sm font-semibold">Project Settings</h4>
|
|
202
|
+
<CollapsibleTrigger render={<Button variant="ghost" size="icon-sm" />}>
|
|
203
|
+
<IconChevronDown className="size-4" />
|
|
204
|
+
<span className="sr-only">Toggle</span>
|
|
205
|
+
</CollapsibleTrigger>
|
|
206
|
+
</div>
|
|
207
|
+
<CollapsibleContent>
|
|
208
|
+
<div className="space-y-3 rounded-md border p-4">
|
|
209
|
+
<div className="space-y-1">
|
|
210
|
+
<h5 className="text-sm font-medium">General</h5>
|
|
211
|
+
<p className="text-muted-foreground text-xs">
|
|
212
|
+
Basic project configuration
|
|
213
|
+
</p>
|
|
214
|
+
</div>
|
|
215
|
+
<div className="space-y-1">
|
|
216
|
+
<h5 className="text-sm font-medium">Permissions</h5>
|
|
217
|
+
<p className="text-muted-foreground text-xs">
|
|
218
|
+
Access control settings
|
|
219
|
+
</p>
|
|
220
|
+
</div>
|
|
221
|
+
<div className="space-y-1">
|
|
222
|
+
<h5 className="text-sm font-medium">Integrations</h5>
|
|
223
|
+
<p className="text-muted-foreground text-xs">
|
|
224
|
+
Third-party service connections
|
|
225
|
+
</p>
|
|
226
|
+
</div>
|
|
227
|
+
</div>
|
|
228
|
+
</CollapsibleContent>
|
|
229
|
+
</Collapsible>
|
|
230
|
+
),
|
|
231
|
+
parameters: {
|
|
232
|
+
docs: {
|
|
233
|
+
description: {
|
|
234
|
+
story:
|
|
235
|
+
"Collapsible with rich nested content including headings and descriptions.",
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Collapsible as CollapsiblePrimitive } from "@base-ui/react/collapsible";
|
|
4
|
+
|
|
5
|
+
function Collapsible({ ...props }: CollapsiblePrimitive.Root.Props) {
|
|
6
|
+
return <CollapsiblePrimitive.Root data-slot="collapsible" {...props} />;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function CollapsibleTrigger({ ...props }: CollapsiblePrimitive.Trigger.Props) {
|
|
10
|
+
return (
|
|
11
|
+
<CollapsiblePrimitive.Trigger data-slot="collapsible-trigger" {...props} />
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function CollapsibleContent({ ...props }: CollapsiblePrimitive.Panel.Props) {
|
|
16
|
+
return (
|
|
17
|
+
<CollapsiblePrimitive.Panel data-slot="collapsible-content" {...props} />
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export { Collapsible, CollapsibleTrigger, CollapsibleContent };
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import {
|
|
3
|
+
IconCalendar,
|
|
4
|
+
IconMail,
|
|
5
|
+
IconMoodSmile,
|
|
6
|
+
IconRocket,
|
|
7
|
+
IconSettings,
|
|
8
|
+
IconUser,
|
|
9
|
+
} from "@tabler/icons-react";
|
|
10
|
+
import {
|
|
11
|
+
Command,
|
|
12
|
+
CommandDialog,
|
|
13
|
+
CommandEmpty,
|
|
14
|
+
CommandGroup,
|
|
15
|
+
CommandInput,
|
|
16
|
+
CommandItem,
|
|
17
|
+
CommandList,
|
|
18
|
+
CommandSeparator,
|
|
19
|
+
CommandShortcut,
|
|
20
|
+
} from "appos/web";
|
|
21
|
+
import { useState } from "react";
|
|
22
|
+
import { expect, userEvent, within } from "storybook/test";
|
|
23
|
+
|
|
24
|
+
const meta = {
|
|
25
|
+
title: "Base/Command",
|
|
26
|
+
component: Command,
|
|
27
|
+
tags: ["autodocs"],
|
|
28
|
+
parameters: {
|
|
29
|
+
layout: "centered",
|
|
30
|
+
docs: {
|
|
31
|
+
description: {
|
|
32
|
+
component:
|
|
33
|
+
"A command palette component for searching and executing commands. Built on cmdk with keyboard navigation, groups, shortcuts, and dialog mode support.",
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
} satisfies Meta<typeof Command>;
|
|
38
|
+
|
|
39
|
+
export default meta;
|
|
40
|
+
type Story = StoryObj<typeof meta>;
|
|
41
|
+
|
|
42
|
+
export const Default: Story = {
|
|
43
|
+
render: () => (
|
|
44
|
+
<Command className="rounded-lg border shadow-md md:min-w-112.5">
|
|
45
|
+
<CommandInput placeholder="Type a command or search..." />
|
|
46
|
+
<CommandList>
|
|
47
|
+
<CommandEmpty>No results found.</CommandEmpty>
|
|
48
|
+
<CommandGroup heading="Suggestions">
|
|
49
|
+
<CommandItem>
|
|
50
|
+
<IconCalendar />
|
|
51
|
+
<span>Calendar</span>
|
|
52
|
+
</CommandItem>
|
|
53
|
+
<CommandItem>
|
|
54
|
+
<IconMoodSmile />
|
|
55
|
+
<span>Search Emoji</span>
|
|
56
|
+
</CommandItem>
|
|
57
|
+
<CommandItem>
|
|
58
|
+
<IconRocket />
|
|
59
|
+
<span>Launch</span>
|
|
60
|
+
</CommandItem>
|
|
61
|
+
</CommandGroup>
|
|
62
|
+
<CommandSeparator />
|
|
63
|
+
<CommandGroup heading="Settings">
|
|
64
|
+
<CommandItem>
|
|
65
|
+
<IconUser />
|
|
66
|
+
<span>Profile</span>
|
|
67
|
+
<CommandShortcut>⌘P</CommandShortcut>
|
|
68
|
+
</CommandItem>
|
|
69
|
+
<CommandItem>
|
|
70
|
+
<IconMail />
|
|
71
|
+
<span>Mail</span>
|
|
72
|
+
<CommandShortcut>⌘B</CommandShortcut>
|
|
73
|
+
</CommandItem>
|
|
74
|
+
<CommandItem>
|
|
75
|
+
<IconSettings />
|
|
76
|
+
<span>Settings</span>
|
|
77
|
+
<CommandShortcut>⌘S</CommandShortcut>
|
|
78
|
+
</CommandItem>
|
|
79
|
+
</CommandGroup>
|
|
80
|
+
</CommandList>
|
|
81
|
+
</Command>
|
|
82
|
+
),
|
|
83
|
+
parameters: {
|
|
84
|
+
docs: {
|
|
85
|
+
description: {
|
|
86
|
+
story:
|
|
87
|
+
"Default command palette with grouped items, icons, and keyboard shortcuts.",
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
play: async ({ canvasElement }) => {
|
|
92
|
+
const canvas = within(canvasElement);
|
|
93
|
+
const input = canvas.getByPlaceholderText(/type a command/i);
|
|
94
|
+
await userEvent.type(input, "cal");
|
|
95
|
+
await expect(canvas.getByText("Calendar")).toBeVisible();
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export const Dialog: Story = {
|
|
100
|
+
render: () => {
|
|
101
|
+
const [open, setOpen] = useState(false);
|
|
102
|
+
return (
|
|
103
|
+
<>
|
|
104
|
+
<p className="text-muted-foreground text-sm">
|
|
105
|
+
Press{" "}
|
|
106
|
+
<kbd className="bg-muted pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border px-1.5 font-mono text-[10px] font-medium opacity-100">
|
|
107
|
+
<span className="text-xs">⌘</span>K
|
|
108
|
+
</kbd>{" "}
|
|
109
|
+
or click below
|
|
110
|
+
</p>
|
|
111
|
+
<button
|
|
112
|
+
type="button"
|
|
113
|
+
onClick={() => setOpen(true)}
|
|
114
|
+
className="mt-2 rounded-md border px-4 py-2 text-sm"
|
|
115
|
+
>
|
|
116
|
+
Open Command Palette
|
|
117
|
+
</button>
|
|
118
|
+
<CommandDialog open={open} onOpenChange={setOpen}>
|
|
119
|
+
<Command>
|
|
120
|
+
<CommandInput placeholder="Type a command or search..." />
|
|
121
|
+
<CommandList>
|
|
122
|
+
<CommandEmpty>No results found.</CommandEmpty>
|
|
123
|
+
<CommandGroup heading="Suggestions">
|
|
124
|
+
<CommandItem onSelect={() => setOpen(false)}>
|
|
125
|
+
<IconCalendar />
|
|
126
|
+
<span>Calendar</span>
|
|
127
|
+
</CommandItem>
|
|
128
|
+
<CommandItem onSelect={() => setOpen(false)}>
|
|
129
|
+
<IconMoodSmile />
|
|
130
|
+
<span>Search Emoji</span>
|
|
131
|
+
</CommandItem>
|
|
132
|
+
</CommandGroup>
|
|
133
|
+
</CommandList>
|
|
134
|
+
</Command>
|
|
135
|
+
</CommandDialog>
|
|
136
|
+
</>
|
|
137
|
+
);
|
|
138
|
+
},
|
|
139
|
+
parameters: {
|
|
140
|
+
docs: {
|
|
141
|
+
description: {
|
|
142
|
+
story:
|
|
143
|
+
"Command palette in a dialog overlay. Use CommandDialog for modal command interfaces.",
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
export const WithFiltering: Story = {
|
|
150
|
+
render: () => (
|
|
151
|
+
<Command className="rounded-lg border shadow-md md:min-w-112.5">
|
|
152
|
+
<CommandInput placeholder="Search frameworks..." />
|
|
153
|
+
<CommandList>
|
|
154
|
+
<CommandEmpty>No framework found.</CommandEmpty>
|
|
155
|
+
<CommandGroup heading="Frontend">
|
|
156
|
+
<CommandItem>React</CommandItem>
|
|
157
|
+
<CommandItem>Vue</CommandItem>
|
|
158
|
+
<CommandItem>Angular</CommandItem>
|
|
159
|
+
<CommandItem>Svelte</CommandItem>
|
|
160
|
+
</CommandGroup>
|
|
161
|
+
<CommandSeparator />
|
|
162
|
+
<CommandGroup heading="Backend">
|
|
163
|
+
<CommandItem>Node.js</CommandItem>
|
|
164
|
+
<CommandItem>Deno</CommandItem>
|
|
165
|
+
<CommandItem>Bun</CommandItem>
|
|
166
|
+
</CommandGroup>
|
|
167
|
+
</CommandList>
|
|
168
|
+
</Command>
|
|
169
|
+
),
|
|
170
|
+
parameters: {
|
|
171
|
+
docs: {
|
|
172
|
+
description: {
|
|
173
|
+
story:
|
|
174
|
+
"Command palette with search filtering. Items are automatically filtered as you type.",
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
export const Checkable: Story = {
|
|
181
|
+
render: () => {
|
|
182
|
+
const [checked, setChecked] = useState<string[]>(["calendar"]);
|
|
183
|
+
const isChecked = (value: string) => checked.includes(value);
|
|
184
|
+
const toggle = (value: string) => {
|
|
185
|
+
setChecked((prev) =>
|
|
186
|
+
prev.includes(value)
|
|
187
|
+
? prev.filter((v) => v !== value)
|
|
188
|
+
: [...prev, value],
|
|
189
|
+
);
|
|
190
|
+
};
|
|
191
|
+
return (
|
|
192
|
+
<Command className="rounded-lg border shadow-md md:min-w-112.5">
|
|
193
|
+
<CommandInput placeholder="Select features..." />
|
|
194
|
+
<CommandList>
|
|
195
|
+
<CommandEmpty>No results found.</CommandEmpty>
|
|
196
|
+
<CommandGroup heading="Features">
|
|
197
|
+
<CommandItem
|
|
198
|
+
data-checked={isChecked("calendar")}
|
|
199
|
+
onSelect={() => toggle("calendar")}
|
|
200
|
+
>
|
|
201
|
+
<IconCalendar />
|
|
202
|
+
<span>Calendar</span>
|
|
203
|
+
</CommandItem>
|
|
204
|
+
<CommandItem
|
|
205
|
+
data-checked={isChecked("mail")}
|
|
206
|
+
onSelect={() => toggle("mail")}
|
|
207
|
+
>
|
|
208
|
+
<IconMail />
|
|
209
|
+
<span>Mail</span>
|
|
210
|
+
</CommandItem>
|
|
211
|
+
<CommandItem
|
|
212
|
+
data-checked={isChecked("settings")}
|
|
213
|
+
onSelect={() => toggle("settings")}
|
|
214
|
+
>
|
|
215
|
+
<IconSettings />
|
|
216
|
+
<span>Settings</span>
|
|
217
|
+
</CommandItem>
|
|
218
|
+
</CommandGroup>
|
|
219
|
+
</CommandList>
|
|
220
|
+
</Command>
|
|
221
|
+
);
|
|
222
|
+
},
|
|
223
|
+
parameters: {
|
|
224
|
+
docs: {
|
|
225
|
+
description: {
|
|
226
|
+
story:
|
|
227
|
+
"Command palette with checkable items. Use data-checked attribute for selection state.",
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
export const Disabled: Story = {
|
|
234
|
+
render: () => (
|
|
235
|
+
<Command className="rounded-lg border shadow-md md:min-w-112.5">
|
|
236
|
+
<CommandInput placeholder="Type a command..." />
|
|
237
|
+
<CommandList>
|
|
238
|
+
<CommandEmpty>No results found.</CommandEmpty>
|
|
239
|
+
<CommandGroup heading="Actions">
|
|
240
|
+
<CommandItem>
|
|
241
|
+
<IconCalendar />
|
|
242
|
+
<span>Calendar</span>
|
|
243
|
+
</CommandItem>
|
|
244
|
+
<CommandItem disabled>
|
|
245
|
+
<IconMail />
|
|
246
|
+
<span>Mail (Disabled)</span>
|
|
247
|
+
</CommandItem>
|
|
248
|
+
<CommandItem>
|
|
249
|
+
<IconSettings />
|
|
250
|
+
<span>Settings</span>
|
|
251
|
+
</CommandItem>
|
|
252
|
+
</CommandGroup>
|
|
253
|
+
</CommandList>
|
|
254
|
+
</Command>
|
|
255
|
+
),
|
|
256
|
+
parameters: {
|
|
257
|
+
docs: {
|
|
258
|
+
description: {
|
|
259
|
+
story:
|
|
260
|
+
"Command palette with a disabled item. Disabled items cannot be selected.",
|
|
261
|
+
},
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
export const Empty: Story = {
|
|
267
|
+
render: () => (
|
|
268
|
+
<Command className="rounded-lg border shadow-md md:min-w-112.5">
|
|
269
|
+
<CommandInput placeholder="Type a command..." />
|
|
270
|
+
<CommandList>
|
|
271
|
+
<CommandEmpty>
|
|
272
|
+
<div className="flex flex-col items-center gap-2 py-4">
|
|
273
|
+
<IconMoodSmile className="text-muted-foreground size-8" />
|
|
274
|
+
<p>No commands found</p>
|
|
275
|
+
<p className="text-muted-foreground text-xs">
|
|
276
|
+
Try searching for something else
|
|
277
|
+
</p>
|
|
278
|
+
</div>
|
|
279
|
+
</CommandEmpty>
|
|
280
|
+
</CommandList>
|
|
281
|
+
</Command>
|
|
282
|
+
),
|
|
283
|
+
parameters: {
|
|
284
|
+
docs: {
|
|
285
|
+
description: {
|
|
286
|
+
story:
|
|
287
|
+
"Custom empty state with icon and description. Use CommandEmpty for no-results messaging.",
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
};
|