@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.
Files changed (61) hide show
  1. package/package.json +5 -12
  2. package/src/components/boundary/boundary.story.tsx +0 -191
  3. package/src/components/data/avatar/avatar.story.tsx +0 -115
  4. package/src/components/data/badge/badge.story.tsx +0 -56
  5. package/src/components/data/calendar/calendar.story.tsx +0 -127
  6. package/src/components/data/carousel/carousel.story.tsx +0 -122
  7. package/src/components/data/progress/progress.story.tsx +0 -97
  8. package/src/components/data/table/table.story.tsx +0 -148
  9. package/src/components/data/toggle/toggle.story.tsx +0 -104
  10. package/src/components/data/toggle-group/toggle-group.story.tsx +0 -118
  11. package/src/components/feedback/alert/alert.story.tsx +0 -77
  12. package/src/components/feedback/empty/empty.story.tsx +0 -115
  13. package/src/components/feedback/preloader/preloader.story.tsx +0 -86
  14. package/src/components/feedback/spinner/spinner.story.tsx +0 -66
  15. package/src/components/forms/button/button.story.tsx +0 -116
  16. package/src/components/forms/button-download/button-download.story.tsx +0 -112
  17. package/src/components/forms/button-group/button-group.story.tsx +0 -79
  18. package/src/components/forms/checkbox/checkbox.story.tsx +0 -89
  19. package/src/components/forms/input/input.story.tsx +0 -77
  20. package/src/components/forms/input-group/input-group.story.tsx +0 -119
  21. package/src/components/forms/input-otp/input-otp.story.tsx +0 -105
  22. package/src/components/forms/label/label.story.tsx +0 -52
  23. package/src/components/forms/radio-group/radio-group.story.tsx +0 -113
  24. package/src/components/forms/slider/slider.story.tsx +0 -134
  25. package/src/components/forms/switch/switch.story.tsx +0 -98
  26. package/src/components/forms/textarea/textarea.story.tsx +0 -94
  27. package/src/components/layout/aspect-ratio/aspect-ratio.story.tsx +0 -94
  28. package/src/components/layout/card/card.story.tsx +0 -105
  29. package/src/components/layout/resizable/resizable.story.tsx +0 -119
  30. package/src/components/layout/scroll-area/scroll-area.story.tsx +0 -172
  31. package/src/components/layout/separator/separator.story.tsx +0 -69
  32. package/src/components/layout/skeleton/skeleton.story.tsx +0 -101
  33. package/src/components/navigation/accordion/accordion.story.tsx +0 -110
  34. package/src/components/navigation/collapsible/collapsible.story.tsx +0 -133
  35. package/src/components/navigation/command/command.story.tsx +0 -121
  36. package/src/components/navigation/context-menu/context-menu.story.tsx +0 -125
  37. package/src/components/navigation/dropdown-menu/dropdown-menu.story.tsx +0 -208
  38. package/src/components/navigation/menubar/menubar.story.tsx +0 -152
  39. package/src/components/navigation/navigation-menu/navigation-menu.story.tsx +0 -154
  40. package/src/components/navigation/tabs/tabs.story.tsx +0 -98
  41. package/src/components/overlay/alert-dialog/alert-dialog.story.tsx +0 -104
  42. package/src/components/overlay/dialog/dialog.story.tsx +0 -212
  43. package/src/components/overlay/drawer/drawer.story.tsx +0 -359
  44. package/src/components/overlay/hover-card/hover-card.story.tsx +0 -102
  45. package/src/components/overlay/popover/popover.story.tsx +0 -127
  46. package/src/components/overlay/responsive-sheet/responsive-sheet.story.tsx +0 -117
  47. package/src/components/overlay/sheet/sheet.story.tsx +0 -148
  48. package/src/components/overlay/tooltip/tooltip.story.tsx +0 -139
  49. package/src/components/select/combobox-async.story.tsx +0 -215
  50. package/src/components/select/combobox.story.tsx +0 -226
  51. package/src/components/select/country-select.story.tsx +0 -261
  52. package/src/components/select/language-select.story.tsx +0 -264
  53. package/src/components/select/multi-select.story.tsx +0 -122
  54. package/src/components/select/select.story.tsx +0 -112
  55. package/src/components/specialized/copy/copy.story.tsx +0 -77
  56. package/src/components/specialized/flag/flag.story.tsx +0 -82
  57. package/src/components/specialized/image-with-fallback/image-with-fallback.story.tsx +0 -105
  58. package/src/components/specialized/kbd/kbd.story.tsx +0 -113
  59. package/src/lib/dialog-service/dialog-service.story.tsx +0 -263
  60. package/src/stories/index.ts +0 -28
  61. 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.382",
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.382",
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.382",
170
- "@djangocfg/playground": "workspace:*",
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=&quot;silent&quot; 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
- );