radtools 0.1.0

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 (133) hide show
  1. package/README.md +108 -0
  2. package/bin/radtools.js +5 -0
  3. package/dist/cli/index.js +427 -0
  4. package/package.json +55 -0
  5. package/templates/api-routes/assets/optimize/route.ts +94 -0
  6. package/templates/api-routes/assets/route.ts +159 -0
  7. package/templates/api-routes/components/create-folder/route.ts +55 -0
  8. package/templates/api-routes/components/route.ts +156 -0
  9. package/templates/api-routes/fonts/route.ts +96 -0
  10. package/templates/api-routes/fonts/upload/route.ts +79 -0
  11. package/templates/api-routes/read-css/route.ts +29 -0
  12. package/templates/api-routes/write-css/route.ts +423 -0
  13. package/templates/components/Rad_os/AppWindow.tsx +423 -0
  14. package/templates/components/Rad_os/MobileAppModal.tsx +76 -0
  15. package/templates/components/Rad_os/WindowTitleBar.tsx +290 -0
  16. package/templates/components/icons/Icon.tsx +224 -0
  17. package/templates/components/icons/README.md +85 -0
  18. package/templates/components/icons/index.ts +20 -0
  19. package/templates/components/icons.tsx +164 -0
  20. package/templates/components/ui/Accordion.tsx +268 -0
  21. package/templates/components/ui/Alert.tsx +111 -0
  22. package/templates/components/ui/Badge.tsx +87 -0
  23. package/templates/components/ui/Breadcrumbs.tsx +88 -0
  24. package/templates/components/ui/Button.tsx +249 -0
  25. package/templates/components/ui/Card.tsx +137 -0
  26. package/templates/components/ui/Checkbox.tsx +137 -0
  27. package/templates/components/ui/ContextMenu.tsx +220 -0
  28. package/templates/components/ui/Dialog.tsx +264 -0
  29. package/templates/components/ui/Divider.tsx +70 -0
  30. package/templates/components/ui/DropdownMenu.tsx +301 -0
  31. package/templates/components/ui/HelpPanel.tsx +119 -0
  32. package/templates/components/ui/Input.tsx +176 -0
  33. package/templates/components/ui/Popover.tsx +211 -0
  34. package/templates/components/ui/Progress.tsx +158 -0
  35. package/templates/components/ui/Select.tsx +134 -0
  36. package/templates/components/ui/Sheet.tsx +316 -0
  37. package/templates/components/ui/Slider.tsx +223 -0
  38. package/templates/components/ui/Switch.tsx +155 -0
  39. package/templates/components/ui/Tabs.tsx +253 -0
  40. package/templates/components/ui/Toast.tsx +192 -0
  41. package/templates/components/ui/Tooltip.tsx +129 -0
  42. package/templates/components/ui/hooks/useModalBehavior.ts +66 -0
  43. package/templates/components/ui/index.ts +84 -0
  44. package/templates/devtools/DevToolsPanel.tsx +261 -0
  45. package/templates/devtools/DevToolsProvider.tsx +43 -0
  46. package/templates/devtools/components/BreakpointIndicator.tsx +49 -0
  47. package/templates/devtools/components/ColorPicker.tsx +33 -0
  48. package/templates/devtools/components/ComponentsSecondaryNav.tsx +44 -0
  49. package/templates/devtools/components/ContextualFooter.tsx +56 -0
  50. package/templates/devtools/components/DraggablePanel.tsx +43 -0
  51. package/templates/devtools/components/PrimaryNavigationFooter.tsx +254 -0
  52. package/templates/devtools/components/SearchableColorDropdown.tsx +253 -0
  53. package/templates/devtools/components/SecondaryNavigation.tsx +36 -0
  54. package/templates/devtools/components/TokenDropdown.tsx +47 -0
  55. package/templates/devtools/components/TypographyFooter.tsx +145 -0
  56. package/templates/devtools/hooks/useMockState.ts +16 -0
  57. package/templates/devtools/index.ts +17 -0
  58. package/templates/devtools/lib/componentScanner.ts +78 -0
  59. package/templates/devtools/lib/cssParser.ts +465 -0
  60. package/templates/devtools/lib/searchIndexes.ts +45 -0
  61. package/templates/devtools/lib/selectorGenerator.ts +86 -0
  62. package/templates/devtools/store/index.ts +66 -0
  63. package/templates/devtools/store/slices/assetsSlice.ts +106 -0
  64. package/templates/devtools/store/slices/componentsSlice.ts +59 -0
  65. package/templates/devtools/store/slices/mockStatesSlice.ts +77 -0
  66. package/templates/devtools/store/slices/panelSlice.ts +17 -0
  67. package/templates/devtools/store/slices/typographySlice.ts +538 -0
  68. package/templates/devtools/store/slices/variablesSlice.ts +167 -0
  69. package/templates/devtools/tabs/AssetsTab/AssetGrid.tsx +76 -0
  70. package/templates/devtools/tabs/AssetsTab/FolderTree.tsx +53 -0
  71. package/templates/devtools/tabs/AssetsTab/UploadDropzone.tsx +76 -0
  72. package/templates/devtools/tabs/AssetsTab/index.tsx +182 -0
  73. package/templates/devtools/tabs/ComponentsTab/AddTabButton.tsx +63 -0
  74. package/templates/devtools/tabs/ComponentsTab/ComponentList.tsx +153 -0
  75. package/templates/devtools/tabs/ComponentsTab/DesignSystemTab.tsx +1515 -0
  76. package/templates/devtools/tabs/ComponentsTab/DynamicFolderTab.tsx +113 -0
  77. package/templates/devtools/tabs/ComponentsTab/PropDisplay.tsx +55 -0
  78. package/templates/devtools/tabs/ComponentsTab/index.tsx +167 -0
  79. package/templates/devtools/tabs/ComponentsTab/previews/.gitkeep +4 -0
  80. package/templates/devtools/tabs/ComponentsTab/previews/Rad_os.tsx +262 -0
  81. package/templates/devtools/tabs/ComponentsTab/tabConfig.ts +53 -0
  82. package/templates/devtools/tabs/MockStatesTab/index.tsx +29 -0
  83. package/templates/devtools/tabs/TypographyTab/FontManager.tsx +421 -0
  84. package/templates/devtools/tabs/TypographyTab/TypographyStylesDisplay.tsx +290 -0
  85. package/templates/devtools/tabs/TypographyTab/index.tsx +98 -0
  86. package/templates/devtools/tabs/VariablesTab/BaseColorEditor.tsx +267 -0
  87. package/templates/devtools/tabs/VariablesTab/BorderRadiusEditor.tsx +37 -0
  88. package/templates/devtools/tabs/VariablesTab/ColorModeSelector.tsx +235 -0
  89. package/templates/devtools/tabs/VariablesTab/index.tsx +100 -0
  90. package/templates/devtools/types/index.ts +99 -0
  91. package/templates/globals.css +574 -0
  92. package/templates/hooks/index.ts +1 -0
  93. package/templates/hooks/useWindowManager.ts +212 -0
  94. package/templates/public/assets/icons/avatar.svg +18 -0
  95. package/templates/public/assets/icons/checkmark-filled.svg +14 -0
  96. package/templates/public/assets/icons/checkmark.svg +14 -0
  97. package/templates/public/assets/icons/chevron-down.svg +14 -0
  98. package/templates/public/assets/icons/close.svg +14 -0
  99. package/templates/public/assets/icons/copy.svg +14 -0
  100. package/templates/public/assets/icons/download.svg +14 -0
  101. package/templates/public/assets/icons/expand.svg +31 -0
  102. package/templates/public/assets/icons/file-blank.svg +17 -0
  103. package/templates/public/assets/icons/file-image.svg +19 -0
  104. package/templates/public/assets/icons/file-written.svg +17 -0
  105. package/templates/public/assets/icons/folder-closed.svg +17 -0
  106. package/templates/public/assets/icons/folder-open.svg +17 -0
  107. package/templates/public/assets/icons/hamburger.svg +18 -0
  108. package/templates/public/assets/icons/home-outline.svg +28 -0
  109. package/templates/public/assets/icons/home.svg +30 -0
  110. package/templates/public/assets/icons/hourglass.svg +25 -0
  111. package/templates/public/assets/icons/information-circle.svg +14 -0
  112. package/templates/public/assets/icons/information.svg +17 -0
  113. package/templates/public/assets/icons/lightning.svg +14 -0
  114. package/templates/public/assets/icons/locked.svg +17 -0
  115. package/templates/public/assets/icons/not-allowed.svg +14 -0
  116. package/templates/public/assets/icons/plus.svg +5 -0
  117. package/templates/public/assets/icons/power-thin.svg +17 -0
  118. package/templates/public/assets/icons/power.svg +17 -0
  119. package/templates/public/assets/icons/question-block.svg +14 -0
  120. package/templates/public/assets/icons/question.svg +17 -0
  121. package/templates/public/assets/icons/refresh-block.svg +14 -0
  122. package/templates/public/assets/icons/refresh.svg +17 -0
  123. package/templates/public/assets/icons/save.svg +14 -0
  124. package/templates/public/assets/icons/search.svg +25 -0
  125. package/templates/public/assets/icons/settings.svg +14 -0
  126. package/templates/public/assets/icons/trash-full.svg +21 -0
  127. package/templates/public/assets/icons/trash-open.svg +23 -0
  128. package/templates/public/assets/icons/trash.svg +18 -0
  129. package/templates/public/assets/icons/unlocked.svg +17 -0
  130. package/templates/public/assets/icons/waring-triangle-filled.svg +17 -0
  131. package/templates/public/assets/icons/warning-triangle-filled-2.svg +30 -0
  132. package/templates/public/assets/icons/warning-triangle-lines.svg +29 -0
  133. package/templates/public/assets/icons/wrench.svg +17 -0
