@djangocfg/ui-core 2.1.382 → 2.1.384
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/package.json +5 -12
- package/src/components/boundary/boundary.story.tsx +0 -191
- package/src/components/data/avatar/avatar.story.tsx +0 -115
- package/src/components/data/badge/badge.story.tsx +0 -56
- package/src/components/data/calendar/calendar.story.tsx +0 -127
- package/src/components/data/carousel/carousel.story.tsx +0 -122
- package/src/components/data/progress/progress.story.tsx +0 -97
- package/src/components/data/table/table.story.tsx +0 -148
- package/src/components/data/toggle/toggle.story.tsx +0 -104
- package/src/components/data/toggle-group/toggle-group.story.tsx +0 -118
- package/src/components/feedback/alert/alert.story.tsx +0 -77
- package/src/components/feedback/empty/empty.story.tsx +0 -115
- package/src/components/feedback/preloader/preloader.story.tsx +0 -86
- package/src/components/feedback/spinner/spinner.story.tsx +0 -66
- package/src/components/forms/button/button.story.tsx +0 -116
- package/src/components/forms/button-download/button-download.story.tsx +0 -112
- package/src/components/forms/button-group/button-group.story.tsx +0 -79
- package/src/components/forms/checkbox/checkbox.story.tsx +0 -89
- package/src/components/forms/input/input.story.tsx +0 -77
- package/src/components/forms/input-group/input-group.story.tsx +0 -119
- package/src/components/forms/input-otp/input-otp.story.tsx +0 -105
- package/src/components/forms/label/label.story.tsx +0 -52
- package/src/components/forms/radio-group/radio-group.story.tsx +0 -113
- package/src/components/forms/slider/slider.story.tsx +0 -134
- package/src/components/forms/switch/switch.story.tsx +0 -98
- package/src/components/forms/textarea/textarea.story.tsx +0 -94
- package/src/components/layout/aspect-ratio/aspect-ratio.story.tsx +0 -94
- package/src/components/layout/card/card.story.tsx +0 -105
- package/src/components/layout/resizable/resizable.story.tsx +0 -119
- package/src/components/layout/scroll-area/scroll-area.story.tsx +0 -172
- package/src/components/layout/separator/separator.story.tsx +0 -69
- package/src/components/layout/skeleton/skeleton.story.tsx +0 -101
- package/src/components/navigation/accordion/accordion.story.tsx +0 -110
- package/src/components/navigation/collapsible/collapsible.story.tsx +0 -133
- package/src/components/navigation/command/command.story.tsx +0 -121
- package/src/components/navigation/context-menu/context-menu.story.tsx +0 -125
- package/src/components/navigation/dropdown-menu/dropdown-menu.story.tsx +0 -208
- package/src/components/navigation/menubar/menubar.story.tsx +0 -152
- package/src/components/navigation/navigation-menu/navigation-menu.story.tsx +0 -154
- package/src/components/navigation/tabs/tabs.story.tsx +0 -98
- package/src/components/overlay/alert-dialog/alert-dialog.story.tsx +0 -104
- package/src/components/overlay/dialog/dialog.story.tsx +0 -212
- package/src/components/overlay/drawer/drawer.story.tsx +0 -359
- package/src/components/overlay/hover-card/hover-card.story.tsx +0 -102
- package/src/components/overlay/popover/popover.story.tsx +0 -127
- package/src/components/overlay/responsive-sheet/responsive-sheet.story.tsx +0 -117
- package/src/components/overlay/sheet/sheet.story.tsx +0 -148
- package/src/components/overlay/tooltip/tooltip.story.tsx +0 -139
- package/src/components/select/combobox-async.story.tsx +0 -215
- package/src/components/select/combobox.story.tsx +0 -226
- package/src/components/select/country-select.story.tsx +0 -261
- package/src/components/select/language-select.story.tsx +0 -264
- package/src/components/select/multi-select.story.tsx +0 -122
- package/src/components/select/select.story.tsx +0 -112
- package/src/components/specialized/copy/copy.story.tsx +0 -77
- package/src/components/specialized/flag/flag.story.tsx +0 -82
- package/src/components/specialized/image-with-fallback/image-with-fallback.story.tsx +0 -105
- package/src/components/specialized/kbd/kbd.story.tsx +0 -113
- package/src/lib/dialog-service/dialog-service.story.tsx +0 -263
- package/src/stories/index.ts +0 -28
- package/src/styles/theme/theme-tokens.story.tsx +0 -157
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@djangocfg/ui-core",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.384",
|
|
4
4
|
"description": "Pure React UI component library without Next.js dependencies - for Electron, Vite, CRA apps",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ui-components",
|
|
@@ -33,11 +33,6 @@
|
|
|
33
33
|
"import": "./src/index.ts",
|
|
34
34
|
"require": "./src/index.ts"
|
|
35
35
|
},
|
|
36
|
-
"./stories": {
|
|
37
|
-
"types": "./src/stories/index.ts",
|
|
38
|
-
"import": "./src/stories/index.ts",
|
|
39
|
-
"require": "./src/stories/index.ts"
|
|
40
|
-
},
|
|
41
36
|
"./components": {
|
|
42
37
|
"types": "./src/components/index.ts",
|
|
43
38
|
"import": "./src/components/index.ts",
|
|
@@ -92,11 +87,10 @@
|
|
|
92
87
|
],
|
|
93
88
|
"scripts": {
|
|
94
89
|
"lint": "eslint .",
|
|
95
|
-
"check": "tsc --noEmit"
|
|
96
|
-
"playground": "playground dev"
|
|
90
|
+
"check": "tsc --noEmit"
|
|
97
91
|
},
|
|
98
92
|
"peerDependencies": {
|
|
99
|
-
"@djangocfg/i18n": "^2.1.
|
|
93
|
+
"@djangocfg/i18n": "^2.1.384",
|
|
100
94
|
"consola": "^3.4.2",
|
|
101
95
|
"lucide-react": "^0.545.0",
|
|
102
96
|
"moment": "^2.30.1",
|
|
@@ -166,9 +160,8 @@
|
|
|
166
160
|
"vaul": "1.1.2"
|
|
167
161
|
},
|
|
168
162
|
"devDependencies": {
|
|
169
|
-
"@djangocfg/i18n": "^2.1.
|
|
170
|
-
"@djangocfg/
|
|
171
|
-
"@djangocfg/typescript-config": "^2.1.382",
|
|
163
|
+
"@djangocfg/i18n": "^2.1.384",
|
|
164
|
+
"@djangocfg/typescript-config": "^2.1.384",
|
|
172
165
|
"@types/node": "^24.7.2",
|
|
173
166
|
"@types/react": "^19.1.0",
|
|
174
167
|
"@types/react-dom": "^19.1.0",
|
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
import { defineStory, useSelect } from '@djangocfg/playground';
|
|
2
|
-
import { useState } from 'react';
|
|
3
|
-
|
|
4
|
-
import { Button } from '../forms/button';
|
|
5
|
-
import { Boundary, useBoundary } from '.';
|
|
6
|
-
import type { BoundaryRenderProps, BoundaryVariant } from '.';
|
|
7
|
-
|
|
8
|
-
export default defineStory({
|
|
9
|
-
title: 'Core/Boundary',
|
|
10
|
-
component: Boundary,
|
|
11
|
-
description:
|
|
12
|
-
'React error boundary with multiple visual variants. Wrap untrusted subtrees (widgets, third-party iframes, dynamic renderers) so a single render error does not crash the whole page. Includes `useBoundary()` hook for async / event-handler errors.',
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
function BoomButton({ label = 'Throw render error' }: { label?: string }) {
|
|
16
|
-
const [boom, setBoom] = useState(false);
|
|
17
|
-
if (boom) throw new Error('Demo crash from BoomButton');
|
|
18
|
-
return (
|
|
19
|
-
<Button variant="outline" size="sm" onClick={() => setBoom(true)}>
|
|
20
|
-
{label}
|
|
21
|
-
</Button>
|
|
22
|
-
);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export const Interactive = () => {
|
|
26
|
-
const [variant] = useSelect('variant', {
|
|
27
|
-
options: ['silent', 'inline', 'card', 'fullscreen'] as const,
|
|
28
|
-
defaultValue: 'card',
|
|
29
|
-
label: 'Variant',
|
|
30
|
-
description: 'Fallback visual style',
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
return (
|
|
34
|
-
<div className="max-w-lg space-y-3">
|
|
35
|
-
<p className="text-sm text-muted-foreground">
|
|
36
|
-
Click the button to throw — the surrounding page stays alive, only this block swaps to the fallback.
|
|
37
|
-
</p>
|
|
38
|
-
<Boundary variant={variant as BoundaryVariant} name="story">
|
|
39
|
-
<div className="rounded-md border p-4">
|
|
40
|
-
<BoomButton />
|
|
41
|
-
</div>
|
|
42
|
-
</Boundary>
|
|
43
|
-
</div>
|
|
44
|
-
);
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
export const Silent = () => (
|
|
48
|
-
<div className="max-w-lg space-y-2">
|
|
49
|
-
<p className="text-sm text-muted-foreground">
|
|
50
|
-
variant="silent" renders nothing on error. Use for non-critical widgets (chat launcher, embeds).
|
|
51
|
-
</p>
|
|
52
|
-
<Boundary variant="silent" name="silent-demo">
|
|
53
|
-
<BoomButton label="Crash silently" />
|
|
54
|
-
</Boundary>
|
|
55
|
-
<p className="text-xs text-muted-foreground">↑ button disappears after click. Page is fine.</p>
|
|
56
|
-
</div>
|
|
57
|
-
);
|
|
58
|
-
|
|
59
|
-
export const Inline = () => (
|
|
60
|
-
<div className="max-w-lg">
|
|
61
|
-
<Boundary variant="inline" name="inline-demo">
|
|
62
|
-
<BoomButton />
|
|
63
|
-
</Boundary>
|
|
64
|
-
</div>
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
export const Card = () => (
|
|
68
|
-
<div className="max-w-lg">
|
|
69
|
-
<Boundary variant="card" name="card-demo">
|
|
70
|
-
<BoomButton />
|
|
71
|
-
</Boundary>
|
|
72
|
-
</div>
|
|
73
|
-
);
|
|
74
|
-
|
|
75
|
-
export const CustomFallback = () => (
|
|
76
|
-
<div className="max-w-lg">
|
|
77
|
-
<Boundary
|
|
78
|
-
fallback={({ error, reset }) => (
|
|
79
|
-
<div className="rounded-md border-2 border-dashed border-amber-500 bg-amber-500/5 p-4">
|
|
80
|
-
<p className="text-sm font-semibold text-amber-700">Custom fallback</p>
|
|
81
|
-
<p className="mt-1 text-xs text-amber-700/80">{error.message}</p>
|
|
82
|
-
<Button size="sm" variant="outline" className="mt-2" onClick={reset}>
|
|
83
|
-
Reset boundary
|
|
84
|
-
</Button>
|
|
85
|
-
</div>
|
|
86
|
-
)}
|
|
87
|
-
>
|
|
88
|
-
<BoomButton />
|
|
89
|
-
</Boundary>
|
|
90
|
-
</div>
|
|
91
|
-
);
|
|
92
|
-
|
|
93
|
-
function MyFallback({ error, reset }: BoundaryRenderProps) {
|
|
94
|
-
return (
|
|
95
|
-
<div className="rounded-md border border-blue-500/40 bg-blue-500/5 p-4">
|
|
96
|
-
<p className="text-sm font-semibold text-blue-700">FallbackComponent prop</p>
|
|
97
|
-
<p className="mt-1 text-xs text-blue-700/80">{error.message}</p>
|
|
98
|
-
<Button size="sm" variant="outline" className="mt-2" onClick={reset}>
|
|
99
|
-
Reset
|
|
100
|
-
</Button>
|
|
101
|
-
</div>
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
export const FallbackComponentProp = () => (
|
|
106
|
-
<div className="max-w-lg space-y-2">
|
|
107
|
-
<p className="text-sm text-muted-foreground">
|
|
108
|
-
Pass a component type instead of a render function — better memoization, easier to test.
|
|
109
|
-
</p>
|
|
110
|
-
<Boundary FallbackComponent={MyFallback}>
|
|
111
|
-
<BoomButton />
|
|
112
|
-
</Boundary>
|
|
113
|
-
</div>
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
export const ResetKeys = () => {
|
|
117
|
-
const [key, setKey] = useState(0);
|
|
118
|
-
return (
|
|
119
|
-
<div className="max-w-lg space-y-3">
|
|
120
|
-
<p className="text-sm text-muted-foreground">
|
|
121
|
-
Pass <code className="text-xs">resetKeys</code> — when any value in the array changes, the boundary auto-resets.
|
|
122
|
-
Good for clearing errors on route change (e.g. <code className="text-xs">[pathname]</code>).
|
|
123
|
-
</p>
|
|
124
|
-
<Button size="sm" onClick={() => setKey((k) => k + 1)}>
|
|
125
|
-
Bump resetKey ({key})
|
|
126
|
-
</Button>
|
|
127
|
-
<Boundary variant="card" resetKeys={[key]} name="resetkeys-demo">
|
|
128
|
-
<BoomButton />
|
|
129
|
-
</Boundary>
|
|
130
|
-
</div>
|
|
131
|
-
);
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
export const OnResetCallback = () => {
|
|
135
|
-
const [resets, setResets] = useState<string[]>([]);
|
|
136
|
-
return (
|
|
137
|
-
<div className="max-w-lg space-y-3">
|
|
138
|
-
<p className="text-sm text-muted-foreground">
|
|
139
|
-
<code className="text-xs">onReset</code> fires when the boundary recovers — wire it to React Query invalidation, refetch, etc.
|
|
140
|
-
</p>
|
|
141
|
-
<Boundary
|
|
142
|
-
variant="card"
|
|
143
|
-
onReset={(details) =>
|
|
144
|
-
setResets((prev) => [...prev, `reset @ ${new Date().toISOString().slice(11, 19)} (${details.reason})`])
|
|
145
|
-
}
|
|
146
|
-
>
|
|
147
|
-
<BoomButton />
|
|
148
|
-
</Boundary>
|
|
149
|
-
<div className="text-xs text-muted-foreground">
|
|
150
|
-
Resets:
|
|
151
|
-
<ul className="mt-1 space-y-0.5">
|
|
152
|
-
{resets.map((r, i) => (
|
|
153
|
-
<li key={i}>· {r}</li>
|
|
154
|
-
))}
|
|
155
|
-
</ul>
|
|
156
|
-
</div>
|
|
157
|
-
</div>
|
|
158
|
-
);
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
function AsyncCrasher() {
|
|
162
|
-
const { showBoundary } = useBoundary();
|
|
163
|
-
return (
|
|
164
|
-
<Button
|
|
165
|
-
variant="outline"
|
|
166
|
-
size="sm"
|
|
167
|
-
onClick={async () => {
|
|
168
|
-
// Regular React boundaries DON'T catch this. useBoundary() does.
|
|
169
|
-
await new Promise((r) => setTimeout(r, 200));
|
|
170
|
-
try {
|
|
171
|
-
throw new Error('Async fetch failed after 200ms');
|
|
172
|
-
} catch (err) {
|
|
173
|
-
showBoundary(err);
|
|
174
|
-
}
|
|
175
|
-
}}
|
|
176
|
-
>
|
|
177
|
-
Throw async error
|
|
178
|
-
</Button>
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
export const AsyncErrorsViaHook = () => (
|
|
183
|
-
<div className="max-w-lg space-y-2">
|
|
184
|
-
<p className="text-sm text-muted-foreground">
|
|
185
|
-
React error boundaries only catch <em>render</em> errors. Use <code className="text-xs">useBoundary().showBoundary(err)</code> to push async / event-handler errors into the nearest boundary.
|
|
186
|
-
</p>
|
|
187
|
-
<Boundary variant="card" name="async-demo">
|
|
188
|
-
<AsyncCrasher />
|
|
189
|
-
</Boundary>
|
|
190
|
-
</div>
|
|
191
|
-
);
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import { defineStory, useSelect } from '@djangocfg/playground';
|
|
2
|
-
import { Avatar, AvatarImage, AvatarFallback } from '.';
|
|
3
|
-
|
|
4
|
-
export default defineStory({
|
|
5
|
-
title: 'Core/Avatar',
|
|
6
|
-
component: Avatar,
|
|
7
|
-
description: 'User avatar with image and fallback support.',
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
const AVATARS = [
|
|
11
|
-
{ src: 'https://github.com/shadcn.png', fallback: 'CN' },
|
|
12
|
-
{ src: 'https://github.com/vercel.png', fallback: 'VC' },
|
|
13
|
-
{ src: 'https://github.com/radix-ui.png', fallback: 'RX' },
|
|
14
|
-
];
|
|
15
|
-
|
|
16
|
-
export const Interactive = () => {
|
|
17
|
-
const [size] = useSelect('size', {
|
|
18
|
-
options: ['sm', 'md', 'lg'] as const,
|
|
19
|
-
defaultValue: 'md',
|
|
20
|
-
label: 'Size',
|
|
21
|
-
description: 'Avatar size',
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
const sizeClasses = {
|
|
25
|
-
sm: 'h-8 w-8',
|
|
26
|
-
md: 'h-10 w-10',
|
|
27
|
-
lg: 'h-14 w-14',
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
return (
|
|
31
|
-
<Avatar className={sizeClasses[size]}>
|
|
32
|
-
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
|
33
|
-
<AvatarFallback>CN</AvatarFallback>
|
|
34
|
-
</Avatar>
|
|
35
|
-
);
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export const Default = () => (
|
|
39
|
-
<Avatar>
|
|
40
|
-
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
|
41
|
-
<AvatarFallback>CN</AvatarFallback>
|
|
42
|
-
</Avatar>
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
export const Fallback = () => (
|
|
46
|
-
<Avatar>
|
|
47
|
-
<AvatarImage src="/broken-image.jpg" alt="User" />
|
|
48
|
-
<AvatarFallback>JD</AvatarFallback>
|
|
49
|
-
</Avatar>
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
export const Sizes = () => (
|
|
53
|
-
<div className="flex items-center gap-4">
|
|
54
|
-
<Avatar className="h-6 w-6">
|
|
55
|
-
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
|
56
|
-
<AvatarFallback className="text-xs">CN</AvatarFallback>
|
|
57
|
-
</Avatar>
|
|
58
|
-
<Avatar className="h-8 w-8">
|
|
59
|
-
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
|
60
|
-
<AvatarFallback>CN</AvatarFallback>
|
|
61
|
-
</Avatar>
|
|
62
|
-
<Avatar className="h-10 w-10">
|
|
63
|
-
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
|
64
|
-
<AvatarFallback>CN</AvatarFallback>
|
|
65
|
-
</Avatar>
|
|
66
|
-
<Avatar className="h-14 w-14">
|
|
67
|
-
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
|
68
|
-
<AvatarFallback>CN</AvatarFallback>
|
|
69
|
-
</Avatar>
|
|
70
|
-
<Avatar className="h-20 w-20">
|
|
71
|
-
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
|
72
|
-
<AvatarFallback className="text-xl">CN</AvatarFallback>
|
|
73
|
-
</Avatar>
|
|
74
|
-
</div>
|
|
75
|
-
);
|
|
76
|
-
|
|
77
|
-
export const Group = () => (
|
|
78
|
-
<div className="flex -space-x-4">
|
|
79
|
-
{AVATARS.map((avatar, i) => (
|
|
80
|
-
<Avatar key={i} className="border-2 border-background">
|
|
81
|
-
<AvatarImage src={avatar.src} />
|
|
82
|
-
<AvatarFallback>{avatar.fallback}</AvatarFallback>
|
|
83
|
-
</Avatar>
|
|
84
|
-
))}
|
|
85
|
-
<Avatar className="border-2 border-background">
|
|
86
|
-
<AvatarFallback>+5</AvatarFallback>
|
|
87
|
-
</Avatar>
|
|
88
|
-
</div>
|
|
89
|
-
);
|
|
90
|
-
|
|
91
|
-
export const WithStatus = () => (
|
|
92
|
-
<div className="flex gap-4">
|
|
93
|
-
<div className="relative">
|
|
94
|
-
<Avatar>
|
|
95
|
-
<AvatarImage src="https://github.com/shadcn.png" />
|
|
96
|
-
<AvatarFallback>CN</AvatarFallback>
|
|
97
|
-
</Avatar>
|
|
98
|
-
<span className="absolute bottom-0 right-0 h-3 w-3 rounded-full bg-green-500 border-2 border-background" />
|
|
99
|
-
</div>
|
|
100
|
-
<div className="relative">
|
|
101
|
-
<Avatar>
|
|
102
|
-
<AvatarImage src="https://github.com/vercel.png" />
|
|
103
|
-
<AvatarFallback>VC</AvatarFallback>
|
|
104
|
-
</Avatar>
|
|
105
|
-
<span className="absolute bottom-0 right-0 h-3 w-3 rounded-full bg-yellow-500 border-2 border-background" />
|
|
106
|
-
</div>
|
|
107
|
-
<div className="relative">
|
|
108
|
-
<Avatar>
|
|
109
|
-
<AvatarImage src="https://github.com/radix-ui.png" />
|
|
110
|
-
<AvatarFallback>RX</AvatarFallback>
|
|
111
|
-
</Avatar>
|
|
112
|
-
<span className="absolute bottom-0 right-0 h-3 w-3 rounded-full bg-gray-400 border-2 border-background" />
|
|
113
|
-
</div>
|
|
114
|
-
</div>
|
|
115
|
-
);
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { defineStory, useSelect } from '@djangocfg/playground';
|
|
2
|
-
import { Badge } from '.';
|
|
3
|
-
|
|
4
|
-
export default defineStory({
|
|
5
|
-
title: 'Core/Badge',
|
|
6
|
-
component: Badge,
|
|
7
|
-
description: 'Small status indicators and labels.',
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
export const Interactive = () => {
|
|
11
|
-
const [variant] = useSelect('variant', {
|
|
12
|
-
options: ['default', 'secondary', 'destructive', 'outline'] as const,
|
|
13
|
-
defaultValue: 'default',
|
|
14
|
-
label: 'Variant',
|
|
15
|
-
description: 'Badge style variant',
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
return (
|
|
19
|
-
<div className="flex gap-4">
|
|
20
|
-
<Badge variant={variant}>Badge</Badge>
|
|
21
|
-
</div>
|
|
22
|
-
);
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export const Variants = () => (
|
|
26
|
-
<div className="flex flex-wrap gap-4">
|
|
27
|
-
<Badge variant="default">Default</Badge>
|
|
28
|
-
<Badge variant="secondary">Secondary</Badge>
|
|
29
|
-
<Badge variant="destructive">Destructive</Badge>
|
|
30
|
-
<Badge variant="outline">Outline</Badge>
|
|
31
|
-
</div>
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
export const StatusBadges = () => (
|
|
35
|
-
<div className="flex flex-wrap gap-4">
|
|
36
|
-
<Badge variant="default">Active</Badge>
|
|
37
|
-
<Badge variant="secondary">Pending</Badge>
|
|
38
|
-
<Badge variant="destructive">Expired</Badge>
|
|
39
|
-
<Badge variant="outline">Draft</Badge>
|
|
40
|
-
</div>
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
export const InContext = () => (
|
|
44
|
-
<div className="space-y-4">
|
|
45
|
-
<div className="flex items-center gap-2">
|
|
46
|
-
<span className="font-medium">Status:</span>
|
|
47
|
-
<Badge variant="default">Published</Badge>
|
|
48
|
-
</div>
|
|
49
|
-
<div className="flex items-center gap-2">
|
|
50
|
-
<span className="font-medium">Tags:</span>
|
|
51
|
-
<Badge variant="secondary">React</Badge>
|
|
52
|
-
<Badge variant="secondary">TypeScript</Badge>
|
|
53
|
-
<Badge variant="secondary">UI</Badge>
|
|
54
|
-
</div>
|
|
55
|
-
</div>
|
|
56
|
-
);
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import { useState } from 'react';
|
|
2
|
-
import { defineStory } from '@djangocfg/playground';
|
|
3
|
-
import { Calendar } from '.';
|
|
4
|
-
import { DatePicker, DateRangePicker, type DateRange } from './date-picker';
|
|
5
|
-
|
|
6
|
-
export default defineStory({
|
|
7
|
-
title: 'Core/Calendar',
|
|
8
|
-
component: Calendar,
|
|
9
|
-
description: 'Calendar and date picker components.',
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
export const Default = () => {
|
|
13
|
-
const [date, setDate] = useState<Date | undefined>(new Date());
|
|
14
|
-
|
|
15
|
-
return (
|
|
16
|
-
<Calendar
|
|
17
|
-
mode="single"
|
|
18
|
-
selected={date}
|
|
19
|
-
onSelect={setDate}
|
|
20
|
-
className="rounded-md border"
|
|
21
|
-
/>
|
|
22
|
-
);
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export const Range = () => {
|
|
26
|
-
const [range, setRange] = useState<DateRange | undefined>({
|
|
27
|
-
from: new Date(),
|
|
28
|
-
to: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
return (
|
|
32
|
-
<Calendar
|
|
33
|
-
mode="range"
|
|
34
|
-
selected={range}
|
|
35
|
-
onSelect={setRange}
|
|
36
|
-
className="rounded-md border"
|
|
37
|
-
numberOfMonths={2}
|
|
38
|
-
/>
|
|
39
|
-
);
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export const Multiple = () => {
|
|
43
|
-
const [dates, setDates] = useState<Date[] | undefined>([]);
|
|
44
|
-
|
|
45
|
-
return (
|
|
46
|
-
<Calendar
|
|
47
|
-
mode="multiple"
|
|
48
|
-
selected={dates}
|
|
49
|
-
onSelect={setDates}
|
|
50
|
-
className="rounded-md border"
|
|
51
|
-
/>
|
|
52
|
-
);
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
export const Picker = () => {
|
|
56
|
-
const [date, setDate] = useState<Date>();
|
|
57
|
-
|
|
58
|
-
return (
|
|
59
|
-
<div className="max-w-xs">
|
|
60
|
-
<DatePicker
|
|
61
|
-
value={date}
|
|
62
|
-
onChange={setDate}
|
|
63
|
-
placeholder="Pick a date"
|
|
64
|
-
/>
|
|
65
|
-
</div>
|
|
66
|
-
);
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
export const PickerWithLabel = () => {
|
|
70
|
-
const [date, setDate] = useState<Date>();
|
|
71
|
-
|
|
72
|
-
return (
|
|
73
|
-
<div className="max-w-xs space-y-2">
|
|
74
|
-
<label className="text-sm font-medium">Date of birth</label>
|
|
75
|
-
<DatePicker
|
|
76
|
-
value={date}
|
|
77
|
-
onChange={setDate}
|
|
78
|
-
placeholder="Select your birth date"
|
|
79
|
-
/>
|
|
80
|
-
</div>
|
|
81
|
-
);
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
export const RangePicker = () => {
|
|
85
|
-
const [range, setRange] = useState<DateRange>();
|
|
86
|
-
|
|
87
|
-
return (
|
|
88
|
-
<div className="max-w-sm">
|
|
89
|
-
<DateRangePicker
|
|
90
|
-
value={range}
|
|
91
|
-
onChange={setRange}
|
|
92
|
-
placeholder="Select date range"
|
|
93
|
-
/>
|
|
94
|
-
</div>
|
|
95
|
-
);
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
export const RangePickerWithPresets = () => {
|
|
99
|
-
const [range, setRange] = useState<DateRange>();
|
|
100
|
-
|
|
101
|
-
return (
|
|
102
|
-
<div className="max-w-sm space-y-2">
|
|
103
|
-
<label className="text-sm font-medium">Booking dates</label>
|
|
104
|
-
<DateRangePicker
|
|
105
|
-
value={range}
|
|
106
|
-
onChange={setRange}
|
|
107
|
-
placeholder="Check-in — Check-out"
|
|
108
|
-
numberOfMonths={2}
|
|
109
|
-
/>
|
|
110
|
-
</div>
|
|
111
|
-
);
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
export const Disabled = () => {
|
|
115
|
-
const [date, setDate] = useState<Date>();
|
|
116
|
-
|
|
117
|
-
return (
|
|
118
|
-
<div className="max-w-xs">
|
|
119
|
-
<DatePicker
|
|
120
|
-
value={date}
|
|
121
|
-
onChange={setDate}
|
|
122
|
-
placeholder="Pick a date"
|
|
123
|
-
disabled
|
|
124
|
-
/>
|
|
125
|
-
</div>
|
|
126
|
-
);
|
|
127
|
-
};
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
import { defineStory, type StoryMeta } from '@djangocfg/playground';
|
|
2
|
-
import {
|
|
3
|
-
Carousel,
|
|
4
|
-
CarouselContent,
|
|
5
|
-
CarouselItem,
|
|
6
|
-
CarouselNext,
|
|
7
|
-
CarouselPrevious,
|
|
8
|
-
} from '.';
|
|
9
|
-
import { Card, CardContent } from '../../layout/card';
|
|
10
|
-
|
|
11
|
-
const meta: StoryMeta = defineStory({
|
|
12
|
-
title: 'Core/Carousel',
|
|
13
|
-
component: Carousel,
|
|
14
|
-
description: 'Carousel/slider component for cycling through content.',
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
export default meta;
|
|
18
|
-
|
|
19
|
-
export const Default = () => (
|
|
20
|
-
<Carousel className="w-full max-w-xs">
|
|
21
|
-
<CarouselContent>
|
|
22
|
-
{Array.from({ length: 5 }).map((_, index) => (
|
|
23
|
-
<CarouselItem key={index}>
|
|
24
|
-
<div className="p-1">
|
|
25
|
-
<Card>
|
|
26
|
-
<CardContent className="flex aspect-square items-center justify-center p-6">
|
|
27
|
-
<span className="text-4xl font-semibold">{index + 1}</span>
|
|
28
|
-
</CardContent>
|
|
29
|
-
</Card>
|
|
30
|
-
</div>
|
|
31
|
-
</CarouselItem>
|
|
32
|
-
))}
|
|
33
|
-
</CarouselContent>
|
|
34
|
-
<CarouselPrevious />
|
|
35
|
-
<CarouselNext />
|
|
36
|
-
</Carousel>
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
export const Multiple = () => (
|
|
40
|
-
<Carousel
|
|
41
|
-
opts={{ align: 'start' }}
|
|
42
|
-
className="w-full max-w-sm"
|
|
43
|
-
>
|
|
44
|
-
<CarouselContent>
|
|
45
|
-
{Array.from({ length: 5 }).map((_, index) => (
|
|
46
|
-
<CarouselItem key={index} className="basis-1/3">
|
|
47
|
-
<div className="p-1">
|
|
48
|
-
<Card>
|
|
49
|
-
<CardContent className="flex aspect-square items-center justify-center p-6">
|
|
50
|
-
<span className="text-3xl font-semibold">{index + 1}</span>
|
|
51
|
-
</CardContent>
|
|
52
|
-
</Card>
|
|
53
|
-
</div>
|
|
54
|
-
</CarouselItem>
|
|
55
|
-
))}
|
|
56
|
-
</CarouselContent>
|
|
57
|
-
<CarouselPrevious />
|
|
58
|
-
<CarouselNext />
|
|
59
|
-
</Carousel>
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
export const Wide = () => (
|
|
63
|
-
<Carousel className="w-full max-w-lg">
|
|
64
|
-
<CarouselContent>
|
|
65
|
-
{Array.from({ length: 3 }).map((_, index) => (
|
|
66
|
-
<CarouselItem key={index}>
|
|
67
|
-
<div className="p-1">
|
|
68
|
-
<Card>
|
|
69
|
-
<CardContent className="flex aspect-video items-center justify-center p-6 bg-muted">
|
|
70
|
-
<span className="text-4xl font-semibold">Slide {index + 1}</span>
|
|
71
|
-
</CardContent>
|
|
72
|
-
</Card>
|
|
73
|
-
</div>
|
|
74
|
-
</CarouselItem>
|
|
75
|
-
))}
|
|
76
|
-
</CarouselContent>
|
|
77
|
-
<CarouselPrevious />
|
|
78
|
-
<CarouselNext />
|
|
79
|
-
</Carousel>
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
export const WithImages = () => (
|
|
83
|
-
<Carousel className="w-full max-w-md">
|
|
84
|
-
<CarouselContent>
|
|
85
|
-
{[
|
|
86
|
-
'https://images.unsplash.com/photo-1494976388531-d1058494cdd8?w=400',
|
|
87
|
-
'https://images.unsplash.com/photo-1503376780353-7e6692767b70?w=400',
|
|
88
|
-
'https://images.unsplash.com/photo-1542362567-b07e54358753?w=400',
|
|
89
|
-
].map((src, index) => (
|
|
90
|
-
<CarouselItem key={index}>
|
|
91
|
-
<div className="p-1">
|
|
92
|
-
<div className="aspect-video rounded-lg overflow-hidden">
|
|
93
|
-
<img src={src} alt={`Slide ${index + 1}`} className="w-full h-full object-cover" />
|
|
94
|
-
</div>
|
|
95
|
-
</div>
|
|
96
|
-
</CarouselItem>
|
|
97
|
-
))}
|
|
98
|
-
</CarouselContent>
|
|
99
|
-
<CarouselPrevious />
|
|
100
|
-
<CarouselNext />
|
|
101
|
-
</Carousel>
|
|
102
|
-
);
|
|
103
|
-
|
|
104
|
-
export const Loop = () => (
|
|
105
|
-
<Carousel opts={{ loop: true }} className="w-full max-w-xs">
|
|
106
|
-
<CarouselContent>
|
|
107
|
-
{Array.from({ length: 5 }).map((_, index) => (
|
|
108
|
-
<CarouselItem key={index}>
|
|
109
|
-
<div className="p-1">
|
|
110
|
-
<Card>
|
|
111
|
-
<CardContent className="flex aspect-square items-center justify-center p-6">
|
|
112
|
-
<span className="text-4xl font-semibold">{index + 1}</span>
|
|
113
|
-
</CardContent>
|
|
114
|
-
</Card>
|
|
115
|
-
</div>
|
|
116
|
-
</CarouselItem>
|
|
117
|
-
))}
|
|
118
|
-
</CarouselContent>
|
|
119
|
-
<CarouselPrevious />
|
|
120
|
-
<CarouselNext />
|
|
121
|
-
</Carousel>
|
|
122
|
-
);
|