@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,17 @@
1
+ ---
2
+ interface Props {
3
+ class?: string;
4
+ [key: string]: unknown;
5
+ }
6
+
7
+ const { class: className, ...rest } = Astro.props;
8
+ ---
9
+
10
+ <div
11
+ class={className}
12
+ data-part="group"
13
+ role="group"
14
+ {...rest}
15
+ >
16
+ <slot />
17
+ </div>
@@ -0,0 +1,48 @@
1
+ ---
2
+ import { tv, type VariantProps } from "tailwind-variants";
3
+
4
+ const dropdownMenuItem = tv({
5
+ base: "relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0",
6
+ variants: {
7
+ variant: {
8
+ default: "",
9
+ destructive:
10
+ "text-destructive focus:bg-destructive focus:text-destructive-foreground",
11
+ },
12
+ inset: {
13
+ true: "pl-8",
14
+ },
15
+ },
16
+ defaultVariants: {
17
+ variant: "default",
18
+ },
19
+ });
20
+
21
+ type MenuItemVariants = VariantProps<typeof dropdownMenuItem>;
22
+
23
+ interface Props {
24
+ variant?: MenuItemVariants["variant"];
25
+ inset?: boolean;
26
+ disabled?: boolean;
27
+ class?: string;
28
+ [key: string]: unknown;
29
+ }
30
+
31
+ const {
32
+ variant = "default",
33
+ inset = false,
34
+ disabled = false,
35
+ class: className,
36
+ ...rest
37
+ } = Astro.props;
38
+ ---
39
+
40
+ <div
41
+ class={dropdownMenuItem({ variant, inset: inset || undefined, class: className })}
42
+ data-part="item"
43
+ role="menuitem"
44
+ data-disabled={disabled ? "true" : undefined}
45
+ {...rest}
46
+ >
47
+ <slot />
48
+ </div>
@@ -0,0 +1,28 @@
1
+ ---
2
+ import { tv } from "tailwind-variants";
3
+
4
+ const dropdownMenuLabel = tv({
5
+ base: "px-2 py-1.5 text-sm font-semibold",
6
+ variants: {
7
+ inset: {
8
+ true: "pl-8",
9
+ },
10
+ },
11
+ });
12
+
13
+ interface Props {
14
+ inset?: boolean;
15
+ class?: string;
16
+ [key: string]: unknown;
17
+ }
18
+
19
+ const { inset = false, class: className, ...rest } = Astro.props;
20
+ ---
21
+
22
+ <div
23
+ class={dropdownMenuLabel({ inset: inset || undefined, class: className })}
24
+ data-part="label"
25
+ {...rest}
26
+ >
27
+ <slot />
28
+ </div>
@@ -0,0 +1,21 @@
1
+ ---
2
+ import { tv } from "tailwind-variants";
3
+
4
+ const dropdownMenuSeparator = tv({
5
+ base: "-mx-1 my-1 h-px bg-muted",
6
+ });
7
+
8
+ interface Props {
9
+ class?: string;
10
+ [key: string]: unknown;
11
+ }
12
+
13
+ const { class: className, ...rest } = Astro.props;
14
+ ---
15
+
16
+ <div
17
+ class={dropdownMenuSeparator({ class: className })}
18
+ role="separator"
19
+ {...rest}
20
+ >
21
+ </div>
@@ -0,0 +1,18 @@
1
+ ---
2
+ import { tv } from "tailwind-variants";
3
+
4
+ const dropdownMenuShortcut = tv({
5
+ base: "ml-auto text-xs tracking-widest text-muted-foreground",
6
+ });
7
+
8
+ interface Props {
9
+ class?: string;
10
+ [key: string]: unknown;
11
+ }
12
+
13
+ const { class: className, ...rest } = Astro.props;
14
+ ---
15
+
16
+ <span class={dropdownMenuShortcut({ class: className })} {...rest}>
17
+ <slot />
18
+ </span>
@@ -0,0 +1,34 @@
1
+ ---
2
+ import { tv } from "tailwind-variants";
3
+
4
+ const dropdownMenuTrigger = tv({
5
+ base: "inline-flex items-center justify-center",
6
+ });
7
+
8
+ interface Props {
9
+ asChild?: boolean;
10
+ class?: string;
11
+ [key: string]: unknown;
12
+ }
13
+
14
+ const { asChild = false, class: className, ...rest } = Astro.props;
15
+ ---
16
+
17
+ {
18
+ asChild ? (
19
+ <span data-part="trigger" data-as-child>
20
+ <slot />
21
+ </span>
22
+ ) : (
23
+ <button
24
+ class={dropdownMenuTrigger({ class: className })}
25
+ data-part="trigger"
26
+ type="button"
27
+ aria-haspopup="menu"
28
+ aria-expanded="false"
29
+ {...rest}
30
+ >
31
+ <slot />
32
+ </button>
33
+ )
34
+ }
@@ -0,0 +1,348 @@
1
+ import { DismissController } from "@dogsbay/primitives/dismiss";
2
+ import { createPortal } from "@dogsbay/primitives/portal";
3
+ import { setupFloating } from "@dogsbay/primitives/floating";
4
+ import { Typeahead } from "@dogsbay/primitives/typeahead";
5
+
6
+ interface DropdownMenuInstance {
7
+ root: HTMLElement;
8
+ trigger: HTMLElement;
9
+ content: HTMLElement;
10
+ items: HTMLElement[];
11
+ dismiss: DismissController;
12
+ typeahead: Typeahead;
13
+ cleanupPortal: (() => void) | null;
14
+ cleanupFloating: (() => void) | null;
15
+ open: boolean;
16
+ highlightedIndex: number;
17
+ }
18
+
19
+ const instances = new WeakMap<HTMLElement, DropdownMenuInstance>();
20
+
21
+ let idCounter = 0;
22
+ function uniqueId(prefix: string) {
23
+ return `${prefix}-${++idCounter}`;
24
+ }
25
+
26
+ function getEnabledItems(items: HTMLElement[]): HTMLElement[] {
27
+ return items.filter(
28
+ (item) => item.getAttribute("data-disabled") !== "true",
29
+ );
30
+ }
31
+
32
+ function initDropdownMenu(root: HTMLElement) {
33
+ if (instances.has(root)) return;
34
+
35
+ const trigger = root.querySelector(
36
+ "[data-part='trigger']",
37
+ ) as HTMLElement | null;
38
+ const content = root.querySelector(
39
+ "[data-part='content']",
40
+ ) as HTMLElement | null;
41
+
42
+ if (!trigger || !content) return;
43
+
44
+ const items = Array.from(
45
+ content.querySelectorAll("[data-part='item']"),
46
+ ) as HTMLElement[];
47
+
48
+ // Generate IDs
49
+ const menuId = uniqueId("base-dropdown-menu");
50
+ const contentId = content.id || `${menuId}-menu`;
51
+ content.id = contentId;
52
+ trigger.setAttribute("aria-controls", contentId);
53
+
54
+ items.forEach((item, i) => {
55
+ const itemId = item.id || `${menuId}-item-${i}`;
56
+ item.id = itemId;
57
+ item.setAttribute("tabindex", "-1");
58
+ });
59
+
60
+ // Link groups to their labels
61
+ content.querySelectorAll("[data-part='group']").forEach((group) => {
62
+ const label = group.querySelector("[data-part='label']") as HTMLElement;
63
+ if (label) {
64
+ const labelId = label.id || uniqueId("base-dropdown-menu-label");
65
+ label.id = labelId;
66
+ (group as HTMLElement).setAttribute("aria-labelledby", labelId);
67
+ }
68
+ });
69
+
70
+ const typeahead = new Typeahead({
71
+ onMatch: (index) => {
72
+ const enabledItems = getEnabledItems(items);
73
+ if (index < enabledItems.length) {
74
+ const actualIndex = items.indexOf(enabledItems[index]);
75
+ highlightItem(root, actualIndex);
76
+ }
77
+ },
78
+ getItemText: (i) => {
79
+ const enabledItems = getEnabledItems(items);
80
+ return enabledItems[i]?.textContent?.trim() || "";
81
+ },
82
+ getItemCount: () => getEnabledItems(items).length,
83
+ });
84
+
85
+ const instance: DropdownMenuInstance = {
86
+ root,
87
+ trigger,
88
+ content,
89
+ items,
90
+ dismiss: new DismissController(content, {
91
+ onDismiss: () => closeDropdownMenu(root),
92
+ }),
93
+ typeahead,
94
+ cleanupPortal: null,
95
+ cleanupFloating: null,
96
+ open: false,
97
+ highlightedIndex: -1,
98
+ };
99
+
100
+ instances.set(root, instance);
101
+
102
+ // Resolve the actual interactive element for asChild
103
+ const actualTrigger = trigger.hasAttribute("data-as-child")
104
+ ? (trigger.firstElementChild as HTMLElement) || trigger
105
+ : trigger;
106
+
107
+ // Copy ARIA attributes to actual trigger for asChild
108
+ if (trigger.hasAttribute("data-as-child")) {
109
+ actualTrigger.setAttribute("aria-haspopup", "menu");
110
+ actualTrigger.setAttribute("aria-expanded", "false");
111
+ actualTrigger.setAttribute("aria-controls", contentId);
112
+ }
113
+
114
+ // Trigger click
115
+ actualTrigger.addEventListener("click", () => {
116
+ if (instance.open) {
117
+ closeDropdownMenu(root);
118
+ } else {
119
+ openDropdownMenu(root);
120
+ }
121
+ });
122
+
123
+ // Trigger keyboard: open on Enter/Space/ArrowDown
124
+ actualTrigger.addEventListener("keydown", (e) => {
125
+ if (instance.open) return; // When open, keyboard is on content
126
+
127
+ if (e.key === "Enter" || e.key === " ") {
128
+ e.preventDefault();
129
+ openDropdownMenu(root);
130
+ } else if (e.key === "ArrowDown") {
131
+ e.preventDefault();
132
+ openDropdownMenu(root);
133
+ } else if (e.key === "ArrowUp") {
134
+ e.preventDefault();
135
+ openDropdownMenu(root, "last");
136
+ }
137
+ });
138
+
139
+ // Content keyboard: navigate and select
140
+ content.addEventListener("keydown", (e) => {
141
+ if (!instance.open) return;
142
+
143
+ const enabledItems = getEnabledItems(items);
144
+ if (enabledItems.length === 0) return;
145
+
146
+ const currentHighlighted =
147
+ instance.highlightedIndex >= 0 ? items[instance.highlightedIndex] : null;
148
+ const currentEnabledIndex = currentHighlighted
149
+ ? enabledItems.indexOf(currentHighlighted)
150
+ : -1;
151
+
152
+ if (e.key === "ArrowDown") {
153
+ e.preventDefault();
154
+ const nextIdx =
155
+ currentEnabledIndex < enabledItems.length - 1
156
+ ? currentEnabledIndex + 1
157
+ : 0;
158
+ highlightItem(root, items.indexOf(enabledItems[nextIdx]));
159
+ } else if (e.key === "ArrowUp") {
160
+ e.preventDefault();
161
+ const prevIdx =
162
+ currentEnabledIndex > 0
163
+ ? currentEnabledIndex - 1
164
+ : enabledItems.length - 1;
165
+ highlightItem(root, items.indexOf(enabledItems[prevIdx]));
166
+ } else if (e.key === "Home") {
167
+ e.preventDefault();
168
+ highlightItem(root, items.indexOf(enabledItems[0]));
169
+ } else if (e.key === "End") {
170
+ e.preventDefault();
171
+ highlightItem(
172
+ root,
173
+ items.indexOf(enabledItems[enabledItems.length - 1]),
174
+ );
175
+ } else if (e.key === "Enter" || e.key === " ") {
176
+ e.preventDefault();
177
+ if (instance.highlightedIndex >= 0) {
178
+ const item = items[instance.highlightedIndex];
179
+ item.click();
180
+ }
181
+ closeDropdownMenu(root);
182
+ } else if (e.key === "Tab") {
183
+ closeDropdownMenu(root);
184
+ } else if (e.key.length === 1) {
185
+ typeahead.handle(e.key);
186
+ }
187
+ });
188
+
189
+ // Item click and hover
190
+ items.forEach((item) => {
191
+ item.addEventListener("click", (e) => {
192
+ if (item.getAttribute("data-disabled") === "true") {
193
+ e.preventDefault();
194
+ return;
195
+ }
196
+ closeDropdownMenu(root);
197
+ });
198
+
199
+ item.addEventListener("pointerenter", () => {
200
+ if (item.getAttribute("data-disabled") === "true") return;
201
+ highlightItem(root, items.indexOf(item));
202
+ });
203
+
204
+ item.addEventListener("pointerleave", () => {
205
+ clearHighlight(root);
206
+ });
207
+ });
208
+ }
209
+
210
+ function openDropdownMenu(root: HTMLElement, initialFocus: "first" | "last" = "first") {
211
+ const instance = instances.get(root);
212
+ if (!instance || instance.open) return;
213
+ instance.open = true;
214
+
215
+ // Resolve asChild trigger
216
+ const actualTrigger = instance.trigger.hasAttribute("data-as-child")
217
+ ? (instance.trigger.firstElementChild as HTMLElement) || instance.trigger
218
+ : instance.trigger;
219
+
220
+ // Portal
221
+ instance.cleanupPortal = createPortal(instance.content, instance.content.id);
222
+
223
+ // Show
224
+ instance.content.hidden = false;
225
+ instance.content.setAttribute("data-state", "open");
226
+ actualTrigger.setAttribute("aria-expanded", "true");
227
+
228
+ // Read placement from content data attribute
229
+ const side = instance.content.dataset.side || "bottom";
230
+ const align = instance.content.dataset.align || "start";
231
+ const placement = `${side}-${align}` as import("@floating-ui/dom").Placement;
232
+
233
+ // Position
234
+ instance.cleanupFloating = setupFloating(
235
+ actualTrigger,
236
+ instance.content,
237
+ {
238
+ placement,
239
+ offset: 4,
240
+ },
241
+ );
242
+
243
+ // Focus first/last enabled item
244
+ const enabledItems = getEnabledItems(instance.items);
245
+ if (enabledItems.length > 0) {
246
+ const targetItem =
247
+ initialFocus === "last"
248
+ ? enabledItems[enabledItems.length - 1]
249
+ : enabledItems[0];
250
+ highlightItem(root, instance.items.indexOf(targetItem));
251
+ }
252
+
253
+ // Dismiss
254
+ instance.dismiss.activate();
255
+
256
+ // Reset typeahead
257
+ instance.typeahead.reset();
258
+ }
259
+
260
+ function closeDropdownMenu(root: HTMLElement) {
261
+ const instance = instances.get(root);
262
+ if (!instance || !instance.open) return;
263
+ instance.open = false;
264
+
265
+ instance.dismiss.deactivate();
266
+
267
+ // Resolve asChild trigger
268
+ const actualTrigger = instance.trigger.hasAttribute("data-as-child")
269
+ ? (instance.trigger.firstElementChild as HTMLElement) || instance.trigger
270
+ : instance.trigger;
271
+
272
+ // Update state
273
+ instance.content.setAttribute("data-state", "closed");
274
+ actualTrigger.setAttribute("aria-expanded", "false");
275
+
276
+ // Clear highlights
277
+ clearHighlight(root);
278
+
279
+ // Hide and cleanup
280
+ instance.content.hidden = true;
281
+ if (instance.cleanupFloating) {
282
+ instance.cleanupFloating();
283
+ instance.cleanupFloating = null;
284
+ }
285
+ if (instance.cleanupPortal) {
286
+ instance.cleanupPortal();
287
+ instance.cleanupPortal = null;
288
+ }
289
+
290
+ // Return focus to trigger
291
+ actualTrigger.focus();
292
+
293
+ // Reset typeahead
294
+ instance.typeahead.reset();
295
+ }
296
+
297
+ function highlightItem(root: HTMLElement, index: number) {
298
+ const instance = instances.get(root);
299
+ if (!instance) return;
300
+ if (index < 0 || index >= instance.items.length) return;
301
+
302
+ // Clear previous highlight
303
+ if (instance.highlightedIndex >= 0) {
304
+ const prev = instance.items[instance.highlightedIndex];
305
+ prev.removeAttribute("data-highlighted");
306
+ prev.setAttribute("tabindex", "-1");
307
+ }
308
+
309
+ // Set new highlight
310
+ instance.highlightedIndex = index;
311
+ const item = instance.items[index];
312
+ item.setAttribute("data-highlighted", "");
313
+ item.setAttribute("tabindex", "0");
314
+ item.focus();
315
+
316
+ // Scroll into view
317
+ item.scrollIntoView({ block: "nearest" });
318
+ }
319
+
320
+ function clearHighlight(root: HTMLElement) {
321
+ const instance = instances.get(root);
322
+ if (!instance) return;
323
+
324
+ if (instance.highlightedIndex >= 0) {
325
+ const prev = instance.items[instance.highlightedIndex];
326
+ prev.removeAttribute("data-highlighted");
327
+ prev.setAttribute("tabindex", "-1");
328
+ }
329
+ instance.highlightedIndex = -1;
330
+ }
331
+
332
+ // Auto-initialize
333
+ function init() {
334
+ document
335
+ .querySelectorAll("[data-component='dropdown-menu']")
336
+ .forEach((el) => {
337
+ initDropdownMenu(el as HTMLElement);
338
+ });
339
+ }
340
+
341
+ if (document.readyState === "loading") {
342
+ document.addEventListener("DOMContentLoaded", init);
343
+ } else {
344
+ init();
345
+ }
346
+ document.addEventListener("astro:page-load", init);
347
+
348
+ export { initDropdownMenu, openDropdownMenu, closeDropdownMenu };
@@ -0,0 +1,8 @@
1
+ export { default as DropdownMenu } from "./DropdownMenu.astro";
2
+ export { default as DropdownMenuTrigger } from "./DropdownMenuTrigger.astro";
3
+ export { default as DropdownMenuContent } from "./DropdownMenuContent.astro";
4
+ export { default as DropdownMenuItem } from "./DropdownMenuItem.astro";
5
+ export { default as DropdownMenuGroup } from "./DropdownMenuGroup.astro";
6
+ export { default as DropdownMenuLabel } from "./DropdownMenuLabel.astro";
7
+ export { default as DropdownMenuSeparator } from "./DropdownMenuSeparator.astro";
8
+ export { default as DropdownMenuShortcut } from "./DropdownMenuShortcut.astro";
@@ -0,0 +1,60 @@
1
+ ---
2
+ /**
3
+ * API endpoint card with URL bar and collapsible sections.
4
+ *
5
+ * Usage:
6
+ * <EndpointCard method="get" path="/pet/{petId}" baseUrl="https://petstore.swagger.io/api/v3">
7
+ * <EndpointSection value="parameters" title="Parameters" default>
8
+ * <PropertyList parameters={params} />
9
+ * </EndpointSection>
10
+ * <EndpointSection value="responses" title="Responses">
11
+ * <ResponseTabs responses={responses} />
12
+ * </EndpointSection>
13
+ * </EndpointCard>
14
+ */
15
+ import { tv } from "tailwind-variants";
16
+ import ApiUrlBar from "../api-url-bar/ApiUrlBar.astro";
17
+ import Badge from "../badge/Badge.astro";
18
+
19
+ const endpointCard = tv({
20
+ base: "space-y-4",
21
+ });
22
+
23
+ interface Props {
24
+ method: "get" | "post" | "put" | "patch" | "delete" | "head" | "options";
25
+ path: string;
26
+ baseUrl?: string;
27
+ summary?: string;
28
+ description?: string;
29
+ deprecated?: boolean;
30
+ class?: string;
31
+ [key: string]: unknown;
32
+ }
33
+
34
+ const { method, path, baseUrl, summary, description, deprecated = false, class: className, ...rest } = Astro.props;
35
+ ---
36
+
37
+ <div
38
+ class={endpointCard({ class: className })}
39
+ data-component="endpoint-card"
40
+ data-deprecated={deprecated ? "" : undefined}
41
+ {...rest}
42
+ >
43
+ <ApiUrlBar method={method} path={path} baseUrl={baseUrl} />
44
+
45
+ {deprecated && (
46
+ <div class="flex items-center gap-2 rounded-lg border border-api-deprecated/30 bg-api-deprecated/10 px-4 py-2 text-sm text-api-deprecated">
47
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"></path><path d="M12 9v4"></path><path d="M12 17h.01"></path></svg>
48
+ <span>This endpoint is deprecated.</span>
49
+ </div>
50
+ )}
51
+
52
+ {summary && <p class="text-sm text-muted-foreground">{summary}</p>}
53
+ {description && description !== summary && (
54
+ <div class="text-sm text-muted-foreground" set:html={description} />
55
+ )}
56
+
57
+ <div class="space-y-3">
58
+ <slot />
59
+ </div>
60
+ </div>
@@ -0,0 +1,22 @@
1
+ ---
2
+ import { tv } from "tailwind-variants";
3
+
4
+ const sectionTitle = tv({
5
+ base: "px-6 py-3 text-xs font-semibold uppercase tracking-wider text-muted-foreground bg-muted/50",
6
+ });
7
+
8
+ interface Props {
9
+ title: string;
10
+ class?: string;
11
+ [key: string]: unknown;
12
+ }
13
+
14
+ const { title, class: className, ...rest } = Astro.props;
15
+ ---
16
+
17
+ <div class={className} {...rest}>
18
+ <h3 class={sectionTitle()}>{title}</h3>
19
+ <div class="px-6 py-4">
20
+ <slot />
21
+ </div>
22
+ </div>
@@ -0,0 +1,35 @@
1
+ ---
2
+ /**
3
+ * Collapsible section within an EndpointCard.
4
+ * Uses native <details>/<summary> for zero-JS expand/collapse.
5
+ *
6
+ * Usage:
7
+ * <EndpointSection title="Parameters" open>
8
+ * <PropertyList ... />
9
+ * </EndpointSection>
10
+ */
11
+
12
+ interface Props {
13
+ title: string;
14
+ open?: boolean;
15
+ class?: string;
16
+ }
17
+
18
+ const { title, open = true, class: className } = Astro.props;
19
+ ---
20
+
21
+ <details open={open} class:list={["rounded-lg border bg-card", className]}>
22
+ <summary class="flex cursor-pointer items-center gap-2 px-4 py-3 text-sm font-semibold list-none [&::-webkit-details-marker]:hidden hover:bg-muted/50 select-none">
23
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-3.5 shrink-0 text-muted-foreground transition-transform duration-200" data-section-chevron aria-hidden="true"><polyline points="9 18 15 12 9 6" /></svg>
24
+ <span>{title}</span>
25
+ </summary>
26
+ <div class="px-4 pb-4 pt-1">
27
+ <slot />
28
+ </div>
29
+ </details>
30
+
31
+ <style is:global>
32
+ details[open] > summary [data-section-chevron] {
33
+ transform: rotate(90deg);
34
+ }
35
+ </style>
@@ -0,0 +1,31 @@
1
+ ---
2
+ import { tv } from "tailwind-variants";
3
+
4
+ const field = tv({
5
+ base: "space-y-2",
6
+ });
7
+
8
+ interface Props {
9
+ name?: string;
10
+ error?: string;
11
+ class?: string;
12
+ [key: string]: unknown;
13
+ }
14
+
15
+ const { name, error, class: className, ...rest } = Astro.props;
16
+ ---
17
+
18
+ <div
19
+ class={field({ class: className })}
20
+ data-component="field"
21
+ data-name={name}
22
+ data-invalid={error ? "" : undefined}
23
+ {...rest}
24
+ >
25
+ <slot />
26
+ {error && (
27
+ <p class="text-sm font-medium text-destructive" data-part="error" role="alert">
28
+ {error}
29
+ </p>
30
+ )}
31
+ </div>