@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,32 @@
1
+ ---
2
+ import { tv } from "tailwind-variants";
3
+
4
+ const dialogClose = tv({
5
+ base: "inline-flex items-center justify-center gap-2 rounded-md border border-input bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
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="close" data-as-child>
20
+ <slot />
21
+ </span>
22
+ ) : (
23
+ <button
24
+ class={dialogClose({ class: className })}
25
+ data-part="close"
26
+ type="button"
27
+ {...rest}
28
+ >
29
+ <slot />
30
+ </button>
31
+ )
32
+ }
@@ -0,0 +1,37 @@
1
+ ---
2
+ import { tv } from "tailwind-variants";
3
+
4
+ const dialogBackdrop = tv({
5
+ base: "fixed inset-0 z-50 bg-black/80",
6
+ });
7
+
8
+ const dialogContent = tv({
9
+ base: "fixed left-1/2 top-1/2 z-[51] grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border bg-background p-6 shadow-lg sm:rounded-lg",
10
+ });
11
+
12
+ interface Props {
13
+ class?: string;
14
+ [key: string]: unknown;
15
+ }
16
+
17
+ const { class: className, ...rest } = Astro.props;
18
+ ---
19
+
20
+ <div
21
+ class={dialogBackdrop()}
22
+ data-part="backdrop"
23
+ data-state="closed"
24
+ hidden
25
+ >
26
+ </div>
27
+ <div
28
+ class={dialogContent({ class: className })}
29
+ data-part="content"
30
+ role="dialog"
31
+ aria-modal="true"
32
+ data-state="closed"
33
+ hidden
34
+ {...rest}
35
+ >
36
+ <slot />
37
+ </div>
@@ -0,0 +1,22 @@
1
+ ---
2
+ import { tv } from "tailwind-variants";
3
+
4
+ const dialogDescription = tv({
5
+ base: "text-sm 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
+ <p
17
+ class={dialogDescription({ class: className })}
18
+ data-part="description"
19
+ {...rest}
20
+ >
21
+ <slot />
22
+ </p>
@@ -0,0 +1,18 @@
1
+ ---
2
+ import { tv } from "tailwind-variants";
3
+
4
+ const dialogFooter = tv({
5
+ base: "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
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 class={dialogFooter({ class: className })} {...rest}>
17
+ <slot />
18
+ </div>
@@ -0,0 +1,18 @@
1
+ ---
2
+ import { tv } from "tailwind-variants";
3
+
4
+ const dialogHeader = tv({
5
+ base: "flex flex-col space-y-1.5 text-center sm:text-left",
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 class={dialogHeader({ class: className })} {...rest}>
17
+ <slot />
18
+ </div>
@@ -0,0 +1,18 @@
1
+ ---
2
+ import { tv } from "tailwind-variants";
3
+
4
+ const dialogTitle = tv({
5
+ base: "text-lg font-semibold leading-none tracking-tight",
6
+ });
7
+
8
+ interface Props {
9
+ class?: string;
10
+ [key: string]: unknown;
11
+ }
12
+
13
+ const { class: className, ...rest } = Astro.props;
14
+ ---
15
+
16
+ <h2 class={dialogTitle({ class: className })} data-part="title" {...rest}>
17
+ <slot />
18
+ </h2>
@@ -0,0 +1,33 @@
1
+ ---
2
+ import { tv } from "tailwind-variants";
3
+
4
+ const dialogTrigger = tv({
5
+ base: "inline-flex items-center justify-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
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={dialogTrigger({ class: className })}
25
+ data-part="trigger"
26
+ type="button"
27
+ aria-haspopup="dialog"
28
+ {...rest}
29
+ >
30
+ <slot />
31
+ </button>
32
+ )
33
+ }
@@ -0,0 +1,291 @@
1
+ import { FocusTrap } from "@dogsbay/primitives/focus-trap";
2
+ import { ScrollLock } from "@dogsbay/primitives/scroll-lock";
3
+ import { DismissController } from "@dogsbay/primitives/dismiss";
4
+ import { markOthersInert } from "@dogsbay/primitives/inert";
5
+ import { createPortal } from "@dogsbay/primitives/portal";
6
+
7
+ interface DialogInstance {
8
+ root: HTMLElement;
9
+ trigger: HTMLElement | null;
10
+ content: HTMLElement;
11
+ backdrop: HTMLElement;
12
+ focusTrap: FocusTrap;
13
+ dismiss: DismissController;
14
+ cleanupPortal: (() => void) | null;
15
+ cleanupInert: (() => void) | null;
16
+ open: boolean;
17
+ /** The element that opened the dialog (may differ from trigger if opened externally). */
18
+ openedBy: HTMLElement | null;
19
+ }
20
+
21
+ /** Map from dialog content ID to its root element, for external trigger lookup. */
22
+ const dialogById = new Map<string, HTMLElement>();
23
+
24
+ const instances = new WeakMap<HTMLElement, DialogInstance>();
25
+
26
+ let idCounter = 0;
27
+ function uniqueId(prefix: string) {
28
+ return `${prefix}-${++idCounter}`;
29
+ }
30
+
31
+ function resolveAsChild(wrapper: HTMLElement): HTMLElement {
32
+ // When asChild is used, the wrapper is a <span data-as-child>.
33
+ // Find the first element child and forward the data-part attribute to it.
34
+ const child = wrapper.firstElementChild as HTMLElement | null;
35
+ if (child) {
36
+ const part = wrapper.getAttribute("data-part");
37
+ if (part) child.setAttribute("data-part", part);
38
+ return child;
39
+ }
40
+ return wrapper;
41
+ }
42
+
43
+ function initDialog(root: HTMLElement) {
44
+ if (instances.has(root)) return;
45
+
46
+ // Find parts that belong to THIS dialog root, not nested ones.
47
+ // A part belongs to us if its closest dialog root ancestor is this root.
48
+ const ownParts = (selector: string) => {
49
+ const all = root.querySelectorAll(selector);
50
+ for (let i = 0; i < all.length; i++) {
51
+ const el = all[i] as HTMLElement;
52
+ if (el.closest("[data-component='dialog']") === root) return el;
53
+ }
54
+ return null;
55
+ };
56
+
57
+ const content = ownParts("[data-part='content']");
58
+ const backdrop = ownParts("[data-part='backdrop']");
59
+ if (!content || !backdrop) return;
60
+
61
+ // Resolve trigger — handle asChild
62
+ const triggerWrapper = ownParts("[data-part='trigger']");
63
+ let trigger = triggerWrapper;
64
+ if (triggerWrapper?.hasAttribute("data-as-child")) {
65
+ trigger = resolveAsChild(triggerWrapper);
66
+ }
67
+
68
+ // Generate unique IDs for ARIA linkage
69
+ const dialogId = content.id || uniqueId("base-dialog");
70
+ content.id = dialogId;
71
+
72
+ if (trigger) {
73
+ trigger.setAttribute("aria-controls", dialogId);
74
+ trigger.setAttribute("aria-expanded", "false");
75
+ if (!trigger.hasAttribute("aria-haspopup")) {
76
+ trigger.setAttribute("aria-haspopup", "dialog");
77
+ }
78
+ }
79
+
80
+ // Link title and description
81
+ const title = content.querySelector(
82
+ "[data-part='title']",
83
+ ) as HTMLElement | null;
84
+ const description = content.querySelector(
85
+ "[data-part='description']",
86
+ ) as HTMLElement | null;
87
+
88
+ if (title) {
89
+ const titleId = title.id || uniqueId("base-dialog-title");
90
+ title.id = titleId;
91
+ content.setAttribute("aria-labelledby", titleId);
92
+ }
93
+ if (description) {
94
+ const descId = description.id || uniqueId("base-dialog-desc");
95
+ description.id = descId;
96
+ content.setAttribute("aria-describedby", descId);
97
+ }
98
+
99
+ const instance: DialogInstance = {
100
+ root,
101
+ trigger,
102
+ content,
103
+ backdrop,
104
+ focusTrap: new FocusTrap(content),
105
+ dismiss: new DismissController(content, {
106
+ onDismiss: (reason) => closeDialog(root, reason),
107
+ }),
108
+ cleanupPortal: null,
109
+ cleanupInert: null,
110
+ open: false,
111
+ openedBy: null,
112
+ };
113
+
114
+ instances.set(root, instance);
115
+ dialogById.set(dialogId, root);
116
+
117
+ // Trigger click
118
+ if (trigger) {
119
+ trigger.addEventListener("click", () => {
120
+ if (instance.open) {
121
+ closeDialog(root, "trigger-press");
122
+ } else {
123
+ openDialog(root, trigger);
124
+ }
125
+ });
126
+ }
127
+
128
+ // Close button handlers — only bind buttons that belong to THIS dialog,
129
+ // not close buttons inside nested dialogs
130
+ content.querySelectorAll("[data-part='close']").forEach((el) => {
131
+ // Skip if this close button is inside a nested dialog's content
132
+ const parentContent = el.closest("[data-part='content']");
133
+ if (parentContent !== content) return;
134
+
135
+ let closeEl = el as HTMLElement;
136
+ if (closeEl.hasAttribute("data-as-child")) {
137
+ closeEl = resolveAsChild(closeEl);
138
+ }
139
+ closeEl.addEventListener("click", () => {
140
+ closeDialog(root, "close-press");
141
+ });
142
+ });
143
+ }
144
+
145
+ function openDialog(root: HTMLElement, opener?: HTMLElement) {
146
+ const instance = instances.get(root);
147
+ if (!instance || instance.open) return;
148
+ instance.open = true;
149
+ instance.openedBy = opener ?? instance.trigger;
150
+
151
+ // Portal: move content and backdrop to body
152
+ const contentPortalCleanup = createPortal(
153
+ instance.content,
154
+ instance.content.id,
155
+ );
156
+ const backdropPortalCleanup = createPortal(
157
+ instance.backdrop,
158
+ `${instance.content.id}-backdrop`,
159
+ );
160
+ instance.cleanupPortal = () => {
161
+ contentPortalCleanup();
162
+ backdropPortalCleanup();
163
+ };
164
+
165
+ // Show
166
+ instance.content.hidden = false;
167
+ instance.backdrop.hidden = false;
168
+ instance.content.setAttribute("data-state", "open");
169
+ instance.backdrop.setAttribute("data-state", "open");
170
+ if (instance.openedBy) {
171
+ instance.openedBy.setAttribute("aria-expanded", "true");
172
+ }
173
+
174
+ // Scroll lock
175
+ ScrollLock.activate();
176
+
177
+ // Inert siblings
178
+ instance.cleanupInert = markOthersInert(instance.content);
179
+
180
+ // Focus trap
181
+ instance.focusTrap.activate();
182
+
183
+ // Dismiss
184
+ instance.dismiss.activate();
185
+
186
+ // Dispatch open event
187
+ root.dispatchEvent(new CustomEvent("base-dialog:open", { bubbles: true }));
188
+ }
189
+
190
+ function closeDialog(root: HTMLElement, reason: string) {
191
+ const instance = instances.get(root);
192
+ if (!instance || !instance.open) {
193
+ return;
194
+ }
195
+ instance.open = false;
196
+
197
+ // Deactivate in reverse order
198
+ instance.dismiss.deactivate();
199
+ instance.focusTrap.deactivate();
200
+
201
+ if (instance.cleanupInert) {
202
+ instance.cleanupInert();
203
+ instance.cleanupInert = null;
204
+ }
205
+
206
+ ScrollLock.deactivate();
207
+
208
+ // Update state attributes
209
+ instance.content.setAttribute("data-state", "closed");
210
+ instance.backdrop.setAttribute("data-state", "closed");
211
+ if (instance.openedBy) {
212
+ instance.openedBy.setAttribute("aria-expanded", "false");
213
+ }
214
+
215
+ // Wait for exit animations before hiding/removing portals
216
+ const animations = instance.content.getAnimations?.() ?? [];
217
+ const cleanup = () => {
218
+ instance.content.hidden = true;
219
+ instance.backdrop.hidden = true;
220
+ if (instance.cleanupPortal) {
221
+ instance.cleanupPortal();
222
+ instance.cleanupPortal = null;
223
+ }
224
+ };
225
+
226
+ if (animations.length > 0) {
227
+ Promise.all(animations.map((a) => a.finished))
228
+ .then(cleanup)
229
+ .catch(cleanup);
230
+ } else {
231
+ cleanup();
232
+ }
233
+
234
+ // Dispatch close event
235
+ root.dispatchEvent(
236
+ new CustomEvent("base-dialog:close", {
237
+ detail: { reason },
238
+ bubbles: true,
239
+ }),
240
+ );
241
+ }
242
+
243
+ /**
244
+ * Bind external triggers — elements with `data-dialog-for="dialogId"` anywhere
245
+ * on the page can open a dialog without being inside its component tree.
246
+ */
247
+ function bindExternalTriggers() {
248
+ document.querySelectorAll("[data-dialog-for]").forEach((el) => {
249
+ const btn = el as HTMLElement;
250
+ // Skip if already bound
251
+ if (btn.hasAttribute("data-dialog-external-bound")) return;
252
+ btn.setAttribute("data-dialog-external-bound", "");
253
+
254
+ const targetId = btn.getAttribute("data-dialog-for")!;
255
+ // Set ARIA attributes on the external trigger
256
+ btn.setAttribute("aria-haspopup", "dialog");
257
+ btn.setAttribute("aria-controls", targetId);
258
+ btn.setAttribute("aria-expanded", "false");
259
+
260
+ btn.addEventListener("click", () => {
261
+ const root = dialogById.get(targetId);
262
+ if (!root) return;
263
+ const instance = instances.get(root);
264
+ if (!instance) return;
265
+
266
+ if (instance.open) {
267
+ closeDialog(root, "trigger-press");
268
+ } else {
269
+ openDialog(root, btn);
270
+ }
271
+ });
272
+ });
273
+ }
274
+
275
+ // Auto-initialize all dialog roots on the page
276
+ function init() {
277
+ document.querySelectorAll("[data-component='dialog']").forEach((el) => {
278
+ initDialog(el as HTMLElement);
279
+ });
280
+ bindExternalTriggers();
281
+ }
282
+
283
+ // Run on load and after Astro View Transitions
284
+ if (document.readyState === "loading") {
285
+ document.addEventListener("DOMContentLoaded", init);
286
+ } else {
287
+ init();
288
+ }
289
+ document.addEventListener("astro:page-load", init);
290
+
291
+ export { initDialog, openDialog, closeDialog };
@@ -0,0 +1,8 @@
1
+ export { default as Dialog } from "./Dialog.astro";
2
+ export { default as DialogTrigger } from "./DialogTrigger.astro";
3
+ export { default as DialogContent } from "./DialogContent.astro";
4
+ export { default as DialogHeader } from "./DialogHeader.astro";
5
+ export { default as DialogTitle } from "./DialogTitle.astro";
6
+ export { default as DialogDescription } from "./DialogDescription.astro";
7
+ export { default as DialogFooter } from "./DialogFooter.astro";
8
+ export { default as DialogClose } from "./DialogClose.astro";
@@ -0,0 +1,50 @@
1
+ ---
2
+ import { tv } from "tailwind-variants";
3
+
4
+ const docsFooter = tv({
5
+ base: "mt-12 border-t pt-6",
6
+ });
7
+
8
+ const footerMeta = tv({
9
+ base: "mb-6 flex flex-wrap items-center gap-4 text-sm text-muted-foreground",
10
+ });
11
+
12
+ interface Props {
13
+ /** URL to edit this page on GitHub */
14
+ editUrl?: string;
15
+ /** Last updated date string */
16
+ lastUpdated?: string;
17
+ class?: string;
18
+ [key: string]: unknown;
19
+ }
20
+
21
+ const { editUrl, lastUpdated, class: className, ...rest } = Astro.props;
22
+
23
+ const showMeta = !!editUrl || !!lastUpdated;
24
+ ---
25
+
26
+ <footer
27
+ class={docsFooter({ class: className })}
28
+ data-component="docs-footer"
29
+ {...rest}
30
+ >
31
+ {showMeta && (
32
+ <div class={footerMeta()}>
33
+ {editUrl && (
34
+ <a
35
+ href={editUrl}
36
+ target="_blank"
37
+ rel="noopener noreferrer"
38
+ class="inline-flex items-center gap-1 hover:text-foreground"
39
+ >
40
+ <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" aria-hidden="true"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path></svg>
41
+ Edit this page
42
+ </a>
43
+ )}
44
+ {lastUpdated && (
45
+ <span>Last updated: {lastUpdated}</span>
46
+ )}
47
+ </div>
48
+ )}
49
+ <slot />
50
+ </footer>
@@ -0,0 +1,32 @@
1
+ ---
2
+ import { tv } from "tailwind-variants";
3
+
4
+ const docsHeader = tv({
5
+ base: "z-40 flex h-14 items-center gap-4 border-b bg-background/95 px-4 backdrop-blur supports-[backdrop-filter]:bg-background/60",
6
+ variants: {
7
+ sticky: {
8
+ true: "sticky top-0",
9
+ },
10
+ },
11
+ defaultVariants: {
12
+ sticky: true,
13
+ },
14
+ });
15
+
16
+ interface Props {
17
+ /** Stick to top of viewport while scrolling (default: true) */
18
+ sticky?: boolean;
19
+ class?: string;
20
+ [key: string]: unknown;
21
+ }
22
+
23
+ const { sticky = true, class: className, ...rest } = Astro.props;
24
+ ---
25
+
26
+ <header
27
+ class={docsHeader({ sticky, class: className })}
28
+ data-component="docs-header"
29
+ {...rest}
30
+ >
31
+ <slot />
32
+ </header>