sonance-brand-mcp 1.1.4 → 1.2.2
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/assets/BRAND_GUIDELINES.md +0 -8
- package/dist/assets/components/accordion.stories.tsx +310 -0
- package/dist/assets/components/accordion.tsx +56 -30
- package/dist/assets/components/alert.stories.tsx +199 -0
- package/dist/assets/components/autocomplete.stories.tsx +307 -0
- package/dist/assets/components/autocomplete.tsx +28 -4
- package/dist/assets/components/avatar.stories.tsx +175 -0
- package/dist/assets/components/badge.stories.tsx +258 -0
- package/dist/assets/components/breadcrumbs.stories.tsx +175 -0
- package/dist/assets/components/button.stories.tsx +362 -0
- package/dist/assets/components/button.tsx +48 -3
- package/dist/assets/components/calendar.stories.tsx +247 -0
- package/dist/assets/components/card.stories.tsx +275 -0
- package/dist/assets/components/card.tsx +26 -1
- package/dist/assets/components/checkbox-group.stories.tsx +281 -0
- package/dist/assets/components/checkbox.stories.tsx +160 -0
- package/dist/assets/components/checkbox.tsx +32 -4
- package/dist/assets/components/code.stories.tsx +265 -0
- package/dist/assets/components/date-input.stories.tsx +278 -0
- package/dist/assets/components/date-input.tsx +24 -2
- package/dist/assets/components/date-picker.stories.tsx +337 -0
- package/dist/assets/components/date-picker.tsx +28 -4
- package/dist/assets/components/date-range-picker.stories.tsx +340 -0
- package/dist/assets/components/dialog.stories.tsx +285 -0
- package/dist/assets/components/divider.stories.tsx +176 -0
- package/dist/assets/components/drawer.stories.tsx +216 -0
- package/dist/assets/components/dropdown.stories.tsx +342 -0
- package/dist/assets/components/dropdown.tsx +55 -10
- package/dist/assets/components/form.stories.tsx +372 -0
- package/dist/assets/components/image.stories.tsx +348 -0
- package/dist/assets/components/input-otp.stories.tsx +336 -0
- package/dist/assets/components/input-otp.tsx +24 -2
- package/dist/assets/components/input.stories.tsx +223 -0
- package/dist/assets/components/input.tsx +27 -2
- package/dist/assets/components/kbd.stories.tsx +272 -0
- package/dist/assets/components/link.stories.tsx +199 -0
- package/dist/assets/components/link.tsx +50 -1
- package/dist/assets/components/listbox.stories.tsx +287 -0
- package/dist/assets/components/listbox.tsx +30 -7
- package/dist/assets/components/navbar.stories.tsx +218 -0
- package/dist/assets/components/number-input.stories.tsx +295 -0
- package/dist/assets/components/number-input.tsx +30 -8
- package/dist/assets/components/pagination.stories.tsx +280 -0
- package/dist/assets/components/pagination.tsx +45 -21
- package/dist/assets/components/popover.stories.tsx +219 -0
- package/dist/assets/components/progress.stories.tsx +153 -0
- package/dist/assets/components/radio-group.stories.tsx +187 -0
- package/dist/assets/components/radio-group.tsx +30 -6
- package/dist/assets/components/range-calendar.stories.tsx +334 -0
- package/dist/assets/components/scroll-shadow.stories.tsx +335 -0
- package/dist/assets/components/select.stories.tsx +192 -0
- package/dist/assets/components/select.tsx +54 -7
- package/dist/assets/components/skeleton.stories.tsx +166 -0
- package/dist/assets/components/slider.stories.tsx +145 -0
- package/dist/assets/components/slider.tsx +43 -8
- package/dist/assets/components/spacer.stories.tsx +216 -0
- package/dist/assets/components/spinner.stories.tsx +149 -0
- package/dist/assets/components/switch.stories.tsx +170 -0
- package/dist/assets/components/switch.tsx +29 -4
- package/dist/assets/components/table.stories.tsx +322 -0
- package/dist/assets/components/tabs.stories.tsx +306 -0
- package/dist/assets/components/tabs.tsx +25 -4
- package/dist/assets/components/textarea.stories.tsx +103 -0
- package/dist/assets/components/textarea.tsx +27 -3
- package/dist/assets/components/theme-toggle.stories.tsx +248 -0
- package/dist/assets/components/time-input.stories.tsx +365 -0
- package/dist/assets/components/time-input.tsx +25 -3
- package/dist/assets/components/toast.stories.tsx +195 -0
- package/dist/assets/components/tooltip.stories.tsx +226 -0
- package/dist/assets/components/user.stories.tsx +274 -0
- package/dist/assets/logo-manifest.json +0 -18
- package/dist/index.js +2142 -85
- package/package.json +1 -1
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/nextjs-vite';
|
|
2
|
+
import { ComponentProps } from 'react';
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { Pagination, CompactPagination, type PaginationButtonState } from './pagination';
|
|
5
|
+
|
|
6
|
+
type PaginationStoryProps = ComponentProps<typeof Pagination> & {
|
|
7
|
+
state?: PaginationButtonState;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const meta: Meta<PaginationStoryProps> = {
|
|
11
|
+
title: 'Components/Navigation/Pagination',
|
|
12
|
+
component: Pagination,
|
|
13
|
+
tags: ['autodocs'],
|
|
14
|
+
parameters: {
|
|
15
|
+
docs: {
|
|
16
|
+
description: {
|
|
17
|
+
component: 'Navigation component for paginated content with multiple display options.',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
argTypes: {
|
|
22
|
+
state: {
|
|
23
|
+
control: 'select',
|
|
24
|
+
options: ['default', 'hover', 'focus', 'active', 'disabled'],
|
|
25
|
+
description: 'Visual state for PaginationButton documentation',
|
|
26
|
+
table: {
|
|
27
|
+
defaultValue: { summary: 'default' },
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export default meta;
|
|
34
|
+
type Story = StoryObj<PaginationStoryProps>;
|
|
35
|
+
|
|
36
|
+
export const Default: Story = {
|
|
37
|
+
render: () => {
|
|
38
|
+
const [page, setPage] = useState(1);
|
|
39
|
+
return (
|
|
40
|
+
<Pagination
|
|
41
|
+
currentPage={page}
|
|
42
|
+
totalPages={10}
|
|
43
|
+
onPageChange={setPage}
|
|
44
|
+
/>
|
|
45
|
+
);
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const ManyPages: Story = {
|
|
50
|
+
render: () => {
|
|
51
|
+
const [page, setPage] = useState(15);
|
|
52
|
+
return (
|
|
53
|
+
<Pagination
|
|
54
|
+
currentPage={page}
|
|
55
|
+
totalPages={50}
|
|
56
|
+
onPageChange={setPage}
|
|
57
|
+
/>
|
|
58
|
+
);
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const FewPages: Story = {
|
|
63
|
+
render: () => {
|
|
64
|
+
const [page, setPage] = useState(2);
|
|
65
|
+
return (
|
|
66
|
+
<Pagination
|
|
67
|
+
currentPage={page}
|
|
68
|
+
totalPages={5}
|
|
69
|
+
onPageChange={setPage}
|
|
70
|
+
/>
|
|
71
|
+
);
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export const FirstPage: Story = {
|
|
76
|
+
render: () => {
|
|
77
|
+
const [page, setPage] = useState(1);
|
|
78
|
+
return (
|
|
79
|
+
<Pagination
|
|
80
|
+
currentPage={page}
|
|
81
|
+
totalPages={10}
|
|
82
|
+
onPageChange={setPage}
|
|
83
|
+
/>
|
|
84
|
+
);
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export const LastPage: Story = {
|
|
89
|
+
render: () => {
|
|
90
|
+
const [page, setPage] = useState(10);
|
|
91
|
+
return (
|
|
92
|
+
<Pagination
|
|
93
|
+
currentPage={page}
|
|
94
|
+
totalPages={10}
|
|
95
|
+
onPageChange={setPage}
|
|
96
|
+
/>
|
|
97
|
+
);
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export const MoreSiblings: Story = {
|
|
102
|
+
render: () => {
|
|
103
|
+
const [page, setPage] = useState(10);
|
|
104
|
+
return (
|
|
105
|
+
<Pagination
|
|
106
|
+
currentPage={page}
|
|
107
|
+
totalPages={20}
|
|
108
|
+
onPageChange={setPage}
|
|
109
|
+
siblingCount={2}
|
|
110
|
+
/>
|
|
111
|
+
);
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export const Compact: Story = {
|
|
116
|
+
render: () => {
|
|
117
|
+
const [page, setPage] = useState(5);
|
|
118
|
+
return (
|
|
119
|
+
<CompactPagination
|
|
120
|
+
currentPage={page}
|
|
121
|
+
totalPages={20}
|
|
122
|
+
onPageChange={setPage}
|
|
123
|
+
/>
|
|
124
|
+
);
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
export const BothStyles: Story = {
|
|
129
|
+
render: () => {
|
|
130
|
+
const [page, setPage] = useState(5);
|
|
131
|
+
return (
|
|
132
|
+
<div className="space-y-8">
|
|
133
|
+
<div>
|
|
134
|
+
<p className="text-xs text-foreground-muted mb-2">Full Pagination</p>
|
|
135
|
+
<Pagination
|
|
136
|
+
currentPage={page}
|
|
137
|
+
totalPages={20}
|
|
138
|
+
onPageChange={setPage}
|
|
139
|
+
/>
|
|
140
|
+
</div>
|
|
141
|
+
<div>
|
|
142
|
+
<p className="text-xs text-foreground-muted mb-2">Compact Pagination</p>
|
|
143
|
+
<CompactPagination
|
|
144
|
+
currentPage={page}
|
|
145
|
+
totalPages={20}
|
|
146
|
+
onPageChange={setPage}
|
|
147
|
+
/>
|
|
148
|
+
</div>
|
|
149
|
+
</div>
|
|
150
|
+
);
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
export const TableExample: Story = {
|
|
155
|
+
render: () => {
|
|
156
|
+
const [page, setPage] = useState(1);
|
|
157
|
+
const itemsPerPage = 5;
|
|
158
|
+
const items = Array.from({ length: 23 }, (_, i) => ({
|
|
159
|
+
id: i + 1,
|
|
160
|
+
name: `Product ${i + 1}`,
|
|
161
|
+
price: `$${((i + 1) * 99).toFixed(2)}`,
|
|
162
|
+
}));
|
|
163
|
+
const totalPages = Math.ceil(items.length / itemsPerPage);
|
|
164
|
+
const displayedItems = items.slice((page - 1) * itemsPerPage, page * itemsPerPage);
|
|
165
|
+
|
|
166
|
+
return (
|
|
167
|
+
<div className="space-y-4">
|
|
168
|
+
<div className="border border-border">
|
|
169
|
+
<table className="w-full text-sm">
|
|
170
|
+
<thead className="bg-background-secondary">
|
|
171
|
+
<tr>
|
|
172
|
+
<th className="px-4 py-2 text-left">ID</th>
|
|
173
|
+
<th className="px-4 py-2 text-left">Name</th>
|
|
174
|
+
<th className="px-4 py-2 text-right">Price</th>
|
|
175
|
+
</tr>
|
|
176
|
+
</thead>
|
|
177
|
+
<tbody>
|
|
178
|
+
{displayedItems.map((item) => (
|
|
179
|
+
<tr key={item.id} className="border-t border-border">
|
|
180
|
+
<td className="px-4 py-2">{item.id}</td>
|
|
181
|
+
<td className="px-4 py-2">{item.name}</td>
|
|
182
|
+
<td className="px-4 py-2 text-right">{item.price}</td>
|
|
183
|
+
</tr>
|
|
184
|
+
))}
|
|
185
|
+
</tbody>
|
|
186
|
+
</table>
|
|
187
|
+
</div>
|
|
188
|
+
<div className="flex items-center justify-between">
|
|
189
|
+
<p className="text-sm text-foreground-muted">
|
|
190
|
+
Showing {(page - 1) * itemsPerPage + 1} to{' '}
|
|
191
|
+
{Math.min(page * itemsPerPage, items.length)} of {items.length} results
|
|
192
|
+
</p>
|
|
193
|
+
<Pagination
|
|
194
|
+
currentPage={page}
|
|
195
|
+
totalPages={totalPages}
|
|
196
|
+
onPageChange={setPage}
|
|
197
|
+
/>
|
|
198
|
+
</div>
|
|
199
|
+
</div>
|
|
200
|
+
);
|
|
201
|
+
},
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
// State Matrix - Visual documentation of all PaginationButton states
|
|
205
|
+
export const StateMatrix: Story = {
|
|
206
|
+
render: () => {
|
|
207
|
+
const states: PaginationButtonState[] = ['default', 'hover', 'focus', 'active', 'disabled'];
|
|
208
|
+
return (
|
|
209
|
+
<div className="space-y-6">
|
|
210
|
+
<h3 className="text-sm font-medium text-foreground-muted">PaginationButton States</h3>
|
|
211
|
+
<p className="text-xs text-foreground-muted">States are demonstrated via the Pagination component's active and disabled props.</p>
|
|
212
|
+
<div className="space-y-4">
|
|
213
|
+
<div>
|
|
214
|
+
<span className="text-xs font-medium text-foreground-muted uppercase">Default + Active</span>
|
|
215
|
+
<Pagination currentPage={3} totalPages={5} onPageChange={() => {}} />
|
|
216
|
+
</div>
|
|
217
|
+
<div>
|
|
218
|
+
<span className="text-xs font-medium text-foreground-muted uppercase">First Page (prev disabled)</span>
|
|
219
|
+
<Pagination currentPage={1} totalPages={5} onPageChange={() => {}} />
|
|
220
|
+
</div>
|
|
221
|
+
<div>
|
|
222
|
+
<span className="text-xs font-medium text-foreground-muted uppercase">Last Page (next disabled)</span>
|
|
223
|
+
<Pagination currentPage={5} totalPages={5} onPageChange={() => {}} />
|
|
224
|
+
</div>
|
|
225
|
+
</div>
|
|
226
|
+
</div>
|
|
227
|
+
);
|
|
228
|
+
},
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
// Responsive Matrix - Mobile, Tablet, Desktop
|
|
232
|
+
export const ResponsiveMatrix: Story = {
|
|
233
|
+
render: () => {
|
|
234
|
+
const [mobilePage, setMobilePage] = useState(3);
|
|
235
|
+
const [tabletPage, setTabletPage] = useState(5);
|
|
236
|
+
const [desktopPage, setDesktopPage] = useState(10);
|
|
237
|
+
|
|
238
|
+
return (
|
|
239
|
+
<div className="space-y-8">
|
|
240
|
+
{/* Mobile */}
|
|
241
|
+
<div>
|
|
242
|
+
<h4 className="text-xs uppercase text-foreground-muted mb-2">Mobile (375px)</h4>
|
|
243
|
+
<div className="w-[375px] border border-dashed border-border p-4">
|
|
244
|
+
<CompactPagination
|
|
245
|
+
currentPage={mobilePage}
|
|
246
|
+
totalPages={20}
|
|
247
|
+
onPageChange={setMobilePage}
|
|
248
|
+
/>
|
|
249
|
+
</div>
|
|
250
|
+
</div>
|
|
251
|
+
{/* Tablet */}
|
|
252
|
+
<div>
|
|
253
|
+
<h4 className="text-xs uppercase text-foreground-muted mb-2">Tablet (768px)</h4>
|
|
254
|
+
<div className="w-[768px] border border-dashed border-border p-4 flex justify-center">
|
|
255
|
+
<Pagination
|
|
256
|
+
currentPage={tabletPage}
|
|
257
|
+
totalPages={15}
|
|
258
|
+
onPageChange={setTabletPage}
|
|
259
|
+
/>
|
|
260
|
+
</div>
|
|
261
|
+
</div>
|
|
262
|
+
{/* Desktop */}
|
|
263
|
+
<div>
|
|
264
|
+
<h4 className="text-xs uppercase text-foreground-muted mb-2">Desktop (1280px)</h4>
|
|
265
|
+
<div className="w-[1280px] border border-dashed border-border p-4 flex items-center justify-between">
|
|
266
|
+
<p className="text-sm text-foreground-muted">
|
|
267
|
+
Showing 91-100 of 500 results
|
|
268
|
+
</p>
|
|
269
|
+
<Pagination
|
|
270
|
+
currentPage={desktopPage}
|
|
271
|
+
totalPages={50}
|
|
272
|
+
onPageChange={setDesktopPage}
|
|
273
|
+
siblingCount={2}
|
|
274
|
+
/>
|
|
275
|
+
</div>
|
|
276
|
+
</div>
|
|
277
|
+
</div>
|
|
278
|
+
);
|
|
279
|
+
},
|
|
280
|
+
};
|
|
@@ -4,6 +4,22 @@ import { forwardRef } from "react";
|
|
|
4
4
|
import { ChevronLeft, ChevronRight, MoreHorizontal } from "lucide-react";
|
|
5
5
|
import { cn } from "@/lib/utils";
|
|
6
6
|
|
|
7
|
+
export type PaginationButtonState = "default" | "hover" | "focus" | "active" | "disabled";
|
|
8
|
+
|
|
9
|
+
// State styles for Storybook/Figma visualization
|
|
10
|
+
const getButtonStateStyles = (state?: PaginationButtonState) => {
|
|
11
|
+
if (!state || state === "default") return "";
|
|
12
|
+
|
|
13
|
+
const stateMap: Record<string, string> = {
|
|
14
|
+
hover: "bg-secondary-hover",
|
|
15
|
+
focus: "ring-2 ring-border-focus ring-offset-2",
|
|
16
|
+
active: "bg-primary text-primary-foreground border-primary",
|
|
17
|
+
disabled: "opacity-50 cursor-not-allowed",
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
return stateMap[state] || "";
|
|
21
|
+
};
|
|
22
|
+
|
|
7
23
|
interface PaginationProps {
|
|
8
24
|
currentPage: number;
|
|
9
25
|
totalPages: number;
|
|
@@ -121,30 +137,38 @@ export function Pagination({
|
|
|
121
137
|
|
|
122
138
|
interface PaginationButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
123
139
|
active?: boolean;
|
|
140
|
+
/** Visual state for Storybook/Figma documentation */
|
|
141
|
+
state?: PaginationButtonState;
|
|
124
142
|
}
|
|
125
143
|
|
|
126
144
|
const PaginationButton = forwardRef<HTMLButtonElement, PaginationButtonProps>(
|
|
127
|
-
({ className, active, disabled, children, ...props }, ref) =>
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
"
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
145
|
+
({ className, active, disabled, state, children, ...props }, ref) => {
|
|
146
|
+
const isActive = active || state === "active";
|
|
147
|
+
const isDisabled = disabled || state === "disabled";
|
|
148
|
+
|
|
149
|
+
return (
|
|
150
|
+
<button
|
|
151
|
+
ref={ref}
|
|
152
|
+
type="button"
|
|
153
|
+
disabled={isDisabled}
|
|
154
|
+
className={cn(
|
|
155
|
+
"flex h-9 min-w-9 items-center justify-center px-3 text-sm font-medium",
|
|
156
|
+
"border transition-colors",
|
|
157
|
+
"focus:outline-none focus:ring-2 focus:ring-border-focus focus:ring-offset-2",
|
|
158
|
+
isActive
|
|
159
|
+
? "bg-primary text-primary-foreground border-primary"
|
|
160
|
+
: isDisabled
|
|
161
|
+
? "bg-transparent text-foreground-subtle border-transparent cursor-not-allowed"
|
|
162
|
+
: "bg-transparent text-foreground border-border hover:bg-secondary-hover",
|
|
163
|
+
getButtonStateStyles(state),
|
|
164
|
+
className
|
|
165
|
+
)}
|
|
166
|
+
{...props}
|
|
167
|
+
>
|
|
168
|
+
{children}
|
|
169
|
+
</button>
|
|
170
|
+
);
|
|
171
|
+
}
|
|
148
172
|
);
|
|
149
173
|
|
|
150
174
|
PaginationButton.displayName = "PaginationButton";
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/nextjs-vite';
|
|
2
|
+
import { Popover, PopoverContent } from './popover';
|
|
3
|
+
import { Button } from './button';
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof Popover> = {
|
|
6
|
+
title: 'Components/Overlays/Popover',
|
|
7
|
+
component: Popover,
|
|
8
|
+
tags: ['autodocs'],
|
|
9
|
+
parameters: {
|
|
10
|
+
docs: {
|
|
11
|
+
description: {
|
|
12
|
+
component: 'A floating panel that appears next to a trigger element.',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
layout: 'centered',
|
|
16
|
+
},
|
|
17
|
+
argTypes: {
|
|
18
|
+
position: {
|
|
19
|
+
control: 'select',
|
|
20
|
+
options: ['top', 'bottom', 'left', 'right'],
|
|
21
|
+
},
|
|
22
|
+
triggerOn: {
|
|
23
|
+
control: 'select',
|
|
24
|
+
options: ['click', 'hover'],
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export default meta;
|
|
30
|
+
type Story = StoryObj<typeof meta>;
|
|
31
|
+
|
|
32
|
+
export const Default: Story = {
|
|
33
|
+
render: () => (
|
|
34
|
+
<Popover trigger={<Button variant="secondary">Click me</Button>}>
|
|
35
|
+
<PopoverContent>
|
|
36
|
+
<p className="text-foreground-secondary">
|
|
37
|
+
This is the popover content. Click outside to close.
|
|
38
|
+
</p>
|
|
39
|
+
</PopoverContent>
|
|
40
|
+
</Popover>
|
|
41
|
+
),
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const OnHover: Story = {
|
|
45
|
+
render: () => (
|
|
46
|
+
<Popover trigger={<Button variant="secondary">Hover me</Button>} triggerOn="hover">
|
|
47
|
+
<PopoverContent>
|
|
48
|
+
<p className="text-foreground-secondary">
|
|
49
|
+
This popover appears on hover.
|
|
50
|
+
</p>
|
|
51
|
+
</PopoverContent>
|
|
52
|
+
</Popover>
|
|
53
|
+
),
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const TopPosition: Story = {
|
|
57
|
+
render: () => (
|
|
58
|
+
<Popover trigger={<Button variant="secondary">Open Top</Button>} position="top">
|
|
59
|
+
<PopoverContent>
|
|
60
|
+
<p className="text-foreground-secondary">Popover on top</p>
|
|
61
|
+
</PopoverContent>
|
|
62
|
+
</Popover>
|
|
63
|
+
),
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const LeftPosition: Story = {
|
|
67
|
+
render: () => (
|
|
68
|
+
<Popover trigger={<Button variant="secondary">Open Left</Button>} position="left">
|
|
69
|
+
<PopoverContent>
|
|
70
|
+
<p className="text-foreground-secondary">Popover on left</p>
|
|
71
|
+
</PopoverContent>
|
|
72
|
+
</Popover>
|
|
73
|
+
),
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export const RightPosition: Story = {
|
|
77
|
+
render: () => (
|
|
78
|
+
<Popover trigger={<Button variant="secondary">Open Right</Button>} position="right">
|
|
79
|
+
<PopoverContent>
|
|
80
|
+
<p className="text-foreground-secondary">Popover on right</p>
|
|
81
|
+
</PopoverContent>
|
|
82
|
+
</Popover>
|
|
83
|
+
),
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export const AllPositions: Story = {
|
|
87
|
+
render: () => (
|
|
88
|
+
<div className="flex items-center gap-8 p-16">
|
|
89
|
+
<Popover trigger={<Button variant="secondary" size="sm">Top</Button>} position="top">
|
|
90
|
+
<PopoverContent>
|
|
91
|
+
<p className="text-sm">Top position</p>
|
|
92
|
+
</PopoverContent>
|
|
93
|
+
</Popover>
|
|
94
|
+
<Popover trigger={<Button variant="secondary" size="sm">Bottom</Button>} position="bottom">
|
|
95
|
+
<PopoverContent>
|
|
96
|
+
<p className="text-sm">Bottom position</p>
|
|
97
|
+
</PopoverContent>
|
|
98
|
+
</Popover>
|
|
99
|
+
<Popover trigger={<Button variant="secondary" size="sm">Left</Button>} position="left">
|
|
100
|
+
<PopoverContent>
|
|
101
|
+
<p className="text-sm">Left position</p>
|
|
102
|
+
</PopoverContent>
|
|
103
|
+
</Popover>
|
|
104
|
+
<Popover trigger={<Button variant="secondary" size="sm">Right</Button>} position="right">
|
|
105
|
+
<PopoverContent>
|
|
106
|
+
<p className="text-sm">Right position</p>
|
|
107
|
+
</PopoverContent>
|
|
108
|
+
</Popover>
|
|
109
|
+
</div>
|
|
110
|
+
),
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
export const MenuExample: Story = {
|
|
114
|
+
render: () => (
|
|
115
|
+
<Popover trigger={<Button variant="secondary">Actions</Button>}>
|
|
116
|
+
<div className="py-2">
|
|
117
|
+
{['Edit', 'Duplicate', 'Archive', 'Delete'].map((action) => (
|
|
118
|
+
<button
|
|
119
|
+
key={action}
|
|
120
|
+
className="w-full px-4 py-2 text-left text-sm text-foreground hover:bg-secondary-hover transition-colors"
|
|
121
|
+
>
|
|
122
|
+
{action}
|
|
123
|
+
</button>
|
|
124
|
+
))}
|
|
125
|
+
</div>
|
|
126
|
+
</Popover>
|
|
127
|
+
),
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
export const UserMenuExample: Story = {
|
|
131
|
+
render: () => (
|
|
132
|
+
<Popover
|
|
133
|
+
trigger={
|
|
134
|
+
<button className="flex items-center gap-2 p-2 hover:bg-secondary-hover rounded transition-colors">
|
|
135
|
+
<div className="w-8 h-8 rounded-full bg-primary" />
|
|
136
|
+
<span className="text-sm text-foreground">John Doe</span>
|
|
137
|
+
</button>
|
|
138
|
+
}
|
|
139
|
+
>
|
|
140
|
+
<div className="w-48">
|
|
141
|
+
<div className="px-4 py-3 border-b border-border">
|
|
142
|
+
<p className="text-sm font-medium text-foreground">John Doe</p>
|
|
143
|
+
<p className="text-xs text-foreground-muted">john@example.com</p>
|
|
144
|
+
</div>
|
|
145
|
+
<div className="py-2">
|
|
146
|
+
{['Profile', 'Settings', 'Billing'].map((item) => (
|
|
147
|
+
<button
|
|
148
|
+
key={item}
|
|
149
|
+
className="w-full px-4 py-2 text-left text-sm text-foreground hover:bg-secondary-hover transition-colors"
|
|
150
|
+
>
|
|
151
|
+
{item}
|
|
152
|
+
</button>
|
|
153
|
+
))}
|
|
154
|
+
</div>
|
|
155
|
+
<div className="py-2 border-t border-border">
|
|
156
|
+
<button className="w-full px-4 py-2 text-left text-sm text-error hover:bg-error-light transition-colors">
|
|
157
|
+
Sign out
|
|
158
|
+
</button>
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
161
|
+
</Popover>
|
|
162
|
+
),
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
// Responsive Matrix - Mobile, Tablet, Desktop
|
|
166
|
+
export const ResponsiveMatrix: Story = {
|
|
167
|
+
render: () => (
|
|
168
|
+
<div className="space-y-8">
|
|
169
|
+
{/* Mobile */}
|
|
170
|
+
<div>
|
|
171
|
+
<h4 className="text-xs uppercase text-foreground-muted mb-2">Mobile (375px)</h4>
|
|
172
|
+
<div className="w-[375px] border border-dashed border-border p-4 flex justify-center">
|
|
173
|
+
<Popover trigger={<Button variant="secondary" size="sm">Actions</Button>}>
|
|
174
|
+
<PopoverContent>
|
|
175
|
+
<p className="text-sm">Popover content</p>
|
|
176
|
+
</PopoverContent>
|
|
177
|
+
</Popover>
|
|
178
|
+
</div>
|
|
179
|
+
</div>
|
|
180
|
+
{/* Tablet */}
|
|
181
|
+
<div>
|
|
182
|
+
<h4 className="text-xs uppercase text-foreground-muted mb-2">Tablet (768px)</h4>
|
|
183
|
+
<div className="w-[768px] border border-dashed border-border p-4 flex justify-center gap-4">
|
|
184
|
+
<Popover trigger={<Button variant="secondary">Top</Button>} position="top">
|
|
185
|
+
<PopoverContent><p className="text-sm">Top popover</p></PopoverContent>
|
|
186
|
+
</Popover>
|
|
187
|
+
<Popover trigger={<Button variant="secondary">Bottom</Button>} position="bottom">
|
|
188
|
+
<PopoverContent><p className="text-sm">Bottom popover</p></PopoverContent>
|
|
189
|
+
</Popover>
|
|
190
|
+
</div>
|
|
191
|
+
</div>
|
|
192
|
+
{/* Desktop */}
|
|
193
|
+
<div>
|
|
194
|
+
<h4 className="text-xs uppercase text-foreground-muted mb-2">Desktop (1280px)</h4>
|
|
195
|
+
<div className="w-[1280px] border border-dashed border-border p-4 flex justify-between items-center">
|
|
196
|
+
<Popover trigger={<Button variant="secondary">User Menu</Button>}>
|
|
197
|
+
<div className="w-48">
|
|
198
|
+
<div className="px-4 py-3 border-b border-border">
|
|
199
|
+
<p className="text-sm font-medium">John Doe</p>
|
|
200
|
+
<p className="text-xs text-foreground-muted">john@example.com</p>
|
|
201
|
+
</div>
|
|
202
|
+
<div className="py-2">
|
|
203
|
+
<button className="w-full px-4 py-2 text-left text-sm hover:bg-secondary-hover">Profile</button>
|
|
204
|
+
<button className="w-full px-4 py-2 text-left text-sm hover:bg-secondary-hover">Settings</button>
|
|
205
|
+
</div>
|
|
206
|
+
</div>
|
|
207
|
+
</Popover>
|
|
208
|
+
<Popover trigger={<Button variant="secondary">Actions</Button>}>
|
|
209
|
+
<div className="py-2">
|
|
210
|
+
{['Edit', 'Duplicate', 'Archive', 'Delete'].map((action) => (
|
|
211
|
+
<button key={action} className="w-full px-4 py-2 text-left text-sm hover:bg-secondary-hover">{action}</button>
|
|
212
|
+
))}
|
|
213
|
+
</div>
|
|
214
|
+
</Popover>
|
|
215
|
+
</div>
|
|
216
|
+
</div>
|
|
217
|
+
</div>
|
|
218
|
+
),
|
|
219
|
+
};
|