@djangocfg/ui-core 2.1.381 → 2.1.383

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 (78) hide show
  1. package/README.md +85 -21
  2. package/package.json +5 -12
  3. package/src/components/boundary/Boundary.tsx +204 -33
  4. package/src/components/boundary/README.md +249 -0
  5. package/src/components/boundary/index.ts +9 -2
  6. package/src/components/index.ts +9 -2
  7. package/src/components/select/combobox.tsx +47 -19
  8. package/src/hooks/audio/createSoundBus.ts +172 -0
  9. package/src/hooks/audio/index.ts +21 -0
  10. package/src/hooks/audio/useAudioPrefs.ts +91 -0
  11. package/src/hooks/audio/useNotificationSounds.ts +271 -0
  12. package/src/hooks/audio/useSoundEffect.ts +78 -0
  13. package/src/hooks/hotkey/formatHotkey.ts +96 -0
  14. package/src/hooks/hotkey/index.ts +10 -0
  15. package/src/hooks/hotkey/useHotkey.ts +106 -34
  16. package/src/hooks/hotkey/useHotkeyChord.ts +96 -0
  17. package/src/hooks/hotkey/useHotkeyHelp.ts +68 -0
  18. package/src/hooks/index.ts +1 -0
  19. package/src/components/boundary/boundary.story.tsx +0 -109
  20. package/src/components/data/avatar/avatar.story.tsx +0 -115
  21. package/src/components/data/badge/badge.story.tsx +0 -56
  22. package/src/components/data/calendar/calendar.story.tsx +0 -127
  23. package/src/components/data/carousel/carousel.story.tsx +0 -122
  24. package/src/components/data/progress/progress.story.tsx +0 -97
  25. package/src/components/data/table/table.story.tsx +0 -148
  26. package/src/components/data/toggle/toggle.story.tsx +0 -104
  27. package/src/components/data/toggle-group/toggle-group.story.tsx +0 -118
  28. package/src/components/feedback/alert/alert.story.tsx +0 -77
  29. package/src/components/feedback/empty/empty.story.tsx +0 -115
  30. package/src/components/feedback/preloader/preloader.story.tsx +0 -86
  31. package/src/components/feedback/spinner/spinner.story.tsx +0 -66
  32. package/src/components/forms/button/button.story.tsx +0 -116
  33. package/src/components/forms/button-download/button-download.story.tsx +0 -112
  34. package/src/components/forms/button-group/button-group.story.tsx +0 -79
  35. package/src/components/forms/checkbox/checkbox.story.tsx +0 -89
  36. package/src/components/forms/input/input.story.tsx +0 -77
  37. package/src/components/forms/input-group/input-group.story.tsx +0 -119
  38. package/src/components/forms/input-otp/input-otp.story.tsx +0 -105
  39. package/src/components/forms/label/label.story.tsx +0 -52
  40. package/src/components/forms/radio-group/radio-group.story.tsx +0 -113
  41. package/src/components/forms/slider/slider.story.tsx +0 -134
  42. package/src/components/forms/switch/switch.story.tsx +0 -98
  43. package/src/components/forms/textarea/textarea.story.tsx +0 -94
  44. package/src/components/layout/aspect-ratio/aspect-ratio.story.tsx +0 -94
  45. package/src/components/layout/card/card.story.tsx +0 -105
  46. package/src/components/layout/resizable/resizable.story.tsx +0 -119
  47. package/src/components/layout/scroll-area/scroll-area.story.tsx +0 -172
  48. package/src/components/layout/separator/separator.story.tsx +0 -69
  49. package/src/components/layout/skeleton/skeleton.story.tsx +0 -101
  50. package/src/components/navigation/accordion/accordion.story.tsx +0 -110
  51. package/src/components/navigation/collapsible/collapsible.story.tsx +0 -133
  52. package/src/components/navigation/command/command.story.tsx +0 -121
  53. package/src/components/navigation/context-menu/context-menu.story.tsx +0 -125
  54. package/src/components/navigation/dropdown-menu/dropdown-menu.story.tsx +0 -208
  55. package/src/components/navigation/menubar/menubar.story.tsx +0 -152
  56. package/src/components/navigation/navigation-menu/navigation-menu.story.tsx +0 -154
  57. package/src/components/navigation/tabs/tabs.story.tsx +0 -98
  58. package/src/components/overlay/alert-dialog/alert-dialog.story.tsx +0 -104
  59. package/src/components/overlay/dialog/dialog.story.tsx +0 -212
  60. package/src/components/overlay/drawer/drawer.story.tsx +0 -359
  61. package/src/components/overlay/hover-card/hover-card.story.tsx +0 -102
  62. package/src/components/overlay/popover/popover.story.tsx +0 -127
  63. package/src/components/overlay/responsive-sheet/responsive-sheet.story.tsx +0 -117
  64. package/src/components/overlay/sheet/sheet.story.tsx +0 -148
  65. package/src/components/overlay/tooltip/tooltip.story.tsx +0 -139
  66. package/src/components/select/combobox-async.story.tsx +0 -215
  67. package/src/components/select/combobox.story.tsx +0 -226
  68. package/src/components/select/country-select.story.tsx +0 -261
  69. package/src/components/select/language-select.story.tsx +0 -264
  70. package/src/components/select/multi-select.story.tsx +0 -122
  71. package/src/components/select/select.story.tsx +0 -112
  72. package/src/components/specialized/copy/copy.story.tsx +0 -77
  73. package/src/components/specialized/flag/flag.story.tsx +0 -82
  74. package/src/components/specialized/image-with-fallback/image-with-fallback.story.tsx +0 -105
  75. package/src/components/specialized/kbd/kbd.story.tsx +0 -113
  76. package/src/lib/dialog-service/dialog-service.story.tsx +0 -263
  77. package/src/stories/index.ts +0 -28
  78. package/src/styles/theme/theme-tokens.story.tsx +0 -157
