@djangocfg/ui-core 2.1.120 → 2.1.121

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 (54) hide show
  1. package/package.json +8 -5
  2. package/src/components/accordion.story.tsx +110 -0
  3. package/src/components/alert-dialog.story.tsx +104 -0
  4. package/src/components/alert.story.tsx +77 -0
  5. package/src/components/aspect-ratio.story.tsx +94 -0
  6. package/src/components/avatar.story.tsx +115 -0
  7. package/src/components/badge.story.tsx +56 -0
  8. package/src/components/button-download.story.tsx +112 -0
  9. package/src/components/button-group.story.tsx +79 -0
  10. package/src/components/button.story.tsx +116 -0
  11. package/src/components/calendar.story.tsx +126 -0
  12. package/src/components/card.story.tsx +105 -0
  13. package/src/components/carousel.story.tsx +122 -0
  14. package/src/components/checkbox.story.tsx +89 -0
  15. package/src/components/collapsible.story.tsx +133 -0
  16. package/src/components/combobox.story.tsx +145 -0
  17. package/src/components/command.story.tsx +121 -0
  18. package/src/components/context-menu.story.tsx +125 -0
  19. package/src/components/copy.story.tsx +77 -0
  20. package/src/components/dialog.story.tsx +137 -0
  21. package/src/components/drawer.story.tsx +131 -0
  22. package/src/components/dropdown-menu.story.tsx +208 -0
  23. package/src/components/empty.story.tsx +115 -0
  24. package/src/components/hover-card.story.tsx +102 -0
  25. package/src/components/image-with-fallback.story.tsx +105 -0
  26. package/src/components/input-group.story.tsx +119 -0
  27. package/src/components/input-otp.story.tsx +105 -0
  28. package/src/components/input.story.tsx +77 -0
  29. package/src/components/kbd.story.tsx +113 -0
  30. package/src/components/label.story.tsx +52 -0
  31. package/src/components/menubar.story.tsx +152 -0
  32. package/src/components/multi-select.story.tsx +122 -0
  33. package/src/components/navigation-menu.story.tsx +154 -0
  34. package/src/components/popover.story.tsx +127 -0
  35. package/src/components/preloader.story.tsx +86 -0
  36. package/src/components/progress.story.tsx +97 -0
  37. package/src/components/radio-group.story.tsx +113 -0
  38. package/src/components/resizable.story.tsx +119 -0
  39. package/src/components/responsive-sheet.story.tsx +117 -0
  40. package/src/components/scroll-area.story.tsx +112 -0
  41. package/src/components/select.story.tsx +112 -0
  42. package/src/components/separator.story.tsx +69 -0
  43. package/src/components/sheet.story.tsx +148 -0
  44. package/src/components/skeleton.story.tsx +101 -0
  45. package/src/components/slider.story.tsx +113 -0
  46. package/src/components/spinner.story.tsx +66 -0
  47. package/src/components/switch.story.tsx +98 -0
  48. package/src/components/table.story.tsx +148 -0
  49. package/src/components/tabs.story.tsx +98 -0
  50. package/src/components/tabs.tsx +1 -1
  51. package/src/components/textarea.story.tsx +94 -0
  52. package/src/components/toggle-group.story.tsx +118 -0
  53. package/src/components/toggle.story.tsx +104 -0
  54. package/src/components/tooltip.story.tsx +139 -0
