@djangocfg/ui-core 2.1.120 → 2.1.123

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 (55) 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/carousel.tsx +2 -2
  15. package/src/components/checkbox.story.tsx +89 -0
  16. package/src/components/collapsible.story.tsx +133 -0
  17. package/src/components/combobox.story.tsx +145 -0
  18. package/src/components/command.story.tsx +121 -0
  19. package/src/components/context-menu.story.tsx +125 -0
  20. package/src/components/copy.story.tsx +77 -0
  21. package/src/components/dialog.story.tsx +137 -0
  22. package/src/components/drawer.story.tsx +131 -0
  23. package/src/components/dropdown-menu.story.tsx +208 -0
  24. package/src/components/empty.story.tsx +115 -0
  25. package/src/components/hover-card.story.tsx +102 -0
  26. package/src/components/image-with-fallback.story.tsx +105 -0
  27. package/src/components/input-group.story.tsx +119 -0
  28. package/src/components/input-otp.story.tsx +105 -0
  29. package/src/components/input.story.tsx +77 -0
  30. package/src/components/kbd.story.tsx +113 -0
  31. package/src/components/label.story.tsx +52 -0
  32. package/src/components/menubar.story.tsx +152 -0
  33. package/src/components/multi-select.story.tsx +122 -0
  34. package/src/components/navigation-menu.story.tsx +154 -0
  35. package/src/components/popover.story.tsx +127 -0
  36. package/src/components/preloader.story.tsx +86 -0
  37. package/src/components/progress.story.tsx +97 -0
  38. package/src/components/radio-group.story.tsx +113 -0
  39. package/src/components/resizable.story.tsx +119 -0
  40. package/src/components/responsive-sheet.story.tsx +117 -0
  41. package/src/components/scroll-area.story.tsx +112 -0
  42. package/src/components/select.story.tsx +112 -0
  43. package/src/components/separator.story.tsx +69 -0
  44. package/src/components/sheet.story.tsx +148 -0
  45. package/src/components/skeleton.story.tsx +101 -0
  46. package/src/components/slider.story.tsx +113 -0
  47. package/src/components/spinner.story.tsx +66 -0
  48. package/src/components/switch.story.tsx +98 -0
  49. package/src/components/table.story.tsx +148 -0
  50. package/src/components/tabs.story.tsx +98 -0
  51. package/src/components/tabs.tsx +1 -1
  52. package/src/components/textarea.story.tsx +94 -0
  53. package/src/components/toggle-group.story.tsx +118 -0
  54. package/src/components/toggle.story.tsx +104 -0
  55. package/src/components/tooltip.story.tsx +139 -0
