@dogsbay/ui 0.2.0-beta.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 (322) hide show
  1. package/package.json +38 -0
  2. package/src/accordion/Accordion.astro +38 -0
  3. package/src/accordion/AccordionContent.astro +25 -0
  4. package/src/accordion/AccordionItem.astro +26 -0
  5. package/src/accordion/AccordionTrigger.astro +38 -0
  6. package/src/accordion/accordion.ts +189 -0
  7. package/src/accordion/index.ts +4 -0
  8. package/src/alert/Alert.astro +69 -0
  9. package/src/alert/AlertDescription.astro +17 -0
  10. package/src/alert/AlertTitle.astro +21 -0
  11. package/src/alert/CollapsibleAlert.astro +103 -0
  12. package/src/alert/icon.ts +32 -0
  13. package/src/alert/index.ts +4 -0
  14. package/src/alert/variants.ts +29 -0
  15. package/src/alert-dialog/AlertDialog.astro +16 -0
  16. package/src/alert-dialog/AlertDialogAction.astro +23 -0
  17. package/src/alert-dialog/AlertDialogCancel.astro +23 -0
  18. package/src/alert-dialog/AlertDialogContent.astro +37 -0
  19. package/src/alert-dialog/AlertDialogDescription.astro +18 -0
  20. package/src/alert-dialog/AlertDialogFooter.astro +18 -0
  21. package/src/alert-dialog/AlertDialogHeader.astro +18 -0
  22. package/src/alert-dialog/AlertDialogTitle.astro +18 -0
  23. package/src/alert-dialog/AlertDialogTrigger.astro +24 -0
  24. package/src/alert-dialog/alert-dialog.ts +154 -0
  25. package/src/alert-dialog/index.ts +9 -0
  26. package/src/api-doc/ApiDoc.astro +52 -0
  27. package/src/api-doc/index.ts +1 -0
  28. package/src/api-layout/ApiCodePanel.astro +21 -0
  29. package/src/api-layout/ApiLayout.astro +29 -0
  30. package/src/api-layout/ExampleBlock.astro +63 -0
  31. package/src/api-params/ApiParams.astro +96 -0
  32. package/src/api-params/index.ts +1 -0
  33. package/src/api-source/ApiSource.astro +20 -0
  34. package/src/api-source/api-source.css +32 -0
  35. package/src/api-source/index.ts +1 -0
  36. package/src/api-symbol/ApiSymbol.astro +48 -0
  37. package/src/api-symbol/api-symbol.css +89 -0
  38. package/src/api-symbol/index.ts +1 -0
  39. package/src/api-url-bar/ApiUrlBar.astro +63 -0
  40. package/src/avatar/Avatar.astro +57 -0
  41. package/src/avatar/index.ts +1 -0
  42. package/src/badge/Badge.astro +37 -0
  43. package/src/badge/index.ts +1 -0
  44. package/src/breadcrumb/Breadcrumb.astro +32 -0
  45. package/src/breadcrumb/BreadcrumbEllipsis.astro +32 -0
  46. package/src/breadcrumb/BreadcrumbItem.astro +41 -0
  47. package/src/breadcrumb/BreadcrumbSeparator.astro +33 -0
  48. package/src/breadcrumb/index.ts +4 -0
  49. package/src/button/Button.astro +70 -0
  50. package/src/button/index.ts +1 -0
  51. package/src/card/Card.astro +17 -0
  52. package/src/card/CardContent.astro +17 -0
  53. package/src/card/CardDescription.astro +17 -0
  54. package/src/card/CardFooter.astro +17 -0
  55. package/src/card/CardHeader.astro +17 -0
  56. package/src/card/CardTitle.astro +17 -0
  57. package/src/card/index.ts +6 -0
  58. package/src/checkbox/Checkbox.astro +70 -0
  59. package/src/checkbox/index.ts +1 -0
  60. package/src/checkbox-group/CheckboxGroup.astro +38 -0
  61. package/src/checkbox-group/checkbox-group.ts +53 -0
  62. package/src/checkbox-group/index.ts +1 -0
  63. package/src/code-block/CodeBlock.astro +160 -0
  64. package/src/code-rich/CodeRich.astro +267 -0
  65. package/src/code-rich/code-rich.css +68 -0
  66. package/src/code-rich/index.ts +1 -0
  67. package/src/code-samples/CodeSamples.astro +59 -0
  68. package/src/collapsible/Collapsible.astro +35 -0
  69. package/src/collapsible/CollapsibleContent.astro +24 -0
  70. package/src/collapsible/CollapsibleTrigger.astro +23 -0
  71. package/src/collapsible/collapsible.ts +42 -0
  72. package/src/collapsible/index.ts +3 -0
  73. package/src/combobox/Combobox.astro +53 -0
  74. package/src/combobox/ComboboxEmpty.astro +18 -0
  75. package/src/combobox/ComboboxItem.astro +28 -0
  76. package/src/combobox/combobox.ts +179 -0
  77. package/src/combobox/index.ts +3 -0
  78. package/src/command/Command.astro +22 -0
  79. package/src/command/CommandEmpty.astro +18 -0
  80. package/src/command/CommandGroup.astro +24 -0
  81. package/src/command/CommandInput.astro +49 -0
  82. package/src/command/CommandItem.astro +26 -0
  83. package/src/command/CommandList.astro +19 -0
  84. package/src/command/CommandSeparator.astro +16 -0
  85. package/src/command/CommandShortcut.astro +18 -0
  86. package/src/command/command.ts +212 -0
  87. package/src/command/index.ts +8 -0
  88. package/src/content-renderer/ContentRenderer.astro +410 -0
  89. package/src/content-renderer/InlineRenderer.astro +149 -0
  90. package/src/context-menu/ContextMenu.astro +22 -0
  91. package/src/context-menu/ContextMenuContent.astro +24 -0
  92. package/src/context-menu/ContextMenuItem.astro +49 -0
  93. package/src/context-menu/ContextMenuSeparator.astro +14 -0
  94. package/src/context-menu/ContextMenuShortcut.astro +14 -0
  95. package/src/context-menu/ContextMenuTrigger.astro +22 -0
  96. package/src/context-menu/context-menu.ts +238 -0
  97. package/src/context-menu/index.ts +6 -0
  98. package/src/copy-button/CopyButton.astro +88 -0
  99. package/src/copy-button/index.ts +1 -0
  100. package/src/diagram/Diagram.astro +15 -0
  101. package/src/diagram/index.ts +1 -0
  102. package/src/dialog/Dialog.astro +22 -0
  103. package/src/dialog/DialogClose.astro +32 -0
  104. package/src/dialog/DialogContent.astro +37 -0
  105. package/src/dialog/DialogDescription.astro +22 -0
  106. package/src/dialog/DialogFooter.astro +18 -0
  107. package/src/dialog/DialogHeader.astro +18 -0
  108. package/src/dialog/DialogTitle.astro +18 -0
  109. package/src/dialog/DialogTrigger.astro +33 -0
  110. package/src/dialog/dialog.ts +291 -0
  111. package/src/dialog/index.ts +8 -0
  112. package/src/docs-footer/DocsFooter.astro +50 -0
  113. package/src/docs-header/DocsHeader.astro +32 -0
  114. package/src/docs-layout/DocsLayout.astro +187 -0
  115. package/src/docs-layout/index.ts +1 -0
  116. package/src/drawer/Drawer.astro +12 -0
  117. package/src/drawer/DrawerClose.astro +12 -0
  118. package/src/drawer/DrawerContent.astro +46 -0
  119. package/src/drawer/DrawerDescription.astro +10 -0
  120. package/src/drawer/DrawerFooter.astro +10 -0
  121. package/src/drawer/DrawerHandle.astro +16 -0
  122. package/src/drawer/DrawerHeader.astro +10 -0
  123. package/src/drawer/DrawerTitle.astro +10 -0
  124. package/src/drawer/DrawerTrigger.astro +25 -0
  125. package/src/drawer/drawer.ts +262 -0
  126. package/src/drawer/index.ts +9 -0
  127. package/src/dropdown-menu/DropdownMenu.astro +22 -0
  128. package/src/dropdown-menu/DropdownMenuContent.astro +33 -0
  129. package/src/dropdown-menu/DropdownMenuGroup.astro +17 -0
  130. package/src/dropdown-menu/DropdownMenuItem.astro +48 -0
  131. package/src/dropdown-menu/DropdownMenuLabel.astro +28 -0
  132. package/src/dropdown-menu/DropdownMenuSeparator.astro +21 -0
  133. package/src/dropdown-menu/DropdownMenuShortcut.astro +18 -0
  134. package/src/dropdown-menu/DropdownMenuTrigger.astro +34 -0
  135. package/src/dropdown-menu/dropdown-menu.ts +348 -0
  136. package/src/dropdown-menu/index.ts +8 -0
  137. package/src/endpoint-card/EndpointCard.astro +60 -0
  138. package/src/endpoint-card/EndpointCardSection.astro +22 -0
  139. package/src/endpoint-card/EndpointSection.astro +35 -0
  140. package/src/field/Field.astro +31 -0
  141. package/src/field/FieldDescription.astro +22 -0
  142. package/src/field/FieldLabel.astro +24 -0
  143. package/src/field/field.ts +61 -0
  144. package/src/field/index.ts +3 -0
  145. package/src/fieldset/Fieldset.astro +24 -0
  146. package/src/fieldset/FieldsetLegend.astro +18 -0
  147. package/src/fieldset/index.ts +2 -0
  148. package/src/footnote/Footnote.astro +37 -0
  149. package/src/footnote/footnote.ts +79 -0
  150. package/src/footnote/index.ts +1 -0
  151. package/src/form/Form.astro +27 -0
  152. package/src/form/form.ts +160 -0
  153. package/src/form/index.ts +1 -0
  154. package/src/grid/Grid.astro +117 -0
  155. package/src/grid/GridItem.astro +95 -0
  156. package/src/grid/index.ts +2 -0
  157. package/src/image/Image.astro +115 -0
  158. package/src/image/index.ts +1 -0
  159. package/src/input/Input.astro +34 -0
  160. package/src/input/index.ts +1 -0
  161. package/src/kbd/Kbd.astro +17 -0
  162. package/src/kbd/index.ts +1 -0
  163. package/src/label/Label.astro +17 -0
  164. package/src/label/index.ts +1 -0
  165. package/src/link-card/LinkCard.astro +47 -0
  166. package/src/link-card/index.ts +1 -0
  167. package/src/map-view/MapView.astro +88 -0
  168. package/src/map-view/index.ts +1 -0
  169. package/src/map-view/map-view.ts +194 -0
  170. package/src/markdown-example/MarkdownExample.astro +138 -0
  171. package/src/markdown-example/index.ts +1 -0
  172. package/src/math/MathKatex.astro +35 -0
  173. package/src/math/index.ts +1 -0
  174. package/src/menubar/Menubar.astro +25 -0
  175. package/src/menubar/MenubarContent.astro +24 -0
  176. package/src/menubar/MenubarItem.astro +26 -0
  177. package/src/menubar/MenubarMenu.astro +12 -0
  178. package/src/menubar/MenubarSeparator.astro +11 -0
  179. package/src/menubar/MenubarShortcut.astro +11 -0
  180. package/src/menubar/MenubarTrigger.astro +27 -0
  181. package/src/menubar/index.ts +7 -0
  182. package/src/menubar/menubar.ts +258 -0
  183. package/src/meter/Meter.astro +75 -0
  184. package/src/meter/index.ts +1 -0
  185. package/src/method-badge/MethodBadge.astro +32 -0
  186. package/src/navigation-menu/NavigationMenu.astro +24 -0
  187. package/src/navigation-menu/NavigationMenuContent.astro +24 -0
  188. package/src/navigation-menu/NavigationMenuItem.astro +22 -0
  189. package/src/navigation-menu/NavigationMenuLink.astro +26 -0
  190. package/src/navigation-menu/NavigationMenuList.astro +22 -0
  191. package/src/navigation-menu/NavigationMenuTrigger.astro +40 -0
  192. package/src/navigation-menu/index.ts +6 -0
  193. package/src/navigation-menu/navigation-menu.ts +192 -0
  194. package/src/number-field/NumberField.astro +84 -0
  195. package/src/number-field/index.ts +1 -0
  196. package/src/number-field/number-field.ts +68 -0
  197. package/src/pagination/Pagination.astro +59 -0
  198. package/src/pagination/index.ts +1 -0
  199. package/src/parameter-table/ParameterTable.astro +75 -0
  200. package/src/popover/Popover.astro +21 -0
  201. package/src/popover/PopoverContent.astro +31 -0
  202. package/src/popover/PopoverTrigger.astro +31 -0
  203. package/src/popover/index.ts +3 -0
  204. package/src/popover/popover.ts +144 -0
  205. package/src/preview-card/PreviewCard.astro +24 -0
  206. package/src/preview-card/PreviewCardContent.astro +24 -0
  207. package/src/preview-card/PreviewCardTrigger.astro +23 -0
  208. package/src/preview-card/index.ts +3 -0
  209. package/src/preview-card/preview-card.ts +91 -0
  210. package/src/progress/Progress.astro +61 -0
  211. package/src/progress/index.ts +1 -0
  212. package/src/property-item/PropertyItem.astro +183 -0
  213. package/src/property-list/PropertyList.astro +68 -0
  214. package/src/radio-group/RadioGroup.astro +41 -0
  215. package/src/radio-group/RadioGroupItem.astro +36 -0
  216. package/src/radio-group/index.ts +2 -0
  217. package/src/radio-group/radio-group.ts +126 -0
  218. package/src/response-tabs/ResponseTabs.astro +60 -0
  219. package/src/schema-viewer/SchemaViewer.astro +42 -0
  220. package/src/scroll-area/ScrollArea.astro +44 -0
  221. package/src/scroll-area/index.ts +1 -0
  222. package/src/scroll-area/scroll-area.ts +176 -0
  223. package/src/select/Select.astro +34 -0
  224. package/src/select/SelectContent.astro +24 -0
  225. package/src/select/SelectGroup.astro +23 -0
  226. package/src/select/SelectItem.astro +28 -0
  227. package/src/select/SelectLabel.astro +18 -0
  228. package/src/select/SelectSeparator.astro +22 -0
  229. package/src/select/SelectTrigger.astro +28 -0
  230. package/src/select/SelectValue.astro +18 -0
  231. package/src/select/index.ts +8 -0
  232. package/src/select/select.ts +381 -0
  233. package/src/separator/Separator.astro +35 -0
  234. package/src/separator/index.ts +1 -0
  235. package/src/sheet/Sheet.astro +12 -0
  236. package/src/sheet/SheetClose.astro +35 -0
  237. package/src/sheet/SheetContent.astro +52 -0
  238. package/src/sheet/SheetDescription.astro +18 -0
  239. package/src/sheet/SheetFooter.astro +18 -0
  240. package/src/sheet/SheetHeader.astro +18 -0
  241. package/src/sheet/SheetTitle.astro +18 -0
  242. package/src/sheet/SheetTrigger.astro +32 -0
  243. package/src/sheet/index.ts +8 -0
  244. package/src/sheet/sheet.ts +173 -0
  245. package/src/sidebar/Sidebar.astro +113 -0
  246. package/src/sidebar/SidebarContent.astro +18 -0
  247. package/src/sidebar/SidebarFooter.astro +18 -0
  248. package/src/sidebar/SidebarGroup.astro +18 -0
  249. package/src/sidebar/SidebarGroupContent.astro +18 -0
  250. package/src/sidebar/SidebarGroupLabel.astro +18 -0
  251. package/src/sidebar/SidebarHeader.astro +18 -0
  252. package/src/sidebar/SidebarInset.astro +18 -0
  253. package/src/sidebar/SidebarMenu.astro +18 -0
  254. package/src/sidebar/SidebarMenuBadge.astro +18 -0
  255. package/src/sidebar/SidebarMenuButton.astro +71 -0
  256. package/src/sidebar/SidebarMenuItem.astro +18 -0
  257. package/src/sidebar/SidebarMenuSub.astro +18 -0
  258. package/src/sidebar/SidebarMenuSubButton.astro +45 -0
  259. package/src/sidebar/SidebarMenuSubItem.astro +12 -0
  260. package/src/sidebar/SidebarNavTree.astro +106 -0
  261. package/src/sidebar/SidebarProvider.astro +23 -0
  262. package/src/sidebar/SidebarRail.astro +25 -0
  263. package/src/sidebar/SidebarSeparator.astro +21 -0
  264. package/src/sidebar/SidebarTrigger.astro +40 -0
  265. package/src/sidebar/index.ts +19 -0
  266. package/src/sidebar/sidebar.ts +265 -0
  267. package/src/skeleton/Skeleton.astro +16 -0
  268. package/src/skeleton/index.ts +1 -0
  269. package/src/skip-link/SkipLink.astro +24 -0
  270. package/src/slider/Slider.astro +61 -0
  271. package/src/slider/index.ts +1 -0
  272. package/src/slider/slider.ts +111 -0
  273. package/src/spinner/Spinner.astro +54 -0
  274. package/src/spinner/index.ts +1 -0
  275. package/src/steps/Step.astro +16 -0
  276. package/src/steps/Steps.astro +122 -0
  277. package/src/steps/SubSteps.astro +73 -0
  278. package/src/switch/Switch.astro +52 -0
  279. package/src/switch/index.ts +1 -0
  280. package/src/switch/switch.ts +109 -0
  281. package/src/table/Table.astro +24 -0
  282. package/src/table/TableBody.astro +18 -0
  283. package/src/table/TableCaption.astro +18 -0
  284. package/src/table/TableCell.astro +18 -0
  285. package/src/table/TableFooter.astro +18 -0
  286. package/src/table/TableHead.astro +18 -0
  287. package/src/table/TableHeader.astro +18 -0
  288. package/src/table/TableRow.astro +18 -0
  289. package/src/table/index.ts +8 -0
  290. package/src/tabs/Tabs.astro +37 -0
  291. package/src/tabs/TabsContent.astro +32 -0
  292. package/src/tabs/TabsList.astro +23 -0
  293. package/src/tabs/TabsTrigger.astro +29 -0
  294. package/src/tabs/index.ts +4 -0
  295. package/src/tabs/tabs.ts +220 -0
  296. package/src/textarea/Textarea.astro +25 -0
  297. package/src/textarea/index.ts +1 -0
  298. package/src/theme-toggle/ThemeToggle.astro +67 -0
  299. package/src/theme-toggle/index.ts +1 -0
  300. package/src/toast/Toaster.astro +39 -0
  301. package/src/toast/index.ts +3 -0
  302. package/src/toast/toast.ts +104 -0
  303. package/src/toc/TableOfContents.astro +225 -0
  304. package/src/toggle/Toggle.astro +56 -0
  305. package/src/toggle/index.ts +1 -0
  306. package/src/toggle/toggle.ts +38 -0
  307. package/src/toggle-group/ToggleGroup.astro +39 -0
  308. package/src/toggle-group/ToggleGroupItem.astro +56 -0
  309. package/src/toggle-group/index.ts +2 -0
  310. package/src/toggle-group/toggle-group.ts +121 -0
  311. package/src/toolbar/Toolbar.astro +26 -0
  312. package/src/toolbar/ToolbarButton.astro +29 -0
  313. package/src/toolbar/ToolbarSeparator.astro +14 -0
  314. package/src/toolbar/index.ts +3 -0
  315. package/src/toolbar/toolbar.ts +65 -0
  316. package/src/tooltip/Tooltip.astro +21 -0
  317. package/src/tooltip/TooltipContent.astro +25 -0
  318. package/src/tooltip/TooltipTrigger.astro +31 -0
  319. package/src/tooltip/index.ts +3 -0
  320. package/src/tooltip/tooltip.ts +156 -0
  321. package/src/youtube/YouTube.astro +119 -0
  322. package/src/youtube/index.ts +1 -0