@@ -0,0 +1,97 @@
1
+ import { useState, useEffect } from 'react';
2
+ import { defineStory, useNumber } from '@djangocfg/playground';
3
+ import { Progress } from './progress';
4
+
5
+ export default defineStory({
6
+ title: 'Core/Progress',
7
+ component: Progress,
8
+ description: 'Progress bar for showing completion status.',
9
+ });
10
+
11
+ export const Interactive = () => {
12
+ const [value] = useNumber('value', {
13
+ defaultValue: 60,
14
+ min: 0,
15
+ max: 100,
16
+ label: 'Progress',
17
+ description: 'Progress percentage',
18
+ });
19
+
20
+ return (
21
+ <div className="max-w-md">
22
+ <Progress value={value} />
23
+ </div>
24
+ );
25
+ };
26
+
27
+ export const Default = () => (
28
+ <div className="max-w-md">
29
+ <Progress value={60} />
30
+ </div>
31
+ );
32
+
33
+ export const Values = () => (
34
+ <div className="max-w-md space-y-4">
35
+ <div className="space-y-1">
36
+ <span className="text-sm">0%</span>
37
+ <Progress value={0} />
38
+ </div>
39
+ <div className="space-y-1">
40
+ <span className="text-sm">25%</span>
41
+ <Progress value={25} />
42
+ </div>
43
+ <div className="space-y-1">
44
+ <span className="text-sm">50%</span>
45
+ <Progress value={50} />
46
+ </div>
47
+ <div className="space-y-1">
48
+ <span className="text-sm">75%</span>
49
+ <Progress value={75} />
50
+ </div>
51
+ <div className="space-y-1">
52
+ <span className="text-sm">100%</span>
53
+ <Progress value={100} />
54
+ </div>
55
+ </div>
56
+ );
57
+
58
+ export const Animated = () => {
59
+ const [progress, setProgress] = useState(0);
60
+
61
+ useEffect(() => {
62
+ const timer = setInterval(() => {
63
+ setProgress((prev) => {
64
+ if (prev >= 100) return 0;
65
+ return prev + 10;
66
+ });
67
+ }, 500);
68
+
69
+ return () => clearInterval(timer);
70
+ }, []);
71
+
72
+ return (
73
+ <div className="max-w-md space-y-2">
74
+ <div className="flex justify-between text-sm">
75
+ <span>Loading...</span>
76
+ <span>{progress}%</span>
77
+ </div>
78
+ <Progress value={progress} />
79
+ </div>
80
+ );
81
+ };
82
+
83
+ export const WithLabel = () => (
84
+ <div className="max-w-md space-y-2">
85
+ <div className="flex justify-between text-sm">
86
+ <span>Upload progress</span>
87
+ <span>75%</span>
88
+ </div>
89
+ <Progress value={75} />
90
+ </div>
91
+ );
92
+
93
+ export const Indeterminate = () => (
94
+ <div className="max-w-md">
95
+ <Progress className="[&>div]:animate-pulse" />
96
+ </div>
97
+ );
@@ -0,0 +1,113 @@
1
+ import { defineStory, useBoolean } from '@djangocfg/playground';
2
+ import { RadioGroup, RadioGroupItem } from './radio-group';
3
+ import { Label } from './label';
4
+
5
+ export default defineStory({
6
+ title: 'Core/Radio Group',
7
+ component: RadioGroup,
8
+ description: 'Radio button group for single selection.',
9
+ });
10
+
11
+ export const Interactive = () => {
12
+ const [disabled] = useBoolean('disabled', {
13
+ defaultValue: false,
14
+ label: 'Disabled',
15
+ description: 'Disable radio group',
16
+ });
17
+
18
+ return (
19
+ <RadioGroup defaultValue="option-1" disabled={disabled}>
20
+ <div className="flex items-center space-x-2">
21
+ <RadioGroupItem value="option-1" id="option-1" />
22
+ <Label htmlFor="option-1">Option 1</Label>
23
+ </div>
24
+ <div className="flex items-center space-x-2">
25
+ <RadioGroupItem value="option-2" id="option-2" />
26
+ <Label htmlFor="option-2">Option 2</Label>
27
+ </div>
28
+ <div className="flex items-center space-x-2">
29
+ <RadioGroupItem value="option-3" id="option-3" />
30
+ <Label htmlFor="option-3">Option 3</Label>
31
+ </div>
32
+ </RadioGroup>
33
+ );
34
+ };
35
+
36
+ export const Default = () => (
37
+ <RadioGroup defaultValue="comfortable">
38
+ <div className="flex items-center space-x-2">
39
+ <RadioGroupItem value="default" id="r1" />
40
+ <Label htmlFor="r1">Default</Label>
41
+ </div>
42
+ <div className="flex items-center space-x-2">
43
+ <RadioGroupItem value="comfortable" id="r2" />
44
+ <Label htmlFor="r2">Comfortable</Label>
45
+ </div>
46
+ <div className="flex items-center space-x-2">
47
+ <RadioGroupItem value="compact" id="r3" />
48
+ <Label htmlFor="r3">Compact</Label>
49
+ </div>
50
+ </RadioGroup>
51
+ );
52
+
53
+ export const Horizontal = () => (
54
+ <RadioGroup defaultValue="card" className="flex gap-4">
55
+ <div className="flex items-center space-x-2">
56
+ <RadioGroupItem value="card" id="card" />
57
+ <Label htmlFor="card">Card</Label>
58
+ </div>
59
+ <div className="flex items-center space-x-2">
60
+ <RadioGroupItem value="paypal" id="paypal" />
61
+ <Label htmlFor="paypal">PayPal</Label>
62
+ </div>
63
+ <div className="flex items-center space-x-2">
64
+ <RadioGroupItem value="apple" id="apple" />
65
+ <Label htmlFor="apple">Apple Pay</Label>
66
+ </div>
67
+ </RadioGroup>
68
+ );
69
+
70
+ export const Disabled = () => (
71
+ <RadioGroup defaultValue="option-1" disabled>
72
+ <div className="flex items-center space-x-2">
73
+ <RadioGroupItem value="option-1" id="d1" />
74
+ <Label htmlFor="d1">Option 1</Label>
75
+ </div>
76
+ <div className="flex items-center space-x-2">
77
+ <RadioGroupItem value="option-2" id="d2" />
78
+ <Label htmlFor="d2">Option 2</Label>
79
+ </div>
80
+ </RadioGroup>
81
+ );
82
+
83
+ export const WithDescriptions = () => (
84
+ <RadioGroup defaultValue="startup" className="space-y-4">
85
+ <div className="flex items-start space-x-3">
86
+ <RadioGroupItem value="startup" id="startup" className="mt-1" />
87
+ <div>
88
+ <Label htmlFor="startup" className="font-medium">Startup</Label>
89
+ <p className="text-sm text-muted-foreground">
90
+ Perfect for small teams and startups.
91
+ </p>
92
+ </div>
93
+ </div>
94
+ <div className="flex items-start space-x-3">
95
+ <RadioGroupItem value="business" id="business" className="mt-1" />
96
+ <div>
97
+ <Label htmlFor="business" className="font-medium">Business</Label>
98
+ <p className="text-sm text-muted-foreground">
99
+ For growing businesses with advanced needs.
100
+ </p>
101
+ </div>
102
+ </div>
103
+ <div className="flex items-start space-x-3">
104
+ <RadioGroupItem value="enterprise" id="enterprise" className="mt-1" />
105
+ <div>
106
+ <Label htmlFor="enterprise" className="font-medium">Enterprise</Label>
107
+ <p className="text-sm text-muted-foreground">
108
+ Custom solutions for large organizations.
109
+ </p>
110
+ </div>
111
+ </div>
112
+ </RadioGroup>
113
+ );
@@ -0,0 +1,119 @@
1
+ import { defineStory } from '@djangocfg/playground';
2
+ import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from './resizable';
3
+
4
+ export default defineStory({
5
+ title: 'Core/Resizable',
6
+ component: ResizablePanelGroup,
7
+ description: 'Resizable panels with drag handles.',
8
+ });
9
+
10
+ export const Horizontal = () => (
11
+ <ResizablePanelGroup
12
+ direction="horizontal"
13
+ className="max-w-md rounded-lg border"
14
+ >
15
+ <ResizablePanel defaultSize={50}>
16
+ <div className="flex h-[200px] items-center justify-center p-6">
17
+ <span className="font-semibold">One</span>
18
+ </div>
19
+ </ResizablePanel>
20
+ <ResizableHandle />
21
+ <ResizablePanel defaultSize={50}>
22
+ <div className="flex h-[200px] items-center justify-center p-6">
23
+ <span className="font-semibold">Two</span>
24
+ </div>
25
+ </ResizablePanel>
26
+ </ResizablePanelGroup>
27
+ );
28
+
29
+ export const Vertical = () => (
30
+ <ResizablePanelGroup
31
+ direction="vertical"
32
+ className="max-w-md rounded-lg border"
33
+ >
34
+ <ResizablePanel defaultSize={25}>
35
+ <div className="flex h-full items-center justify-center p-6">
36
+ <span className="font-semibold">Header</span>
37
+ </div>
38
+ </ResizablePanel>
39
+ <ResizableHandle />
40
+ <ResizablePanel defaultSize={75}>
41
+ <div className="flex h-full items-center justify-center p-6">
42
+ <span className="font-semibold">Content</span>
43
+ </div>
44
+ </ResizablePanel>
45
+ </ResizablePanelGroup>
46
+ );
47
+
48
+ export const ThreePanels = () => (
49
+ <ResizablePanelGroup
50
+ direction="horizontal"
51
+ className="max-w-lg rounded-lg border"
52
+ >
53
+ <ResizablePanel defaultSize={25} minSize={15}>
54
+ <div className="flex h-[200px] items-center justify-center p-6">
55
+ <span className="font-semibold">Sidebar</span>
56
+ </div>
57
+ </ResizablePanel>
58
+ <ResizableHandle />
59
+ <ResizablePanel defaultSize={50}>
60
+ <div className="flex h-[200px] items-center justify-center p-6">
61
+ <span className="font-semibold">Content</span>
62
+ </div>
63
+ </ResizablePanel>
64
+ <ResizableHandle />
65
+ <ResizablePanel defaultSize={25} minSize={15}>
66
+ <div className="flex h-[200px] items-center justify-center p-6">
67
+ <span className="font-semibold">Details</span>
68
+ </div>
69
+ </ResizablePanel>
70
+ </ResizablePanelGroup>
71
+ );
72
+
73
+ export const Nested = () => (
74
+ <ResizablePanelGroup
75
+ direction="horizontal"
76
+ className="max-w-lg rounded-lg border"
77
+ >
78
+ <ResizablePanel defaultSize={25}>
79
+ <div className="flex h-[300px] items-center justify-center p-6">
80
+ <span className="font-semibold">Sidebar</span>
81
+ </div>
82
+ </ResizablePanel>
83
+ <ResizableHandle />
84
+ <ResizablePanel defaultSize={75}>
85
+ <ResizablePanelGroup direction="vertical">
86
+ <ResizablePanel defaultSize={50}>
87
+ <div className="flex h-full items-center justify-center p-6">
88
+ <span className="font-semibold">Top</span>
89
+ </div>
90
+ </ResizablePanel>
91
+ <ResizableHandle />
92
+ <ResizablePanel defaultSize={50}>
93
+ <div className="flex h-full items-center justify-center p-6">
94
+ <span className="font-semibold">Bottom</span>
95
+ </div>
96
+ </ResizablePanel>
97
+ </ResizablePanelGroup>
98
+ </ResizablePanel>
99
+ </ResizablePanelGroup>
100
+ );
101
+
102
+ export const WithHandle = () => (
103
+ <ResizablePanelGroup
104
+ direction="horizontal"
105
+ className="max-w-md rounded-lg border"
106
+ >
107
+ <ResizablePanel defaultSize={50}>
108
+ <div className="flex h-[200px] items-center justify-center p-6">
109
+ <span className="font-semibold">Left</span>
110
+ </div>
111
+ </ResizablePanel>
112
+ <ResizableHandle withHandle />
113
+ <ResizablePanel defaultSize={50}>
114
+ <div className="flex h-[200px] items-center justify-center p-6">
115
+ <span className="font-semibold">Right</span>
116
+ </div>
117
+ </ResizablePanel>
118
+ </ResizablePanelGroup>
119
+ );
@@ -0,0 +1,117 @@
1
+ import { useState } from 'react';
2
+ import { defineStory } from '@djangocfg/playground';
3
+ import {
4
+ ResponsiveSheet,
5
+ ResponsiveSheetContent,
6
+ ResponsiveSheetHeader,
7
+ ResponsiveSheetTitle,
8
+ ResponsiveSheetDescription,
9
+ ResponsiveSheetFooter,
10
+ } from './responsive-sheet';
11
+ import { Button } from './button';
12
+ import { Input } from './input';
13
+ import { Label } from './label';
14
+
15
+ export default defineStory({
16
+ title: 'Core/ResponsiveSheet',
17
+ component: ResponsiveSheet,
18
+ description: 'Dialog on desktop, Drawer on mobile.',
19
+ });
20
+
21
+ export const Default = () => {
22
+ const [open, setOpen] = useState(false);
23
+
24
+ return (
25
+ <>
26
+ <Button onClick={() => setOpen(true)}>Open Sheet</Button>
27
+ <ResponsiveSheet open={open} onOpenChange={setOpen}>
28
+ <ResponsiveSheetContent>
29
+ <ResponsiveSheetHeader>
30
+ <ResponsiveSheetTitle>Responsive Sheet</ResponsiveSheetTitle>
31
+ <ResponsiveSheetDescription>
32
+ This component shows as a Dialog on desktop and a Drawer on mobile.
33
+ </ResponsiveSheetDescription>
34
+ </ResponsiveSheetHeader>
35
+ <div className="p-4">
36
+ <p className="text-sm text-muted-foreground">
37
+ Resize your browser window to see the responsive behavior.
38
+ </p>
39
+ </div>
40
+ <ResponsiveSheetFooter>
41
+ <Button variant="outline" onClick={() => setOpen(false)}>
42
+ Cancel
43
+ </Button>
44
+ <Button onClick={() => setOpen(false)}>Continue</Button>
45
+ </ResponsiveSheetFooter>
46
+ </ResponsiveSheetContent>
47
+ </ResponsiveSheet>
48
+ </>
49
+ );
50
+ };
51
+
52
+ export const WithForm = () => {
53
+ const [open, setOpen] = useState(false);
54
+
55
+ return (
56
+ <>
57
+ <Button onClick={() => setOpen(true)}>Edit Profile</Button>
58
+ <ResponsiveSheet open={open} onOpenChange={setOpen}>
59
+ <ResponsiveSheetContent className="sm:max-w-md">
60
+ <ResponsiveSheetHeader>
61
+ <ResponsiveSheetTitle>Edit Profile</ResponsiveSheetTitle>
62
+ <ResponsiveSheetDescription>
63
+ Make changes to your profile here. Click save when you're done.
64
+ </ResponsiveSheetDescription>
65
+ </ResponsiveSheetHeader>
66
+ <div className="space-y-4 p-4">
67
+ <div className="space-y-2">
68
+ <Label htmlFor="name">Name</Label>
69
+ <Input id="name" defaultValue="John Doe" />
70
+ </div>
71
+ <div className="space-y-2">
72
+ <Label htmlFor="email">Email</Label>
73
+ <Input id="email" type="email" defaultValue="john@example.com" />
74
+ </div>
75
+ </div>
76
+ <ResponsiveSheetFooter>
77
+ <Button variant="outline" onClick={() => setOpen(false)}>
78
+ Cancel
79
+ </Button>
80
+ <Button onClick={() => setOpen(false)}>Save changes</Button>
81
+ </ResponsiveSheetFooter>
82
+ </ResponsiveSheetContent>
83
+ </ResponsiveSheet>
84
+ </>
85
+ );
86
+ };
87
+
88
+ export const Confirmation = () => {
89
+ const [open, setOpen] = useState(false);
90
+
91
+ return (
92
+ <>
93
+ <Button variant="destructive" onClick={() => setOpen(true)}>
94
+ Delete Account
95
+ </Button>
96
+ <ResponsiveSheet open={open} onOpenChange={setOpen}>
97
+ <ResponsiveSheetContent>
98
+ <ResponsiveSheetHeader>
99
+ <ResponsiveSheetTitle>Are you sure?</ResponsiveSheetTitle>
100
+ <ResponsiveSheetDescription>
101
+ This action cannot be undone. This will permanently delete your
102
+ account and remove your data from our servers.
103
+ </ResponsiveSheetDescription>
104
+ </ResponsiveSheetHeader>
105
+ <ResponsiveSheetFooter>
106
+ <Button variant="outline" onClick={() => setOpen(false)}>
107
+ Cancel
108
+ </Button>
109
+ <Button variant="destructive" onClick={() => setOpen(false)}>
110
+ Delete Account
111
+ </Button>
112
+ </ResponsiveSheetFooter>
113
+ </ResponsiveSheetContent>
114
+ </ResponsiveSheet>
115
+ </>
116
+ );
117
+ };
@@ -0,0 +1,112 @@
1
+ import { defineStory } from '@djangocfg/playground';
2
+ import { ScrollArea, ScrollBar } from './scroll-area';
3
+ import { Separator } from './separator';
4
+
5
+ export default defineStory({
6
+ title: 'Core/Scroll Area',
7
+ component: ScrollArea,
8
+ description: 'Custom scrollable area with styled scrollbars.',
9
+ });
10
+
11
+ const tags = Array.from({ length: 50 }).map(
12
+ (_, i, a) => `v1.2.0-beta.${a.length - i}`
13
+ );
14
+
15
+ const works = [
16
+ { artist: 'Ornella Binni', art: 'Sunset Dreams' },
17
+ { artist: 'Tom Byrom', art: 'Mountain Peak' },
18
+ { artist: 'Vladimir Malyavko', art: 'City Lights' },
19
+ { artist: 'Fabio Fistarol', art: 'Ocean Blue' },
20
+ { artist: 'Anthony Intraversato', art: 'Forest Path' },
21
+ { artist: 'Ash Edmonds', art: 'Desert Storm' },
22
+ ];
23
+
24
+ export const Vertical = () => (
25
+ <ScrollArea className="h-72 w-48 rounded-md border">
26
+ <div className="p-4">
27
+ <h4 className="mb-4 text-sm font-medium leading-none">Tags</h4>
28
+ {tags.map((tag) => (
29
+ <div key={tag}>
30
+ <div className="text-sm">{tag}</div>
31
+ <Separator className="my-2" />
32
+ </div>
33
+ ))}
34
+ </div>
35
+ </ScrollArea>
36
+ );
37
+
38
+ export const Horizontal = () => (
39
+ <ScrollArea className="w-96 whitespace-nowrap rounded-md border">
40
+ <div className="flex w-max space-x-4 p-4">
41
+ {works.map((work) => (
42
+ <figure key={work.artist} className="shrink-0">
43
+ <div className="overflow-hidden rounded-md">
44
+ <div className="h-[150px] w-[150px] bg-muted flex items-center justify-center">
45
+ <span className="text-muted-foreground text-sm">{work.art}</span>
46
+ </div>
47
+ </div>
48
+ <figcaption className="pt-2 text-xs text-muted-foreground">
49
+ Photo by{' '}
50
+ <span className="font-semibold text-foreground">{work.artist}</span>
51
+ </figcaption>
52
+ </figure>
53
+ ))}
54
+ </div>
55
+ <ScrollBar orientation="horizontal" />
56
+ </ScrollArea>
57
+ );
58
+
59
+ export const Both = () => (
60
+ <ScrollArea className="h-72 w-72 rounded-md border">
61
+ <div className="p-4">
62
+ {Array.from({ length: 20 }).map((_, i) => (
63
+ <div key={i} className="whitespace-nowrap py-2">
64
+ This is a very long line of text that will require horizontal scrolling. Item {i + 1}
65
+ </div>
66
+ ))}
67
+ </div>
68
+ <ScrollBar orientation="horizontal" />
69
+ </ScrollArea>
70
+ );
71
+
72
+ export const InCard = () => (
73
+ <div className="rounded-lg border p-4 max-w-sm">
74
+ <h4 className="font-medium mb-2">Notifications</h4>
75
+ <ScrollArea className="h-48">
76
+ <div className="space-y-2">
77
+ {Array.from({ length: 10 }).map((_, i) => (
78
+ <div key={i} className="rounded-md border p-3">
79
+ <p className="text-sm font-medium">Notification {i + 1}</p>
80
+ <p className="text-xs text-muted-foreground">Just now</p>
81
+ </div>
82
+ ))}
83
+ </div>
84
+ </ScrollArea>
85
+ </div>
86
+ );
87
+
88
+ export const Chat = () => (
89
+ <div className="rounded-lg border max-w-md">
90
+ <div className="p-4 border-b">
91
+ <h4 className="font-medium">Chat</h4>
92
+ </div>
93
+ <ScrollArea className="h-64 p-4">
94
+ <div className="space-y-4">
95
+ {Array.from({ length: 15 }).map((_, i) => (
96
+ <div
97
+ key={i}
98
+ className={`flex ${i % 2 === 0 ? 'justify-start' : 'justify-end'}`}
99
+ >
100
+ <div
101
+ className={`rounded-lg px-3 py-2 max-w-[80%] ${
102
+ i % 2 === 0 ? 'bg-muted' : 'bg-primary text-primary-foreground'
103
+ }`}
104
+ >
105
+ <p className="text-sm">Message {i + 1}</p>
106
+ </div>
107
+ </div>
108
+ ))}
109
+ </div>
110
+ </ScrollArea>
111
+ </div>
112
+ );
@@ -0,0 +1,112 @@
1
+ import { defineStory, useBoolean } from '@djangocfg/playground';
2
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from './select';
3
+ import { Label } from './label';
4
+
5
+ export default defineStory({
6
+ title: 'Core/Select',
7
+ component: Select,
8
+ description: 'Dropdown select component for choosing from options.',
9
+ });
10
+
11
+ export const Interactive = () => {
12
+ const [disabled] = useBoolean('disabled', {
13
+ defaultValue: false,
14
+ label: 'Disabled',
15
+ description: 'Disable select',
16
+ });
17
+
18
+ return (
19
+ <div className="max-w-xs space-y-2">
20
+ <Label>Framework</Label>
21
+ <Select disabled={disabled}>
22
+ <SelectTrigger>
23
+ <SelectValue placeholder="Select a framework" />
24
+ </SelectTrigger>
25
+ <SelectContent>
26
+ <SelectItem value="react">React</SelectItem>
27
+ <SelectItem value="vue">Vue</SelectItem>
28
+ <SelectItem value="angular">Angular</SelectItem>
29
+ <SelectItem value="svelte">Svelte</SelectItem>
30
+ </SelectContent>
31
+ </Select>
32
+ </div>
33
+ );
34
+ };
35
+
36
+ export const Default = () => (
37
+ <div className="max-w-xs">
38
+ <Select>
39
+ <SelectTrigger>
40
+ <SelectValue placeholder="Select an option" />
41
+ </SelectTrigger>
42
+ <SelectContent>
43
+ <SelectItem value="option1">Option 1</SelectItem>
44
+ <SelectItem value="option2">Option 2</SelectItem>
45
+ <SelectItem value="option3">Option 3</SelectItem>
46
+ </SelectContent>
47
+ </Select>
48
+ </div>
49
+ );
50
+
51
+ export const WithDefaultValue = () => (
52
+ <div className="max-w-xs">
53
+ <Select defaultValue="vue">
54
+ <SelectTrigger>
55
+ <SelectValue placeholder="Select a framework" />
56
+ </SelectTrigger>
57
+ <SelectContent>
58
+ <SelectItem value="react">React</SelectItem>
59
+ <SelectItem value="vue">Vue</SelectItem>
60
+ <SelectItem value="angular">Angular</SelectItem>
61
+ </SelectContent>
62
+ </Select>
63
+ </div>
64
+ );
65
+
66
+ export const Disabled = () => (
67
+ <div className="max-w-xs">
68
+ <Select disabled>
69
+ <SelectTrigger>
70
+ <SelectValue placeholder="Disabled select" />
71
+ </SelectTrigger>
72
+ <SelectContent>
73
+ <SelectItem value="option1">Option 1</SelectItem>
74
+ </SelectContent>
75
+ </Select>
76
+ </div>
77
+ );
78
+
79
+ export const Countries = () => (
80
+ <div className="max-w-xs space-y-2">
81
+ <Label>Country</Label>
82
+ <Select>
83
+ <SelectTrigger>
84
+ <SelectValue placeholder="Select country" />
85
+ </SelectTrigger>
86
+ <SelectContent>
87
+ <SelectItem value="us">United States</SelectItem>
88
+ <SelectItem value="uk">United Kingdom</SelectItem>
89
+ <SelectItem value="de">Germany</SelectItem>
90
+ <SelectItem value="fr">France</SelectItem>
91
+ <SelectItem value="jp">Japan</SelectItem>
92
+ <SelectItem value="kr">South Korea</SelectItem>
93
+ <SelectItem value="cn">China</SelectItem>
94
+ </SelectContent>
95
+ </Select>
96
+ </div>
97
+ );
98
+
99
+ export const WithDisabledItems = () => (
100
+ <div className="max-w-xs">
101
+ <Select>
102
+ <SelectTrigger>
103
+ <SelectValue placeholder="Select plan" />
104
+ </SelectTrigger>
105
+ <SelectContent>
106
+ <SelectItem value="free">Free</SelectItem>
107
+ <SelectItem value="pro">Pro - $9/mo</SelectItem>
108
+ <SelectItem value="enterprise" disabled>Enterprise (Coming Soon)</SelectItem>
109
+ </SelectContent>
110
+ </Select>
111
+ </div>
112
+ );