@@ -0,0 +1,1515 @@
1
+ 'use client';
2
+
3
+ import React, { useState, useRef, useEffect } from 'react';
4
+ import {
5
+ Button,
6
+ Card,
7
+ CardHeader,
8
+ CardBody,
9
+ CardFooter,
10
+ Tabs,
11
+ TabList,
12
+ TabTrigger,
13
+ TabContent,
14
+ Input,
15
+ TextArea,
16
+ Label,
17
+ Select,
18
+ Checkbox,
19
+ Radio,
20
+ Badge,
21
+ Progress,
22
+ Spinner,
23
+ Tooltip,
24
+ Divider,
25
+ ContextMenu,
26
+ ContextMenuContent,
27
+ ContextMenuItem,
28
+ ContextMenuSeparator,
29
+ Alert,
30
+ Breadcrumbs,
31
+ Switch,
32
+ Slider,
33
+ ToastProvider,
34
+ useToast,
35
+ HelpPanel,
36
+ } from '@/components/ui';
37
+ import {
38
+ Dialog,
39
+ DialogTrigger,
40
+ DialogContent,
41
+ DialogHeader,
42
+ DialogTitle,
43
+ DialogDescription,
44
+ DialogBody,
45
+ DialogFooter,
46
+ DialogClose,
47
+ } from '@/components/ui/Dialog';
48
+ import {
49
+ DropdownMenu,
50
+ DropdownMenuTrigger,
51
+ DropdownMenuContent,
52
+ DropdownMenuItem,
53
+ DropdownMenuSeparator,
54
+ DropdownMenuLabel,
55
+ } from '@/components/ui/DropdownMenu';
56
+ import {
57
+ Popover,
58
+ PopoverTrigger,
59
+ PopoverContent,
60
+ } from '@/components/ui/Popover';
61
+ import {
62
+ Sheet,
63
+ SheetTrigger,
64
+ SheetContent,
65
+ SheetHeader,
66
+ SheetTitle,
67
+ SheetDescription,
68
+ SheetBody,
69
+ SheetFooter,
70
+ SheetClose,
71
+ } from '@/components/ui/Sheet';
72
+
73
+ // ============================================================================
74
+ // Section Component
75
+ // ============================================================================
76
+
77
+ function Section({
78
+ title,
79
+ children,
80
+ variant = 'h3',
81
+ subsectionId,
82
+ className,
83
+ 'data-edit-scope': editScope,
84
+ 'data-component': component,
85
+ ...rest
86
+ }: {
87
+ title: string;
88
+ children: React.ReactNode;
89
+ variant?: 'h3' | 'h4';
90
+ subsectionId?: string;
91
+ className?: string;
92
+ 'data-edit-scope'?: string;
93
+ 'data-component'?: string;
94
+ }) {
95
+ const HeadingTag = variant === 'h4' ? 'h4' : 'h3';
96
+ const hasMarginOverride = className?.includes('mb-');
97
+ const isSubsection = variant === 'h4';
98
+ const subsectionClasses = isSubsection ? 'p-4 border border-black bg-[var(--color-cream)]' : '';
99
+ const baseClasses = `${hasMarginOverride ? '' : 'mb-4'} ${subsectionClasses} rounded flex flex-col gap-4`.trim();
100
+ return (
101
+ <div
102
+ className={`${baseClasses} ${className || ''}`}
103
+ data-subsection-id={subsectionId}
104
+ data-edit-scope={editScope}
105
+ data-component={component}
106
+ {...rest}
107
+ >
108
+ <HeadingTag>
109
+ {title}
110
+ </HeadingTag>
111
+ <div className="flex flex-col gap-4">
112
+ {children}
113
+ </div>
114
+ </div>
115
+ );
116
+ }
117
+
118
+ function PropsDisplay({ props }: { props: string }) {
119
+ return (
120
+ <code className="bg-black/5 px-2 py-1 rounded-sm block mt-2">
121
+ {props}
122
+ </code>
123
+ );
124
+ }
125
+
126
+ function Row({ children, props }: {
127
+ children: React.ReactNode;
128
+ props?: string;
129
+ }) {
130
+ return (
131
+ <div>
132
+ <div className="flex flex-wrap items-center gap-2">
133
+ {children}
134
+ </div>
135
+ {props && <PropsDisplay props={props} />}
136
+ </div>
137
+ );
138
+ }
139
+
140
+ // ============================================================================
141
+ // Accordion Content Components
142
+ // ============================================================================
143
+
144
+ // Loading button demo component
145
+ function LoadingButtonDemo() {
146
+ const [loading1, setLoading1] = useState(false);
147
+ const [loading2, setLoading2] = useState(false);
148
+ const [loading3, setLoading3] = useState(false);
149
+
150
+ const handleClick1 = () => {
151
+ setLoading1(true);
152
+ setTimeout(() => setLoading1(false), 2000);
153
+ };
154
+
155
+ const handleClick2 = () => {
156
+ setLoading2(true);
157
+ setTimeout(() => setLoading2(false), 2000);
158
+ };
159
+
160
+ const handleClick3 = () => {
161
+ setLoading3(true);
162
+ setTimeout(() => setLoading3(false), 2000);
163
+ };
164
+
165
+ return (
166
+ <>
167
+ <Button
168
+ variant="primary"
169
+ size="md"
170
+ iconOnly={true}
171
+ iconName="refresh"
172
+ loading={loading1}
173
+ onClick={handleClick1}
174
+ data-edit-scope="component-definition"
175
+ data-component="Button"
176
+ >
177
+ {''}
178
+ </Button>
179
+ <Button
180
+ variant="secondary"
181
+ size="md"
182
+ iconOnly={true}
183
+ iconName="download"
184
+ loading={loading2}
185
+ onClick={handleClick2}
186
+ data-edit-scope="component-definition"
187
+ data-component="Button"
188
+ data-edit-variant="secondary"
189
+ >
190
+ {''}
191
+ </Button>
192
+ <Button
193
+ variant="primary"
194
+ size="md"
195
+ iconName="copy"
196
+ loading={loading3}
197
+ onClick={handleClick3}
198
+ data-edit-scope="component-definition"
199
+ data-component="Button"
200
+ >
201
+ Copy
202
+ </Button>
203
+ </>
204
+ );
205
+ }
206
+
207
+ function ButtonsContent() {
208
+ return (
209
+ <div className="space-y-6">
210
+ <Section title="Button Variants" variant="h4" subsectionId="button-variants" className="mb-4">
211
+ <Row props='variant="primary" | "secondary" | "outline" | "ghost"'>
212
+ <Button variant="primary" size="md" fullWidth={false} iconOnly={false} data-edit-scope="component-definition" data-component="Button">Primary</Button>
213
+ <Button variant="primary" size="md" fullWidth={false} iconOnly={false} disabled data-edit-scope="component-definition" data-component="Button">Disabled</Button>
214
+ </Row>
215
+ <Row props='variant="secondary"'>
216
+ <Button variant="secondary" size="md" fullWidth={false} iconOnly={false} data-edit-scope="component-definition" data-component="Button" data-edit-variant="secondary">Secondary</Button>
217
+ <Button variant="secondary" size="md" fullWidth={false} iconOnly={false} disabled data-edit-scope="component-definition" data-component="Button" data-edit-variant="secondary">Disabled</Button>
218
+ </Row>
219
+ <Row props='variant="outline"'>
220
+ <Button variant="outline" size="md" fullWidth={false} iconOnly={false} data-edit-scope="component-definition" data-component="Button" data-edit-variant="outline">Outline</Button>
221
+ <Button variant="outline" size="md" fullWidth={false} iconOnly={false} disabled data-edit-scope="component-definition" data-component="Button" data-edit-variant="outline">Disabled</Button>
222
+ </Row>
223
+ <Row props='variant="ghost"'>
224
+ <Button variant="ghost" size="md" fullWidth={false} iconOnly={false} data-edit-scope="component-definition" data-component="Button" data-edit-variant="ghost">Ghost</Button>
225
+ <Button variant="ghost" size="md" fullWidth={false} iconOnly={false} disabled data-edit-scope="component-definition" data-component="Button" data-edit-variant="ghost">Disabled</Button>
226
+ </Row>
227
+ </Section>
228
+
229
+ <Section title="Button Sizes" variant="h4" subsectionId="button-sizes">
230
+ <Row props='size="sm" | "md" | "lg"'>
231
+ <Button variant="primary" size="sm" fullWidth={false} iconOnly={false}>Small</Button>
232
+ </Row>
233
+ <Row props='size="md"'>
234
+ <Button variant="primary" size="md" fullWidth={false} iconOnly={false}>Medium</Button>
235
+ </Row>
236
+ <Row props='size="lg"'>
237
+ <Button variant="primary" size="lg" fullWidth={false} iconOnly={false}>Large</Button>
238
+ </Row>
239
+ </Section>
240
+
241
+ <Section title="Button with Icon" variant="h4" subsectionId="button-with-icon">
242
+ <Row props='iconName="..."'>
243
+ <Button variant="primary" size="md" iconName="copy" fullWidth={false} iconOnly={false} data-edit-scope="component-definition" data-component="Button">
244
+ Download
245
+ </Button>
246
+ <Button variant="secondary" size="md" iconName="copy" fullWidth={false} iconOnly={false} data-edit-scope="component-definition" data-component="Button" data-edit-variant="secondary">
247
+ Copy
248
+ </Button>
249
+ </Row>
250
+ <Row props='iconOnly={true} iconName="..."'>
251
+ <Button variant="primary" size="md" iconOnly={true} iconName="close" fullWidth={false} data-edit-scope="component-definition" data-component="Button">{''}</Button>
252
+ <Button variant="primary" size="md" iconOnly={true} iconName="copy" fullWidth={false} data-edit-scope="component-definition" data-component="Button">{''}</Button>
253
+ <Button variant="primary" size="lg" iconOnly={true} iconName="copy" fullWidth={false} data-edit-scope="component-definition" data-component="Button">{''}</Button>
254
+ </Row>
255
+ <Row props='loading={boolean} (only applies to buttons with icons)'>
256
+ <LoadingButtonDemo />
257
+ </Row>
258
+ <Row props='fullWidth={true}'>
259
+ <div className="w-64">
260
+ <Button variant="primary" size="md" fullWidth={true} iconOnly={false} data-edit-scope="component-definition" data-component="Button">Full Width Button</Button>
261
+ </div>
262
+ </Row>
263
+ </Section>
264
+ </div>
265
+ );
266
+ }
267
+
268
+ function CardsContent() {
269
+ return (
270
+ <div className="space-y-6">
271
+ <Section title="Card Variants" variant="h4" subsectionId="card-variants">
272
+ <Row props='variant="default" | "dark" | "raised"'>
273
+ <div className="grid grid-cols-3 gap-4 w-full">
274
+ <Card variant="default" noPadding={false} data-edit-scope="component-definition" data-component="Card">
275
+ <p className="font-joystix text-xs mb-2">Default Card</p>
276
+ <p>
277
+ Cream background with black border
278
+ </p>
279
+ </Card>
280
+ <Card variant="dark" noPadding={false} data-edit-scope="component-definition" data-component="Card" data-edit-variant="dark">
281
+ <p className="mb-2">Dark Card</p>
282
+ <p>
283
+ Black background with cream text
284
+ </p>
285
+ </Card>
286
+ <Card variant="raised" noPadding={false} data-edit-scope="component-definition" data-component="Card" data-edit-variant="raised">
287
+ <p className="mb-2">Raised Card</p>
288
+ <p>
289
+ Pixel shadow effect
290
+ </p>
291
+ </Card>
292
+ </div>
293
+ </Row>
294
+ </Section>
295
+
296
+ <Section title="Card with Header/Footer" variant="h4" subsectionId="card-with-header-footer">
297
+ <Row props='noPadding={true} className="max-w-md"'>
298
+ <Card variant="default" noPadding={true} className="max-w-md" data-edit-scope="component-definition" data-component="Card">
299
+ <CardHeader>
300
+ <h4>Card Header</h4>
301
+ </CardHeader>
302
+ <CardBody>
303
+ <p>
304
+ This is the card body content. It can contain any elements.
305
+ </p>
306
+ </CardBody>
307
+ <CardFooter className="flex justify-end gap-2">
308
+ <Button variant="ghost" size="md" fullWidth={false} iconOnly={false}>Cancel</Button>
309
+ <Button variant="primary" size="md" fullWidth={false} iconOnly={false}>Confirm</Button>
310
+ </CardFooter>
311
+ </Card>
312
+ </Row>
313
+ </Section>
314
+ </div>
315
+ );
316
+ }
317
+
318
+ function FormsContent() {
319
+ const [selectValue, setSelectValue] = useState('');
320
+ const [checkboxChecked, setCheckboxChecked] = useState(false);
321
+ const [radioValue, setRadioValue] = useState('option1');
322
+ const [switchChecked, setSwitchChecked] = useState(false);
323
+ const [sliderValue, setSliderValue] = useState(50);
324
+
325
+ return (
326
+ <div className="space-y-6">
327
+ <Section title="Text Inputs" variant="h4" subsectionId="text-inputs">
328
+ <Row props='size="md" error={false} fullWidth={true}'>
329
+ <div className="max-w-md w-full">
330
+ <Label htmlFor="input-default">Default Input</Label>
331
+ <Input id="input-default" size="md" error={false} fullWidth={true} placeholder="Enter text..." data-edit-scope="component-definition" data-component="Input" />
332
+ </div>
333
+ </Row>
334
+ <Row props='error={true} fullWidth={true}'>
335
+ <div className="max-w-md w-full">
336
+ <Label htmlFor="input-error" required>Error State</Label>
337
+ <Input id="input-error" size="md" error={true} fullWidth={true} placeholder="Invalid input" data-edit-scope="component-definition" data-component="Input" />
338
+ </div>
339
+ </Row>
340
+ <Row props='disabled fullWidth={true}'>
341
+ <div className="max-w-md w-full">
342
+ <Label htmlFor="input-disabled">Disabled</Label>
343
+ <Input id="input-disabled" size="md" error={false} fullWidth={true} disabled placeholder="Disabled" data-edit-scope="component-definition" data-component="Input" />
344
+ </div>
345
+ </Row>
346
+ </Section>
347
+
348
+ <Section title="Input Sizes" variant="h4" subsectionId="input-sizes">
349
+ <Row props='size="sm" | "md" | "lg"'>
350
+ <div className="max-w-md w-full">
351
+ <Label htmlFor="input-sm">Small</Label>
352
+ <Input id="input-sm" size="sm" error={false} fullWidth={true} placeholder="Small" data-edit-scope="component-definition" data-component="Input" />
353
+ </div>
354
+ </Row>
355
+ <Row props='size="md"'>
356
+ <div className="max-w-md w-full">
357
+ <Label htmlFor="input-md">Medium</Label>
358
+ <Input id="input-md" size="md" error={false} fullWidth={true} placeholder="Medium" data-edit-scope="component-definition" data-component="Input" />
359
+ </div>
360
+ </Row>
361
+ <Row props='size="lg"'>
362
+ <div className="max-w-md w-full">
363
+ <Label htmlFor="input-lg">Large</Label>
364
+ <Input id="input-lg" size="lg" error={false} fullWidth={true} placeholder="Large" data-edit-scope="component-definition" data-component="Input" />
365
+ </div>
366
+ </Row>
367
+ </Section>
368
+
369
+ <Section title="TextArea" variant="h4" subsectionId="textarea">
370
+ <Row props='error={false} fullWidth={true} rows={4}'>
371
+ <div className="max-w-md w-full">
372
+ <Label htmlFor="textarea">Description</Label>
373
+ <TextArea id="textarea" error={false} fullWidth={true} rows={4} placeholder="Enter description..." data-edit-scope="component-definition" data-component="TextArea" />
374
+ </div>
375
+ </Row>
376
+ </Section>
377
+
378
+ <Section title="Select" variant="h4" subsectionId="select">
379
+ <Row props='options={[...]} value={string} onChange={fn} placeholder="..." fullWidth={true}'>
380
+ <div className="max-w-xs w-full">
381
+ <Label htmlFor="select">Choose an option</Label>
382
+ <Select
383
+ options={[
384
+ { value: 'option1', label: 'Option One' },
385
+ { value: 'option2', label: 'Option Two' },
386
+ { value: 'option3', label: 'Option Three' },
387
+ { value: 'disabled', label: 'Disabled Option', disabled: true },
388
+ ]}
389
+ value={selectValue}
390
+ onChange={setSelectValue}
391
+ placeholder="Select..."
392
+ fullWidth={true}
393
+ data-edit-scope="component-definition"
394
+ data-component="Select"
395
+ />
396
+ </div>
397
+ </Row>
398
+ </Section>
399
+
400
+ <Section title="Checkbox & Radio" variant="h4" subsectionId="checkbox-radio">
401
+ <Row props='label="..." checked={boolean} onChange={fn} disabled={boolean}'>
402
+ <Checkbox
403
+ label="Check me"
404
+ checked={checkboxChecked}
405
+ onChange={(e) => setCheckboxChecked(e.target.checked)}
406
+ disabled={false}
407
+ data-edit-scope="component-definition"
408
+ data-component="Checkbox"
409
+ />
410
+ <Checkbox label="Disabled" checked={false} onChange={() => {}} disabled={true} data-edit-scope="component-definition" data-component="Checkbox" />
411
+ <Checkbox label="Checked & Disabled" checked={true} onChange={() => {}} disabled={true} data-edit-scope="component-definition" data-component="Checkbox" />
412
+ </Row>
413
+ <Row props='name="..." value="..." label="..." checked={boolean} onChange={fn}'>
414
+ <Radio
415
+ name="radio-group"
416
+ value="option1"
417
+ label="Option 1"
418
+ checked={radioValue === 'option1'}
419
+ onChange={() => setRadioValue('option1')}
420
+ data-edit-scope="component-definition"
421
+ data-component="Radio"
422
+ />
423
+ <Radio
424
+ name="radio-group"
425
+ value="option2"
426
+ label="Option 2"
427
+ checked={radioValue === 'option2'}
428
+ onChange={() => setRadioValue('option2')}
429
+ data-edit-scope="component-definition"
430
+ data-component="Radio"
431
+ />
432
+ <Radio
433
+ name="radio-group"
434
+ value="option3"
435
+ label="Option 3"
436
+ checked={radioValue === 'option3'}
437
+ onChange={() => setRadioValue('option3')}
438
+ data-edit-scope="component-definition"
439
+ data-component="Radio"
440
+ />
441
+ </Row>
442
+ </Section>
443
+
444
+ <Section title="Switch" variant="h4" subsectionId="switch">
445
+ <Row props='checked={boolean} onChange={fn} size="sm" | "md" | "lg" label="..." labelPosition="left" | "right"'>
446
+ <Switch
447
+ checked={switchChecked}
448
+ onChange={setSwitchChecked}
449
+ size="md"
450
+ label="Enable notifications"
451
+ labelPosition="right"
452
+ data-edit-scope="component-definition"
453
+ data-component="Switch"
454
+ />
455
+ <Switch
456
+ checked={!switchChecked}
457
+ onChange={() => setSwitchChecked(!switchChecked)}
458
+ size="md"
459
+ label="Disabled"
460
+ labelPosition="right"
461
+ disabled={true}
462
+ data-edit-scope="component-definition"
463
+ data-component="Switch"
464
+ />
465
+ </Row>
466
+ <Row props='size="sm" | "md" | "lg"'>
467
+ <Switch checked={true} onChange={() => {}} size="sm" data-edit-scope="component-definition" data-component="Switch" />
468
+ <Switch checked={true} onChange={() => {}} size="md" data-edit-scope="component-definition" data-component="Switch" />
469
+ <Switch checked={true} onChange={() => {}} size="lg" data-edit-scope="component-definition" data-component="Switch" />
470
+ </Row>
471
+ <Row props='labelPosition="left"'>
472
+ <Switch
473
+ checked={switchChecked}
474
+ onChange={setSwitchChecked}
475
+ size="md"
476
+ label="Label on left"
477
+ labelPosition="left"
478
+ data-edit-scope="component-definition"
479
+ data-component="Switch"
480
+ />
481
+ </Row>
482
+ </Section>
483
+
484
+ <Section title="Slider" variant="h4" subsectionId="slider">
485
+ <Row props='value={number} onChange={fn} min={number} max={number} step={number} size="sm" | "md" | "lg" showValue={boolean} label="..."'>
486
+ <div className="max-w-md w-full">
487
+ <Slider
488
+ value={sliderValue}
489
+ onChange={setSliderValue}
490
+ min={0}
491
+ max={100}
492
+ step={1}
493
+ size="md"
494
+ label="Volume"
495
+ showValue={true}
496
+ data-edit-scope="component-definition"
497
+ data-component="Slider"
498
+ />
499
+ </div>
500
+ </Row>
501
+ <Row props='size="sm" | "md" | "lg"'>
502
+ <div className="max-w-md w-full">
503
+ <Slider value={30} onChange={() => {}} size="sm" showValue={true} data-edit-scope="component-definition" data-component="Slider" />
504
+ </div>
505
+ </Row>
506
+ <Row props='size="md"'>
507
+ <div className="max-w-md w-full">
508
+ <Slider value={60} onChange={() => {}} size="md" showValue={true} data-edit-scope="component-definition" data-component="Slider" />
509
+ </div>
510
+ </Row>
511
+ <Row props='size="lg"'>
512
+ <div className="max-w-md w-full">
513
+ <Slider value={80} onChange={() => {}} size="lg" showValue={true} data-edit-scope="component-definition" data-component="Slider" />
514
+ </div>
515
+ </Row>
516
+ <Row props='disabled'>
517
+ <div className="max-w-md w-full">
518
+ <Slider value={50} onChange={() => {}} disabled={true} showValue={true} data-edit-scope="component-definition" data-component="Slider" />
519
+ </div>
520
+ </Row>
521
+ </Section>
522
+ </div>
523
+ );
524
+ }
525
+
526
+ function FeedbackContent() {
527
+ const { addToast } = useToast();
528
+
529
+ return (
530
+ <div className="space-y-6">
531
+ <Section title="Alert" variant="h4" subsectionId="alert">
532
+ <Row props='variant="default" | "success" | "warning" | "error" | "info" title="..." iconName="..." closable={boolean} onClose={fn}'>
533
+ <div className="max-w-md w-full">
534
+ <Alert variant="default" title="Default Alert" data-edit-scope="component-definition" data-component="Alert">
535
+ This is a default alert message.
536
+ </Alert>
537
+ </div>
538
+ </Row>
539
+ <Row props='variant="success"'>
540
+ <div className="max-w-md w-full">
541
+ <Alert variant="success" title="Success" data-edit-scope="component-definition" data-component="Alert" data-edit-variant="success">
542
+ Operation completed successfully!
543
+ </Alert>
544
+ </div>
545
+ </Row>
546
+ <Row props='variant="warning"'>
547
+ <div className="max-w-md w-full">
548
+ <Alert variant="warning" title="Warning" data-edit-scope="component-definition" data-component="Alert" data-edit-variant="warning">
549
+ Please review this information carefully.
550
+ </Alert>
551
+ </div>
552
+ </Row>
553
+ <Row props='variant="error"'>
554
+ <div className="max-w-md w-full">
555
+ <Alert variant="error" title="Error" data-edit-scope="component-definition" data-component="Alert" data-edit-variant="error">
556
+ Something went wrong. Please try again.
557
+ </Alert>
558
+ </div>
559
+ </Row>
560
+ <Row props='variant="info"'>
561
+ <div className="max-w-md w-full">
562
+ <Alert variant="info" title="Info" data-edit-scope="component-definition" data-component="Alert" data-edit-variant="info">
563
+ Here's some helpful information for you.
564
+ </Alert>
565
+ </div>
566
+ </Row>
567
+ <Row props='iconName="..." (overrides variant default)'>
568
+ <div className="max-w-md w-full">
569
+ <Alert variant="success" title="Custom Icon" iconName="checkmark" data-edit-scope="component-definition" data-component="Alert" data-edit-variant="success">
570
+ Using a custom icon instead of the variant default.
571
+ </Alert>
572
+ </div>
573
+ </Row>
574
+ <Row props='closable={true} onClose={fn}'>
575
+ <div className="max-w-md w-full">
576
+ <Alert
577
+ variant="default"
578
+ title="Closable Alert"
579
+ closable={true}
580
+ onClose={() => alert('Alert closed!')}
581
+ data-edit-scope="component-definition"
582
+ data-component="Alert"
583
+ >
584
+ This alert can be closed by clicking the X button.
585
+ </Alert>
586
+ </div>
587
+ </Row>
588
+ <Row props='No title'>
589
+ <div className="max-w-md w-full">
590
+ <Alert variant="default" data-edit-scope="component-definition" data-component="Alert">
591
+ Alert without a title - just the message content.
592
+ </Alert>
593
+ </div>
594
+ </Row>
595
+ </Section>
596
+
597
+ <Section title="Badge Variants" variant="h4" subsectionId="badge-variants">
598
+ <Row props='variant="default" | "success" | "warning" | "error" | "info" size="md"'>
599
+ <Badge variant="default" size="md" data-edit-scope="component-definition" data-component="Badge">Default</Badge>
600
+ <Badge variant="success" size="md" data-edit-scope="component-definition" data-component="Badge" data-edit-variant="success">Success</Badge>
601
+ <Badge variant="warning" size="md" data-edit-scope="component-definition" data-component="Badge" data-edit-variant="warning">Warning</Badge>
602
+ <Badge variant="error" size="md" data-edit-scope="component-definition" data-component="Badge" data-edit-variant="error">Error</Badge>
603
+ <Badge variant="info" size="md" data-edit-scope="component-definition" data-component="Badge" data-edit-variant="info">Info</Badge>
604
+ </Row>
605
+ <Row props='size="sm" | "md"'>
606
+ <Badge variant="default" size="sm" data-edit-scope="component-definition" data-component="Badge">Small</Badge>
607
+ <Badge variant="success" size="sm" data-edit-scope="component-definition" data-component="Badge" data-edit-variant="success">Success</Badge>
608
+ <Badge variant="error" size="sm" data-edit-scope="component-definition" data-component="Badge" data-edit-variant="error">Error</Badge>
609
+ </Row>
610
+ </Section>
611
+
612
+ <Section title="Progress" variant="h4" subsectionId="progress">
613
+ <Row props='value={number} variant="default" size="md" showLabel={false}'>
614
+ <div className="max-w-md w-full">
615
+ <Label htmlFor="progress-default">Default (50%)</Label>
616
+ <Progress value={50} variant="default" size="md" showLabel={false} data-edit-scope="component-definition" data-component="Progress" />
617
+ </div>
618
+ </Row>
619
+ <Row props='variant="success"'>
620
+ <div className="max-w-md w-full">
621
+ <Label htmlFor="progress-success">Success (75%)</Label>
622
+ <Progress value={75} variant="success" size="md" showLabel={false} data-edit-scope="component-definition" data-component="Progress" data-edit-variant="success" />
623
+ </div>
624
+ </Row>
625
+ <Row props='variant="warning"'>
626
+ <div className="max-w-md w-full">
627
+ <Label htmlFor="progress-warning">Warning (25%)</Label>
628
+ <Progress value={25} variant="warning" size="md" showLabel={false} data-edit-scope="component-definition" data-component="Progress" data-edit-variant="warning" />
629
+ </div>
630
+ </Row>
631
+ <Row props='showLabel={true}'>
632
+ <div className="max-w-md w-full">
633
+ <Label htmlFor="progress-label">Error with Label</Label>
634
+ <Progress value={90} variant="error" size="md" showLabel={true} data-edit-scope="component-definition" data-component="Progress" data-edit-variant="error" />
635
+ </div>
636
+ </Row>
637
+ </Section>
638
+
639
+ <Section title="Progress Sizes" variant="h4" subsectionId="progress-sizes">
640
+ <Row props='size="sm" | "md" | "lg"'>
641
+ <div className="max-w-md w-full">
642
+ <Label htmlFor="progress-sm">Small</Label>
643
+ <Progress value={60} variant="default" size="sm" showLabel={false} />
644
+ </div>
645
+ </Row>
646
+ <Row props='size="md"'>
647
+ <div className="max-w-md w-full">
648
+ <Label htmlFor="progress-md">Medium</Label>
649
+ <Progress value={60} variant="default" size="md" showLabel={false} />
650
+ </div>
651
+ </Row>
652
+ <Row props='size="lg"'>
653
+ <div className="max-w-md w-full">
654
+ <Label htmlFor="progress-lg">Large</Label>
655
+ <Progress value={60} variant="default" size="lg" showLabel={false} />
656
+ </div>
657
+ </Row>
658
+ </Section>
659
+
660
+ <Section title="Spinner" variant="h4" subsectionId="spinner">
661
+ <Row props='size={number}'>
662
+ <Spinner size={16} data-edit-scope="component-definition" data-component="Spinner" />
663
+ <Spinner size={24} data-edit-scope="component-definition" data-component="Spinner" />
664
+ <Spinner size={32} data-edit-scope="component-definition" data-component="Spinner" />
665
+ </Row>
666
+ </Section>
667
+
668
+ <Section title="Toast" variant="h4" subsectionId="toast">
669
+ <Row props='useToast() hook - addToast({ title, description?, variant?, duration? })'>
670
+ <div className="flex flex-wrap gap-2">
671
+ <Button
672
+ variant="primary"
673
+ size="md"
674
+
675
+ fullWidth={false}
676
+ iconOnly={false}
677
+ onClick={() => addToast({ title: 'Default Toast', variant: 'default' })}
678
+ >
679
+ Default Toast
680
+ </Button>
681
+ <Button
682
+ variant="primary"
683
+ size="md"
684
+
685
+ fullWidth={false}
686
+ iconOnly={false}
687
+ onClick={() => addToast({ title: 'Success!', description: 'Operation completed successfully.', variant: 'success' })}
688
+ >
689
+ Success Toast
690
+ </Button>
691
+ <Button
692
+ variant="primary"
693
+ size="md"
694
+
695
+ fullWidth={false}
696
+ iconOnly={false}
697
+ onClick={() => addToast({ title: 'Warning', description: 'Please review this carefully.', variant: 'warning' })}
698
+ >
699
+ Warning Toast
700
+ </Button>
701
+ <Button
702
+ variant="primary"
703
+ size="md"
704
+
705
+ fullWidth={false}
706
+ iconOnly={false}
707
+ onClick={() => addToast({ title: 'Error', description: 'Something went wrong.', variant: 'error' })}
708
+ >
709
+ Error Toast
710
+ </Button>
711
+ <Button
712
+ variant="primary"
713
+ size="md"
714
+
715
+ fullWidth={false}
716
+ iconOnly={false}
717
+ onClick={() => addToast({ title: 'Info', description: 'Here\'s some helpful information.', variant: 'info' })}
718
+ >
719
+ Info Toast
720
+ </Button>
721
+ </div>
722
+ </Row>
723
+ </Section>
724
+
725
+ <Section title="Tooltip" variant="h4" subsectionId="tooltip">
726
+ <Row props='content="..." position="top" | "bottom" | "left" | "right" size="sm" | "md" | "lg"'>
727
+ <Tooltip content="Top tooltip" position="top" size="sm" data-edit-scope="component-definition" data-component="Tooltip">
728
+ <Button variant="primary" size="md" fullWidth={false} iconOnly={false}>Top</Button>
729
+ </Tooltip>
730
+ <Tooltip content="Bottom tooltip" position="bottom" size="sm" data-edit-scope="component-definition" data-component="Tooltip">
731
+ <Button variant="primary" size="md" fullWidth={false} iconOnly={false}>Bottom</Button>
732
+ </Tooltip>
733
+ <Tooltip content="Left tooltip" position="left" size="sm" data-edit-scope="component-definition" data-component="Tooltip">
734
+ <Button variant="primary" size="md" fullWidth={false} iconOnly={false}>Left</Button>
735
+ </Tooltip>
736
+ <Tooltip content="Right tooltip" position="right" size="sm" data-edit-scope="component-definition" data-component="Tooltip">
737
+ <Button variant="primary" size="md" fullWidth={false} iconOnly={false}>Right</Button>
738
+ </Tooltip>
739
+ </Row>
740
+ </Section>
741
+ </div>
742
+ );
743
+ }
744
+
745
+ function NavigationContent() {
746
+ return (
747
+ <div className="space-y-6">
748
+ <Section title="Breadcrumbs" variant="h4" subsectionId="breadcrumbs">
749
+ <Row props='items={[{ label: string, href?: string }]} separator={string}'>
750
+ <Breadcrumbs
751
+ items={[
752
+ { label: 'Home', href: '#' },
753
+ { label: 'Products', href: '#' },
754
+ { label: 'Electronics', href: '#' },
755
+ { label: 'Current Page' },
756
+ ]}
757
+ data-edit-scope="component-definition"
758
+ data-component="Breadcrumbs"
759
+ />
760
+ </Row>
761
+ <Row props='separator="→"'>
762
+ <Breadcrumbs
763
+ items={[
764
+ { label: 'Home', href: '#' },
765
+ { label: 'About', href: '#' },
766
+ { label: 'Team' },
767
+ ]}
768
+ separator="→"
769
+ />
770
+ </Row>
771
+ <Row props='separator="•"'>
772
+ <Breadcrumbs
773
+ items={[
774
+ { label: 'Dashboard', href: '#' },
775
+ { label: 'Settings', href: '#' },
776
+ { label: 'Profile' },
777
+ ]}
778
+ separator="•"
779
+ />
780
+ </Row>
781
+ <Row props='Single item'>
782
+ <Breadcrumbs items={[{ label: 'Home' }]} />
783
+ </Row>
784
+ </Section>
785
+
786
+ <Section title="Tabs - Pill Variant" variant="h4" subsectionId="tabs-pill-variant">
787
+ <Row props='variant="pill" | "line" defaultValue="tab1" iconName="..."'>
788
+ <Card variant="default" noPadding={false} className="max-w-lg">
789
+ <Tabs defaultValue="tab1" variant="pill" data-edit-scope="component-definition" data-component="Tabs">
790
+ <TabList className="">
791
+ <TabTrigger value="tab1" iconName="home" className="">Tab One</TabTrigger>
792
+ <TabTrigger value="tab2" iconName="settings" className="">Tab Two</TabTrigger>
793
+ <TabTrigger value="tab3" iconName="information-circle" className="">Tab Three</TabTrigger>
794
+ </TabList>
795
+ <TabContent value="tab1" className="mt-4">
796
+ <p>Content for Tab One</p>
797
+ </TabContent>
798
+ <TabContent value="tab2" className="mt-4">
799
+ <p>Content for Tab Two</p>
800
+ </TabContent>
801
+ <TabContent value="tab3" className="mt-4">
802
+ <p>Content for Tab Three</p>
803
+ </TabContent>
804
+ </Tabs>
805
+ </Card>
806
+ </Row>
807
+ </Section>
808
+
809
+ <Section title="Tabs - Line Variant" variant="h4" subsectionId="tabs-line-variant">
810
+ <Row props='variant="line" iconName="..."'>
811
+ <Card variant="default" noPadding={false} className="max-w-lg">
812
+ <Tabs defaultValue="tab1" variant="line" data-edit-scope="component-definition" data-component="Tabs" data-edit-variant="line">
813
+ <TabList className="">
814
+ <TabTrigger value="tab1" iconName="home" className="">First</TabTrigger>
815
+ <TabTrigger value="tab2" iconName="settings" className="">Second</TabTrigger>
816
+ <TabTrigger value="tab3" iconName="information-circle" className="">Third</TabTrigger>
817
+ </TabList>
818
+ <TabContent value="tab1" className="mt-4">
819
+ <p>First tab content</p>
820
+ </TabContent>
821
+ <TabContent value="tab2" className="mt-4">
822
+ <p>Second tab content</p>
823
+ </TabContent>
824
+ <TabContent value="tab3" className="mt-4">
825
+ <p>Third tab content</p>
826
+ </TabContent>
827
+ </Tabs>
828
+ </Card>
829
+ </Row>
830
+ </Section>
831
+
832
+ <Section title="Dividers" variant="h4" subsectionId="dividers">
833
+ <Row props='variant="solid" | "dashed" | "decorated" orientation="horizontal"'>
834
+ <div className="w-full max-w-md">
835
+ <Label htmlFor="divider-solid">Solid</Label>
836
+ <Divider orientation="horizontal" variant="solid" data-edit-scope="component-definition" data-component="Divider" />
837
+ </div>
838
+ </Row>
839
+ <Row props='variant="dashed"'>
840
+ <div className="w-full max-w-md">
841
+ <Label htmlFor="divider-dashed">Dashed</Label>
842
+ <Divider orientation="horizontal" variant="dashed" data-edit-scope="component-definition" data-component="Divider" data-edit-variant="dashed" />
843
+ </div>
844
+ </Row>
845
+ <Row props='variant="decorated"'>
846
+ <div className="w-full max-w-md">
847
+ <Label htmlFor="divider-decorated">Decorated</Label>
848
+ <Divider orientation="horizontal" variant="decorated" data-edit-scope="component-definition" data-component="Divider" data-edit-variant="decorated" />
849
+ </div>
850
+ </Row>
851
+ </Section>
852
+
853
+ <Section title="Vertical Divider" variant="h4" subsectionId="vertical-divider">
854
+ <Row props='orientation="vertical"'>
855
+ <div className="flex items-center h-12 gap-4">
856
+ <span className="font-mondwest text-base">Left</span>
857
+ <Divider orientation="vertical" variant="solid" />
858
+ <span className="font-mondwest text-base">Right</span>
859
+ </div>
860
+ </Row>
861
+ </Section>
862
+ </div>
863
+ );
864
+ }
865
+
866
+ function OverlaysContent() {
867
+ const [dialogOpen, setDialogOpen] = useState(false);
868
+ const [sheetOpen, setSheetOpen] = useState(false);
869
+ const [helpPanelOpen, setHelpPanelOpen] = useState(false);
870
+
871
+ return (
872
+ <div className="space-y-6">
873
+ <Section title="Dialog" variant="h4" subsectionId="dialog">
874
+ <Row props='open={boolean} onOpenChange={fn} defaultOpen={boolean}'>
875
+ <Dialog open={dialogOpen} onOpenChange={setDialogOpen} data-edit-scope="component-definition" data-component="Dialog">
876
+ <DialogTrigger asChild>
877
+ <Button variant="primary" size="md" fullWidth={false} iconOnly={false}>
878
+ Open Dialog
879
+ </Button>
880
+ </DialogTrigger>
881
+ <DialogContent>
882
+ <DialogHeader>
883
+ <DialogTitle>Dialog Title</DialogTitle>
884
+ <DialogDescription>
885
+ This is a description of what the dialog does.
886
+ </DialogDescription>
887
+ </DialogHeader>
888
+ <DialogBody>
889
+ <p>
890
+ Dialog content goes here. You can put any content in the body.
891
+ </p>
892
+ </DialogBody>
893
+ <DialogFooter>
894
+ <DialogClose asChild>
895
+ <Button variant="ghost" size="md" fullWidth={false} iconOnly={false}>
896
+ Cancel
897
+ </Button>
898
+ </DialogClose>
899
+ <DialogClose asChild>
900
+ <Button variant="primary" size="md" fullWidth={false} iconOnly={false}>
901
+ Confirm
902
+ </Button>
903
+ </DialogClose>
904
+ </DialogFooter>
905
+ </DialogContent>
906
+ </Dialog>
907
+ </Row>
908
+ </Section>
909
+
910
+ <Section title="Dropdown Menu" variant="h4" subsectionId="dropdown-menu">
911
+ <Row props='open={boolean} onOpenChange={fn} position="bottom-start" | "bottom-end" | "top-start" | "top-end"'>
912
+ <DropdownMenu data-edit-scope="component-definition" data-component="DropdownMenu">
913
+ <DropdownMenuTrigger asChild>
914
+ <Button variant="primary" size="md" fullWidth={false} iconOnly={false}>
915
+ Open Menu ▼
916
+ </Button>
917
+ </DropdownMenuTrigger>
918
+ <DropdownMenuContent>
919
+ <DropdownMenuLabel>Actions</DropdownMenuLabel>
920
+ <DropdownMenuItem onClick={() => alert('Copy clicked!')} destructive={false} disabled={false}>
921
+ Copy
922
+ </DropdownMenuItem>
923
+ <DropdownMenuItem onClick={() => alert('Cut clicked!')} destructive={false} disabled={false}>
924
+ Cut
925
+ </DropdownMenuItem>
926
+ <DropdownMenuItem onClick={() => alert('Paste clicked!')} destructive={false} disabled={false}>
927
+ Paste
928
+ </DropdownMenuItem>
929
+ <DropdownMenuSeparator />
930
+ <DropdownMenuItem onClick={() => alert('Delete clicked!')} destructive={true} disabled={false}>
931
+ Delete
932
+ </DropdownMenuItem>
933
+ <DropdownMenuItem onClick={() => alert('Disabled item')} destructive={false} disabled={true}>
934
+ Disabled Item
935
+ </DropdownMenuItem>
936
+ </DropdownMenuContent>
937
+ </DropdownMenu>
938
+ </Row>
939
+ </Section>
940
+
941
+ <Section title="Popover" variant="h4" subsectionId="popover">
942
+ <Row props='open={boolean} onOpenChange={fn} position="top" | "bottom" | "left" | "right" align="start" | "center" | "end"'>
943
+ <Popover data-edit-scope="component-definition" data-component="Popover">
944
+ <PopoverTrigger asChild>
945
+ <Button variant="primary" size="md" fullWidth={false} iconOnly={false}>
946
+ Open Popover
947
+ </Button>
948
+ </PopoverTrigger>
949
+ <PopoverContent>
950
+ <p className="font-joystix text-xs uppercase mb-2">Popover Title</p>
951
+ <p className="font-mondwest text-base text-black/70">
952
+ This is popover content. It can contain any elements.
953
+ </p>
954
+ </PopoverContent>
955
+ </Popover>
956
+ </Row>
957
+ <Row props='position="top"'>
958
+ <Popover position="top" data-edit-scope="component-definition" data-component="Popover">
959
+ <PopoverTrigger asChild>
960
+ <Button variant="outline" size="md" fullWidth={false} iconOnly={false}>
961
+ Top Popover
962
+ </Button>
963
+ </PopoverTrigger>
964
+ <PopoverContent>
965
+ <p>Popover appears above</p>
966
+ </PopoverContent>
967
+ </Popover>
968
+ </Row>
969
+ </Section>
970
+
971
+ <Section title="Sheet" variant="h4" subsectionId="sheet">
972
+ <Row props='open={boolean} onOpenChange={fn} side="left" | "right" | "top" | "bottom"'>
973
+ <Sheet open={sheetOpen} onOpenChange={setSheetOpen} side="right" data-edit-scope="component-definition" data-component="Sheet">
974
+ <SheetTrigger asChild>
975
+ <Button variant="primary" size="md" fullWidth={false} iconOnly={false}>
976
+ Open Sheet (Right)
977
+ </Button>
978
+ </SheetTrigger>
979
+ <SheetContent>
980
+ <SheetHeader>
981
+ <SheetTitle>Sheet Title</SheetTitle>
982
+ <SheetDescription>
983
+ This is a description of the sheet content.
984
+ </SheetDescription>
985
+ </SheetHeader>
986
+ <SheetBody>
987
+ <p>
988
+ Sheet content goes here. This is a slide-in panel from the right side.
989
+ </p>
990
+ </SheetBody>
991
+ <SheetFooter>
992
+ <SheetClose asChild>
993
+ <Button variant="ghost" size="md" fullWidth={false} iconOnly={false}>
994
+ Cancel
995
+ </Button>
996
+ </SheetClose>
997
+ <SheetClose asChild>
998
+ <Button variant="primary" size="md" fullWidth={false} iconOnly={false}>
999
+ Save
1000
+ </Button>
1001
+ </SheetClose>
1002
+ </SheetFooter>
1003
+ </SheetContent>
1004
+ </Sheet>
1005
+ </Row>
1006
+ <Row props='side="left"'>
1007
+ <Sheet side="left" data-edit-scope="component-definition" data-component="Sheet">
1008
+ <SheetTrigger asChild>
1009
+ <Button variant="outline" size="md" fullWidth={false} iconOnly={false}>
1010
+ Open Sheet (Left)
1011
+ </Button>
1012
+ </SheetTrigger>
1013
+ <SheetContent>
1014
+ <SheetHeader>
1015
+ <SheetTitle>Left Side Sheet</SheetTitle>
1016
+ </SheetHeader>
1017
+ <SheetBody>
1018
+ <p>Sheet slides in from the left</p>
1019
+ </SheetBody>
1020
+ </SheetContent>
1021
+ </Sheet>
1022
+ </Row>
1023
+ </Section>
1024
+
1025
+ <Section title="Help Panel" variant="h4" subsectionId="help-panel">
1026
+ <Row props='isOpen={boolean} onClose={fn} title={string}'>
1027
+ <div className="relative w-full max-w-md h-64 border border-black rounded-sm bg-warm-cloud overflow-hidden">
1028
+ <div className="p-4">
1029
+ <Button
1030
+ variant="primary"
1031
+ size="md"
1032
+
1033
+ fullWidth={false}
1034
+ iconOnly={false}
1035
+ onClick={() => setHelpPanelOpen(true)}
1036
+ >
1037
+ Open Help Panel
1038
+ </Button>
1039
+ </div>
1040
+ <HelpPanel
1041
+ isOpen={helpPanelOpen}
1042
+ onClose={() => setHelpPanelOpen(false)}
1043
+ title="Help"
1044
+ data-edit-scope="component-definition"
1045
+ data-component="HelpPanel"
1046
+ >
1047
+ <div>
1048
+ <p className="font-joystix text-xs uppercase mb-2">Help Content</p>
1049
+ <p className="mb-4">
1050
+ This is a contextual help panel that slides in from the right side of its container.
1051
+ </p>
1052
+ <p>
1053
+ It's useful for providing contextual help within app windows or modals.
1054
+ </p>
1055
+ </div>
1056
+ </HelpPanel>
1057
+ </div>
1058
+ </Row>
1059
+ </Section>
1060
+
1061
+ <Section title="Context Menu" variant="h4" subsectionId="context-menu">
1062
+ <Row props='onClick={fn} destructive={boolean} disabled={boolean}'>
1063
+ <p className="mb-4 w-full">
1064
+ Right-click on the card below to see the context menu:
1065
+ </p>
1066
+ <ContextMenu data-edit-scope="component-definition" data-component="ContextMenu">
1067
+ <Card variant="default" noPadding={false} className="max-w-xs cursor-context-menu">
1068
+ <p className="font-joystix text-xs mb-2">Right-click me!</p>
1069
+ <p className="font-mondwest text-base text-black/70">
1070
+ This card has a context menu attached.
1071
+ </p>
1072
+ </Card>
1073
+ <ContextMenuContent>
1074
+ <ContextMenuItem onClick={() => alert('Copy clicked!')} destructive={false} disabled={false}>
1075
+ Copy
1076
+ </ContextMenuItem>
1077
+ <ContextMenuItem onClick={() => alert('Paste clicked!')} destructive={false} disabled={false}>
1078
+ Paste
1079
+ </ContextMenuItem>
1080
+ <ContextMenuItem onClick={() => alert('Duplicate clicked!')} destructive={false} disabled={false}>
1081
+ Duplicate
1082
+ </ContextMenuItem>
1083
+ <ContextMenuSeparator />
1084
+ <ContextMenuItem onClick={() => alert('Delete clicked!')} destructive={true} disabled={false}>
1085
+ Delete
1086
+ </ContextMenuItem>
1087
+ </ContextMenuContent>
1088
+ </ContextMenu>
1089
+ </Row>
1090
+ </Section>
1091
+ </div>
1092
+ );
1093
+ }
1094
+
1095
+ // ============================================================================
1096
+ // Search Index
1097
+ // ============================================================================
1098
+
1099
+ export interface SearchableItem {
1100
+ text: string;
1101
+ sectionId: string;
1102
+ subsectionTitle?: string;
1103
+ type: 'section' | 'subsection' | 'button' | 'label' | 'checkbox' | 'radio' | 'switch' | 'slider' | 'badge' | 'alert' | 'toast' | 'tooltip' | 'breadcrumb' | 'tab' | 'divider' | 'menu';
1104
+ }
1105
+
1106
+ export const SEARCH_INDEX: SearchableItem[] = [
1107
+ // Buttons section
1108
+ { text: 'Buttons', sectionId: 'buttons', type: 'section' },
1109
+ { text: 'Button Variants', sectionId: 'buttons', subsectionTitle: 'Button Variants', type: 'subsection' },
1110
+ { text: 'Button Sizes', sectionId: 'buttons', subsectionTitle: 'Button Sizes', type: 'subsection' },
1111
+ { text: 'Button with Icon', sectionId: 'buttons', subsectionTitle: 'Button with Icon', type: 'subsection' },
1112
+ { text: 'Primary', sectionId: 'buttons', type: 'button' },
1113
+ { text: 'Secondary', sectionId: 'buttons', type: 'button' },
1114
+ { text: 'Outline', sectionId: 'buttons', type: 'button' },
1115
+ { text: 'Ghost', sectionId: 'buttons', type: 'button' },
1116
+ { text: 'Disabled', sectionId: 'buttons', type: 'button' },
1117
+ { text: 'Small', sectionId: 'buttons', type: 'button' },
1118
+ { text: 'Medium', sectionId: 'buttons', type: 'button' },
1119
+ { text: 'Large', sectionId: 'buttons', type: 'button' },
1120
+ { text: 'Download', sectionId: 'buttons', type: 'button' },
1121
+ { text: 'Copy', sectionId: 'buttons', type: 'button' },
1122
+ { text: 'Full Width Button', sectionId: 'buttons', type: 'button' },
1123
+
1124
+ // Cards section
1125
+ { text: 'Cards', sectionId: 'cards', type: 'section' },
1126
+ { text: 'Card Variants', sectionId: 'cards', subsectionTitle: 'Card Variants', type: 'subsection' },
1127
+ { text: 'Card with Header/Footer', sectionId: 'cards', subsectionTitle: 'Card with Header/Footer', type: 'subsection' },
1128
+ { text: 'Default Card', sectionId: 'cards', type: 'label' },
1129
+ { text: 'Dark Card', sectionId: 'cards', type: 'label' },
1130
+ { text: 'Raised Card', sectionId: 'cards', type: 'label' },
1131
+ { text: 'Card Header', sectionId: 'cards', type: 'label' },
1132
+ { text: 'Cancel', sectionId: 'cards', type: 'button' },
1133
+ { text: 'Confirm', sectionId: 'cards', type: 'button' },
1134
+
1135
+ // Forms section
1136
+ { text: 'Forms', sectionId: 'forms', type: 'section' },
1137
+ { text: 'Text Inputs', sectionId: 'forms', subsectionTitle: 'Text Inputs', type: 'subsection' },
1138
+ { text: 'Input Sizes', sectionId: 'forms', subsectionTitle: 'Input Sizes', type: 'subsection' },
1139
+ { text: 'TextArea', sectionId: 'forms', subsectionTitle: 'TextArea', type: 'subsection' },
1140
+ { text: 'Select', sectionId: 'forms', subsectionTitle: 'Select', type: 'subsection' },
1141
+ { text: 'Checkbox & Radio', sectionId: 'forms', subsectionTitle: 'Checkbox & Radio', type: 'subsection' },
1142
+ { text: 'Switch', sectionId: 'forms', subsectionTitle: 'Switch', type: 'subsection' },
1143
+ { text: 'Slider', sectionId: 'forms', subsectionTitle: 'Slider', type: 'subsection' },
1144
+ { text: 'Default Input', sectionId: 'forms', type: 'label' },
1145
+ { text: 'Error State', sectionId: 'forms', type: 'label' },
1146
+ { text: 'Description', sectionId: 'forms', type: 'label' },
1147
+ { text: 'Choose an option', sectionId: 'forms', type: 'label' },
1148
+ { text: 'Check me', sectionId: 'forms', type: 'checkbox' },
1149
+ { text: 'Checked & Disabled', sectionId: 'forms', type: 'checkbox' },
1150
+ { text: 'Option 1', sectionId: 'forms', type: 'radio' },
1151
+ { text: 'Option 2', sectionId: 'forms', type: 'radio' },
1152
+ { text: 'Option 3', sectionId: 'forms', type: 'radio' },
1153
+ { text: 'Enable notifications', sectionId: 'forms', type: 'switch' },
1154
+ { text: 'Label on left', sectionId: 'forms', type: 'switch' },
1155
+ { text: 'Volume', sectionId: 'forms', type: 'slider' },
1156
+ { text: 'Default (50%)', sectionId: 'forms', type: 'label' },
1157
+ { text: 'Success (75%)', sectionId: 'forms', type: 'label' },
1158
+ { text: 'Warning (25%)', sectionId: 'forms', type: 'label' },
1159
+ { text: 'Error with Label', sectionId: 'forms', type: 'label' },
1160
+
1161
+ // Feedback section
1162
+ { text: 'Feedback', sectionId: 'feedback', type: 'section' },
1163
+ { text: 'Alert', sectionId: 'feedback', subsectionTitle: 'Alert', type: 'subsection' },
1164
+ { text: 'Badge Variants', sectionId: 'feedback', subsectionTitle: 'Badge Variants', type: 'subsection' },
1165
+ { text: 'Progress', sectionId: 'feedback', subsectionTitle: 'Progress', type: 'subsection' },
1166
+ { text: 'Progress Sizes', sectionId: 'feedback', subsectionTitle: 'Progress Sizes', type: 'subsection' },
1167
+ { text: 'Spinner', sectionId: 'feedback', subsectionTitle: 'Spinner', type: 'subsection' },
1168
+ { text: 'Toast', sectionId: 'feedback', subsectionTitle: 'Toast', type: 'subsection' },
1169
+ { text: 'Tooltip', sectionId: 'feedback', subsectionTitle: 'Tooltip', type: 'subsection' },
1170
+ { text: 'Default Alert', sectionId: 'feedback', type: 'alert' },
1171
+ { text: 'Success', sectionId: 'feedback', type: 'alert' },
1172
+ { text: 'Warning', sectionId: 'feedback', type: 'alert' },
1173
+ { text: 'Error', sectionId: 'feedback', type: 'alert' },
1174
+ { text: 'Info', sectionId: 'feedback', type: 'alert' },
1175
+ { text: 'Closable Alert', sectionId: 'feedback', type: 'alert' },
1176
+ { text: 'Default Toast', sectionId: 'feedback', type: 'toast' },
1177
+ { text: 'Success Toast', sectionId: 'feedback', type: 'toast' },
1178
+ { text: 'Warning Toast', sectionId: 'feedback', type: 'toast' },
1179
+ { text: 'Error Toast', sectionId: 'feedback', type: 'toast' },
1180
+ { text: 'Info Toast', sectionId: 'feedback', type: 'toast' },
1181
+ { text: 'Top', sectionId: 'feedback', type: 'tooltip' },
1182
+ { text: 'Bottom', sectionId: 'feedback', type: 'tooltip' },
1183
+ { text: 'Left', sectionId: 'feedback', type: 'tooltip' },
1184
+ { text: 'Right', sectionId: 'feedback', type: 'tooltip' },
1185
+
1186
+ // Navigation section
1187
+ { text: 'Navigation', sectionId: 'navigation', type: 'section' },
1188
+ { text: 'Breadcrumbs', sectionId: 'navigation', subsectionTitle: 'Breadcrumbs', type: 'subsection' },
1189
+ { text: 'Tabs - Pill Variant', sectionId: 'navigation', subsectionTitle: 'Tabs - Pill Variant', type: 'subsection' },
1190
+ { text: 'Tabs - Line Variant', sectionId: 'navigation', subsectionTitle: 'Tabs - Line Variant', type: 'subsection' },
1191
+ { text: 'Dividers', sectionId: 'navigation', subsectionTitle: 'Dividers', type: 'subsection' },
1192
+ { text: 'Vertical Divider', sectionId: 'navigation', subsectionTitle: 'Vertical Divider', type: 'subsection' },
1193
+ { text: 'Home', sectionId: 'navigation', type: 'breadcrumb' },
1194
+ { text: 'Products', sectionId: 'navigation', type: 'breadcrumb' },
1195
+ { text: 'Electronics', sectionId: 'navigation', type: 'breadcrumb' },
1196
+ { text: 'Current Page', sectionId: 'navigation', type: 'breadcrumb' },
1197
+ { text: 'About', sectionId: 'navigation', type: 'breadcrumb' },
1198
+ { text: 'Team', sectionId: 'navigation', type: 'breadcrumb' },
1199
+ { text: 'Dashboard', sectionId: 'navigation', type: 'breadcrumb' },
1200
+ { text: 'Settings', sectionId: 'navigation', type: 'breadcrumb' },
1201
+ { text: 'Profile', sectionId: 'navigation', type: 'breadcrumb' },
1202
+ { text: 'Tab One', sectionId: 'navigation', type: 'tab' },
1203
+ { text: 'Tab Two', sectionId: 'navigation', type: 'tab' },
1204
+ { text: 'Tab Three', sectionId: 'navigation', type: 'tab' },
1205
+ { text: 'First', sectionId: 'navigation', type: 'tab' },
1206
+ { text: 'Second', sectionId: 'navigation', type: 'tab' },
1207
+ { text: 'Third', sectionId: 'navigation', type: 'tab' },
1208
+ { text: 'Solid', sectionId: 'navigation', type: 'divider' },
1209
+ { text: 'Dashed', sectionId: 'navigation', type: 'divider' },
1210
+ { text: 'Decorated', sectionId: 'navigation', type: 'divider' },
1211
+
1212
+ // Overlays section
1213
+ { text: 'Overlays', sectionId: 'overlays', type: 'section' },
1214
+ { text: 'Dialog', sectionId: 'overlays', subsectionTitle: 'Dialog', type: 'subsection' },
1215
+ { text: 'Dropdown Menu', sectionId: 'overlays', subsectionTitle: 'Dropdown Menu', type: 'subsection' },
1216
+ { text: 'Popover', sectionId: 'overlays', subsectionTitle: 'Popover', type: 'subsection' },
1217
+ { text: 'Sheet', sectionId: 'overlays', subsectionTitle: 'Sheet', type: 'subsection' },
1218
+ { text: 'Help Panel', sectionId: 'overlays', subsectionTitle: 'Help Panel', type: 'subsection' },
1219
+ { text: 'Context Menu', sectionId: 'overlays', subsectionTitle: 'Context Menu', type: 'subsection' },
1220
+ { text: 'Open Dialog', sectionId: 'overlays', type: 'button' },
1221
+ { text: 'Open Menu', sectionId: 'overlays', type: 'button' },
1222
+ { text: 'Open Popover', sectionId: 'overlays', type: 'button' },
1223
+ { text: 'Top Popover', sectionId: 'overlays', type: 'button' },
1224
+ { text: 'Open Sheet (Right)', sectionId: 'overlays', type: 'button' },
1225
+ { text: 'Open Sheet (Left)', sectionId: 'overlays', type: 'button' },
1226
+ { text: 'Open Help Panel', sectionId: 'overlays', type: 'button' },
1227
+ { text: 'Save', sectionId: 'overlays', type: 'button' },
1228
+ { text: 'Actions', sectionId: 'overlays', type: 'menu' },
1229
+ { text: 'Cut', sectionId: 'overlays', type: 'menu' },
1230
+ { text: 'Paste', sectionId: 'overlays', type: 'menu' },
1231
+ { text: 'Duplicate', sectionId: 'overlays', type: 'menu' },
1232
+ { text: 'Disabled Item', sectionId: 'overlays', type: 'menu' },
1233
+ ];
1234
+
1235
+ // Section title lookup map
1236
+ const SECTION_TITLES: Record<string, string> = {
1237
+ buttons: 'Buttons',
1238
+ cards: 'Cards',
1239
+ forms: 'Forms',
1240
+ feedback: 'Feedback',
1241
+ navigation: 'Navigation',
1242
+ overlays: 'Overlays',
1243
+ };
1244
+
1245
+ // Subsection title to ID mapping
1246
+ const SUBSECTION_ID_MAP: Record<string, string> = {
1247
+ 'Button Variants': 'button-variants',
1248
+ 'Button Sizes': 'button-sizes',
1249
+ 'Button with Icon': 'button-with-icon',
1250
+ 'Card Variants': 'card-variants',
1251
+ 'Card with Header/Footer': 'card-with-header-footer',
1252
+ 'Text Inputs': 'text-inputs',
1253
+ 'Input Sizes': 'input-sizes',
1254
+ 'TextArea': 'textarea',
1255
+ 'Select': 'select',
1256
+ 'Checkbox & Radio': 'checkbox-radio',
1257
+ 'Switch': 'switch',
1258
+ 'Slider': 'slider',
1259
+ 'Alert': 'alert',
1260
+ 'Badge Variants': 'badge-variants',
1261
+ 'Progress': 'progress',
1262
+ 'Progress Sizes': 'progress-sizes',
1263
+ 'Spinner': 'spinner',
1264
+ 'Toast': 'toast',
1265
+ 'Tooltip': 'tooltip',
1266
+ 'Breadcrumbs': 'breadcrumbs',
1267
+ 'Tabs - Pill Variant': 'tabs-pill-variant',
1268
+ 'Tabs - Line Variant': 'tabs-line-variant',
1269
+ 'Dividers': 'dividers',
1270
+ 'Vertical Divider': 'vertical-divider',
1271
+ 'Dialog': 'dialog',
1272
+ 'Dropdown Menu': 'dropdown-menu',
1273
+ 'Popover': 'popover',
1274
+ 'Sheet': 'sheet',
1275
+ 'Help Panel': 'help-panel',
1276
+ 'Context Menu': 'context-menu',
1277
+ };
1278
+
1279
+ // ============================================================================
1280
+ // Autocomplete Component
1281
+ // ============================================================================
1282
+
1283
+ interface AutocompleteProps {
1284
+ query: string;
1285
+ suggestions: SearchableItem[];
1286
+ selectedIndex: number;
1287
+ onSelect: (item: SearchableItem) => void;
1288
+ onClose: () => void;
1289
+ }
1290
+
1291
+ function Autocomplete({ query, suggestions, selectedIndex, onSelect, onClose }: AutocompleteProps) {
1292
+ const listRef = useRef<HTMLDivElement>(null);
1293
+
1294
+ useEffect(() => {
1295
+ if (listRef.current && selectedIndex >= 0 && selectedIndex < suggestions.length) {
1296
+ const selectedElement = listRef.current.children[selectedIndex] as HTMLElement;
1297
+ if (selectedElement) {
1298
+ selectedElement.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
1299
+ }
1300
+ }
1301
+ }, [selectedIndex, suggestions.length]);
1302
+
1303
+ if (suggestions.length === 0 || !query) {
1304
+ return null;
1305
+ }
1306
+
1307
+ const highlightText = (text: string, query: string) => {
1308
+ const index = text.toLowerCase().indexOf(query.toLowerCase());
1309
+ if (index === -1) return text;
1310
+ return (
1311
+ <>
1312
+ {text.substring(0, index)}
1313
+ <span className="bg-sun-yellow">{text.substring(index, index + query.length)}</span>
1314
+ {text.substring(index + query.length)}
1315
+ </>
1316
+ );
1317
+ };
1318
+
1319
+ return (
1320
+ <div
1321
+ ref={listRef}
1322
+ className="absolute z-50 w-full mt-1 bg-warm-cloud border border-black rounded-sm shadow-[4px_4px_0_0_var(--color-black)] max-h-64 overflow-y-auto"
1323
+ >
1324
+ {suggestions.map((item, index) => {
1325
+ const sectionTitle = SECTION_TITLES[item.sectionId];
1326
+ const isSubsection = item.subsectionTitle !== undefined;
1327
+ const displayTitle = isSubsection ? item.subsectionTitle : sectionTitle;
1328
+
1329
+ return (
1330
+ <button
1331
+ key={`${item.sectionId}-${item.text}-${index}`}
1332
+ type="button"
1333
+ onClick={() => onSelect(item)}
1334
+ className={`w-full text-left px-3 py-2 font-mondwest text-sm transition-colors ${
1335
+ index === selectedIndex
1336
+ ? 'bg-sun-yellow text-black'
1337
+ : 'bg-warm-cloud text-black hover:bg-black/5'
1338
+ } ${isSubsection ? 'pl-6' : ''}`}
1339
+ >
1340
+ <div className="flex items-center justify-between">
1341
+ <div className="flex flex-col gap-0.5">
1342
+ {displayTitle && (
1343
+ <span className="font-joystix text-xs font-bold text-black/60 uppercase">
1344
+ {displayTitle}
1345
+ </span>
1346
+ )}
1347
+ <span>{highlightText(item.text, query)}</span>
1348
+ </div>
1349
+ <span className="text-xs text-black/40 uppercase">{item.type}</span>
1350
+ </div>
1351
+ </button>
1352
+ );
1353
+ })}
1354
+ </div>
1355
+ );
1356
+ }
1357
+
1358
+ // ============================================================================
1359
+ // Main Component
1360
+ // ============================================================================
1361
+
1362
+ // Component sections for search filtering
1363
+ const COMPONENT_SECTIONS = [
1364
+ { id: 'buttons', title: 'Buttons', content: <ButtonsContent /> },
1365
+ { id: 'cards', title: 'Cards', content: <CardsContent /> },
1366
+ { id: 'forms', title: 'Forms', content: <FormsContent /> },
1367
+ { id: 'feedback', title: 'Feedback', content: <FeedbackContent /> },
1368
+ { id: 'navigation', title: 'Navigation', content: <NavigationContent /> },
1369
+ { id: 'overlays', title: 'Overlays', content: <OverlaysContent /> },
1370
+ ];
1371
+
1372
+ interface DesignSystemTabProps {
1373
+ searchQuery?: string;
1374
+ }
1375
+
1376
+ export function DesignSystemTab({ searchQuery: propSearchQuery = '' }: DesignSystemTabProps) {
1377
+ const searchQuery = propSearchQuery;
1378
+
1379
+ // Get matching suggestions (for autocomplete in footer)
1380
+ const suggestions = searchQuery
1381
+ ? SEARCH_INDEX.filter((item) =>
1382
+ item.text.toLowerCase().includes(searchQuery.toLowerCase())
1383
+ ).slice(0, 10)
1384
+ : [];
1385
+
1386
+ // Filter sections based on search query
1387
+ const filteredSections = searchQuery
1388
+ ? (() => {
1389
+ const queryLower = searchQuery.toLowerCase().trim();
1390
+
1391
+ // Check for exact match first (case-insensitive)
1392
+ const exactMatch = SEARCH_INDEX.find(
1393
+ (item) => item.text.toLowerCase() === queryLower
1394
+ );
1395
+
1396
+ if (exactMatch) {
1397
+ // If exact match is a subsection, we'll filter subsections via CSS
1398
+ if (exactMatch.subsectionTitle) {
1399
+ // Show the section containing this subsection
1400
+ return COMPONENT_SECTIONS.filter(
1401
+ (section) => section.id === exactMatch.sectionId
1402
+ );
1403
+ }
1404
+ // If exact match is a section title, show all subsections in that section
1405
+ if (exactMatch.type === 'section') {
1406
+ return COMPONENT_SECTIONS.filter(
1407
+ (section) => section.id === exactMatch.sectionId
1408
+ );
1409
+ }
1410
+ // Otherwise, only show the section containing that item
1411
+ return COMPONENT_SECTIONS.filter(
1412
+ (section) => section.id === exactMatch.sectionId
1413
+ );
1414
+ }
1415
+
1416
+ // Check if query matches a subsection title
1417
+ const subsectionMatch = Object.keys(SUBSECTION_ID_MAP).find(
1418
+ (title) => title.toLowerCase() === queryLower
1419
+ );
1420
+
1421
+ if (subsectionMatch) {
1422
+ const subsectionId = SUBSECTION_ID_MAP[subsectionMatch];
1423
+ // Find which section contains this subsection
1424
+ const subsectionItem = SEARCH_INDEX.find(
1425
+ (item) => item.subsectionTitle === subsectionMatch
1426
+ );
1427
+ if (subsectionItem) {
1428
+ return COMPONENT_SECTIONS.filter(
1429
+ (section) => section.id === subsectionItem.sectionId
1430
+ );
1431
+ }
1432
+ }
1433
+
1434
+ // Check if query matches a section title
1435
+ const sectionMatch = Object.values(SECTION_TITLES).find(
1436
+ (title) => title.toLowerCase() === queryLower
1437
+ );
1438
+
1439
+ if (sectionMatch) {
1440
+ // Show all subsections in that section
1441
+ const sectionId = Object.keys(SECTION_TITLES).find(
1442
+ (id) => SECTION_TITLES[id] === sectionMatch
1443
+ );
1444
+ if (sectionId) {
1445
+ return COMPONENT_SECTIONS.filter(
1446
+ (section) => section.id === sectionId
1447
+ );
1448
+ }
1449
+ }
1450
+
1451
+ // Otherwise, use the existing fuzzy matching logic
1452
+ return COMPONENT_SECTIONS.filter((section) => {
1453
+ // Check if section title matches
1454
+ if (section.title.toLowerCase().includes(queryLower)) {
1455
+ return true;
1456
+ }
1457
+ // Check if any searchable item in this section matches
1458
+ return SEARCH_INDEX.some(
1459
+ (item) =>
1460
+ item.sectionId === section.id &&
1461
+ item.text.toLowerCase().includes(queryLower)
1462
+ );
1463
+ });
1464
+ })()
1465
+ : COMPONENT_SECTIONS;
1466
+
1467
+ // Determine which subsection to show (if any)
1468
+ const activeSubsectionId = searchQuery
1469
+ ? (() => {
1470
+ const queryLower = searchQuery.toLowerCase().trim();
1471
+ const exactMatch = SEARCH_INDEX.find(
1472
+ (item) => item.text.toLowerCase() === queryLower
1473
+ );
1474
+ if (exactMatch?.subsectionTitle) {
1475
+ return SUBSECTION_ID_MAP[exactMatch.subsectionTitle];
1476
+ }
1477
+ const subsectionMatch = Object.keys(SUBSECTION_ID_MAP).find(
1478
+ (title) => title.toLowerCase() === queryLower
1479
+ );
1480
+ if (subsectionMatch) {
1481
+ return SUBSECTION_ID_MAP[subsectionMatch];
1482
+ }
1483
+ return null;
1484
+ })()
1485
+ : null;
1486
+
1487
+
1488
+ return (
1489
+ <ToastProvider>
1490
+ <div className="flex flex-col h-full overflow-auto pt-4 pb-4 pl-4 pr-2 bg-[var(--color-white)] border border-black rounded">
1491
+ {/* Component Sections */}
1492
+ {activeSubsectionId && (
1493
+ <style>{`
1494
+ div[data-subsection-id]:not([data-subsection-id="${activeSubsectionId}"]) {
1495
+ display: none !important;
1496
+ }
1497
+ `}</style>
1498
+ )}
1499
+ <div className="space-y-0">
1500
+ {filteredSections.length > 0 ? (
1501
+ filteredSections.map((section) => (
1502
+ <div key={section.id} className="mb-6">
1503
+ <Section title={section.title}>{section.content}</Section>
1504
+ </div>
1505
+ ))
1506
+ ) : (
1507
+ <div className="text-center py-8 text-black/60 font-mondwest text-base">
1508
+ No components match "{searchQuery}"
1509
+ </div>
1510
+ )}
1511
+ </div>
1512
+ </div>
1513
+ </ToastProvider>
1514
+ );
1515
+ }