@@ -0,0 +1,89 @@
1
+ import { useState } from 'react';
2
+ import { defineStory, useBoolean } from '@djangocfg/playground';
3
+ import { Checkbox } from './checkbox';
4
+ import { Label } from './label';
5
+
6
+ export default defineStory({
7
+ title: 'Core/Checkbox',
8
+ component: Checkbox,
9
+ description: 'Checkbox input for boolean selections.',
10
+ });
11
+
12
+ export const Interactive = () => {
13
+ const [disabled] = useBoolean('disabled', {
14
+ defaultValue: false,
15
+ label: 'Disabled',
16
+ description: 'Disable checkbox',
17
+ });
18
+
19
+ return (
20
+ <div className="flex items-center space-x-2">
21
+ <Checkbox id="terms" disabled={disabled} />
22
+ <Label htmlFor="terms">Accept terms and conditions</Label>
23
+ </div>
24
+ );
25
+ };
26
+
27
+ export const Default = () => (
28
+ <div className="flex items-center space-x-2">
29
+ <Checkbox id="default" />
30
+ <Label htmlFor="default">Default checkbox</Label>
31
+ </div>
32
+ );
33
+
34
+ export const Checked = () => (
35
+ <div className="flex items-center space-x-2">
36
+ <Checkbox id="checked" defaultChecked />
37
+ <Label htmlFor="checked">Checked by default</Label>
38
+ </div>
39
+ );
40
+
41
+ export const Disabled = () => (
42
+ <div className="space-y-4">
43
+ <div className="flex items-center space-x-2">
44
+ <Checkbox id="disabled-unchecked" disabled />
45
+ <Label htmlFor="disabled-unchecked">Disabled unchecked</Label>
46
+ </div>
47
+ <div className="flex items-center space-x-2">
48
+ <Checkbox id="disabled-checked" disabled defaultChecked />
49
+ <Label htmlFor="disabled-checked">Disabled checked</Label>
50
+ </div>
51
+ </div>
52
+ );
53
+
54
+ export const WithForm = () => {
55
+ const [items, setItems] = useState({
56
+ notifications: true,
57
+ marketing: false,
58
+ updates: true,
59
+ });
60
+
61
+ return (
62
+ <div className="space-y-4">
63
+ <div className="flex items-center space-x-2">
64
+ <Checkbox
65
+ id="notifications"
66
+ checked={items.notifications}
67
+ onCheckedChange={(checked) => setItems({ ...items, notifications: !!checked })}
68
+ />
69
+ <Label htmlFor="notifications">Receive notifications</Label>
70
+ </div>
71
+ <div className="flex items-center space-x-2">
72
+ <Checkbox
73
+ id="marketing"
74
+ checked={items.marketing}
75
+ onCheckedChange={(checked) => setItems({ ...items, marketing: !!checked })}
76
+ />
77
+ <Label htmlFor="marketing">Receive marketing emails</Label>
78
+ </div>
79
+ <div className="flex items-center space-x-2">
80
+ <Checkbox
81
+ id="updates"
82
+ checked={items.updates}
83
+ onCheckedChange={(checked) => setItems({ ...items, updates: !!checked })}
84
+ />
85
+ <Label htmlFor="updates">Receive product updates</Label>
86
+ </div>
87
+ </div>
88
+ );
89
+ };
@@ -0,0 +1,133 @@
1
+ import { useState } from 'react';
2
+ import { defineStory } from '@djangocfg/playground';
3
+ import { Collapsible, CollapsibleContent, CollapsibleTrigger } from './collapsible';
4
+ import { Button } from './button';
5
+ import { ChevronsUpDown } from 'lucide-react';
6
+
7
+ export default defineStory({
8
+ title: 'Core/Collapsible',
9
+ component: Collapsible,
10
+ description: 'Expandable/collapsible content section.',
11
+ });
12
+
13
+ export const Default = () => {
14
+ const [isOpen, setIsOpen] = useState(false);
15
+
16
+ return (
17
+ <Collapsible
18
+ open={isOpen}
19
+ onOpenChange={setIsOpen}
20
+ className="w-[350px] space-y-2"
21
+ >
22
+ <div className="flex items-center justify-between space-x-4 px-4">
23
+ <h4 className="text-sm font-semibold">
24
+ @peduarte starred 3 repositories
25
+ </h4>
26
+ <CollapsibleTrigger asChild>
27
+ <Button variant="ghost" size="sm" className="w-9 p-0">
28
+ <ChevronsUpDown className="h-4 w-4" />
29
+ <span className="sr-only">Toggle</span>
30
+ </Button>
31
+ </CollapsibleTrigger>
32
+ </div>
33
+ <div className="rounded-md border px-4 py-3 font-mono text-sm">
34
+ @radix-ui/primitives
35
+ </div>
36
+ <CollapsibleContent className="space-y-2">
37
+ <div className="rounded-md border px-4 py-3 font-mono text-sm">
38
+ @radix-ui/colors
39
+ </div>
40
+ <div className="rounded-md border px-4 py-3 font-mono text-sm">
41
+ @stitches/react
42
+ </div>
43
+ </CollapsibleContent>
44
+ </Collapsible>
45
+ );
46
+ };
47
+
48
+ export const OpenByDefault = () => {
49
+ const [isOpen, setIsOpen] = useState(true);
50
+
51
+ return (
52
+ <Collapsible
53
+ open={isOpen}
54
+ onOpenChange={setIsOpen}
55
+ className="w-[350px] space-y-2"
56
+ >
57
+ <div className="flex items-center justify-between space-x-4 px-4">
58
+ <h4 className="text-sm font-semibold">Notifications</h4>
59
+ <CollapsibleTrigger asChild>
60
+ <Button variant="ghost" size="sm">
61
+ {isOpen ? 'Hide' : 'Show'}
62
+ </Button>
63
+ </CollapsibleTrigger>
64
+ </div>
65
+ <CollapsibleContent className="space-y-2">
66
+ <div className="rounded-md border px-4 py-3 text-sm">
67
+ You have 3 new notifications
68
+ </div>
69
+ <div className="rounded-md border px-4 py-3 text-sm">
70
+ Your order has been shipped
71
+ </div>
72
+ <div className="rounded-md border px-4 py-3 text-sm">
73
+ New comment on your post
74
+ </div>
75
+ </CollapsibleContent>
76
+ </Collapsible>
77
+ );
78
+ };
79
+
80
+ export const Simple = () => (
81
+ <Collapsible className="w-[350px]">
82
+ <CollapsibleTrigger asChild>
83
+ <Button variant="outline" className="w-full justify-between">
84
+ Can I use this in my project?
85
+ <ChevronsUpDown className="h-4 w-4" />
86
+ </Button>
87
+ </CollapsibleTrigger>
88
+ <CollapsibleContent className="pt-2">
89
+ <p className="text-sm text-muted-foreground px-1">
90
+ Yes! This component is free to use in your personal and commercial projects.
91
+ No attribution required.
92
+ </p>
93
+ </CollapsibleContent>
94
+ </Collapsible>
95
+ );
96
+
97
+ export const Multiple = () => (
98
+ <div className="w-[350px] space-y-2">
99
+ <Collapsible>
100
+ <CollapsibleTrigger asChild>
101
+ <Button variant="ghost" className="w-full justify-between">
102
+ Section 1
103
+ <ChevronsUpDown className="h-4 w-4" />
104
+ </Button>
105
+ </CollapsibleTrigger>
106
+ <CollapsibleContent className="px-4 py-2">
107
+ Content for section 1
108
+ </CollapsibleContent>
109
+ </Collapsible>
110
+ <Collapsible>
111
+ <CollapsibleTrigger asChild>
112
+ <Button variant="ghost" className="w-full justify-between">
113
+ Section 2
114
+ <ChevronsUpDown className="h-4 w-4" />
115
+ </Button>
116
+ </CollapsibleTrigger>
117
+ <CollapsibleContent className="px-4 py-2">
118
+ Content for section 2
119
+ </CollapsibleContent>
120
+ </Collapsible>
121
+ <Collapsible>
122
+ <CollapsibleTrigger asChild>
123
+ <Button variant="ghost" className="w-full justify-between">
124
+ Section 3
125
+ <ChevronsUpDown className="h-4 w-4" />
126
+ </Button>
127
+ </CollapsibleTrigger>
128
+ <CollapsibleContent className="px-4 py-2">
129
+ Content for section 3
130
+ </CollapsibleContent>
131
+ </Collapsible>
132
+ </div>
133
+ );
@@ -0,0 +1,145 @@
1
+ import { useState } from 'react';
2
+ import { defineStory, useBoolean } from '@djangocfg/playground';
3
+ import { Combobox, type ComboboxOption } from './combobox';
4
+ import { Label } from './label';
5
+
6
+ export default defineStory({
7
+ title: 'Core/Combobox',
8
+ component: Combobox,
9
+ description: 'Searchable select with autocomplete.',
10
+ });
11
+
12
+ const frameworks: ComboboxOption[] = [
13
+ { value: 'next.js', label: 'Next.js' },
14
+ { value: 'sveltekit', label: 'SvelteKit' },
15
+ { value: 'nuxt.js', label: 'Nuxt.js' },
16
+ { value: 'remix', label: 'Remix' },
17
+ { value: 'astro', label: 'Astro' },
18
+ ];
19
+
20
+ const countries: ComboboxOption[] = [
21
+ { value: 'us', label: 'United States' },
22
+ { value: 'uk', label: 'United Kingdom' },
23
+ { value: 'de', label: 'Germany' },
24
+ { value: 'fr', label: 'France' },
25
+ { value: 'jp', label: 'Japan' },
26
+ { value: 'kr', label: 'South Korea' },
27
+ { value: 'cn', label: 'China' },
28
+ { value: 'au', label: 'Australia' },
29
+ { value: 'ca', label: 'Canada' },
30
+ { value: 'br', label: 'Brazil' },
31
+ ];
32
+
33
+ export const Interactive = () => {
34
+ const [value, setValue] = useState('');
35
+ const [disabled] = useBoolean('disabled', {
36
+ defaultValue: false,
37
+ label: 'Disabled',
38
+ description: 'Disable combobox',
39
+ });
40
+
41
+ return (
42
+ <div className="max-w-xs space-y-2">
43
+ <Label>Framework</Label>
44
+ <Combobox
45
+ options={frameworks}
46
+ value={value}
47
+ onValueChange={setValue}
48
+ placeholder="Select framework..."
49
+ searchPlaceholder="Search framework..."
50
+ emptyText="No framework found."
51
+ disabled={disabled}
52
+ />
53
+ </div>
54
+ );
55
+ };
56
+
57
+ export const Default = () => {
58
+ const [value, setValue] = useState('');
59
+
60
+ return (
61
+ <div className="max-w-xs">
62
+ <Combobox
63
+ options={frameworks}
64
+ value={value}
65
+ onValueChange={setValue}
66
+ placeholder="Select framework..."
67
+ searchPlaceholder="Search framework..."
68
+ emptyText="No framework found."
69
+ />
70
+ </div>
71
+ );
72
+ };
73
+
74
+ export const WithDefaultValue = () => {
75
+ const [value, setValue] = useState('next.js');
76
+
77
+ return (
78
+ <div className="max-w-xs">
79
+ <Combobox
80
+ options={frameworks}
81
+ value={value}
82
+ onValueChange={setValue}
83
+ placeholder="Select framework..."
84
+ />
85
+ </div>
86
+ );
87
+ };
88
+
89
+ export const Countries = () => {
90
+ const [value, setValue] = useState('');
91
+
92
+ return (
93
+ <div className="max-w-xs space-y-2">
94
+ <Label>Country</Label>
95
+ <Combobox
96
+ options={countries}
97
+ value={value}
98
+ onValueChange={setValue}
99
+ placeholder="Select country..."
100
+ searchPlaceholder="Search countries..."
101
+ emptyText="No country found."
102
+ />
103
+ </div>
104
+ );
105
+ };
106
+
107
+ export const Disabled = () => (
108
+ <div className="max-w-xs">
109
+ <Combobox
110
+ options={frameworks}
111
+ value=""
112
+ onValueChange={() => {}}
113
+ placeholder="Select framework..."
114
+ disabled
115
+ />
116
+ </div>
117
+ );
118
+
119
+ export const Form = () => {
120
+ const [framework, setFramework] = useState('');
121
+ const [country, setCountry] = useState('');
122
+
123
+ return (
124
+ <div className="max-w-xs space-y-4">
125
+ <div className="space-y-2">
126
+ <Label>Framework</Label>
127
+ <Combobox
128
+ options={frameworks}
129
+ value={framework}
130
+ onValueChange={setFramework}
131
+ placeholder="Select framework..."
132
+ />
133
+ </div>
134
+ <div className="space-y-2">
135
+ <Label>Country</Label>
136
+ <Combobox
137
+ options={countries}
138
+ value={country}
139
+ onValueChange={setCountry}
140
+ placeholder="Select country..."
141
+ />
142
+ </div>
143
+ </div>
144
+ );
145
+ };
@@ -0,0 +1,121 @@
1
+ import { defineStory } from '@djangocfg/playground';
2
+ import {
3
+ Command,
4
+ CommandDialog,
5
+ CommandEmpty,
6
+ CommandGroup,
7
+ CommandInput,
8
+ CommandItem,
9
+ CommandList,
10
+ CommandSeparator,
11
+ CommandShortcut,
12
+ } from './command';
13
+ import { useState } from 'react';
14
+ import { Button } from './button';
15
+ import { Calendar, Smile, Calculator, User, CreditCard, Settings } from 'lucide-react';
16
+
17
+ export default defineStory({
18
+ title: 'Core/Command',
19
+ component: Command,
20
+ description: 'Command palette for search and quick actions.',
21
+ });
22
+
23
+ export const Default = () => (
24
+ <Command className="rounded-lg border shadow-md max-w-md">
25
+ <CommandInput placeholder="Type a command or search..." />
26
+ <CommandList>
27
+ <CommandEmpty>No results found.</CommandEmpty>
28
+ <CommandGroup heading="Suggestions">
29
+ <CommandItem>
30
+ <Calendar className="mr-2 h-4 w-4" />
31
+ <span>Calendar</span>
32
+ </CommandItem>
33
+ <CommandItem>
34
+ <Smile className="mr-2 h-4 w-4" />
35
+ <span>Search Emoji</span>
36
+ </CommandItem>
37
+ <CommandItem>
38
+ <Calculator className="mr-2 h-4 w-4" />
39
+ <span>Calculator</span>
40
+ </CommandItem>
41
+ </CommandGroup>
42
+ <CommandSeparator />
43
+ <CommandGroup heading="Settings">
44
+ <CommandItem>
45
+ <User className="mr-2 h-4 w-4" />
46
+ <span>Profile</span>
47
+ <CommandShortcut>⌘P</CommandShortcut>
48
+ </CommandItem>
49
+ <CommandItem>
50
+ <CreditCard className="mr-2 h-4 w-4" />
51
+ <span>Billing</span>
52
+ <CommandShortcut>⌘B</CommandShortcut>
53
+ </CommandItem>
54
+ <CommandItem>
55
+ <Settings className="mr-2 h-4 w-4" />
56
+ <span>Settings</span>
57
+ <CommandShortcut>⌘S</CommandShortcut>
58
+ </CommandItem>
59
+ </CommandGroup>
60
+ </CommandList>
61
+ </Command>
62
+ );
63
+
64
+ export const Dialog = () => {
65
+ const [open, setOpen] = useState(false);
66
+
67
+ return (
68
+ <>
69
+ <Button onClick={() => setOpen(true)}>
70
+ Open Command Palette
71
+ </Button>
72
+ <CommandDialog open={open} onOpenChange={setOpen}>
73
+ <CommandInput placeholder="Type a command or search..." />
74
+ <CommandList>
75
+ <CommandEmpty>No results found.</CommandEmpty>
76
+ <CommandGroup heading="Suggestions">
77
+ <CommandItem onSelect={() => setOpen(false)}>
78
+ <Calendar className="mr-2 h-4 w-4" />
79
+ <span>Calendar</span>
80
+ </CommandItem>
81
+ <CommandItem onSelect={() => setOpen(false)}>
82
+ <Smile className="mr-2 h-4 w-4" />
83
+ <span>Search Emoji</span>
84
+ </CommandItem>
85
+ <CommandItem onSelect={() => setOpen(false)}>
86
+ <Calculator className="mr-2 h-4 w-4" />
87
+ <span>Calculator</span>
88
+ </CommandItem>
89
+ </CommandGroup>
90
+ <CommandSeparator />
91
+ <CommandGroup heading="Settings">
92
+ <CommandItem onSelect={() => setOpen(false)}>
93
+ <User className="mr-2 h-4 w-4" />
94
+ <span>Profile</span>
95
+ <CommandShortcut>⌘P</CommandShortcut>
96
+ </CommandItem>
97
+ <CommandItem onSelect={() => setOpen(false)}>
98
+ <Settings className="mr-2 h-4 w-4" />
99
+ <span>Settings</span>
100
+ <CommandShortcut>⌘S</CommandShortcut>
101
+ </CommandItem>
102
+ </CommandGroup>
103
+ </CommandList>
104
+ </CommandDialog>
105
+ </>
106
+ );
107
+ };
108
+
109
+ export const Simple = () => (
110
+ <Command className="rounded-lg border max-w-sm">
111
+ <CommandInput placeholder="Search..." />
112
+ <CommandList>
113
+ <CommandEmpty>No results.</CommandEmpty>
114
+ <CommandGroup>
115
+ <CommandItem>Item 1</CommandItem>
116
+ <CommandItem>Item 2</CommandItem>
117
+ <CommandItem>Item 3</CommandItem>
118
+ </CommandGroup>
119
+ </CommandList>
120
+ </Command>
121
+ );
@@ -0,0 +1,125 @@
1
+ import { useState } from 'react';
2
+ import { defineStory } from '@djangocfg/playground';
3
+ import {
4
+ ContextMenu,
5
+ ContextMenuTrigger,
6
+ ContextMenuContent,
7
+ ContextMenuItem,
8
+ ContextMenuSeparator,
9
+ ContextMenuShortcut,
10
+ ContextMenuSub,
11
+ ContextMenuSubTrigger,
12
+ ContextMenuSubContent,
13
+ ContextMenuCheckboxItem,
14
+ ContextMenuRadioGroup,
15
+ ContextMenuRadioItem,
16
+ ContextMenuLabel,
17
+ } from './context-menu';
18
+
19
+ export default defineStory({
20
+ title: 'Core/ContextMenu',
21
+ component: ContextMenu,
22
+ description: 'Right-click context menu.',
23
+ });
24
+
25
+ export const Default = () => (
26
+ <ContextMenu>
27
+ <ContextMenuTrigger className="flex h-40 w-80 items-center justify-center rounded-md border border-dashed text-sm">
28
+ Right click here
29
+ </ContextMenuTrigger>
30
+ <ContextMenuContent className="w-64">
31
+ <ContextMenuItem>
32
+ Back
33
+ <ContextMenuShortcut>⌘[</ContextMenuShortcut>
34
+ </ContextMenuItem>
35
+ <ContextMenuItem disabled>
36
+ Forward
37
+ <ContextMenuShortcut>⌘]</ContextMenuShortcut>
38
+ </ContextMenuItem>
39
+ <ContextMenuItem>
40
+ Reload
41
+ <ContextMenuShortcut>⌘R</ContextMenuShortcut>
42
+ </ContextMenuItem>
43
+ <ContextMenuSeparator />
44
+ <ContextMenuItem>
45
+ Save Page As...
46
+ <ContextMenuShortcut>⌘S</ContextMenuShortcut>
47
+ </ContextMenuItem>
48
+ <ContextMenuItem>Print...</ContextMenuItem>
49
+ </ContextMenuContent>
50
+ </ContextMenu>
51
+ );
52
+
53
+ export const WithSubMenu = () => (
54
+ <ContextMenu>
55
+ <ContextMenuTrigger className="flex h-40 w-80 items-center justify-center rounded-md border border-dashed text-sm">
56
+ Right click here
57
+ </ContextMenuTrigger>
58
+ <ContextMenuContent className="w-64">
59
+ <ContextMenuItem>New Tab</ContextMenuItem>
60
+ <ContextMenuItem>New Window</ContextMenuItem>
61
+ <ContextMenuSeparator />
62
+ <ContextMenuSub>
63
+ <ContextMenuSubTrigger>More Tools</ContextMenuSubTrigger>
64
+ <ContextMenuSubContent className="w-48">
65
+ <ContextMenuItem>Save Page As...</ContextMenuItem>
66
+ <ContextMenuItem>Create Shortcut...</ContextMenuItem>
67
+ <ContextMenuItem>Name Window...</ContextMenuItem>
68
+ <ContextMenuSeparator />
69
+ <ContextMenuItem>Developer Tools</ContextMenuItem>
70
+ </ContextMenuSubContent>
71
+ </ContextMenuSub>
72
+ <ContextMenuSeparator />
73
+ <ContextMenuItem>Settings</ContextMenuItem>
74
+ </ContextMenuContent>
75
+ </ContextMenu>
76
+ );
77
+
78
+ export const WithCheckboxes = () => {
79
+ const [showBookmarks, setShowBookmarks] = useState(true);
80
+ const [showFullUrls, setShowFullUrls] = useState(false);
81
+
82
+ return (
83
+ <ContextMenu>
84
+ <ContextMenuTrigger className="flex h-40 w-80 items-center justify-center rounded-md border border-dashed text-sm">
85
+ Right click here
86
+ </ContextMenuTrigger>
87
+ <ContextMenuContent className="w-64">
88
+ <ContextMenuCheckboxItem
89
+ checked={showBookmarks}
90
+ onCheckedChange={setShowBookmarks}
91
+ >
92
+ Show Bookmarks Bar
93
+ <ContextMenuShortcut>⌘⇧B</ContextMenuShortcut>
94
+ </ContextMenuCheckboxItem>
95
+ <ContextMenuCheckboxItem
96
+ checked={showFullUrls}
97
+ onCheckedChange={setShowFullUrls}
98
+ >
99
+ Show Full URLs
100
+ </ContextMenuCheckboxItem>
101
+ </ContextMenuContent>
102
+ </ContextMenu>
103
+ );
104
+ };
105
+
106
+ export const WithRadioGroup = () => {
107
+ const [person, setPerson] = useState('pedro');
108
+
109
+ return (
110
+ <ContextMenu>
111
+ <ContextMenuTrigger className="flex h-40 w-80 items-center justify-center rounded-md border border-dashed text-sm">
112
+ Right click here
113
+ </ContextMenuTrigger>
114
+ <ContextMenuContent className="w-64">
115
+ <ContextMenuLabel>People</ContextMenuLabel>
116
+ <ContextMenuSeparator />
117
+ <ContextMenuRadioGroup value={person} onValueChange={setPerson}>
118
+ <ContextMenuRadioItem value="pedro">Pedro Duarte</ContextMenuRadioItem>
119
+ <ContextMenuRadioItem value="colm">Colm Tuite</ContextMenuRadioItem>
120
+ <ContextMenuRadioItem value="jamie">Jamie Kyle</ContextMenuRadioItem>
121
+ </ContextMenuRadioGroup>
122
+ </ContextMenuContent>
123
+ </ContextMenu>
124
+ );
125
+ };
@@ -0,0 +1,77 @@
1
+ import { defineStory, useSelect } from '@djangocfg/playground';
2
+ import { CopyButton, CopyField } from './copy';
3
+
4
+ export default defineStory({
5
+ title: 'Core/Copy',
6
+ component: CopyButton,
7
+ description: 'Copy to clipboard components.',
8
+ });
9
+
10
+ export const Button = () => (
11
+ <CopyButton value="Hello, World!" />
12
+ );
13
+
14
+ export const ButtonWithText = () => (
15
+ <CopyButton value="npm install @djangocfg/ui-core">
16
+ Copy command
17
+ </CopyButton>
18
+ );
19
+
20
+ export const ButtonVariants = () => (
21
+ <div className="flex gap-2">
22
+ <CopyButton value="Text" variant="default" />
23
+ <CopyButton value="Text" variant="outline" />
24
+ <CopyButton value="Text" variant="ghost" />
25
+ </div>
26
+ );
27
+
28
+ export const ButtonSizes = () => (
29
+ <div className="flex items-center gap-2">
30
+ <CopyButton value="Text" size="sm" />
31
+ <CopyButton value="Text" size="default" />
32
+ <CopyButton value="Text" size="icon" />
33
+ </div>
34
+ );
35
+
36
+ export const Field = () => (
37
+ <div className="max-w-md">
38
+ <CopyField value="npm install @djangocfg/ui-core" />
39
+ </div>
40
+ );
41
+
42
+ export const FieldWithLabel = () => (
43
+ <div className="max-w-md space-y-2">
44
+ <label className="text-sm font-medium">Installation command</label>
45
+ <CopyField value="npm install @djangocfg/ui-core" />
46
+ </div>
47
+ );
48
+
49
+ export const ApiKey = () => (
50
+ <div className="max-w-md space-y-2">
51
+ <label className="text-sm font-medium">API Key</label>
52
+ <CopyField value="sk-1234567890abcdefghijklmnopqrstuvwxyz" />
53
+ </div>
54
+ );
55
+
56
+ export const URLs = () => (
57
+ <div className="max-w-lg space-y-4">
58
+ <div className="space-y-2">
59
+ <label className="text-sm font-medium">Share Link</label>
60
+ <CopyField value="https://example.com/share/abc123" />
61
+ </div>
62
+ <div className="space-y-2">
63
+ <label className="text-sm font-medium">Embed Code</label>
64
+ <CopyField value='<iframe src="https://example.com/embed/abc123"></iframe>' />
65
+ </div>
66
+ </div>
67
+ );
68
+
69
+ export const InCard = () => (
70
+ <div className="rounded-lg border p-4 max-w-md">
71
+ <h4 className="font-medium mb-2">Invite Link</h4>
72
+ <p className="text-sm text-muted-foreground mb-4">
73
+ Share this link with your team members.
74
+ </p>
75
+ <CopyField value="https://app.example.com/invite/team-abc123" />
76
+ </div>
77
+ );