@catalystsoftware/ui 1.0.2 → 1.0.5

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 (157) hide show
  1. package/data/tailwind.config.js +261 -3821
  2. package/dist/components/catalyst-ui/buttons/burger.tsx +207 -0
  3. package/dist/components/catalyst-ui/core/data-display/timeline.tsx +210 -0
  4. package/dist/components/catalyst-ui/core/feedback/alert.tsx +491 -0
  5. package/dist/components/catalyst-ui/core/feedback/spinner-1.tsx +65 -0
  6. package/dist/components/catalyst-ui/core/feedback/toast.tsx +1857 -0
  7. package/dist/components/catalyst-ui/core/navigation/menu.tsx +164 -0
  8. package/dist/components/catalyst-ui/forms/toggle-class.tsx +176 -0
  9. package/dist/components/catalyst-ui/hooks/use-copy-to-clipboard.tsx +419 -0
  10. package/dist/components/catalyst-ui/hooks/use-counter.tsx +13 -0
  11. package/dist/components/catalyst-ui/hooks/use-event-listener.tsx +23 -0
  12. package/dist/components/catalyst-ui/hooks/use-export-markdown.tsx +47 -0
  13. package/dist/components/catalyst-ui/hooks/use-focus.tsx +17 -0
  14. package/dist/components/catalyst-ui/hooks/use-interval.tsx +23 -0
  15. package/dist/components/catalyst-ui/hooks/use-is-client.tsx +16 -0
  16. package/dist/components/catalyst-ui/hooks/use-media-query.tsx +19 -0
  17. package/dist/components/catalyst-ui/hooks/use-mobile.tsx +19 -0
  18. package/dist/components/catalyst-ui/hooks/use-resize-observer.tsx +81 -0
  19. package/dist/components/catalyst-ui/hooks/use-timeout.tsx +21 -0
  20. package/dist/components/catalyst-ui/hooks/use-timer.tsx +209 -0
  21. package/dist/components/catalyst-ui/hooks/use-toggle.tsx +12 -0
  22. package/dist/components/catalyst-ui/media/image.tsx +13 -0
  23. package/dist/components/catalyst-ui/overlays/dual-sidebar.tsx +4142 -0
  24. package/dist/components/catalyst-ui/overlays/sidebar-original.tsx +726 -0
  25. package/dist/components/catalyst-ui/primitives/accordion.tsx +250 -0
  26. package/dist/components/catalyst-ui/primitives/alert-dialog.tsx +126 -0
  27. package/dist/components/catalyst-ui/primitives/aspect-ratio.tsx +9 -0
  28. package/dist/components/catalyst-ui/primitives/avatar.tsx +296 -0
  29. package/dist/components/catalyst-ui/primitives/badge.tsx +57 -0
  30. package/dist/components/catalyst-ui/primitives/breadcrumb.tsx +101 -0
  31. package/dist/components/catalyst-ui/primitives/button.tsx +265 -0
  32. package/dist/components/catalyst-ui/primitives/calendar-v4.tsx +208 -0
  33. package/dist/components/catalyst-ui/primitives/calendar.tsx +295 -0
  34. package/dist/components/catalyst-ui/primitives/card.tsx +618 -0
  35. package/dist/components/catalyst-ui/primitives/carousel.tsx +238 -0
  36. package/dist/components/catalyst-ui/primitives/chart.tsx +347 -0
  37. package/dist/components/catalyst-ui/primitives/checkbox.tsx +225 -0
  38. package/dist/components/catalyst-ui/primitives/collapsible.tsx +212 -0
  39. package/dist/components/catalyst-ui/primitives/command.tsx +393 -0
  40. package/dist/components/catalyst-ui/primitives/context-menu.tsx +236 -0
  41. package/dist/components/catalyst-ui/primitives/dialog.tsx +471 -0
  42. package/dist/components/catalyst-ui/primitives/drawer.tsx +761 -0
  43. package/dist/components/catalyst-ui/primitives/dropdown-menu.tsx +290 -0
  44. package/dist/components/catalyst-ui/primitives/empty.tsx +104 -0
  45. package/dist/components/catalyst-ui/primitives/field.tsx +244 -0
  46. package/dist/components/catalyst-ui/primitives/hover-card.tsx +124 -0
  47. package/dist/components/catalyst-ui/primitives/input-otp.tsx +76 -0
  48. package/dist/components/catalyst-ui/primitives/input.tsx +64 -0
  49. package/dist/components/catalyst-ui/primitives/item.tsx +196 -0
  50. package/dist/components/catalyst-ui/primitives/kbd.tsx +75 -0
  51. package/dist/components/catalyst-ui/primitives/label.tsx +24 -0
  52. package/dist/components/catalyst-ui/primitives/navigation-menu.tsx +150 -0
  53. package/dist/components/catalyst-ui/primitives/pagination.tsx +198 -0
  54. package/dist/components/catalyst-ui/primitives/popover.tsx +232 -0
  55. package/dist/components/catalyst-ui/primitives/progress.tsx +34 -0
  56. package/dist/components/catalyst-ui/primitives/radio-group.tsx +43 -0
  57. package/dist/components/catalyst-ui/primitives/resizable.tsx +56 -0
  58. package/dist/components/catalyst-ui/primitives/select.tsx +155 -0
  59. package/dist/components/catalyst-ui/primitives/separator.tsx +74 -0
  60. package/dist/components/catalyst-ui/primitives/sheet.tsx +126 -0
  61. package/dist/components/catalyst-ui/primitives/skeleton.tsx +15 -0
  62. package/dist/components/catalyst-ui/primitives/slider.tsx +27 -0
  63. package/dist/components/catalyst-ui/primitives/switch.tsx +187 -0
  64. package/dist/components/catalyst-ui/primitives/tabs.tsx +335 -0
  65. package/dist/components/catalyst-ui/primitives/textarea.tsx +24 -0
  66. package/dist/components/catalyst-ui/primitives/toggle-group.tsx +55 -0
  67. package/dist/components/catalyst-ui/primitives/toggle.tsx +42 -0
  68. package/dist/components/catalyst-ui/primitives/tooltip.tsx +116 -0
  69. package/dist/components/catalyst-ui/utils/basic-auth.tsx +40 -0
  70. package/dist/components/catalyst-ui/utils/context-storage.tsx +19 -0
  71. package/dist/components/catalyst-ui/utils/cors-middleware.tsx +71 -0
  72. package/dist/components/catalyst-ui/utils/deferred-content.tsx +595 -0
  73. package/dist/components/catalyst-ui/utils/honeypot-middleware.tsx +38 -0
  74. package/dist/components/catalyst-ui/utils/incId.tsx +75 -0
  75. package/dist/components/catalyst-ui/utils/jwk-auth.tsx +36 -0
  76. package/dist/components/catalyst-ui/utils/request-id.tsx +14 -0
  77. package/dist/components/catalyst-ui/utils/secure-headers.tsx +37 -0
  78. package/dist/components/catalyst-ui/utils/server-timing.tsx +23 -0
  79. package/dist/components/catalyst-ui/utils/utils.ts +43 -0
  80. package/dist/components/catalyst-ui/utils/with-cookie.tsx +43 -0
  81. package/dist/components/catalyst-ui/x/accordian-x.tsx +428 -0
  82. package/dist/components/catalyst-ui/x/alert-x.tsx +413 -0
  83. package/dist/components/catalyst-ui/x/animated-text-x.tsx +2242 -0
  84. package/dist/components/catalyst-ui/x/avatar-x.tsx +515 -0
  85. package/dist/components/catalyst-ui/x/badge-x.tsx +670 -0
  86. package/dist/components/catalyst-ui/x/button-X.tsx +2857 -0
  87. package/dist/components/catalyst-ui/x/button-group-x.tsx +847 -0
  88. package/dist/components/catalyst-ui/x/calendar-x.tsx +1910 -0
  89. package/dist/components/catalyst-ui/x/card-x.tsx +2597 -0
  90. package/dist/components/catalyst-ui/x/checkbox-x.tsx +656 -0
  91. package/dist/components/catalyst-ui/x/collapsible-x.tsx +1360 -0
  92. package/dist/components/catalyst-ui/x/combobox-x.tsx +911 -0
  93. package/dist/components/catalyst-ui/x/data-table-x.tsx +1753 -0
  94. package/dist/components/catalyst-ui/x/date-picker-x.tsx +648 -0
  95. package/dist/components/catalyst-ui/x/dialog-x.tsx +659 -0
  96. package/dist/components/catalyst-ui/x/dropdown-menu-x.tsx +612 -0
  97. package/dist/components/catalyst-ui/x/hover-card-x.tsx +375 -0
  98. package/dist/components/catalyst-ui/x/icon-x.tsx +840 -0
  99. package/dist/components/catalyst-ui/x/input-mask-x.tsx +981 -0
  100. package/dist/components/catalyst-ui/x/input-otp-x.tsx +659 -0
  101. package/dist/components/catalyst-ui/x/loader-x.tsx +1757 -0
  102. package/dist/components/catalyst-ui/x/pagination-x.tsx +622 -0
  103. package/dist/components/catalyst-ui/x/popover-x.tsx +744 -0
  104. package/dist/components/catalyst-ui/x/radio-group-x.tsx +499 -0
  105. package/dist/components/catalyst-ui/x/select-x.tsx +1127 -0
  106. package/dist/components/catalyst-ui/x/sheet-x.tsx +668 -0
  107. package/dist/components/catalyst-ui/x/switch-x.tsx +681 -0
  108. package/dist/components/catalyst-ui/x/table-x.tsx +574 -0
  109. package/dist/components/catalyst-ui/x/tabs-x.tsx +839 -0
  110. package/dist/components/catalyst-ui/x/textarea-x.tsx +1263 -0
  111. package/dist/components/catalyst-ui/x/tooltip-x.tsx +396 -0
  112. package/dist/components/catalyst-ui/x/tracker-x.tsx +560 -0
  113. package/dist/data/bg-data.tsx +901 -0
  114. package/dist/data/buttons-data.tsx +2327 -0
  115. package/dist/data/charts-data.tsx +102 -0
  116. package/dist/data/chat-data.tsx +83 -0
  117. package/dist/data/code-data.tsx +1040 -0
  118. package/dist/data/comboboxes-data.tsx +1843 -0
  119. package/dist/data/command-data.tsx +1381 -0
  120. package/dist/data/core-data.tsx +15953 -0
  121. package/dist/data/crm-data.tsx +47 -0
  122. package/dist/data/data.tsx +159 -0
  123. package/dist/data/date-and-time-data.tsx +554 -0
  124. package/dist/data/dependencies.tsx +7 -0
  125. package/dist/data/ecommerce-data.tsx +1387 -0
  126. package/dist/data/forms-data.tsx +7890 -0
  127. package/dist/data/hooks-data.tsx +5487 -0
  128. package/dist/data/index.ts +34 -0
  129. package/dist/data/inputs-data.tsx +557 -0
  130. package/dist/data/interactive-data.tsx +5394 -0
  131. package/dist/data/lofi-data.tsx +18295 -0
  132. package/dist/data/marketing-data.tsx +2546 -0
  133. package/dist/data/media-data.tsx +1510 -0
  134. package/dist/data/motion-data.tsx +5801 -0
  135. package/dist/data/overlay-data.tsx +4136 -0
  136. package/dist/data/pdf-data.tsx +124 -0
  137. package/dist/data/pos-data.tsx +213 -0
  138. package/dist/data/postcss.config.js +6 -0
  139. package/dist/data/primitive-data.tsx +5170 -0
  140. package/dist/data/prompt-data.tsx +1226 -0
  141. package/dist/data/requiredLibs.ts +4 -0
  142. package/dist/data/sandbox-data.tsx +1 -0
  143. package/dist/data/sidebars-data.tsx +5421 -0
  144. package/dist/data/stacks-data.tsx +32 -0
  145. package/dist/data/table-data.tsx +706 -0
  146. package/dist/data/tailwind.config.js +270 -0
  147. package/dist/data/tailwind.config.ngin.js +3830 -0
  148. package/dist/data/tailwind.css +431 -0
  149. package/dist/data/tools-data.tsx +6910 -0
  150. package/dist/data/typography-data.tsx +2050 -0
  151. package/dist/data/utils-data.tsx +6500 -0
  152. package/dist/data/x-data.tsx +1171 -0
  153. package/dist/data.tsx +159 -0
  154. package/package.json +1 -1
  155. package/dist/index.d.ts +0 -3
  156. package/dist/index.d.ts.map +0 -1
  157. package/dist/index.js.map +0 -362