@@ -0,0 +1,212 @@
1
+ interface CommandInstance {
2
+ root: HTMLElement;
3
+ input: HTMLInputElement;
4
+ list: HTMLElement;
5
+ empty: HTMLElement | null;
6
+ items: HTMLElement[];
7
+ groups: HTMLElement[];
8
+ selectedIndex: number;
9
+ filter: (item: HTMLElement, query: string) => boolean;
10
+ }
11
+
12
+ const instances = new WeakMap<HTMLElement, CommandInstance>();
13
+
14
+ function defaultFilter(item: HTMLElement, query: string): boolean {
15
+ const text = item.textContent?.toLowerCase() || "";
16
+ const keywords = item.dataset.keywords?.toLowerCase() || "";
17
+ const q = query.toLowerCase();
18
+ return text.includes(q) || keywords.includes(q);
19
+ }
20
+
21
+ function initCommand(root: HTMLElement) {
22
+ if (instances.has(root)) return;
23
+
24
+ const input = root.querySelector(
25
+ "[data-part='input']",
26
+ ) as HTMLInputElement | null;
27
+ const list = root.querySelector(
28
+ "[data-part='list']",
29
+ ) as HTMLElement | null;
30
+ const empty = root.querySelector(
31
+ "[data-part='empty']",
32
+ ) as HTMLElement | null;
33
+
34
+ if (!input || !list) return;
35
+
36
+ // ARIA linkage: combobox → listbox
37
+ if (!list.id) list.id = `command-list-${Math.random().toString(36).slice(2, 8)}`;
38
+ input.setAttribute("aria-controls", list.id);
39
+
40
+ const items = Array.from(
41
+ list.querySelectorAll("[data-part='item']"),
42
+ ) as HTMLElement[];
43
+ const groups = Array.from(
44
+ list.querySelectorAll("[data-part='group']"),
45
+ ) as HTMLElement[];
46
+
47
+ const instance: CommandInstance = {
48
+ root,
49
+ input,
50
+ list,
51
+ empty,
52
+ items,
53
+ groups,
54
+ selectedIndex: -1,
55
+ filter: defaultFilter,
56
+ };
57
+
58
+ instances.set(root, instance);
59
+
60
+ // Input filtering
61
+ input.addEventListener("input", () => {
62
+ filterItems(root);
63
+ });
64
+
65
+ // Keyboard navigation
66
+ input.addEventListener("keydown", (e) => {
67
+ const visibleItems = getVisibleItems(instance);
68
+ if (visibleItems.length === 0) return;
69
+
70
+ if (e.key === "ArrowDown") {
71
+ e.preventDefault();
72
+ const currentVisible = instance.selectedIndex >= 0
73
+ ? visibleItems.indexOf(instance.items[instance.selectedIndex])
74
+ : -1;
75
+ const nextIdx = currentVisible < visibleItems.length - 1
76
+ ? currentVisible + 1
77
+ : 0;
78
+ selectItem(root, instance.items.indexOf(visibleItems[nextIdx]));
79
+ } else if (e.key === "ArrowUp") {
80
+ e.preventDefault();
81
+ const currentVisible = instance.selectedIndex >= 0
82
+ ? visibleItems.indexOf(instance.items[instance.selectedIndex])
83
+ : -1;
84
+ const prevIdx = currentVisible > 0
85
+ ? currentVisible - 1
86
+ : visibleItems.length - 1;
87
+ selectItem(root, instance.items.indexOf(visibleItems[prevIdx]));
88
+ } else if (e.key === "Home") {
89
+ e.preventDefault();
90
+ selectItem(root, instance.items.indexOf(visibleItems[0]));
91
+ } else if (e.key === "End") {
92
+ e.preventDefault();
93
+ selectItem(
94
+ root,
95
+ instance.items.indexOf(visibleItems[visibleItems.length - 1]),
96
+ );
97
+ } else if (e.key === "Enter") {
98
+ e.preventDefault();
99
+ if (instance.selectedIndex >= 0) {
100
+ const item = instance.items[instance.selectedIndex];
101
+ if (!item.hidden && item.dataset.disabled !== "true") {
102
+ item.click();
103
+ }
104
+ }
105
+ }
106
+ });
107
+
108
+ // Item hover
109
+ items.forEach((item) => {
110
+ item.addEventListener("pointerenter", () => {
111
+ if (item.hidden || item.dataset.disabled === "true") return;
112
+ selectItem(root, instance.items.indexOf(item));
113
+ });
114
+ });
115
+
116
+ // Initial filter (empty query shows all)
117
+ filterItems(root);
118
+
119
+ // Select first visible item
120
+ const visibleItems = getVisibleItems(instance);
121
+ if (visibleItems.length > 0) {
122
+ selectItem(root, instance.items.indexOf(visibleItems[0]));
123
+ }
124
+ }
125
+
126
+ function getVisibleItems(instance: CommandInstance): HTMLElement[] {
127
+ return instance.items.filter(
128
+ (item) => !item.hidden && item.dataset.disabled !== "true",
129
+ );
130
+ }
131
+
132
+ function filterItems(root: HTMLElement) {
133
+ const instance = instances.get(root);
134
+ if (!instance) return;
135
+
136
+ const query = instance.input.value.trim();
137
+
138
+ // Filter items
139
+ let anyVisible = false;
140
+ instance.items.forEach((item) => {
141
+ const matches = query === "" || instance.filter(item, query);
142
+ item.hidden = !matches;
143
+ if (matches) anyVisible = true;
144
+ });
145
+
146
+ // Hide empty groups (groups where all items are hidden)
147
+ instance.groups.forEach((group) => {
148
+ const groupItems = Array.from(
149
+ group.querySelectorAll("[data-part='item']"),
150
+ ) as HTMLElement[];
151
+ const hasVisible = groupItems.some((item) => !item.hidden);
152
+ group.hidden = !hasVisible;
153
+ });
154
+
155
+ // Show/hide empty message
156
+ if (instance.empty) {
157
+ instance.empty.hidden = anyVisible || query === "";
158
+ }
159
+
160
+ // Select first visible item
161
+ const visibleItems = getVisibleItems(instance);
162
+ if (visibleItems.length > 0) {
163
+ selectItem(root, instance.items.indexOf(visibleItems[0]));
164
+ } else {
165
+ clearSelection(root);
166
+ }
167
+ }
168
+
169
+ function selectItem(root: HTMLElement, index: number) {
170
+ const instance = instances.get(root);
171
+ if (!instance) return;
172
+ if (index < 0 || index >= instance.items.length) return;
173
+
174
+ // Clear previous
175
+ if (instance.selectedIndex >= 0) {
176
+ instance.items[instance.selectedIndex].removeAttribute("data-selected");
177
+ }
178
+
179
+ instance.selectedIndex = index;
180
+ const item = instance.items[index];
181
+ item.setAttribute("data-selected", "true");
182
+ item.scrollIntoView({ block: "nearest" });
183
+ }
184
+
185
+ function clearSelection(root: HTMLElement) {
186
+ const instance = instances.get(root);
187
+ if (!instance) return;
188
+
189
+ if (instance.selectedIndex >= 0) {
190
+ instance.items[instance.selectedIndex].removeAttribute("data-selected");
191
+ }
192
+ instance.selectedIndex = -1;
193
+ }
194
+
195
+ // Auto-initialize
196
+ function init() {
197
+ document
198
+ .querySelectorAll("[data-component='command']")
199
+ .forEach((el) => {
200
+ initCommand(el as HTMLElement);
201
+ });
202
+ }
203
+
204
+ if (document.readyState === "loading") {
205
+ document.addEventListener("DOMContentLoaded", init);
206
+ } else {
207
+ init();
208
+ }
209
+ document.addEventListener("astro:page-load", init);
210
+ document.addEventListener("astro:after-swap", init);
211
+
212
+ export { initCommand, filterItems };
@@ -0,0 +1,8 @@
1
+ export { default as Command } from "./Command.astro";
2
+ export { default as CommandInput } from "./CommandInput.astro";
3
+ export { default as CommandList } from "./CommandList.astro";
4
+ export { default as CommandEmpty } from "./CommandEmpty.astro";
5
+ export { default as CommandGroup } from "./CommandGroup.astro";
6
+ export { default as CommandItem } from "./CommandItem.astro";
7
+ export { default as CommandSeparator } from "./CommandSeparator.astro";
8
+ export { default as CommandShortcut } from "./CommandShortcut.astro";
@@ -0,0 +1,410 @@
1
+ ---
2
+ /**
3
+ * ContentRenderer — recursive TreeNode[] renderer (DEPRECATED).
4
+ *
5
+ * STATUS: deprecated. Frozen for new TreeNode types. Scheduled for removal.
6
+ *
7
+ * The canonical TreeNode → Astro path is `@dogsbay/format-astro` (the
8
+ * `treeToAstro()` serializer + `exportAstroProject()` project generator).
9
+ * That path emits editable `.astro` source files with explicit component
10
+ * imports — same shipping model as the rest of Dogsbay (you own the source).
11
+ *
12
+ * This component existed as a stop-gap before format-astro shipped — a
13
+ * runtime renderer that walks a TreeNode and emits markup at Astro build
14
+ * time. The four format exporters (format-astro, format-mkdocs,
15
+ * format-obsidian, format-dogsbay-md) all follow the "compile to source"
16
+ * model and bypass this renderer.
17
+ *
18
+ * What still uses ContentRenderer (kept working until removal):
19
+ * - apps/demo/src/pages/{docs,material,mkdocs,mkdocs-material}/[...slug].astro
20
+ * - apps/material-docs/src/pages/docs/[...slug].astro
21
+ * - apps/ui-docs/src/pages/handbook/styling.astro
22
+ * - the legacy `--dynamic` flag on `dogsbay import-mkdocs`
23
+ *
24
+ * DO NOT add new TreeNode-type cases here. Add them to format-astro
25
+ * instead. When the listed consumers are migrated, this file can be
26
+ * deleted.
27
+ *
28
+ * Imports: alert, code-block, code-rich, tabs, table, steps, diagram,
29
+ * api-params, api-symbol, api-doc, api-source, youtube, image, grid
30
+ */
31
+ import Alert from "../alert/Alert.astro";
32
+ import AlertTitle from "../alert/AlertTitle.astro";
33
+ import AlertDescription from "../alert/AlertDescription.astro";
34
+ import CollapsibleAlert from "../alert/CollapsibleAlert.astro";
35
+ import Steps from "../steps/Steps.astro";
36
+ import Step from "../steps/Step.astro";
37
+ import SubSteps from "../steps/SubSteps.astro";
38
+ import CodeBlock from "../code-block/CodeBlock.astro";
39
+ import CodeRich from "../code-rich/CodeRich.astro";
40
+ import "../code-rich/code-rich.css";
41
+ import Diagram from "../diagram/Diagram.astro";
42
+ import ApiParams from "../api-params/ApiParams.astro";
43
+ import ApiSymbol from "../api-symbol/ApiSymbol.astro";
44
+ import ApiDoc from "../api-doc/ApiDoc.astro";
45
+ import ApiSource from "../api-source/ApiSource.astro";
46
+ import Grid from "../grid/Grid.astro";
47
+ import YouTube from "../youtube/YouTube.astro";
48
+ import BlockImage from "../image/Image.astro";
49
+ import Tabs from "../tabs/Tabs.astro";
50
+ import TabsList from "../tabs/TabsList.astro";
51
+ import TabsTrigger from "../tabs/TabsTrigger.astro";
52
+ import TabsContent from "../tabs/TabsContent.astro";
53
+ import Table from "../table/Table.astro";
54
+ import TableHeader from "../table/TableHeader.astro";
55
+ import TableBody from "../table/TableBody.astro";
56
+ import TableRow from "../table/TableRow.astro";
57
+ import TableHead from "../table/TableHead.astro";
58
+ import TableCell from "../table/TableCell.astro";
59
+ import InlineRenderer from "./InlineRenderer.astro";
60
+ import MathKatex from "../math/MathKatex.astro";
61
+
62
+ interface InlineNode {
63
+ type: string;
64
+ [key: string]: unknown;
65
+ }
66
+
67
+ interface TreeNode {
68
+ type: string;
69
+ props?: Record<string, unknown>;
70
+ html?: string;
71
+ inline?: InlineNode[];
72
+ children?: TreeNode[];
73
+ }
74
+
75
+ interface Props {
76
+ node: TreeNode;
77
+ images?: Record<string, ImageMetadata>;
78
+ icons?: any;
79
+ }
80
+
81
+ const { node, images = {}, icons } = Astro.props;
82
+ const children = node.children || [];
83
+
84
+ // Determine if code block needs CodeRich (annotations/line numbers)
85
+ const isRichCode = node.type === "code" && (
86
+ node.props?.lineNumbers ||
87
+ node.props?.highlights ||
88
+ ((node.props?.code as string) || "").includes("[!code")
89
+ );
90
+
91
+ // html-container helpers
92
+ const containerAttrs = node.type === "html-container"
93
+ ? (node.props?.attrs as Record<string, string>) || {}
94
+ : {};
95
+ const containerClass = containerAttrs.class || "";
96
+ const isColumns = node.type === "html-container" && containerClass.includes("mdx-columns");
97
+ const isGridCards = node.type === "html-container" && containerClass.includes("grid") && containerClass.includes("cards");
98
+
99
+ // Block image detection: paragraph with sole image (or link-wrapped image) inline child
100
+ const blockImage = (() => {
101
+ if (node.type !== "paragraph" || !node.children?.length) return null;
102
+ const prose = node.children[0];
103
+ if (prose?.type !== "prose" || !prose.inline) return null;
104
+ const meaningful = prose.inline.filter((n: InlineNode) => !(n.type === "text" && (n.text as string || "").trim() === ""));
105
+ if (meaningful.length !== 1) return null;
106
+ const sole = meaningful[0];
107
+ if (sole.type === "image") return sole;
108
+ if (sole.type === "link") {
109
+ const linkChildren = (sole.children as InlineNode[]) || [];
110
+ if (linkChildren.length === 1 && linkChildren[0].type === "image") return linkChildren[0];
111
+ }
112
+ return null;
113
+ })();
114
+
115
+ /** Convert InlineNode[] to HTML string (for headings rendered via set:html). */
116
+ function inlineToHtml(nodes: InlineNode[]): string {
117
+ return nodes.map(n => {
118
+ switch (n.type) {
119
+ case "text": {
120
+ let s = String(n.text || "");
121
+ if (n.bold) s = `<strong>${s}</strong>`;
122
+ if (n.italic) s = `<em>${s}</em>`;
123
+ if (n.strikethrough) s = `<s>${s}</s>`;
124
+ return s;
125
+ }
126
+ case "code": return `<code>${n.text || ""}</code>`;
127
+ case "highlight": return `<mark>${inlineToHtml((n.children || []) as InlineNode[])}</mark>`;
128
+ case "link": return `<a href="${n.href || ""}">${inlineToHtml((n.children || []) as InlineNode[])}</a>`;
129
+ case "image": return `<img src="${n.src || ""}" alt="${n.alt || ""}">`;
130
+ case "kbd": return (n.keys as string[] || []).map((k: string) => `<kbd>${k}</kbd>`).join("+");
131
+ case "html-inline": return String(n.html || "");
132
+ case "break": return "<br>";
133
+ default: return "";
134
+ }
135
+ }).join("");
136
+ }
137
+
138
+ /** Resolve an image src path to ImageMetadata from the images map. */
139
+ function resolveImage(src: string): ImageMetadata | undefined {
140
+ if (!src || src.startsWith("http")) return undefined;
141
+ const normalized = "/" + src.replace(/^(?:\.\.\/)+/, "").replace(/^\/+/, "");
142
+ const clean = normalized.replace(/#.*$/, "");
143
+ return images[clean];
144
+ }
145
+ ---
146
+
147
+ {/* ── Prose ──────────────────────────────────────────────── */}
148
+ {node.type === "prose" && node.inline && (
149
+ <Fragment>
150
+ {node.inline.map(span => <InlineRenderer node={span} icons={icons} images={images} />)}
151
+ </Fragment>
152
+ )}
153
+ {node.type === "prose" && !node.inline && <Fragment set:html={node.html} />}
154
+
155
+ {/* ── Heading with anchor ────────────────────────────────── */}
156
+ {node.type === "heading" && (
157
+ <Fragment set:html={
158
+ `<h${node.props!.level} id="${node.props!.slug || ''}" class="group scroll-mt-20">` +
159
+ `${node.inline ? inlineToHtml(node.inline) : (node.html?.replace(/<h\d[^>]*>|<\/h\d>/g, '') || node.props!.text || '')}` +
160
+ `<a href="#${node.props!.slug || ''}" class="no-underline ml-2 opacity-0 group-hover:opacity-50 transition-opacity text-muted-foreground" aria-label="Link to this heading">¶</a>` +
161
+ `</h${node.props!.level}>`
162
+ } />
163
+ )}
164
+
165
+ {/* ── Paragraph — block image gets <figure>, normal gets <p> */}
166
+ {node.type === "paragraph" && blockImage && (
167
+ <BlockImage
168
+ src={blockImage.src as string}
169
+ alt={blockImage.alt as string || ""}
170
+ title={blockImage.title as string}
171
+ width={blockImage.width as number}
172
+ height={blockImage.height as number}
173
+ imageData={resolveImage(blockImage.src as string)}
174
+ block
175
+ />
176
+ )}
177
+ {node.type === "paragraph" && !blockImage && (
178
+ <p>{children.map(child => <Astro.self node={child} images={images} icons={icons} />)}</p>
179
+ )}
180
+
181
+ {/* ── Code block — smart routing to CodeBlock or CodeRich ── */}
182
+ {node.type === "code" && !isRichCode && (
183
+ <CodeBlock
184
+ code={(node.props?.code as string) || ""}
185
+ lang={(node.props?.lang as string) || "plaintext"}
186
+ title={node.props?.title as string}
187
+ />
188
+ )}
189
+ {node.type === "code" && isRichCode && (
190
+ <CodeRich
191
+ code={(node.props?.code as string) || ""}
192
+ lang={(node.props?.lang as string) || "plaintext"}
193
+ title={node.props?.title as string}
194
+ lineNumbers={!!node.props?.lineNumbers}
195
+ highlights={node.props?.highlights as string}
196
+ />
197
+ )}
198
+
199
+ {/* ── Callout / Admonition ───────────────────────────────── */}
200
+ {node.type === "callout" && (
201
+ <Alert variant={(node.props?.variant as any) || "note"} class="my-4">
202
+ {node.props?.title && <AlertTitle>{node.props.title}</AlertTitle>}
203
+ <AlertDescription>
204
+ {children.map(child => <Astro.self node={child} images={images} icons={icons} />)}
205
+ </AlertDescription>
206
+ </Alert>
207
+ )}
208
+
209
+ {/* ── Details / Collapsible admonition ───────────────────── */}
210
+ {node.type === "details" && (
211
+ <CollapsibleAlert
212
+ variant={(node.props?.variant as any) || "note"}
213
+ title={(node.props?.title || node.props?.variant || "Details") as string}
214
+ open={node.props?.open as boolean}
215
+ class="my-4"
216
+ >
217
+ {children.map(child => <Astro.self node={child} images={images} icons={icons} />)}
218
+ </CollapsibleAlert>
219
+ )}
220
+
221
+ {/* ── Steps ──────────────────────────────────────────────── */}
222
+ {node.type === "steps" && (
223
+ <Steps>
224
+ {children.map(child => <Astro.self node={child} images={images} icons={icons} />)}
225
+ </Steps>
226
+ )}
227
+ {node.type === "step" && (
228
+ <Step>
229
+ {children.map(child => <Astro.self node={child} images={images} icons={icons} />)}
230
+ </Step>
231
+ )}
232
+ {node.type === "substeps" && (
233
+ <SubSteps>
234
+ {children.map(child => <Astro.self node={child} images={images} icons={icons} />)}
235
+ </SubSteps>
236
+ )}
237
+
238
+ {/* ── Tabs ────────────────────────────────────────────────── */}
239
+ {node.type === "tabs" && (
240
+ <Tabs defaultValue={(children[0]?.props?.value || children[0]?.props?.label || "tab-0") as string} syncKey={node.props?.syncKey as string | undefined} class="my-4">
241
+ <TabsList>
242
+ {children.map((tab, i) => (
243
+ <TabsTrigger value={(tab.props?.value || tab.props?.label || `tab-${i}`) as string}>
244
+ {tab.inline
245
+ ? tab.inline.map((span: any) => <InlineRenderer node={span} icons={icons} images={images} />)
246
+ : (tab.props?.label || tab.props?.title) as string
247
+ }
248
+ </TabsTrigger>
249
+ ))}
250
+ </TabsList>
251
+ {children.map((tab, i) => (
252
+ <TabsContent value={(tab.props?.value || tab.props?.label || `tab-${i}`) as string}>
253
+ {(tab.children || []).map(child => <Astro.self node={child} images={images} icons={icons} />)}
254
+ </TabsContent>
255
+ ))}
256
+ </Tabs>
257
+ )}
258
+ {node.type === "tab" && (
259
+ <div>{children.map(child => <Astro.self node={child} images={images} icons={icons} />)}</div>
260
+ )}
261
+
262
+ {/* ── Definition list ────────────────────────────────────── */}
263
+ {node.type === "deflist" && (
264
+ <dl class="my-4 space-y-2">
265
+ {children.map(child => <Astro.self node={child} images={images} icons={icons} />)}
266
+ </dl>
267
+ )}
268
+ {node.type === "dt" && (
269
+ <dt class="font-semibold">{children.map(child => <Astro.self node={child} images={images} icons={icons} />)}</dt>
270
+ )}
271
+ {node.type === "dd" && (
272
+ <dd class="ml-6 text-muted-foreground">{children.map(child => <Astro.self node={child} images={images} icons={icons} />)}</dd>
273
+ )}
274
+
275
+ {/* ── Table ──────────────────────────────────────────────── */}
276
+ {node.type === "table" && (
277
+ <Table class="my-4">
278
+ {children.map(child => <Astro.self node={child} images={images} icons={icons} />)}
279
+ </Table>
280
+ )}
281
+ {node.type === "thead" && <TableHeader>{children.map(child => <Astro.self node={child} images={images} icons={icons} />)}</TableHeader>}
282
+ {node.type === "tbody" && <TableBody>{children.map(child => <Astro.self node={child} images={images} icons={icons} />)}</TableBody>}
283
+ {node.type === "tr" && <TableRow>{children.map(child => <Astro.self node={child} images={images} icons={icons} />)}</TableRow>}
284
+ {node.type === "th" && <TableHead>{children.map(child => <Astro.self node={child} images={images} icons={icons} />)}</TableHead>}
285
+ {node.type === "td" && <TableCell>{children.map(child => <Astro.self node={child} images={images} icons={icons} />)}</TableCell>}
286
+
287
+ {/* ── Standard block elements ────────────────────────────── */}
288
+ {node.type === "ordered-list" && <ol>{children.map(child => <Astro.self node={child} images={images} icons={icons} />)}</ol>}
289
+ {node.type === "unordered-list" && <ul>{children.map(child => <Astro.self node={child} images={images} icons={icons} />)}</ul>}
290
+ {node.type === "list-item" && <li>{children.map(child => <Astro.self node={child} images={images} icons={icons} />)}</li>}
291
+ {node.type === "blockquote" && (
292
+ <blockquote class="border-l-4 border-border pl-4 italic text-muted-foreground">
293
+ {children.map(child => <Astro.self node={child} images={images} icons={icons} />)}
294
+ </blockquote>
295
+ )}
296
+ {node.type === "hr" && <hr class="my-8 border-border" />}
297
+ {node.type === "html" && (() => {
298
+ let html = node.html || "";
299
+ if (html.includes("<img") && Object.keys(images).length > 0) {
300
+ html = html.replace(/src="([^"]+)"/g, (_match: string, src: string) => {
301
+ const resolved = resolveImage(src);
302
+ if (resolved) return `src="${resolved.src}" width="${resolved.width}" height="${resolved.height}"`;
303
+ return _match;
304
+ });
305
+ }
306
+ return <Fragment set:html={html} />;
307
+ })()}
308
+
309
+ {/* ── API Documentation ──────────────────────────────────── */}
310
+ {(node.type === "api-class" || node.type === "api-member") && (
311
+ <ApiSymbol
312
+ name={(node.props?.name as string) || ""}
313
+ kind={(node.props?.kind as any) || "func"}
314
+ signature={node.props?.signature as string}
315
+ bases={(node.props?.bases as string[]) || []}
316
+ type={node.props?.type as string}
317
+ level={node.type === "api-class" ? 2 : 3}
318
+ >
319
+ {children.map(child => <Astro.self node={child} images={images} icons={icons} />)}
320
+ </ApiSymbol>
321
+ )}
322
+ {node.type === "api-doc" && (
323
+ <ApiDoc html={(node.props?.html as string) || ""} />
324
+ )}
325
+ {node.type === "api-params" && (
326
+ <ApiParams params={(node.props?.params as any[]) || []} />
327
+ )}
328
+ {node.type === "api-source" && (
329
+ <ApiSource
330
+ code={(node.props?.code as string) || ""}
331
+ file={node.props?.file as string}
332
+ line={node.props?.line as number}
333
+ />
334
+ )}
335
+
336
+ {/* ── Diagram — pre-rendered SVG ─────────────────────────── */}
337
+ {node.type === "diagram" && (
338
+ <Diagram
339
+ lang={(node.props?.lang as string) || "mermaid"}
340
+ code={(node.props?.code as string) || ""}
341
+ svg={(node.props?.svg as string) || ""}
342
+ title={node.props?.title as string}
343
+ />
344
+ )}
345
+
346
+ {/* ── Footnotes ──────────────────────────────────────────── */}
347
+ {node.type === "footnote-list" && (
348
+ <ol class="list-decimal pl-6 space-y-1" data-footnote-list>
349
+ {children.map(child => <Astro.self node={child} images={images} icons={icons} />)}
350
+ </ol>
351
+ )}
352
+ {node.type === "footnote-def" && (
353
+ <li id={(node.props?.id as string) || ""} class="text-sm text-muted-foreground">
354
+ {node.inline
355
+ ? <span>{node.inline.map(span => <InlineRenderer node={span} icons={icons} images={images} />)}</span>
356
+ : <Fragment set:html={node.html} />
357
+ }
358
+ {" "}<a href={`#${node.props?.backrefId || ""}`} class="text-primary hover:underline" aria-label={`Back to reference ${node.props?.label}`}>↩</a>
359
+ </li>
360
+ )}
361
+
362
+ {/* ── Math block ─────────────────────────────────────────── */}
363
+ {node.type === "math-block" && (
364
+ <MathKatex latex={(node.props?.latex as string) || ""} display />
365
+ )}
366
+
367
+ {/* ── YouTube embed ──────────────────────────────────────── */}
368
+ {node.type === "youtube" && (
369
+ <YouTube
370
+ id={(node.props?.id as string) || ""}
371
+ title={(node.props?.title as string) || "YouTube video"}
372
+ class="my-4"
373
+ />
374
+ )}
375
+
376
+ {/* ── Annotation list ────────────────────────────────────── */}
377
+ {node.type === "annotation-list" && (
378
+ <div class="my-2 rounded-md border-l-4 border-info/50 bg-info/5 p-4">
379
+ {children.map(child => <Astro.self node={child} images={images} icons={icons} />)}
380
+ </div>
381
+ )}
382
+
383
+ {/* ── HTML containers: columns, grid cards, generic ──────── */}
384
+ {node.type === "html-container" && isColumns && (
385
+ <div class="columns-1 sm:columns-2 gap-4 [&_ul]:m-0">
386
+ {children.map(child => <Astro.self node={child} images={images} icons={icons} />)}
387
+ </div>
388
+ )}
389
+ {node.type === "html-container" && isGridCards && (
390
+ <Grid cols={[1, 2]} gap={4}>
391
+ {children
392
+ .filter(c => c.type === "unordered-list")
393
+ .flatMap(ul => ul.children || [])
394
+ .map(item => (
395
+ <div class="rounded-lg border bg-card p-4 text-card-foreground shadow-sm [&_hr]:my-3 [&_hr]:border-border">
396
+ {(item.children || []).map(child => <Astro.self node={child} images={images} icons={icons} />)}
397
+ </div>
398
+ ))
399
+ }
400
+ </Grid>
401
+ )}
402
+ {node.type === "html-container" && !isColumns && !isGridCards && (
403
+ <Fragment>
404
+ {children.map(child => <Astro.self node={child} images={images} icons={icons} />)}
405
+ </Fragment>
406
+ )}
407
+
408
+ <script>
409
+ import "@dogsbay/elements/db-tabs";
410
+ </script>