@@ -1,264 +0,0 @@
1
- import { useState } from 'react';
2
- import { defineStory } from '@djangocfg/playground';
3
- import { LanguageSelect, type TLanguageCode } from './language-select';
4
- import { Label } from '../forms/label';
5
-
6
- export default defineStory({
7
- title: 'Core/LanguageSelect',
8
- component: LanguageSelect,
9
- description: 'Language selector. Supports dropdown and inline variants, single and multiple selection.',
10
- });
11
-
12
- // ============================================================================
13
- // Dropdown Variants
14
- // ============================================================================
15
-
16
- export const SingleDropdown = () => {
17
- const [value, setValue] = useState<string[]>([]);
18
-
19
- return (
20
- <div className="max-w-sm space-y-2">
21
- <Label>Select language</Label>
22
- <LanguageSelect
23
- value={value}
24
- onChange={setValue}
25
- placeholder="Choose a language..."
26
- />
27
- {value.length > 0 && (
28
- <p className="text-sm text-muted-foreground">Selected: {value[0]}</p>
29
- )}
30
- </div>
31
- );
32
- };
33
-
34
- export const MultipleDropdown = () => {
35
- const [value, setValue] = useState<string[]>([]);
36
-
37
- return (
38
- <div className="max-w-sm space-y-2">
39
- <Label>Select languages</Label>
40
- <LanguageSelect
41
- multiple
42
- value={value}
43
- onChange={setValue}
44
- placeholder="Choose languages..."
45
- />
46
- {value.length > 0 && (
47
- <p className="text-sm text-muted-foreground">Selected: {value.join(', ')}</p>
48
- )}
49
- </div>
50
- );
51
- };
52
-
53
- export const WithDefaultValue = () => {
54
- const [value, setValue] = useState<string[]>(['en', 'es', 'fr']);
55
-
56
- return (
57
- <div className="max-w-sm space-y-2">
58
- <Label>Preselected languages</Label>
59
- <LanguageSelect
60
- multiple
61
- value={value}
62
- onChange={setValue}
63
- />
64
- </div>
65
- );
66
- };
67
-
68
- export const WithNativeNames = () => {
69
- const [value, setValue] = useState<string[]>([]);
70
-
71
- return (
72
- <div className="max-w-sm space-y-2">
73
- <Label>With native names</Label>
74
- <LanguageSelect
75
- multiple
76
- value={value}
77
- onChange={setValue}
78
- showNativeName
79
- />
80
- </div>
81
- );
82
- };
83
-
84
- // ============================================================================
85
- // Inline Variants
86
- // ============================================================================
87
-
88
- export const InlineSingle = () => {
89
- const [value, setValue] = useState<string[]>([]);
90
-
91
- return (
92
- <div className="max-w-sm space-y-2">
93
- <Label>Select your language</Label>
94
- <LanguageSelect
95
- variant="inline"
96
- value={value}
97
- onChange={setValue}
98
- maxHeight={250}
99
- />
100
- {value.length > 0 && (
101
- <p className="text-sm text-muted-foreground">Selected: {value[0]}</p>
102
- )}
103
- </div>
104
- );
105
- };
106
-
107
- export const InlineMultiple = () => {
108
- const [value, setValue] = useState<string[]>([]);
109
-
110
- return (
111
- <div className="max-w-sm space-y-2">
112
- <Label>Select target languages</Label>
113
- <LanguageSelect
114
- variant="inline"
115
- multiple
116
- value={value}
117
- onChange={setValue}
118
- maxHeight={300}
119
- />
120
- </div>
121
- );
122
- };
123
-
124
- export const InlineWithNativeNames = () => {
125
- const [value, setValue] = useState<string[]>(['ko', 'ja']);
126
-
127
- return (
128
- <div className="max-w-sm space-y-2">
129
- <Label>Languages with native names</Label>
130
- <LanguageSelect
131
- variant="inline"
132
- multiple
133
- value={value}
134
- onChange={setValue}
135
- showNativeName
136
- maxHeight={300}
137
- />
138
- </div>
139
- );
140
- };
141
-
142
- export const InlineNoSearch = () => {
143
- const [value, setValue] = useState<string[]>([]);
144
-
145
- return (
146
- <div className="max-w-sm space-y-2">
147
- <Label>Without search</Label>
148
- <LanguageSelect
149
- variant="inline"
150
- multiple
151
- value={value}
152
- onChange={setValue}
153
- showSearch={false}
154
- maxHeight={200}
155
- />
156
- </div>
157
- );
158
- };
159
-
160
- // ============================================================================
161
- // Filtered Languages
162
- // ============================================================================
163
-
164
- const EUROPEAN_LANGUAGES: TLanguageCode[] = ['en', 'de', 'fr', 'es', 'it', 'pt', 'nl', 'pl', 'sv', 'da', 'no', 'fi'];
165
- const ASIAN_LANGUAGES: TLanguageCode[] = ['zh', 'ja', 'ko', 'vi', 'th', 'id', 'ms', 'tl'];
166
- const TTS_SUPPORTED: TLanguageCode[] = ['en', 'es', 'fr', 'de', 'it', 'pt', 'ja', 'ko', 'zh', 'ru', 'ar', 'hi'];
167
-
168
- export const FilteredEuropean = () => {
169
- const [value, setValue] = useState<string[]>([]);
170
-
171
- return (
172
- <div className="max-w-sm space-y-2">
173
- <Label>European Languages only</Label>
174
- <LanguageSelect
175
- variant="inline"
176
- multiple
177
- value={value}
178
- onChange={setValue}
179
- allowedLanguages={EUROPEAN_LANGUAGES}
180
- maxHeight={300}
181
- />
182
- </div>
183
- );
184
- };
185
-
186
- export const FilteredAsian = () => {
187
- const [value, setValue] = useState<string[]>([]);
188
-
189
- return (
190
- <div className="max-w-sm space-y-2">
191
- <Label>Asian Languages</Label>
192
- <LanguageSelect
193
- multiple
194
- value={value}
195
- onChange={setValue}
196
- allowedLanguages={ASIAN_LANGUAGES}
197
- showNativeName
198
- />
199
- </div>
200
- );
201
- };
202
-
203
- export const TTSSupportedLanguages = () => {
204
- const [value, setValue] = useState<string[]>(['en']);
205
-
206
- return (
207
- <div className="max-w-sm space-y-2">
208
- <Label>TTS Supported Languages</Label>
209
- <LanguageSelect
210
- value={value}
211
- onChange={setValue}
212
- allowedLanguages={TTS_SUPPORTED}
213
- showNativeName
214
- />
215
- <p className="text-xs text-muted-foreground">
216
- Only languages with TTS support are shown
217
- </p>
218
- </div>
219
- );
220
- };
221
-
222
- // ============================================================================
223
- // States
224
- // ============================================================================
225
-
226
- export const Disabled = () => (
227
- <div className="max-w-sm space-y-4">
228
- <div className="space-y-2">
229
- <Label>Disabled dropdown</Label>
230
- <LanguageSelect
231
- value={['en']}
232
- onChange={() => {}}
233
- disabled
234
- />
235
- </div>
236
- <div className="space-y-2">
237
- <Label>Disabled inline</Label>
238
- <LanguageSelect
239
- variant="inline"
240
- multiple
241
- value={['en', 'es']}
242
- onChange={() => {}}
243
- disabled
244
- maxHeight={150}
245
- />
246
- </div>
247
- </div>
248
- );
249
-
250
- export const MaxDisplayBadges = () => {
251
- const [value, setValue] = useState<string[]>(['en', 'es', 'fr', 'de', 'it', 'pt']);
252
-
253
- return (
254
- <div className="max-w-sm space-y-2">
255
- <Label>Max 2 badges displayed</Label>
256
- <LanguageSelect
257
- multiple
258
- value={value}
259
- onChange={setValue}
260
- maxDisplay={2}
261
- />
262
- </div>
263
- );
264
- };
@@ -1,122 +0,0 @@
1
- import { useState } from 'react';
2
- import { defineStory } from '@djangocfg/playground';
3
- import { MultiSelect, type MultiSelectOption } from './multi-select';
4
- import { Label } from '../forms/label';
5
-
6
- export default defineStory({
7
- title: 'Core/MultiSelect',
8
- component: MultiSelect,
9
- description: 'Multi-select dropdown with badges.',
10
- });
11
-
12
- const frameworks: MultiSelectOption[] = [
13
- { value: 'react', label: 'React' },
14
- { value: 'vue', label: 'Vue' },
15
- { value: 'angular', label: 'Angular' },
16
- { value: 'svelte', label: 'Svelte' },
17
- { value: 'solid', label: 'Solid' },
18
- { value: 'preact', label: 'Preact' },
19
- ];
20
-
21
- const languages: MultiSelectOption[] = [
22
- { value: 'typescript', label: 'TypeScript', description: 'Typed JavaScript' },
23
- { value: 'javascript', label: 'JavaScript', description: 'Dynamic scripting' },
24
- { value: 'python', label: 'Python', description: 'General purpose' },
25
- { value: 'rust', label: 'Rust', description: 'Systems programming' },
26
- { value: 'go', label: 'Go', description: 'Backend services' },
27
- { value: 'java', label: 'Java', description: 'Enterprise apps' },
28
- ];
29
-
30
- export const Default = () => {
31
- const [value, setValue] = useState<string[]>([]);
32
-
33
- return (
34
- <div className="max-w-sm">
35
- <MultiSelect
36
- options={frameworks}
37
- value={value}
38
- onChange={setValue}
39
- placeholder="Select frameworks..."
40
- />
41
- </div>
42
- );
43
- };
44
-
45
- export const WithLabel = () => {
46
- const [value, setValue] = useState<string[]>([]);
47
-
48
- return (
49
- <div className="max-w-sm space-y-2">
50
- <Label>Frameworks</Label>
51
- <MultiSelect
52
- options={frameworks}
53
- value={value}
54
- onChange={setValue}
55
- placeholder="Select frameworks..."
56
- searchPlaceholder="Search frameworks..."
57
- emptyText="No frameworks found."
58
- />
59
- </div>
60
- );
61
- };
62
-
63
- export const WithDescriptions = () => {
64
- const [value, setValue] = useState<string[]>([]);
65
-
66
- return (
67
- <div className="max-w-sm space-y-2">
68
- <Label>Languages</Label>
69
- <MultiSelect
70
- options={languages}
71
- value={value}
72
- onChange={setValue}
73
- placeholder="Select languages..."
74
- />
75
- </div>
76
- );
77
- };
78
-
79
- export const WithDefaultValue = () => {
80
- const [value, setValue] = useState<string[]>(['react', 'vue']);
81
-
82
- return (
83
- <div className="max-w-sm space-y-2">
84
- <Label>Selected Frameworks</Label>
85
- <MultiSelect
86
- options={frameworks}
87
- value={value}
88
- onChange={setValue}
89
- placeholder="Select frameworks..."
90
- />
91
- </div>
92
- );
93
- };
94
-
95
- export const MaxDisplay = () => {
96
- const [value, setValue] = useState<string[]>(['react', 'vue', 'angular', 'svelte']);
97
-
98
- return (
99
- <div className="max-w-sm space-y-2">
100
- <Label>Frameworks (max 2 displayed)</Label>
101
- <MultiSelect
102
- options={frameworks}
103
- value={value}
104
- onChange={setValue}
105
- placeholder="Select frameworks..."
106
- maxDisplay={2}
107
- />
108
- </div>
109
- );
110
- };
111
-
112
- export const Disabled = () => (
113
- <div className="max-w-sm">
114
- <MultiSelect
115
- options={frameworks}
116
- value={['react']}
117
- onChange={() => {}}
118
- placeholder="Select frameworks..."
119
- disabled
120
- />
121
- </div>
122
- );
@@ -1,112 +0,0 @@
1
- import { defineStory, useBoolean } from '@djangocfg/playground';
2
- import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '.';
3
- import { Label } from '../forms/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
- );
@@ -1,77 +0,0 @@
1
- import { defineStory, useSelect } from '@djangocfg/playground';
2
- import { CopyButton, CopyField } from '.';
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
- );
@@ -1,82 +0,0 @@
1
- import * as React from 'react';
2
-
3
- import { defineStory, useSelect } from '@djangocfg/playground';
4
-
5
- import { Flag, LanguageFlag } from '.';
6
- import { Input } from '../../forms/input';
7
-
8
- export default defineStory({
9
- title: 'Core/Flag',
10
- component: Flag,
11
- description:
12
- 'SVG country flag (3:2). Flag takes a country code; LanguageFlag resolves a locale → country.',
13
- });
14
-
15
- export const Default = () => <Flag countryCode="US" className="h-6 w-9" />;
16
-
17
- export const Rounded = () => (
18
- <div className="flex items-center gap-3">
19
- <Flag countryCode="US" className="h-6 w-9" />
20
- <Flag countryCode="US" rounded className="h-6 w-9" />
21
- </div>
22
- );
23
-
24
- export const Interactive = () => {
25
- const [code] = useSelect('country', {
26
- options: ['US', 'JP', 'BR', 'DE', 'FR', 'KR', 'CN', 'RU', 'GB', 'IL'] as const,
27
- defaultValue: 'US',
28
- label: 'Country code',
29
- });
30
- const [size] = useSelect('size', {
31
- options: ['h-3 w-4', 'h-4 w-6', 'h-6 w-9', 'h-10 w-14'] as const,
32
- defaultValue: 'h-6 w-9',
33
- label: 'Size',
34
- });
35
- return <Flag countryCode={code} rounded className={size} />;
36
- };
37
-
38
- export const LanguageInteractive = () => {
39
- const [code, setCode] = React.useState('pt-BR');
40
- return (
41
- <div className="space-y-3">
42
- <div className="flex items-center gap-3 text-sm">
43
- <LanguageFlag code={code} rounded className="h-6 w-9" />
44
- <span className="font-mono text-muted-foreground">{code}</span>
45
- </div>
46
- <Input
47
- value={code}
48
- onChange={(e) => setCode(e.target.value)}
49
- placeholder="Locale (en, pt-BR, zh-CN, …)"
50
- className="max-w-xs"
51
- />
52
- </div>
53
- );
54
- };
55
-
56
- export const Grid = () => {
57
- const codes = [
58
- 'US', 'GB', 'CA', 'BR', 'DE', 'FR', 'IT', 'ES', 'PT',
59
- 'NL', 'SE', 'NO', 'DK', 'FI', 'PL', 'CZ', 'GR', 'TR',
60
- 'RU', 'UA', 'JP', 'KR', 'CN', 'IN', 'TH', 'VN', 'ID', 'IL', 'SA',
61
- ];
62
- return (
63
- <div className="grid grid-cols-6 gap-3">
64
- {codes.map((c) => (
65
- <div key={c} className="flex flex-col items-center gap-1">
66
- <Flag countryCode={c} rounded className="h-6 w-9" />
67
- <span className="font-mono text-xs text-muted-foreground">{c}</span>
68
- </div>
69
- ))}
70
- </div>
71
- );
72
- };
73
-
74
- export const UnknownCode = () => (
75
- <div className="text-sm text-muted-foreground">
76
- Unknown code renders nothing:{' '}
77
- <span className="inline-flex items-center gap-1.5">
78
- <Flag countryCode="ZZ" className="h-3 w-4" />
79
- <span>(no flag here →)</span>
80
- </span>
81
- </div>
82
- );