@@ -0,0 +1,1381 @@
1
+ export const commands = [
2
+ {
3
+ name: "nested command dialog",
4
+ value: "nested-command-dialog",
5
+ importPath: "~/components/catalyst-ui/commands/nested-command-dialog",
6
+ path: "/components/catalyst-ui/commands/nested-command-dialog.tsx",
7
+ premium: true,
8
+ source: null,
9
+ category: "Commands",
10
+ tags: ["utils", "auth", "user auth"],
11
+ features: ["utils", "auth", "user auth"],
12
+ dependencies: [],
13
+ basicusage: ``,
14
+ usage: `
15
+
16
+
17
+ const [open, setOpen] = useState(false);
18
+ const [basicOpen, setBasicOpen] = useState(false);
19
+ const [themeOpen, setThemeOpen] = useState(false);
20
+
21
+ const commandPages = [
22
+ {
23
+ id: 'main',
24
+ title: 'Actions',
25
+ items: [
26
+ {
27
+ id: 'search-projects',
28
+ label: 'Search projects...',
29
+ icon: <FolderOpen size={16} />,
30
+ navigateTo: 'projects',
31
+ shortcut: '⌘P'
32
+ },
33
+ {
34
+ id: 'join-team',
35
+ label: 'Join a team...',
36
+ icon: <Users size={16} />,
37
+ navigateTo: 'teams',
38
+ shortcut: '⌘T'
39
+ },
40
+ {
41
+ id: 'settings',
42
+ label: 'Settings...',
43
+ icon: <Settings size={16} />,
44
+ navigateTo: 'settings',
45
+ shortcut: '⌘,'
46
+ },
47
+ {
48
+ id: 'theme',
49
+ label: 'Change theme...',
50
+ icon: <Palette size={16} />,
51
+ navigateTo: 'theme',
52
+ }
53
+ ]
54
+ },
55
+ {
56
+ id: 'projects',
57
+ title: 'Projects',
58
+ items: [
59
+ {
60
+ id: 'project-a',
61
+ label: 'Project Alpha',
62
+ icon: <FolderOpen size={16} />,
63
+ value: 'React application with TypeScript',
64
+ onSelect: () => console.log('Selected Project Alpha')
65
+ },
66
+ {
67
+ id: 'project-b',
68
+ label: 'Project Beta',
69
+ icon: <FolderOpen size={16} />,
70
+ value: 'Vue.js dashboard application',
71
+ onSelect: () => console.log('Selected Project Beta')
72
+ },
73
+ {
74
+ id: 'project-c',
75
+ label: 'Project Gamma',
76
+ icon: <FolderOpen size={16} />,
77
+ value: 'Next.js e-commerce site',
78
+ onSelect: () => console.log('Selected Project Gamma')
79
+ }
80
+ ]
81
+ },
82
+ {
83
+ id: 'teams',
84
+ title: 'Teams',
85
+ items: [
86
+ {
87
+ id: 'team-1',
88
+ label: 'Frontend Team',
89
+ icon: <Users size={16} />,
90
+ value: '12 members • Active',
91
+ onSelect: () => console.log('Joined Frontend Team')
92
+ },
93
+ {
94
+ id: 'team-2',
95
+ label: 'Backend Team',
96
+ icon: <Users size={16} />,
97
+ value: '8 members • Active',
98
+ onSelect: () => console.log('Joined Backend Team')
99
+ },
100
+ {
101
+ id: 'team-3',
102
+ label: 'Design Team',
103
+ icon: <Users size={16} />,
104
+ value: '6 members • Active',
105
+ onSelect: () => console.log('Joined Design Team')
106
+ }
107
+ ]
108
+ },
109
+ {
110
+ id: 'settings',
111
+ title: 'Settings',
112
+ items: [
113
+ {
114
+ id: 'profile',
115
+ label: 'Profile Settings',
116
+ icon: <Settings size={16} />,
117
+ onSelect: () => console.log('Opening Profile Settings')
118
+ },
119
+ {
120
+ id: 'notifications',
121
+ label: 'Notifications',
122
+ icon: <Bell size={16} />,
123
+ onSelect: () => console.log('Opening Notifications')
124
+ },
125
+ {
126
+ id: 'security',
127
+ label: 'Security & Privacy',
128
+ icon: <Shield size={16} />,
129
+ onSelect: () => console.log('Opening Security Settings')
130
+ },
131
+ {
132
+ id: 'help',
133
+ label: 'Help & Support',
134
+ icon: <HelpCircle size={16} />,
135
+ onSelect: () => console.log('Opening Help')
136
+ }
137
+ ]
138
+ },
139
+ {
140
+ id: 'theme',
141
+ title: 'Theme',
142
+ items: [
143
+ {
144
+ id: 'light-theme',
145
+ label: 'Light Theme',
146
+ icon: <Sun size={16} />,
147
+ onSelect: () => console.log('Switched to Light Theme')
148
+ },
149
+ {
150
+ id: 'dark-theme',
151
+ label: 'Dark Theme',
152
+ icon: <Moon size={16} />,
153
+ onSelect: () => console.log('Switched to Dark Theme')
154
+ }
155
+ ]
156
+ }
157
+ ];
158
+
159
+ const basicPages = [
160
+ {
161
+ id: 'root',
162
+ items: [
163
+ {
164
+ id: 'calendar',
165
+ label: 'Calendar',
166
+ icon: <Calendar size={16} />,
167
+ shortcut: '⌘K',
168
+ onSelect: () => console.log('Calendar selected')
169
+ },
170
+ {
171
+ id: 'emoji',
172
+ label: 'Search Emoji',
173
+ icon: <Search size={16} />,
174
+ onSelect: () => console.log('Emoji search selected')
175
+ },
176
+ {
177
+ id: 'calculator',
178
+ label: 'Calculator',
179
+ icon: <Calculator size={16} />,
180
+ onSelect: () => console.log('Calculator selected')
181
+ }
182
+ ]
183
+ }
184
+ ];
185
+
186
+ const themePages = [
187
+ {
188
+ id: 'main',
189
+ title: 'Quick Actions',
190
+ items: [
191
+ {
192
+ id: 'theme-settings',
193
+ label: 'Change theme...',
194
+ icon: <Palette size={16} />,
195
+ navigateTo: 'themes'
196
+ },
197
+ {
198
+ id: 'home',
199
+ label: 'Go to Dashboard',
200
+ icon: <Home size={16} />,
201
+ shortcut: '⌘H',
202
+ onSelect: () => console.log('Going to Dashboard')
203
+ }
204
+ ]
205
+ },
206
+ {
207
+ id: 'themes',
208
+ title: 'Available Themes',
209
+ items: [
210
+ {
211
+ id: 'light',
212
+ label: 'Light theme',
213
+ icon: <Sun size={16} />,
214
+ onSelect: () => console.log('Light theme selected')
215
+ },
216
+ {
217
+ id: 'dark',
218
+ label: 'Dark theme',
219
+ icon: <Moon size={16} />,
220
+ onSelect: () => console.log('Dark theme selected')
221
+ }
222
+ ]
223
+ }
224
+ ]
225
+ <div className="max-w-4xl mx-auto p-6 space-y-8 bg-background text-foreground">
226
+ <div className="text-center">
227
+ <h1 className="text-3xl font-bold mb-2">NestedCommandDialog Component</h1>
228
+ <p className="text-muted-foreground">A command palette with nested navigation support</p>
229
+ </div>
230
+
231
+ <div className="space-y-6">
232
+ <div className="space-y-4">
233
+ <h2 className="text-xl font-semibold">Complex Nested Command</h2>
234
+ <p className="text-sm text-muted-foreground">
235
+ Navigate through multiple levels: Projects, Teams, Settings, and Theme selection
236
+ </p>
237
+ <Button onClick={() => setOpen(true)} variant="outline">
238
+ Open Complex Command
239
+ <CommandShortcut>⌘K</CommandShortcut>
240
+ </Button>
241
+ </div>
242
+
243
+ <div className="space-y-4">
244
+ <h2 className="text-xl font-semibold">Basic Command (No Nesting)</h2>
245
+ <p className="text-sm text-muted-foreground">
246
+ Simple command palette without navigation
247
+ </p>
248
+ <Button onClick={() => setBasicOpen(true)} variant="outline">
249
+ Open Basic Command
250
+ </Button>
251
+ </div>
252
+
253
+ <div className="space-y-4">
254
+ <h2 className="text-xl font-semibold">Theme Selector Example</h2>
255
+ <p className="text-sm text-muted-foreground">
256
+ Example showing theme selection with navigation (like the original pattern)
257
+ </p>
258
+ <Button onClick={() => setThemeOpen(true)} variant="outline">
259
+ Open Theme Command
260
+ </Button>
261
+ </div>
262
+
263
+ <div className="space-y-4">
264
+ <h2 className="text-xl font-semibold">Navigation Instructions</h2>
265
+ <div className="text-sm text-muted-foreground space-y-1">
266
+ <p><kbd className="px-1 py-0.5 bg-muted rounded text-xs">Escape</kbd> - Go back or close</p>
267
+ <p><kbd className="px-1 py-0.5 bg-muted rounded text-xs">Backspace</kbd> - Go back when search is empty</p>
268
+ <p><kbd className="px-1 py-0.5 bg-muted rounded text-xs">Enter</kbd> - Select item or navigate deeper</p>
269
+ <p><kbd className="px-1 py-0.5 bg-muted rounded text-xs">↑↓</kbd> - Navigate items</p>
270
+ </div>
271
+ </div>
272
+ </div>
273
+
274
+ <NestedCommandDialog
275
+ open={open}
276
+ onOpenChange={setOpen}
277
+ pages={commandPages}
278
+ placeholder="Type a command or search..."
279
+ onItemSelect={(item, pageId) => {
280
+ console.log'Selected $ {item.label} from page $ {pageId}');
281
+ }}
282
+ />
283
+
284
+ <NestedCommandDialog
285
+ open={basicOpen}
286
+ onOpenChange={setBasicOpen}
287
+ pages={basicPages}
288
+ placeholder="Search commands..."
289
+ defaultPage="root"
290
+ />
291
+
292
+ <NestedCommandDialog
293
+ open={themeOpen}
294
+ onOpenChange={setThemeOpen}
295
+ pages={themePages}
296
+ placeholder="Search theme options..."
297
+ onItemSelect={(item, pageId) => {
298
+ console.log('Theme action: $ {item.label} from $ {pageId}');
299
+ }}
300
+ />
301
+ </div>`,
302
+ usagePath: "/components/catalyst-ui/commands/nested-command.tsx",
303
+ props: {
304
+ "NestedCommandDialog": [
305
+ { name: "open", type: "boolean", default: "false", required: false },
306
+ { name: "onOpenChange", type: "(open: boolean) => void", default: "null", required: false },
307
+ { name: "placeholder", type: "string", default: "Type a command or search...", required: false },
308
+ { name: "emptyMessage", type: "string", default: "No results found.", required: false },
309
+ { name: "pages", type: "CommandPage[]", default: "null", required: true },
310
+ { name: "className", type: "string", default: "null", required: false },
311
+ { name: "defaultPage", type: "string", default: "null", required: false },
312
+ { name: "onItemSelect", type: "(item: CommandItemData, pageId: string) => void", default: "null", required: false },
313
+ ],
314
+ },
315
+ desc: null,
316
+ customize: null
317
+ },
318
+ {
319
+ name: "nested command",
320
+ value: "nested-command",
321
+ importPath: "~/components/catalyst-ui/commands/nested-command",
322
+ path: "/components/catalyst-ui/commands/nested-command.tsx",
323
+ premium: true,
324
+ source: null,
325
+ category: "Commands",
326
+ tags: ["utils", "auth", "user auth"],
327
+ features: ["utils", "auth", "user auth"],
328
+ dependencies: [],
329
+ basicusage: `
330
+
331
+
332
+ const commandPages = [
333
+ {
334
+ id: 'main',
335
+ title: 'Actions',
336
+ items: [
337
+ {
338
+ id: 'search-projects',
339
+ label: 'Search projects...',
340
+ icon: <FolderOpen size={16} />,
341
+ navigateTo: 'projects',
342
+ shortcut: '⌘P'
343
+ },
344
+ {
345
+ id: 'join-team',
346
+ label: 'Join a team...',
347
+ icon: <Users size={16} />,
348
+ navigateTo: 'teams',
349
+ shortcut: '⌘T'
350
+ },
351
+ {
352
+ id: 'settings',
353
+ label: 'Settings...',
354
+ icon: <Settings size={16} />,
355
+ navigateTo: 'settings',
356
+ shortcut: '⌘,'
357
+ },
358
+ {
359
+ id: 'theme',
360
+ label: 'Change theme...',
361
+ icon: <Palette size={16} />,
362
+ navigateTo: 'theme',
363
+ }
364
+ ]
365
+ },
366
+ {
367
+ id: 'projects',
368
+ title: 'Projects',
369
+ items: [
370
+ {
371
+ id: 'project-a',
372
+ label: 'Project Alpha',
373
+ icon: <FolderOpen size={16} />,
374
+ value: 'React application with TypeScript',
375
+ onSelect: () => console.log('Selected Project Alpha')
376
+ },
377
+ {
378
+ id: 'project-b',
379
+ label: 'Project Beta',
380
+ icon: <FolderOpen size={16} />,
381
+ value: 'Vue.js dashboard application',
382
+ onSelect: () => console.log('Selected Project Beta')
383
+ },
384
+ {
385
+ id: 'project-c',
386
+ label: 'Project Gamma',
387
+ icon: <FolderOpen size={16} />,
388
+ value: 'Next.js e-commerce site',
389
+ onSelect: () => console.log('Selected Project Gamma')
390
+ }
391
+ ]
392
+ },
393
+ {
394
+ id: 'teams',
395
+ title: 'Teams',
396
+ items: [
397
+ {
398
+ id: 'team-1',
399
+ label: 'Frontend Team',
400
+ icon: <Users size={16} />,
401
+ value: '12 members • Active',
402
+ onSelect: () => console.log('Joined Frontend Team')
403
+ },
404
+ {
405
+ id: 'team-2',
406
+ label: 'Backend Team',
407
+ icon: <Users size={16} />,
408
+ value: '8 members • Active',
409
+ onSelect: () => console.log('Joined Backend Team')
410
+ },
411
+ {
412
+ id: 'team-3',
413
+ label: 'Design Team',
414
+ icon: <Users size={16} />,
415
+ value: '6 members • Active',
416
+ onSelect: () => console.log('Joined Design Team')
417
+ }
418
+ ]
419
+ },
420
+ {
421
+ id: 'settings',
422
+ title: 'Settings',
423
+ items: [
424
+ {
425
+ id: 'profile',
426
+ label: 'Profile Settings',
427
+ icon: <Settings size={16} />,
428
+ onSelect: () => console.log('Opening Profile Settings')
429
+ },
430
+ {
431
+ id: 'notifications',
432
+ label: 'Notifications',
433
+ icon: <Bell size={16} />,
434
+ onSelect: () => console.log('Opening Notifications')
435
+ },
436
+ {
437
+ id: 'security',
438
+ label: 'Security & Privacy',
439
+ icon: <Shield size={16} />,
440
+ onSelect: () => console.log('Opening Security Settings')
441
+ },
442
+ {
443
+ id: 'help',
444
+ label: 'Help & Support',
445
+ icon: <HelpCircle size={16} />,
446
+ onSelect: () => console.log('Opening Help')
447
+ }
448
+ ]
449
+ },
450
+ {
451
+ id: 'theme',
452
+ title: 'Theme',
453
+ items: [
454
+ {
455
+ id: 'light-theme',
456
+ label: 'Light Theme',
457
+ icon: <Sun size={16} />,
458
+ onSelect: () => console.log('Switched to Light Theme')
459
+ },
460
+ {
461
+ id: 'dark-theme',
462
+ label: 'Dark Theme',
463
+ icon: <Moon size={16} />,
464
+ onSelect: () => console.log('Switched to Dark Theme')
465
+ }
466
+ ]
467
+ }
468
+ ];
469
+
470
+ const basicPages = [
471
+ {
472
+ id: 'root',
473
+ items: [
474
+ {
475
+ id: 'calendar',
476
+ label: 'Calendar',
477
+ icon: <Calendar size={16} />,
478
+ shortcut: '⌘K',
479
+ onSelect: () => console.log('Calendar selected')
480
+ },
481
+ {
482
+ id: 'emoji',
483
+ label: 'Search Emoji',
484
+ icon: <Search size={16} />,
485
+ onSelect: () => console.log('Emoji search selected')
486
+ },
487
+ {
488
+ id: 'calculator',
489
+ label: 'Calculator',
490
+ icon: <Calculator size={16} />,
491
+ onSelect: () => console.log('Calculator selected')
492
+ }
493
+ ]
494
+ }
495
+ ];
496
+
497
+ const themePages = [
498
+ {
499
+ id: 'main',
500
+ title: 'Quick Actions',
501
+ items: [
502
+ {
503
+ id: 'theme-settings',
504
+ label: 'Change theme...',
505
+ icon: <Palette size={16} />,
506
+ navigateTo: 'themes'
507
+ },
508
+ {
509
+ id: 'home',
510
+ label: 'Go to Dashboard',
511
+ icon: <Home size={16} />,
512
+ shortcut: '⌘H',
513
+ onSelect: () => console.log('Going to Dashboard')
514
+ }
515
+ ]
516
+ },
517
+ {
518
+ id: 'themes',
519
+ title: 'Available Themes',
520
+ items: [
521
+ {
522
+ id: 'light',
523
+ label: 'Light theme',
524
+ icon: <Sun size={16} />,
525
+ onSelect: () => console.log('Light theme selected')
526
+ },
527
+ {
528
+ id: 'dark',
529
+ label: 'Dark theme',
530
+ icon: <Moon size={16} />,
531
+ onSelect: () => console.log('Dark theme selected')
532
+ }
533
+ ]
534
+ }
535
+ ]
536
+ <NestedCommand
537
+ pages={commandPages}
538
+ placeholder="Search..."
539
+ onItemSelect={(item, pageId) => {
540
+ console.log('Selected $ {item.label} from page $ {pageId}');
541
+ }}
542
+ />
543
+ <NestedCommand
544
+ pages={basicPages}
545
+ placeholder="Search..."
546
+ defaultPage="root"
547
+ />
548
+ <NestedCommand
549
+ pages={themePages}
550
+ placeholder="Search theme options..."
551
+ onItemSelect={(item, pageId) => {
552
+ console.log('Theme action: $ {item.label} from $ {pageId}');
553
+ }}
554
+ />`,
555
+ usage: `
556
+ export function NestedCommandDemo() {
557
+ const [open, setOpen] = useState(false);
558
+ const [basicOpen, setBasicOpen] = useState(false);
559
+ const [themeOpen, setThemeOpen] = useState(false);
560
+
561
+ const commandPages: CommandPage[] = [
562
+ {
563
+ id: 'main',
564
+ title: 'Actions',
565
+ items: [
566
+ {
567
+ id: 'search-projects',
568
+ label: 'Search projects...',
569
+ icon: <FolderOpen size={16} />,
570
+ navigateTo: 'projects',
571
+ shortcut: '⌘P'
572
+ },
573
+ {
574
+ id: 'join-team',
575
+ label: 'Join a team...',
576
+ icon: <Users size={16} />,
577
+ navigateTo: 'teams',
578
+ shortcut: '⌘T'
579
+ },
580
+ {
581
+ id: 'settings',
582
+ label: 'Settings...',
583
+ icon: <Settings size={16} />,
584
+ navigateTo: 'settings',
585
+ shortcut: '⌘,'
586
+ },
587
+ {
588
+ id: 'theme',
589
+ label: 'Change theme...',
590
+ icon: <Palette size={16} />,
591
+ navigateTo: 'theme',
592
+ }
593
+ ]
594
+ },
595
+ {
596
+ id: 'projects',
597
+ title: 'Projects',
598
+ items: [
599
+ {
600
+ id: 'project-a',
601
+ label: 'Project Alpha',
602
+ icon: <FolderOpen size={16} />,
603
+ value: 'React application with TypeScript',
604
+ onSelect: () => console.log('Selected Project Alpha')
605
+ },
606
+ {
607
+ id: 'project-b',
608
+ label: 'Project Beta',
609
+ icon: <FolderOpen size={16} />,
610
+ value: 'Vue.js dashboard application',
611
+ onSelect: () => console.log('Selected Project Beta')
612
+ },
613
+ {
614
+ id: 'project-c',
615
+ label: 'Project Gamma',
616
+ icon: <FolderOpen size={16} />,
617
+ value: 'Next.js e-commerce site',
618
+ onSelect: () => console.log('Selected Project Gamma')
619
+ }
620
+ ]
621
+ },
622
+ {
623
+ id: 'teams',
624
+ title: 'Teams',
625
+ items: [
626
+ {
627
+ id: 'team-1',
628
+ label: 'Frontend Team',
629
+ icon: <Users size={16} />,
630
+ value: '12 members • Active',
631
+ onSelect: () => console.log('Joined Frontend Team')
632
+ },
633
+ {
634
+ id: 'team-2',
635
+ label: 'Backend Team',
636
+ icon: <Users size={16} />,
637
+ value: '8 members • Active',
638
+ onSelect: () => console.log('Joined Backend Team')
639
+ },
640
+ {
641
+ id: 'team-3',
642
+ label: 'Design Team',
643
+ icon: <Users size={16} />,
644
+ value: '6 members • Active',
645
+ onSelect: () => console.log('Joined Design Team')
646
+ }
647
+ ]
648
+ },
649
+ {
650
+ id: 'settings',
651
+ title: 'Settings',
652
+ items: [
653
+ {
654
+ id: 'profile',
655
+ label: 'Profile Settings',
656
+ icon: <Settings size={16} />,
657
+ onSelect: () => console.log('Opening Profile Settings')
658
+ },
659
+ {
660
+ id: 'notifications',
661
+ label: 'Notifications',
662
+ icon: <Bell size={16} />,
663
+ onSelect: () => console.log('Opening Notifications')
664
+ },
665
+ {
666
+ id: 'security',
667
+ label: 'Security & Privacy',
668
+ icon: <Shield size={16} />,
669
+ onSelect: () => console.log('Opening Security Settings')
670
+ },
671
+ {
672
+ id: 'help',
673
+ label: 'Help & Support',
674
+ icon: <HelpCircle size={16} />,
675
+ onSelect: () => console.log('Opening Help')
676
+ }
677
+ ]
678
+ },
679
+ {
680
+ id: 'theme',
681
+ title: 'Theme',
682
+ items: [
683
+ {
684
+ id: 'light-theme',
685
+ label: 'Light Theme',
686
+ icon: <Sun size={16} />,
687
+ onSelect: () => console.log('Switched to Light Theme')
688
+ },
689
+ {
690
+ id: 'dark-theme',
691
+ label: 'Dark Theme',
692
+ icon: <Moon size={16} />,
693
+ onSelect: () => console.log('Switched to Dark Theme')
694
+ }
695
+ ]
696
+ }
697
+ ];
698
+
699
+ const basicPages: CommandPage[] = [
700
+ {
701
+ id: 'root',
702
+ items: [
703
+ {
704
+ id: 'calendar',
705
+ label: 'Calendar',
706
+ icon: <Calendar size={16} />,
707
+ shortcut: '⌘K',
708
+ onSelect: () => console.log('Calendar selected')
709
+ },
710
+ {
711
+ id: 'emoji',
712
+ label: 'Search Emoji',
713
+ icon: <Search size={16} />,
714
+ onSelect: () => console.log('Emoji search selected')
715
+ },
716
+ {
717
+ id: 'calculator',
718
+ label: 'Calculator',
719
+ icon: <Calculator size={16} />,
720
+ onSelect: () => console.log('Calculator selected')
721
+ }
722
+ ]
723
+ }
724
+ ];
725
+
726
+ const themePages: CommandPage[] = [
727
+ {
728
+ id: 'main',
729
+ title: 'Quick Actions',
730
+ items: [
731
+ {
732
+ id: 'theme-settings',
733
+ label: 'Change theme...',
734
+ icon: <Palette size={16} />,
735
+ navigateTo: 'themes'
736
+ },
737
+ {
738
+ id: 'home',
739
+ label: 'Go to Dashboard',
740
+ icon: <Home size={16} />,
741
+ shortcut: '⌘H',
742
+ onSelect: () => console.log('Going to Dashboard')
743
+ }
744
+ ]
745
+ },
746
+ {
747
+ id: 'themes',
748
+ title: 'Available Themes',
749
+ items: [
750
+ {
751
+ id: 'light',
752
+ label: 'Light theme',
753
+ icon: <Sun size={16} />,
754
+ onSelect: () => console.log('Light theme selected')
755
+ },
756
+ {
757
+ id: 'dark',
758
+ label: 'Dark theme',
759
+ icon: <Moon size={16} />,
760
+ onSelect: () => console.log('Dark theme selected')
761
+ }
762
+ ]
763
+ }
764
+ ];
765
+
766
+ return (
767
+ <div className="max-w-4xl mx-auto p-6 space-y-8 bg-background text-foreground">
768
+ <div className="text-center">
769
+ <h1 className="text-3xl font-bold mb-2">NestedCommand Component</h1>
770
+ <p className="text-muted-foreground">A command palette with nested navigation support</p>
771
+ </div>
772
+
773
+ <div className="space-y-6">
774
+ <div className="space-y-4">
775
+ <h2 className="text-xl font-semibold">Complex Nested Command</h2>
776
+ <p className="text-sm text-muted-foreground">
777
+ Navigate through multiple levels: Projects, Teams, Settings, and Theme selection
778
+ </p>
779
+ <NestedCommand
780
+ pages={commandPages}
781
+ placeholder="Search..."
782
+ onItemSelect={(item, pageId) => {
783
+ }}
784
+ />
785
+ </div>
786
+
787
+ <div className="space-y-4">
788
+ <h2 className="text-xl font-semibold">Basic Command (No Nesting)</h2>
789
+ <p className="text-sm text-muted-foreground">
790
+ Simple command palette without navigation
791
+ </p>
792
+ <NestedCommand
793
+ pages={basicPages}
794
+ placeholder="Search..."
795
+ defaultPage="root"
796
+ />
797
+ </div>
798
+
799
+ <div className="space-y-4">
800
+ <h2 className="text-xl font-semibold">Theme Selector Example</h2>
801
+ <p className="text-sm text-muted-foreground">
802
+ Example showing theme selection with navigation (like the original pattern)
803
+ </p>
804
+ <NestedCommand
805
+ pages={themePages}
806
+ placeholder="Search theme options..."
807
+ onItemSelect={(item, pageId) => {
808
+ }}
809
+ />
810
+ </div>
811
+
812
+ <div className="space-y-4">
813
+ <h2 className="text-xl font-semibold">Navigation Instructions</h2>
814
+ <div className="text-sm text-muted-foreground space-y-1">
815
+ <p><kbd className="px-1 py-0.5 bg-muted rounded text-xs">Escape</kbd> - Go back or close</p>
816
+ <p><kbd className="px-1 py-0.5 bg-muted rounded text-xs">Backspace</kbd> - Go back when search is empty</p>
817
+ <p><kbd className="px-1 py-0.5 bg-muted rounded text-xs">Enter</kbd> - Select item or navigate deeper</p>
818
+ <p><kbd className="px-1 py-0.5 bg-muted rounded text-xs">↑↓</kbd> - Navigate items</p>
819
+ </div>
820
+ </div>
821
+ </div>
822
+ </div>
823
+ );
824
+ }`,
825
+ usagePath: null,
826
+ props: {
827
+ "NestedCommand": [
828
+ { name: "placeholder", type: "string", default: "Search...", required: false },
829
+ { name: "emptyMessage", type: "string", default: "No results found.", required: false },
830
+ { name: "pages", type: "CommandPage[]", default: "null", required: true },
831
+ { name: "className", type: "string", default: "null", required: false },
832
+ { name: "defaultPage", type: "string", default: "null", required: false },
833
+ { name: "MHList", type: "string", default: "max-h-[575px]", required: false },
834
+ { name: "onItemSelect", type: "(item: CommandItemData, pageId: string) => void", default: "null", required: false },
835
+ ],
836
+ },
837
+ desc: null,
838
+ customize: null
839
+ },
840
+ {
841
+ name: "Command V2",
842
+ value: "command-2",
843
+ importPath: "~/components/catalyst-ui/commands/command-2",
844
+ multiImport: null,
845
+ basicusage: `
846
+ const items = [
847
+ {
848
+ id: "1",
849
+ label: "Profile",
850
+ value: "profile",
851
+ icon: <Search className="h-4 w-4" />,
852
+ shortcut: "⌘P",
853
+ group: "Settings"
854
+ },
855
+ ];
856
+
857
+ <CommandV2
858
+ items={items}
859
+ onItemSelect={(item) => console.log(item)}
860
+ placeholder="Search..." // not req
861
+ className="" // not req
862
+ maxHeight="max-h-[400px]" // not req
863
+ />`,
864
+ path: "/components/catalyst-ui/commands/command-2.tsx",
865
+ source: null,
866
+ usagePath: "/components/catalyst-ui/commands/command-2.tsx",
867
+ usage: null,
868
+ premium: true,
869
+ category: "Commands",
870
+ tags: ["command", "search", "dialog", "navigation"],
871
+ features: ["Responsive", "TypeScript", "Accessible", "Keyboard Navigation"],
872
+ dependencies: ["lucide-react", "react"],
873
+ props: {
874
+ "Command": [
875
+ { name: "variant", type: "'default' | 'framer' | 'linear' | 'raycast' | 'vercel' | 'search'", default: "'default'" },
876
+ { name: "className", type: "string", default: "undefined" },
877
+ { name: "label", type: "string", default: "undefined", description: "Accessible label for the command menu" },
878
+ { name: "shouldFilter", type: "boolean", default: "true", description: "Enable/disable built-in filtering" },
879
+ { name: "filter", type: "(value: string, search: string, keywords?: string[]) => number", default: "undefined", description: "Custom filter function" },
880
+ { name: "defaultValue", type: "string", default: "undefined", description: "Default selected item value" },
881
+ { name: "value", type: "string", default: "undefined", description: "Controlled selected item value" },
882
+ { name: "onValueChange", type: "(value: string) => void", default: "undefined", description: "Callback when selected value changes" },
883
+ { name: "loop", type: "boolean", default: "false", description: "Enable keyboard navigation loop" },
884
+ { name: "disablePointerSelection", type: "boolean", default: "false", description: "Disable pointer-based selection" },
885
+ { name: "vimBindings", type: "boolean", default: "true", description: "Enable vim-style keyboard bindings" },
886
+ { name: "...props", type: "React.ComponentPropsWithoutRef<typeof CommandPrimitive>", default: "undefined" },
887
+ ],
888
+ "CommandInput": [
889
+ { name: "placeholder", type: "string", default: "'Search...'" },
890
+ { name: "className", type: "string", default: "undefined" },
891
+ { name: "value", type: "string", default: "undefined", description: "Controlled input value" },
892
+ { name: "onValueChange", type: "(search: string) => void", default: "undefined", description: "Callback when input value changes" },
893
+ { name: "...props", type: "React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>", default: "undefined" },
894
+ ],
895
+ "CommandList": [
896
+ { name: "MHList", type: "string", default: "'max-h-[700px]'" },
897
+ { name: "className", type: "string", default: "undefined" },
898
+ { name: "label", type: "string", default: "undefined", description: "Accessible label for the list" },
899
+ { name: "...props", type: "React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>", default: "undefined" },
900
+ ],
901
+ "CommandEmpty": [
902
+ { name: "className", type: "string", default: "undefined" },
903
+ { name: "children", type: "React.ReactNode", default: "undefined", description: "Content to show when no results" },
904
+ { name: "...props", type: "React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>", default: "undefined" },
905
+ ],
906
+ "CommandGroup": [
907
+ { name: "className", type: "string", default: "undefined" },
908
+ { name: "heading", type: "string", default: "undefined", description: "Group heading text" },
909
+ { name: "value", type: "string", default: "undefined", description: "Optional value for the group" },
910
+ { name: "forceMount", type: "boolean", default: "undefined", description: "Force mount the group even when empty" },
911
+ { name: "...props", type: "React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>", default: "undefined" },
912
+ ],
913
+ "CommandItem": [
914
+ { name: "className", type: "string", default: "undefined" },
915
+ { name: "value", type: "string", default: "undefined", description: "Value for filtering and selection" },
916
+ { name: "keywords", type: "string[]", default: "undefined", description: "Additional keywords for filtering" },
917
+ { name: "onSelect", type: "(value: string) => void", default: "undefined", description: "Callback when item is selected" },
918
+ { name: "disabled", type: "boolean", default: "false", description: "Disable the item" },
919
+ { name: "forceMount", type: "boolean", default: "undefined", description: "Force mount the item" },
920
+ { name: "...props", type: "React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>", default: "undefined" },
921
+ ],
922
+ "CommandShortcut": [
923
+ { name: "className", type: "string", default: "undefined" },
924
+ { name: "...props", type: "React.HTMLAttributes<HTMLSpanElement>", default: "undefined" },
925
+ ],
926
+ "CommandSeparator": [
927
+ { name: "className", type: "string", default: "undefined" },
928
+ { name: "alwaysRender", type: "boolean", default: "false", description: "Render separator even when adjacent to hidden items" },
929
+ { name: "...props", type: "React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>", default: "undefined" },
930
+ ],
931
+ "CommandDialog": [
932
+ { name: "variant", type: "'default' | 'framer' | 'linear' | 'raycast' | 'vercel' | 'search'", default: "'default'" },
933
+ { name: "buttonChildren", type: "React.ReactNode", default: "undefined" },
934
+ { name: "children", type: "React.ReactNode", default: "undefined" },
935
+ { name: "open", type: "boolean", default: "undefined", description: "Controlled open state" },
936
+ { name: "onOpenChange", type: "(open: boolean) => void", default: "undefined", description: "Callback when open state changes" },
937
+ { name: "...props", type: "React.ComponentProps<typeof Dialog>", default: "undefined" },
938
+ ],
939
+ "CommandDialogButton": [
940
+ { name: "variant", type: "string", default: "'outline'" },
941
+ { name: "setOpen", type: "(open: boolean) => void", default: "undefined" },
942
+ { name: "buttonChildren", type: "React.ReactNode", default: "undefined" },
943
+ { name: "...buttonProps", type: "any", default: "undefined" },
944
+ ],
945
+ "CommandDialogCustom": [
946
+ { name: "variant", type: "'default' | 'framer' | 'linear' | 'raycast' | 'vercel' | 'search'", default: "'default'" },
947
+ { name: "children", type: "React.ReactNode", default: "undefined" },
948
+ { name: "open", type: "boolean", default: "undefined", description: "Controlled open state" },
949
+ { name: "onOpenChange", type: "(open: boolean) => void", default: "undefined", description: "Callback when open state changes" },
950
+ { name: "...props", type: "any", default: "undefined" },
951
+ ],
952
+ "NestedCommand": [
953
+ { name: "variant", type: "'default' | 'framer' | 'linear' | 'raycast' | 'vercel' | 'search'", default: "'default'" },
954
+ { name: "open", type: "boolean", default: "undefined" },
955
+ { name: "onOpenChange", type: "(open: boolean) => void", default: "undefined" },
956
+ { name: "placeholder", type: "string", default: "'Search...'" },
957
+ { name: "emptyMessage", type: "string", default: "'No results found.'" },
958
+ { name: "pages", type: "CommandPage[]", default: "required" },
959
+ { name: "className", type: "string", default: "undefined" },
960
+ { name: "defaultPage", type: "string", default: "undefined" },
961
+ { name: "MHList", type: "string", default: "'max-h-[700px]'" },
962
+ { name: "onItemSelect", type: "(item: CommandItemData, pageId: string) => void", default: "undefined" },
963
+ ],
964
+ },
965
+ desc: null,
966
+ status: null,
967
+ lastUpdated: null
968
+ },
969
+ {
970
+ name: "nested command-dialog",
971
+ value: "nested-command-dialog",
972
+ importPath: "~/components/catalyst-ui/commands/nested-command-dialog",
973
+ path: "/components/catalyst-ui/components/overlay/nested-command-dialog.tsx",
974
+ premium: true,
975
+ source: `
976
+
977
+
978
+
979
+
980
+
981
+
982
+ interface CommandItemData {
983
+ id: string;
984
+ label: string;
985
+ value?: string;
986
+ icon?: React.ReactNode;
987
+ onSelect?: () => void;
988
+ navigateTo?: string;
989
+ shortcut?: string;
990
+ disabled?: boolean;
991
+ }
992
+
993
+ interface CommandPage {
994
+ id: string;
995
+ title?: string;
996
+ items: CommandItemData[];
997
+ backLabel?: string;
998
+ }
999
+
1000
+ interface NestedCommandProps {
1001
+ open?: boolean;
1002
+ onOpenChange?: (open: boolean) => void;
1003
+ placeholder?: string;
1004
+ emptyMessage?: string;
1005
+ pages: CommandPage[];
1006
+ className?: string;
1007
+ defaultPage?: string;
1008
+ onItemSelect?: (item: CommandItemData, pageId: string) => void;
1009
+ }
1010
+
1011
+ export function NestedCommandDialog({
1012
+ open = false,
1013
+ onOpenChange,
1014
+ placeholder = "Type a command or search...",
1015
+ emptyMessage = "No results found.",
1016
+ pages,
1017
+ className,
1018
+ defaultPage,
1019
+ onItemSelect,
1020
+ }: NestedCommandProps) {
1021
+ const [search, setSearch] = useState('');
1022
+ const [pageStack, setPageStack] = useState<string[]>(defaultPage ? [defaultPage] : []);
1023
+ const ref = useRef(null);
1024
+
1025
+ const currentPage = pageStack.length > 0 ? pages.find(p => p.id === pageStack[pageStack.length - 1]) : null;
1026
+ const isRootPage = pageStack.length === 0;
1027
+
1028
+ const handleKeyDown = (e: React.KeyboardEvent) => {
1029
+ if (e.key === 'Escape' || (e.key === 'Backspace' && !search)) {
1030
+ e.preventDefault();
1031
+ if (pageStack.length > 0) {
1032
+ setPageStack(pages => pages.slice(0, -1));
1033
+ }
1034
+ }
1035
+ };
1036
+
1037
+ const handleItemSelect = (item: CommandItemData) => {
1038
+ if (item.disabled) return;
1039
+
1040
+ if (item.navigateTo) {
1041
+ const targetPage = pages.find(p => p.id === item.navigateTo);
1042
+ if (targetPage) {
1043
+ setPageStack(prev => [...prev, item.navigateTo!]);
1044
+ setSearch('');
1045
+ }
1046
+ } else {
1047
+ item.onSelect?.();
1048
+ const pageId = currentPage?.id || (isRootPage ? 'root' : '');
1049
+ onItemSelect?.(item, pageId);
1050
+ if (onOpenChange) {
1051
+ onOpenChange(false);
1052
+ }
1053
+ }
1054
+ };
1055
+
1056
+ const renderItems = () => {
1057
+ if (!currentPage && isRootPage) {
1058
+ return pages.map(page => (
1059
+ <CommandGroup key={page.id} heading={page.title}>
1060
+ {page.items.map((item) => (
1061
+ <CommandItem
1062
+ key={item.id}
1063
+ onSelect={() => handleItemSelect(item)}
1064
+ disabled={item.disabled}
1065
+ className="flex items-center gap-2"
1066
+ >
1067
+ {item.icon}
1068
+ <span className="flex-1">{item.label}</span>
1069
+ {item.navigateTo && <ChevronRight size={14} className="text-muted-foreground" />}
1070
+ {item.shortcut && <CommandShortcut>{item.shortcut}</CommandShortcut>}
1071
+ </CommandItem>
1072
+ ))}
1073
+ </CommandGroup>
1074
+ ));
1075
+ }
1076
+
1077
+ if (!currentPage) return null;
1078
+
1079
+ return (
1080
+ <CommandGroup heading={currentPage.title}>
1081
+ {currentPage.items.map((item) => (
1082
+ <CommandItem
1083
+ key={item.id}
1084
+ onSelect={() => handleItemSelect(item)}
1085
+ disabled={item.disabled}
1086
+ className="flex items-center gap-2"
1087
+ >
1088
+ {item.icon}
1089
+ <span className="flex-1">{item.label}</span>
1090
+ {item.navigateTo && <ChevronRight size={14} className="text-muted-foreground" />}
1091
+ {item.shortcut && <CommandShortcut>{item.shortcut}</CommandShortcut>}
1092
+ </CommandItem>
1093
+ ))}
1094
+ </CommandGroup>
1095
+ );
1096
+ };
1097
+
1098
+ return (
1099
+ <CommandDialogCustom open={open} onOpenChange={onOpenChange}>
1100
+ <Command ref={ref} onKeyDown={handleKeyDown} className={className}>
1101
+ <CommandInput
1102
+ placeholder={placeholder}
1103
+ value={search}
1104
+ onValueChange={setSearch}
1105
+ />
1106
+ <CommandList>
1107
+ <CommandEmpty>{emptyMessage}</CommandEmpty>
1108
+ {renderItems()}
1109
+ </CommandList>
1110
+ </Command>
1111
+ </CommandDialogCustom>
1112
+ );
1113
+ }`,
1114
+ usage: `
1115
+ const [open, setOpen] = useState(false);
1116
+ const [basicOpen, setBasicOpen] = useState(false);
1117
+ const [themeOpen, setThemeOpen] = useState(false);
1118
+
1119
+ const commandPages = [
1120
+ {
1121
+ id: 'main',
1122
+ title: 'Actions',
1123
+ items: [
1124
+ {
1125
+ id: 'search-projects',
1126
+ label: 'Search projects...',
1127
+ icon: <FolderOpen size={16} />,
1128
+ navigateTo: 'projects',
1129
+ shortcut: '⌘P'
1130
+ },
1131
+ {
1132
+ id: 'join-team',
1133
+ label: 'Join a team...',
1134
+ icon: <Users size={16} />,
1135
+ navigateTo: 'teams',
1136
+ shortcut: '⌘T'
1137
+ },
1138
+ {
1139
+ id: 'settings',
1140
+ label: 'Settings...',
1141
+ icon: <Settings size={16} />,
1142
+ navigateTo: 'settings',
1143
+ shortcut: '⌘,'
1144
+ },
1145
+ {
1146
+ id: 'theme',
1147
+ label: 'Change theme...',
1148
+ icon: <Palette size={16} />,
1149
+ navigateTo: 'theme',
1150
+ }
1151
+ ]
1152
+ },
1153
+ {
1154
+ id: 'projects',
1155
+ title: 'Projects',
1156
+ items: [
1157
+ {
1158
+ id: 'project-a',
1159
+ label: 'Project Alpha',
1160
+ icon: <FolderOpen size={16} />,
1161
+ value: 'React application with TypeScript',
1162
+ onSelect: () => console.log('Selected Project Alpha')
1163
+ },
1164
+ {
1165
+ id: 'project-b',
1166
+ label: 'Project Beta',
1167
+ icon: <FolderOpen size={16} />,
1168
+ value: 'Vue.js dashboard application',
1169
+ onSelect: () => console.log('Selected Project Beta')
1170
+ },
1171
+ {
1172
+ id: 'project-c',
1173
+ label: 'Project Gamma',
1174
+ icon: <FolderOpen size={16} />,
1175
+ value: 'Next.js e-commerce site',
1176
+ onSelect: () => console.log('Selected Project Gamma')
1177
+ }
1178
+ ]
1179
+ },
1180
+ {
1181
+ id: 'teams',
1182
+ title: 'Teams',
1183
+ items: [
1184
+ {
1185
+ id: 'team-1',
1186
+ label: 'Frontend Team',
1187
+ icon: <Users size={16} />,
1188
+ value: '12 members • Active',
1189
+ onSelect: () => console.log('Joined Frontend Team')
1190
+ },
1191
+ {
1192
+ id: 'team-2',
1193
+ label: 'Backend Team',
1194
+ icon: <Users size={16} />,
1195
+ value: '8 members • Active',
1196
+ onSelect: () => console.log('Joined Backend Team')
1197
+ },
1198
+ {
1199
+ id: 'team-3',
1200
+ label: 'Design Team',
1201
+ icon: <Users size={16} />,
1202
+ value: '6 members • Active',
1203
+ onSelect: () => console.log('Joined Design Team')
1204
+ }
1205
+ ]
1206
+ },
1207
+ {
1208
+ id: 'settings',
1209
+ title: 'Settings',
1210
+ items: [
1211
+ {
1212
+ id: 'profile',
1213
+ label: 'Profile Settings',
1214
+ icon: <Settings size={16} />,
1215
+ onSelect: () => console.log('Opening Profile Settings')
1216
+ },
1217
+ {
1218
+ id: 'notifications',
1219
+ label: 'Notifications',
1220
+ icon: <Bell size={16} />,
1221
+ onSelect: () => console.log('Opening Notifications')
1222
+ },
1223
+ {
1224
+ id: 'security',
1225
+ label: 'Security & Privacy',
1226
+ icon: <Shield size={16} />,
1227
+ onSelect: () => console.log('Opening Security Settings')
1228
+ },
1229
+ {
1230
+ id: 'help',
1231
+ label: 'Help & Support',
1232
+ icon: <HelpCircle size={16} />,
1233
+ onSelect: () => console.log('Opening Help')
1234
+ }
1235
+ ]
1236
+ },
1237
+ {
1238
+ id: 'theme',
1239
+ title: 'Theme',
1240
+ items: [
1241
+ {
1242
+ id: 'light-theme',
1243
+ label: 'Light Theme',
1244
+ icon: <Sun size={16} />,
1245
+ onSelect: () => console.log('Switched to Light Theme')
1246
+ },
1247
+ {
1248
+ id: 'dark-theme',
1249
+ label: 'Dark Theme',
1250
+ icon: <Moon size={16} />,
1251
+ onSelect: () => console.log('Switched to Dark Theme')
1252
+ }
1253
+ ]
1254
+ }
1255
+ ];
1256
+
1257
+ const basicPages = [
1258
+ {
1259
+ id: 'root',
1260
+ items: [
1261
+ {
1262
+ id: 'calendar',
1263
+ label: 'Calendar',
1264
+ icon: <Calendar size={16} />,
1265
+ shortcut: '⌘K',
1266
+ onSelect: () => console.log('Calendar selected')
1267
+ },
1268
+ {
1269
+ id: 'emoji',
1270
+ label: 'Search Emoji',
1271
+ icon: <Search size={16} />,
1272
+ onSelect: () => console.log('Emoji search selected')
1273
+ },
1274
+ {
1275
+ id: 'calculator',
1276
+ label: 'Calculator',
1277
+ icon: <Calculator size={16} />,
1278
+ onSelect: () => console.log('Calculator selected')
1279
+ }
1280
+ ]
1281
+ }
1282
+ ];
1283
+
1284
+ const themePages = [
1285
+ {
1286
+ id: 'main',
1287
+ title: 'Quick Actions',
1288
+ items: [
1289
+ {
1290
+ id: 'theme-settings',
1291
+ label: 'Change theme...',
1292
+ icon: <Palette size={16} />,
1293
+ navigateTo: 'themes'
1294
+ },
1295
+ {
1296
+ id: 'home',
1297
+ label: 'Go to Dashboard',
1298
+ icon: <Home size={16} />,
1299
+ shortcut: '⌘H',
1300
+ onSelect: () => console.log('Going to Dashboard')
1301
+ }
1302
+ ]
1303
+ },
1304
+ {
1305
+ id: 'themes',
1306
+ title: 'Available Themes',
1307
+ items: [
1308
+ {
1309
+ id: 'light',
1310
+ label: 'Light theme',
1311
+ icon: <Sun size={16} />,
1312
+ onSelect: () => console.log('Light theme selected')
1313
+ },
1314
+ {
1315
+ id: 'dark',
1316
+ label: 'Dark theme',
1317
+ icon: <Moon size={16} />,
1318
+ onSelect: () => console.log('Dark theme selected')
1319
+ }
1320
+ ]
1321
+ }
1322
+ ]
1323
+ <Button onClick={() => setOpen(true)} variant="outline">
1324
+ Open Complex Command
1325
+ <CommandShortcut>⌘K</CommandShortcut>
1326
+ </Button>
1327
+ <Button onClick={() => setBasicOpen(true)} variant="outline">
1328
+ Open Basic Command
1329
+ </Button>
1330
+ <Button onClick={() => setThemeOpen(true)} variant="outline">
1331
+ Open Theme Command
1332
+ </Button>
1333
+ <NestedCommandDialog
1334
+ open={open}
1335
+ onOpenChange={setOpen}
1336
+ pages={commandPages}
1337
+ placeholder="Type a command or search..."
1338
+ onItemSelect={(item, pageId) => {
1339
+ console.log();
1340
+ }}
1341
+ />
1342
+
1343
+ <NestedCommandDialog
1344
+ open={basicOpen}
1345
+ onOpenChange={setBasicOpen}
1346
+ pages={basicPages}
1347
+ placeholder="Search commands..."
1348
+ defaultPage="root"
1349
+ />
1350
+
1351
+ <NestedCommandDialog
1352
+ open={themeOpen}
1353
+ onOpenChange={setThemeOpen}
1354
+ pages={themePages}
1355
+ placeholder="Search theme options..."
1356
+ onItemSelect={(item, pageId) => {
1357
+ console.log();
1358
+ }}
1359
+ />
1360
+ `,
1361
+ usagePath: null,
1362
+ category: "Commands",
1363
+ tags: ["ui", "components", "interactive"],
1364
+ features: ["Responsive", "TypeScript", "Accessible"],
1365
+ dependencies: ["@radix-ui/react-aspect-ratio"],
1366
+ props: [
1367
+ { "name": "open", "type": "boolean", "default": "false" },
1368
+ { "name": "onOpenChange", "type": "(open: boolean) => void", "default": "undefined" },
1369
+ { "name": "placeholder", "type": "string", "default": "\"Type a command or search...\"" },
1370
+ { "name": "emptyMessage", "type": "string", "default": "\"No results found.\"" },
1371
+ { "name": "pages", "type": "CommandPage[]", "default": "undefined", "required": true },
1372
+ { "name": "className", "type": "string", "default": "undefined" },
1373
+ { "name": "defaultPage", "type": "string", "default": "undefined" },
1374
+ { "name": "onItemSelect", "type": "(item: CommandItemData, pageId: string) => void", "default": "undefined" }
1375
+ ],
1376
+ props2: [],
1377
+ desc: null,
1378
+ status: null,
1379
+ lastUpdated: null
1380
+ },
1381
+ ];