@thomasfosterau/components 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (340) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +817 -2
  3. package/dist/canvas/VectorCanvas.svelte +239 -0
  4. package/dist/canvas/VectorCanvas.svelte.d.ts +87 -0
  5. package/dist/canvas/history.d.ts +105 -0
  6. package/dist/canvas/history.js +147 -0
  7. package/dist/canvas/index.d.ts +15 -0
  8. package/dist/canvas/index.js +14 -0
  9. package/dist/canvas/types.d.ts +91 -0
  10. package/dist/canvas/types.js +13 -0
  11. package/dist/canvas/utils.d.ts +66 -0
  12. package/dist/canvas/utils.js +114 -0
  13. package/dist/charts/Chart.svelte +300 -0
  14. package/dist/charts/Chart.svelte.d.ts +50 -0
  15. package/dist/charts/index.d.ts +11 -0
  16. package/dist/charts/index.js +10 -0
  17. package/dist/charts/types.d.ts +28 -0
  18. package/dist/charts/types.js +6 -0
  19. package/dist/citations/BookCitation.svelte +53 -0
  20. package/dist/citations/BookCitation.svelte.d.ts +41 -0
  21. package/dist/citations/ChapterCitation.svelte +38 -0
  22. package/dist/citations/ChapterCitation.svelte.d.ts +50 -0
  23. package/dist/citations/Citation.svelte +47 -0
  24. package/dist/citations/Citation.svelte.d.ts +24 -0
  25. package/dist/citations/CreditList.svelte +69 -0
  26. package/dist/citations/CreditList.svelte.d.ts +47 -0
  27. package/dist/citations/DOILink.svelte +28 -0
  28. package/dist/citations/DOILink.svelte.d.ts +19 -0
  29. package/dist/citations/Footnote.svelte +39 -0
  30. package/dist/citations/Footnote.svelte.d.ts +17 -0
  31. package/dist/citations/FootnoteList.svelte +36 -0
  32. package/dist/citations/FootnoteList.svelte.d.ts +21 -0
  33. package/dist/citations/ISBNLink.svelte +29 -0
  34. package/dist/citations/ISBNLink.svelte.d.ts +19 -0
  35. package/dist/citations/ISSNLink.svelte +29 -0
  36. package/dist/citations/ISSNLink.svelte.d.ts +19 -0
  37. package/dist/citations/Publisher.svelte +34 -0
  38. package/dist/citations/Publisher.svelte.d.ts +14 -0
  39. package/dist/citations/ReferenceList.svelte +53 -0
  40. package/dist/citations/ReferenceList.svelte.d.ts +21 -0
  41. package/dist/citations/ReportCitation.svelte +41 -0
  42. package/dist/citations/ReportCitation.svelte.d.ts +36 -0
  43. package/dist/citations/ScholarlyArticleCitation.svelte +64 -0
  44. package/dist/citations/ScholarlyArticleCitation.svelte.d.ts +41 -0
  45. package/dist/citations/ThesisCitation.svelte +35 -0
  46. package/dist/citations/ThesisCitation.svelte.d.ts +29 -0
  47. package/dist/citations/bibliography.svelte.d.ts +55 -0
  48. package/dist/citations/bibliography.svelte.js +78 -0
  49. package/dist/citations/citation.d.ts +71 -0
  50. package/dist/citations/citation.js +121 -0
  51. package/dist/citations/csl.d.ts +102 -0
  52. package/dist/citations/csl.js +20 -0
  53. package/dist/citations/index.d.ts +31 -0
  54. package/dist/citations/index.js +36 -0
  55. package/dist/citations/list-format.d.ts +34 -0
  56. package/dist/citations/list-format.js +38 -0
  57. package/dist/context.svelte.d.ts +46 -0
  58. package/dist/context.svelte.js +51 -0
  59. package/dist/data/DataGrid.svelte +150 -0
  60. package/dist/data/DataGrid.svelte.d.ts +118 -0
  61. package/dist/data/DescriptionList.svelte +47 -0
  62. package/dist/data/DescriptionList.svelte.d.ts +26 -0
  63. package/dist/data/DescriptionRow.svelte +55 -0
  64. package/dist/data/DescriptionRow.svelte.d.ts +21 -0
  65. package/dist/data/DiffText.svelte +29 -0
  66. package/dist/data/DiffText.svelte.d.ts +19 -0
  67. package/dist/data/ItemList.svelte +80 -0
  68. package/dist/data/ItemList.svelte.d.ts +52 -0
  69. package/dist/data/LinkListItem.svelte +46 -0
  70. package/dist/data/LinkListItem.svelte.d.ts +21 -0
  71. package/dist/data/Pagination.svelte +136 -0
  72. package/dist/data/Pagination.svelte.d.ts +71 -0
  73. package/dist/data/PaginationFooter.svelte +41 -0
  74. package/dist/data/PaginationFooter.svelte.d.ts +59 -0
  75. package/dist/data/ResultCount.svelte +27 -0
  76. package/dist/data/ResultCount.svelte.d.ts +18 -0
  77. package/dist/data/Table.svelte +145 -0
  78. package/dist/data/Table.svelte.d.ts +75 -0
  79. package/dist/data/TreeList.svelte +41 -0
  80. package/dist/data/TreeList.svelte.d.ts +17 -0
  81. package/dist/data/TreeListItem.svelte +29 -0
  82. package/dist/data/TreeListItem.svelte.d.ts +10 -0
  83. package/dist/data/description-context.d.ts +33 -0
  84. package/dist/data/description-context.js +35 -0
  85. package/dist/data/diff.d.ts +14 -0
  86. package/dist/data/diff.js +10 -0
  87. package/dist/data/index.d.ts +35 -0
  88. package/dist/data/index.js +35 -0
  89. package/dist/data/list-item.d.ts +30 -0
  90. package/dist/data/list-item.js +19 -0
  91. package/dist/data/pagination.d.ts +81 -0
  92. package/dist/data/pagination.js +79 -0
  93. package/dist/data/table-types.d.ts +64 -0
  94. package/dist/data/table-types.js +35 -0
  95. package/dist/feedback/ConfirmDialog.svelte +79 -0
  96. package/dist/feedback/ConfirmDialog.svelte.d.ts +82 -0
  97. package/dist/feedback/Dialog.svelte +77 -0
  98. package/dist/feedback/Dialog.svelte.d.ts +37 -0
  99. package/dist/feedback/LoadingBoundary.svelte +61 -0
  100. package/dist/feedback/LoadingBoundary.svelte.d.ts +34 -0
  101. package/dist/feedback/ProgressBar.svelte +46 -0
  102. package/dist/feedback/ProgressBar.svelte.d.ts +28 -0
  103. package/dist/feedback/SegmentBar.svelte +83 -0
  104. package/dist/feedback/SegmentBar.svelte.d.ts +36 -0
  105. package/dist/feedback/StatTile.svelte +77 -0
  106. package/dist/feedback/StatTile.svelte.d.ts +49 -0
  107. package/dist/feedback/Stats.svelte +18 -0
  108. package/dist/feedback/Stats.svelte.d.ts +16 -0
  109. package/dist/feedback/Timeline.svelte +86 -0
  110. package/dist/feedback/Timeline.svelte.d.ts +52 -0
  111. package/dist/feedback/Toaster.svelte +78 -0
  112. package/dist/feedback/Toaster.svelte.d.ts +32 -0
  113. package/dist/feedback/index.d.ts +31 -0
  114. package/dist/feedback/index.js +27 -0
  115. package/dist/feedback/sizes.d.ts +27 -0
  116. package/dist/feedback/sizes.js +41 -0
  117. package/dist/feedback/toaster.d.ts +48 -0
  118. package/dist/feedback/toaster.js +29 -0
  119. package/dist/fields/Checkbox.svelte +33 -0
  120. package/dist/fields/Checkbox.svelte.d.ts +24 -0
  121. package/dist/fields/CheckboxGroup.svelte +41 -0
  122. package/dist/fields/CheckboxGroup.svelte.d.ts +40 -0
  123. package/dist/fields/Combobox.svelte +222 -0
  124. package/dist/fields/Combobox.svelte.d.ts +98 -0
  125. package/dist/fields/DateInput.svelte +31 -0
  126. package/dist/fields/DateInput.svelte.d.ts +29 -0
  127. package/dist/fields/FieldErrors.svelte +30 -0
  128. package/dist/fields/FieldErrors.svelte.d.ts +11 -0
  129. package/dist/fields/Fieldset.svelte +48 -0
  130. package/dist/fields/Fieldset.svelte.d.ts +26 -0
  131. package/dist/fields/FileInput.svelte +67 -0
  132. package/dist/fields/FileInput.svelte.d.ts +33 -0
  133. package/dist/fields/FormField.svelte +54 -0
  134. package/dist/fields/FormField.svelte.d.ts +29 -0
  135. package/dist/fields/ImageInput.svelte +87 -0
  136. package/dist/fields/ImageInput.svelte.d.ts +39 -0
  137. package/dist/fields/PushToggle.svelte +93 -0
  138. package/dist/fields/PushToggle.svelte.d.ts +55 -0
  139. package/dist/fields/RadioGroup.svelte +85 -0
  140. package/dist/fields/RadioGroup.svelte.d.ts +41 -0
  141. package/dist/fields/SearchInput.svelte +57 -0
  142. package/dist/fields/SearchInput.svelte.d.ts +33 -0
  143. package/dist/fields/Select.svelte +36 -0
  144. package/dist/fields/Select.svelte.d.ts +29 -0
  145. package/dist/fields/TextInput.svelte +26 -0
  146. package/dist/fields/TextInput.svelte.d.ts +30 -0
  147. package/dist/fields/Textarea.svelte +22 -0
  148. package/dist/fields/Textarea.svelte.d.ts +25 -0
  149. package/dist/fields/Toggle.svelte +72 -0
  150. package/dist/fields/Toggle.svelte.d.ts +32 -0
  151. package/dist/fields/VideoInput.svelte +35 -0
  152. package/dist/fields/VideoInput.svelte.d.ts +40 -0
  153. package/dist/fields/field-types.d.ts +51 -0
  154. package/dist/fields/field-types.js +60 -0
  155. package/dist/fields/index.d.ts +34 -0
  156. package/dist/fields/index.js +34 -0
  157. package/dist/formatting/DateTime.svelte +35 -0
  158. package/dist/formatting/DateTime.svelte.d.ts +26 -0
  159. package/dist/formatting/FormatList.svelte +31 -0
  160. package/dist/formatting/FormatList.svelte.d.ts +46 -0
  161. package/dist/formatting/Highlight.svelte +47 -0
  162. package/dist/formatting/Highlight.svelte.d.ts +15 -0
  163. package/dist/formatting/Number.svelte +35 -0
  164. package/dist/formatting/Number.svelte.d.ts +43 -0
  165. package/dist/formatting/RelativeTime.svelte +69 -0
  166. package/dist/formatting/RelativeTime.svelte.d.ts +26 -0
  167. package/dist/formatting/Year.svelte +39 -0
  168. package/dist/formatting/Year.svelte.d.ts +21 -0
  169. package/dist/formatting/index.d.ts +12 -0
  170. package/dist/formatting/index.js +14 -0
  171. package/dist/forms/EntityForm.svelte +177 -0
  172. package/dist/forms/EntityForm.svelte.d.ts +57 -0
  173. package/dist/forms/FormActions.svelte +29 -0
  174. package/dist/forms/FormActions.svelte.d.ts +37 -0
  175. package/dist/forms/FormErrors.svelte +21 -0
  176. package/dist/forms/FormErrors.svelte.d.ts +16 -0
  177. package/dist/forms/HiddenField.svelte +22 -0
  178. package/dist/forms/HiddenField.svelte.d.ts +11 -0
  179. package/dist/forms/SearchForm.svelte +43 -0
  180. package/dist/forms/SearchForm.svelte.d.ts +36 -0
  181. package/dist/forms/entity-form.d.ts +12 -0
  182. package/dist/forms/entity-form.js +12 -0
  183. package/dist/forms/index.d.ts +14 -0
  184. package/dist/forms/index.js +14 -0
  185. package/dist/hotkeys/HotkeyBadge.svelte +39 -0
  186. package/dist/hotkeys/HotkeyBadge.svelte.d.ts +25 -0
  187. package/dist/hotkeys/HotkeyHelpDialog.svelte +68 -0
  188. package/dist/hotkeys/HotkeyHelpDialog.svelte.d.ts +35 -0
  189. package/dist/hotkeys/HotkeyProvider.svelte +92 -0
  190. package/dist/hotkeys/HotkeyProvider.svelte.d.ts +4 -0
  191. package/dist/hotkeys/context.svelte.d.ts +47 -0
  192. package/dist/hotkeys/context.svelte.js +72 -0
  193. package/dist/hotkeys/index.d.ts +23 -0
  194. package/dist/hotkeys/index.js +22 -0
  195. package/dist/hotkeys/match.d.ts +65 -0
  196. package/dist/hotkeys/match.js +133 -0
  197. package/dist/hotkeys/registry.svelte.d.ts +55 -0
  198. package/dist/hotkeys/registry.svelte.js +110 -0
  199. package/dist/hotkeys/types.d.ts +72 -0
  200. package/dist/hotkeys/types.js +18 -0
  201. package/dist/index.d.ts +36 -0
  202. package/dist/index.js +36 -0
  203. package/dist/infobox/Infobox.svelte +79 -0
  204. package/dist/infobox/Infobox.svelte.d.ts +26 -0
  205. package/dist/infobox/InfoboxHeader.svelte +27 -0
  206. package/dist/infobox/InfoboxHeader.svelte.d.ts +11 -0
  207. package/dist/infobox/InfoboxImage.svelte +38 -0
  208. package/dist/infobox/InfoboxImage.svelte.d.ts +21 -0
  209. package/dist/infobox/InfoboxRow.svelte +50 -0
  210. package/dist/infobox/InfoboxRow.svelte.d.ts +25 -0
  211. package/dist/infobox/InfoboxSection.svelte +24 -0
  212. package/dist/infobox/InfoboxSection.svelte.d.ts +12 -0
  213. package/dist/infobox/index.d.ts +21 -0
  214. package/dist/infobox/index.js +20 -0
  215. package/dist/infobox/types.d.ts +86 -0
  216. package/dist/infobox/types.js +27 -0
  217. package/dist/layout/Breadcrumbs.svelte +52 -0
  218. package/dist/layout/Breadcrumbs.svelte.d.ts +18 -0
  219. package/dist/layout/DetailLayout.svelte +50 -0
  220. package/dist/layout/DetailLayout.svelte.d.ts +19 -0
  221. package/dist/layout/FilterBar.svelte +40 -0
  222. package/dist/layout/FilterBar.svelte.d.ts +12 -0
  223. package/dist/layout/Footer.svelte +32 -0
  224. package/dist/layout/Footer.svelte.d.ts +12 -0
  225. package/dist/layout/Main.svelte +30 -0
  226. package/dist/layout/Main.svelte.d.ts +15 -0
  227. package/dist/layout/Navbar.svelte +68 -0
  228. package/dist/layout/Navbar.svelte.d.ts +31 -0
  229. package/dist/layout/PageHeader.svelte +77 -0
  230. package/dist/layout/PageHeader.svelte.d.ts +33 -0
  231. package/dist/layout/Section.svelte +72 -0
  232. package/dist/layout/Section.svelte.d.ts +40 -0
  233. package/dist/layout/Sidebar.svelte +54 -0
  234. package/dist/layout/Sidebar.svelte.d.ts +27 -0
  235. package/dist/layout/Tabs.svelte +85 -0
  236. package/dist/layout/Tabs.svelte.d.ts +42 -0
  237. package/dist/layout/index.d.ts +29 -0
  238. package/dist/layout/index.js +29 -0
  239. package/dist/layout/types.d.ts +52 -0
  240. package/dist/layout/types.js +27 -0
  241. package/dist/links/ContextLinks.svelte +28 -0
  242. package/dist/links/ContextLinks.svelte.d.ts +20 -0
  243. package/dist/links/EmailLink.svelte +26 -0
  244. package/dist/links/EmailLink.svelte.d.ts +20 -0
  245. package/dist/links/index.d.ts +7 -0
  246. package/dist/links/index.js +7 -0
  247. package/dist/media/Figure.svelte +26 -0
  248. package/dist/media/Figure.svelte.d.ts +12 -0
  249. package/dist/media/Image.svelte +76 -0
  250. package/dist/media/Image.svelte.d.ts +41 -0
  251. package/dist/media/Video.svelte +65 -0
  252. package/dist/media/Video.svelte.d.ts +29 -0
  253. package/dist/media/image-dimensions.d.ts +28 -0
  254. package/dist/media/image-dimensions.js +34 -0
  255. package/dist/media/index.d.ts +10 -0
  256. package/dist/media/index.js +10 -0
  257. package/dist/search/CommandPalette.svelte +257 -0
  258. package/dist/search/CommandPalette.svelte.d.ts +59 -0
  259. package/dist/search/index.d.ts +13 -0
  260. package/dist/search/index.js +13 -0
  261. package/dist/search/types.d.ts +37 -0
  262. package/dist/search/types.js +20 -0
  263. package/dist/seo/Head.svelte +190 -0
  264. package/dist/seo/Head.svelte.d.ts +86 -0
  265. package/dist/seo/JsonLd.svelte +30 -0
  266. package/dist/seo/JsonLd.svelte.d.ts +20 -0
  267. package/dist/seo/index.d.ts +18 -0
  268. package/dist/seo/index.js +17 -0
  269. package/dist/seo/json-ld.d.ts +33 -0
  270. package/dist/seo/json-ld.js +29 -0
  271. package/dist/seo/og-image.d.ts +71 -0
  272. package/dist/seo/og-image.js +81 -0
  273. package/dist/seo/types.d.ts +43 -0
  274. package/dist/seo/types.js +6 -0
  275. package/dist/theme.css +161 -0
  276. package/dist/tips/PopoverTip.svelte +80 -0
  277. package/dist/tips/PopoverTip.svelte.d.ts +33 -0
  278. package/dist/tips/Tip.svelte +91 -0
  279. package/dist/tips/Tip.svelte.d.ts +25 -0
  280. package/dist/tips/index.d.ts +15 -0
  281. package/dist/tips/index.js +14 -0
  282. package/dist/tips/tip-stack.d.ts +25 -0
  283. package/dist/tips/tip-stack.js +37 -0
  284. package/dist/tips/tip-store.svelte.d.ts +74 -0
  285. package/dist/tips/tip-store.svelte.js +158 -0
  286. package/dist/tips/types.d.ts +46 -0
  287. package/dist/tips/types.js +6 -0
  288. package/dist/ui/Alert.svelte +61 -0
  289. package/dist/ui/Alert.svelte.d.ts +37 -0
  290. package/dist/ui/Badge.svelte +39 -0
  291. package/dist/ui/Badge.svelte.d.ts +32 -0
  292. package/dist/ui/Button.svelte +43 -0
  293. package/dist/ui/Button.svelte.d.ts +29 -0
  294. package/dist/ui/Card.svelte +49 -0
  295. package/dist/ui/Card.svelte.d.ts +44 -0
  296. package/dist/ui/Chip.svelte +58 -0
  297. package/dist/ui/Chip.svelte.d.ts +21 -0
  298. package/dist/ui/ConfirmButton.svelte +75 -0
  299. package/dist/ui/ConfirmButton.svelte.d.ts +48 -0
  300. package/dist/ui/Disclosure.svelte +39 -0
  301. package/dist/ui/Disclosure.svelte.d.ts +22 -0
  302. package/dist/ui/EmptyState.svelte +37 -0
  303. package/dist/ui/EmptyState.svelte.d.ts +22 -0
  304. package/dist/ui/ExternalLink.svelte +38 -0
  305. package/dist/ui/ExternalLink.svelte.d.ts +34 -0
  306. package/dist/ui/Heading.svelte +58 -0
  307. package/dist/ui/Heading.svelte.d.ts +22 -0
  308. package/dist/ui/Link.svelte +34 -0
  309. package/dist/ui/Link.svelte.d.ts +20 -0
  310. package/dist/ui/LinkButton.svelte +51 -0
  311. package/dist/ui/LinkButton.svelte.d.ts +33 -0
  312. package/dist/ui/Menu.svelte +54 -0
  313. package/dist/ui/Menu.svelte.d.ts +34 -0
  314. package/dist/ui/MenuItem.svelte +75 -0
  315. package/dist/ui/MenuItem.svelte.d.ts +21 -0
  316. package/dist/ui/MenuSeparator.svelte +26 -0
  317. package/dist/ui/MenuSeparator.svelte.d.ts +8 -0
  318. package/dist/ui/Popover.svelte +63 -0
  319. package/dist/ui/Popover.svelte.d.ts +40 -0
  320. package/dist/ui/ShareButton.svelte +64 -0
  321. package/dist/ui/ShareButton.svelte.d.ts +39 -0
  322. package/dist/ui/Skeleton.svelte +43 -0
  323. package/dist/ui/Skeleton.svelte.d.ts +22 -0
  324. package/dist/ui/ThemeToggle.svelte +65 -0
  325. package/dist/ui/ThemeToggle.svelte.d.ts +24 -0
  326. package/dist/ui/Tooltip.svelte +54 -0
  327. package/dist/ui/Tooltip.svelte.d.ts +35 -0
  328. package/dist/ui/VisuallyHidden.svelte +23 -0
  329. package/dist/ui/VisuallyHidden.svelte.d.ts +10 -0
  330. package/dist/ui/colour-token.d.ts +41 -0
  331. package/dist/ui/colour-token.js +49 -0
  332. package/dist/ui/index.d.ts +44 -0
  333. package/dist/ui/index.js +44 -0
  334. package/dist/ui/menu-context.d.ts +22 -0
  335. package/dist/ui/menu-context.js +26 -0
  336. package/dist/ui/slug.d.ts +19 -0
  337. package/dist/ui/slug.js +25 -0
  338. package/dist/ui/tones.d.ts +68 -0
  339. package/dist/ui/tones.js +150 -0
  340. package/package.json +101 -3
@@ -0,0 +1,31 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+ interface Props extends HTMLAttributes<HTMLElement> {
4
+ /**
5
+ * Accessible name of the `<nav>` landmark.
6
+ * @defaultValue `'Primary'`
7
+ */
8
+ label?: string | undefined;
9
+ /**
10
+ * Accessible name of the responsive menu toggle.
11
+ * @defaultValue `'Menu'`
12
+ */
13
+ menuLabel?: string | undefined;
14
+ /** Whether the responsive panel is open. Bindable. */
15
+ menuOpen?: boolean | undefined;
16
+ /** Leading region — the brand link. */
17
+ start: Snippet<[]>;
18
+ /** Middle region — the primary links. Hidden below `lg`. */
19
+ center?: Snippet<[]> | undefined;
20
+ /** Trailing region — search, theme, account. */
21
+ end?: Snippet<[]> | undefined;
22
+ /**
23
+ * The panel the toggle opens. Given one, the toggle appears below `lg`;
24
+ * without one there is nothing to disclose and no button is rendered.
25
+ */
26
+ menu?: Snippet<[]> | undefined;
27
+ }
28
+ /** The site banner: brand, primary links and account controls, with a disclosure for what does not fit on a narrow viewport. */
29
+ declare const Navbar: import("svelte").Component<Props, {}, "menuOpen">;
30
+ type Navbar = ReturnType<typeof Navbar>;
31
+ export default Navbar;
@@ -0,0 +1,77 @@
1
+ <!-- @component
2
+ The block at the top of a page: its heading, supporting facts and actions.
3
+ -->
4
+ <!--
5
+ PageHeader — the block at the top of a page: what the page is about, and
6
+ what you can do to it.
7
+
8
+ `title` takes a string OR a snippet because a page title is sometimes
9
+ marked up — a species name in italics, a title with a `<Badge>` after it —
10
+ and an app should not have to choose between the component and its own
11
+ typography.
12
+
13
+ ARIA contract: `title` is a real heading, at `headingLevel` (an `<h1>` by
14
+ default, because this is the page's heading and a page has one). The level
15
+ is a prop and not a consequence of the type scale: the outline is document
16
+ structure, the scale is decoration, and `class` moves the second without
17
+ touching the first. `actions` is a `role="group"` named by `actionsLabel`,
18
+ so the cluster announces itself as one thing ("Page actions, group") rather
19
+ than as loose buttons floating beside a heading. `icon` is decorative and
20
+ hidden — it repeats what the title already says.
21
+
22
+ The `<header>` element is a `banner` landmark only when it is NOT inside
23
+ `<main>`, `<article>`, `<aside>`, `<nav>` or `<section>`. A page header is
24
+ inside `Main`, so it is not a banner, which is correct: the banner is the
25
+ site chrome (`Navbar`), of which there is one per page.
26
+ -->
27
+ <script lang="ts">let { title, subtitle, headingLevel = 1, actionsLabel = "Page actions", eyebrow, icon, meta, actions, children, class: className, ...rest } = $props();
28
+ // The page title's scale is the page's, not the outline's — an `<h2>` used
29
+ // as a page heading (a panel, a dialog body) still reads as the title.
30
+ const titleClasses = "text-3xl font-semibold tracking-tight text-balance sm:text-4xl";
31
+ export {};
32
+ </script>
33
+
34
+ <header {...rest} class={['space-y-3', className]}>
35
+ {#if eyebrow}
36
+ <div class="text-base-content/70 text-sm">{@render eyebrow()}</div>
37
+ {/if}
38
+
39
+ <div class="flex flex-col gap-4 md:flex-row md:items-end md:justify-between">
40
+ <div class="flex min-w-0 flex-1 items-start gap-x-5">
41
+ {#if icon}
42
+ <div class="avatar shrink-0" aria-hidden="true">
43
+ <div class="bg-base-200 size-16 rounded-full">{@render icon()}</div>
44
+ </div>
45
+ {/if}
46
+ <div class="min-w-0 flex-1 space-y-1">
47
+ <svelte:element this={`h${headingLevel}`} class={titleClasses}>
48
+ {#if typeof title === 'string'}
49
+ {title}
50
+ {:else}
51
+ {@render title()}
52
+ {/if}
53
+ </svelte:element>
54
+ {#if subtitle !== undefined}
55
+ <p class="text-base-content/70 text-lg leading-7">{subtitle}</p>
56
+ {/if}
57
+ {#if meta}
58
+ <div
59
+ class="text-base-content/70 flex flex-col gap-2 pt-1 text-sm leading-6 sm:flex-row sm:flex-wrap sm:gap-x-6"
60
+ >
61
+ {@render meta()}
62
+ </div>
63
+ {/if}
64
+ </div>
65
+ </div>
66
+
67
+ {#if actions}
68
+ <div role="group" aria-label={actionsLabel} class="flex shrink-0 flex-wrap gap-2">
69
+ {@render actions()}
70
+ </div>
71
+ {/if}
72
+ </div>
73
+
74
+ {#if children}
75
+ <div>{@render children()}</div>
76
+ {/if}
77
+ </header>
@@ -0,0 +1,33 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+ import type { HeadingLevel } from '../ui/tones.ts';
4
+ interface Props extends Omit<HTMLAttributes<HTMLElement>, 'title' | 'children'> {
5
+ /** The page's heading — its own text, or a snippet for richer markup. */
6
+ title: string | Snippet<[]>;
7
+ /** Supporting line under the heading. */
8
+ subtitle?: string | undefined;
9
+ /**
10
+ * The heading level, so the page outline stays intact.
11
+ * @defaultValue `1`
12
+ */
13
+ headingLevel?: HeadingLevel | undefined;
14
+ /**
15
+ * Accessible name of the `actions` group.
16
+ * @defaultValue `'Page actions'`
17
+ */
18
+ actionsLabel?: string | undefined;
19
+ /** Rendered above the heading — breadcrumbs, an eyebrow label, a badge. */
20
+ eyebrow?: Snippet<[]> | undefined;
21
+ /** A leading avatar or emblem, in a round frame. Decorative. */
22
+ icon?: Snippet<[]> | undefined;
23
+ /** Small facts under the heading — dates, counts, status. */
24
+ meta?: Snippet<[]> | undefined;
25
+ /** Buttons and links, aligned to the end of the heading row. */
26
+ actions?: Snippet<[]> | undefined;
27
+ /** Free content under the whole header block — a tab strip, a filter row. */
28
+ children?: Snippet<[]> | undefined;
29
+ }
30
+ /** The block at the top of a page: its heading, supporting facts and actions. */
31
+ declare const PageHeader: import("svelte").Component<Props, {}, "">;
32
+ type PageHeader = ReturnType<typeof PageHeader>;
33
+ export default PageHeader;
@@ -0,0 +1,72 @@
1
+ <!-- @component
2
+ A titled block of a page: a heading, an optional count, optional actions, and either the rows or an empty state.
3
+ -->
4
+ <!--
5
+ Section — a titled block of a page: a heading, an optional count beside it,
6
+ optional actions opposite, and either the rows or an honest empty state.
7
+
8
+ Every detail page is a stack of these —
9
+ `InboundSection` and `DetailSection` — that differed only in which optional
10
+ parts they carried. The eight lines were copied per section in the apps,
11
+ and eight copies is eight places to forget the empty state, which renders as
12
+ a section that looks broken rather than one that is honestly empty.
13
+
14
+ `count` is deliberately separate from the rows: a section shows a preview
15
+ (the first fifty) beside the real unpaged total, so the two numbers differ
16
+ and the heading has to say the second one. It is formatted through `Intl`,
17
+ so a five-figure count reads as `12,480` in the reader's locale.
18
+
19
+ ARIA contract: a `<section aria-labelledby>` pointing at its own heading, so
20
+ it is a named `region` — a landmark a reader can jump between, which is the
21
+ whole reason a long detail page is cut into sections. The heading is real
22
+ and at `headingLevel`, defaulting to `<h2>` (one level under the page's
23
+ `<h1>`). `headingId` defaults to a slug of `title`, which makes the section
24
+ addressable by URL fragment and is stable across server and client render.
25
+ -->
26
+ <script lang="ts">import { getComponentsContext } from "../context.svelte.js";
27
+ import { slugify } from "../ui/slug.js";
28
+ let { title, headingLevel = 2, headingId, count, description, empty = false, emptyMessage = "Nothing here yet.", locales, actions, emptyState, children, class: className, ...rest } = $props();
29
+ const context = getComponentsContext();
30
+ const fallbackId = $props.id();
31
+ // A title of nothing but punctuation slugs to `''`, which is not an id —
32
+ // fall back to a generated one rather than emit `aria-labelledby=""`.
33
+ const slugged = $derived(slugify(title));
34
+ const resolvedHeadingId = $derived(headingId ?? (slugged === "" ? fallbackId : slugged));
35
+ // The PERF-CPU-003 shape: the formatter is built in one `$derived` and only
36
+ // `.format()` runs in the next, so re-rendering a count does not re-resolve
37
+ // the locale data.
38
+ const formatter = $derived(new Intl.NumberFormat(locales ?? context.locale()));
39
+ const formattedCount = $derived(count === undefined ? undefined : formatter.format(count));
40
+ </script>
41
+
42
+ <section {...rest} aria-labelledby={resolvedHeadingId} class={['space-y-3', className]}>
43
+ <div class="flex flex-wrap items-baseline justify-between gap-x-4 gap-y-1">
44
+ <svelte:element
45
+ this={`h${headingLevel}`}
46
+ id={resolvedHeadingId}
47
+ class="scroll-mt-16 text-xl font-semibold sm:text-2xl"
48
+ >
49
+ {title}
50
+ {#if formattedCount !== undefined}
51
+ <span class="text-base-content/60 text-base font-normal">({formattedCount})</span>
52
+ {/if}
53
+ </svelte:element>
54
+ {#if actions}
55
+ <div class="flex shrink-0 flex-wrap gap-2">{@render actions()}</div>
56
+ {/if}
57
+ </div>
58
+
59
+ {#if description !== undefined}
60
+ <p class="text-base-content/70 text-sm leading-6">{description}</p>
61
+ {/if}
62
+
63
+ {#if empty}
64
+ {#if emptyState}
65
+ {@render emptyState()}
66
+ {:else}
67
+ <p class="text-base-content/60">{emptyMessage}</p>
68
+ {/if}
69
+ {:else}
70
+ {@render children()}
71
+ {/if}
72
+ </section>
@@ -0,0 +1,40 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+ import type { HeadingLevel } from '../ui/tones.ts';
4
+ interface Props extends HTMLAttributes<HTMLElement> {
5
+ /** The section's heading. */
6
+ title: string;
7
+ /**
8
+ * The heading level, so the page outline stays intact.
9
+ * @defaultValue `2`
10
+ */
11
+ headingLevel?: HeadingLevel | undefined;
12
+ /**
13
+ * Explicit heading id. Defaults to a slug of `title`, so the section is
14
+ * addressable; pass one when two sections on a page share a title.
15
+ */
16
+ headingId?: string | undefined;
17
+ /** The unpaged total, rendered beside the heading. */
18
+ count?: number | undefined;
19
+ /** A line under the heading saying what the section contains. */
20
+ description?: string | undefined;
21
+ /** Whether there is anything to show. Drives the empty state. */
22
+ empty?: boolean | undefined;
23
+ /**
24
+ * The default empty state's text.
25
+ * @defaultValue `'Nothing here yet.'`
26
+ */
27
+ emptyMessage?: string | undefined;
28
+ /** `Intl` locales for `count`; falls back to the context's. */
29
+ locales?: string | readonly string[] | undefined;
30
+ /** A "see all" link or an "add" button, opposite the heading. */
31
+ actions?: Snippet<[]> | undefined;
32
+ /** Replaces the default empty paragraph — usually an `EmptyState`. */
33
+ emptyState?: Snippet<[]> | undefined;
34
+ /** The section's rows; replaced by the empty state when `empty`. */
35
+ children: Snippet<[]>;
36
+ }
37
+ /** A titled block of a page: a heading, an optional count, optional actions, and either the rows or an empty state. */
38
+ declare const Section: import("svelte").Component<Props, {}, "">;
39
+ type Section = ReturnType<typeof Section>;
40
+ export default Section;
@@ -0,0 +1,54 @@
1
+ <!-- @component
2
+ The app shell’s navigation column: a brand mark, the primary links and an account block.
3
+ -->
4
+ <!--
5
+ Sidebar — the app shell's standing navigation column: a brand mark at the
6
+ top, the primary links in the middle, an account block at the bottom.
7
+
8
+ A thin composition and nothing more. The links themselves are `MenuItem`s
9
+ inside a `Menu mode="nav"`, which already owns the whole navigation
10
+ contract — the `<nav aria-label>` landmark, the `<ul class="menu">`, and
11
+ `aria-current="page"` on the item the reader is on. This adds only what a
12
+ sidebar has and a menu does not.
13
+
14
+ What it deliberately does NOT do is wrap the column in an `<aside>`, which
15
+ is what that original did. `<aside>` is the `complementary` landmark — "content
16
+ related to the main content, meaningful on its own" — and a site's primary
17
+ navigation is neither. Wrapping it makes the app's most important landmark
18
+ announce itself as an afterthought, and puts a second landmark around the
19
+ `navigation` one, which a reader then has to step through twice.
20
+
21
+ ARIA contract: the navigation landmark is `Menu`'s. When `title` is shown,
22
+ it is also the landmark's accessible name by default, so the name a reader
23
+ hears is the text a reader sees. `brand` and `footer` are plain regions: the
24
+ brand is a link, the footer block is usually a second short `Menu`.
25
+ -->
26
+ <script lang="ts">import Menu from "../ui/Menu.svelte";
27
+ let { label, title, headingLevel = 2, brand, footer, children, class: className, ...rest } = $props();
28
+ const navLabel = $derived(label ?? title ?? "Primary");
29
+ </script>
30
+
31
+ <div
32
+ {...rest}
33
+ class={['bg-base-100 border-base-300 flex min-h-full w-72 flex-col border-r', className]}
34
+ >
35
+ {#if brand}
36
+ <div class="flex h-16 shrink-0 items-center px-6">{@render brand()}</div>
37
+ {/if}
38
+
39
+ <div class="min-h-0 flex-1 space-y-2 px-4 py-2">
40
+ {#if title !== undefined}
41
+ <svelte:element
42
+ this={`h${headingLevel}`}
43
+ class="text-base-content/60 px-1 text-xs font-semibold tracking-wide uppercase"
44
+ >
45
+ {title}
46
+ </svelte:element>
47
+ {/if}
48
+ <Menu label={navLabel}>{@render children()}</Menu>
49
+ </div>
50
+
51
+ {#if footer}
52
+ <div class="border-base-300 shrink-0 border-t px-4 py-4">{@render footer()}</div>
53
+ {/if}
54
+ </div>
@@ -0,0 +1,27 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+ import type { HeadingLevel } from '../ui/tones.ts';
4
+ interface Props extends HTMLAttributes<HTMLElement> {
5
+ /**
6
+ * Accessible name of the navigation landmark. Defaults to `title` when
7
+ * one is shown, and to `Primary` when it is not.
8
+ */
9
+ label?: string | undefined;
10
+ /** A visible heading over the links ("Browse", "Your account"). */
11
+ title?: string | undefined;
12
+ /**
13
+ * The heading level, so the page outline stays intact.
14
+ * @defaultValue `2`
15
+ */
16
+ headingLevel?: HeadingLevel | undefined;
17
+ /** The brand mark, above the links. */
18
+ brand?: Snippet<[]> | undefined;
19
+ /** A block pinned under the links — the signed-in account menu. */
20
+ footer?: Snippet<[]> | undefined;
21
+ /** The `MenuItem`s. */
22
+ children: Snippet<[]>;
23
+ }
24
+ /** The app shell’s navigation column: a brand mark, the primary links and an account block. */
25
+ declare const Sidebar: import("svelte").Component<Props, {}, "">;
26
+ type Sidebar = ReturnType<typeof Sidebar>;
27
+ export default Sidebar;
@@ -0,0 +1,85 @@
1
+ <!-- @component
2
+ A tab strip that is either a tab widget over panels (`mode="panels"`) or navigation between sibling routes (`mode="links"`).
3
+ -->
4
+ <!--
5
+ Tabs — one strip, two things.
6
+
7
+ `mode="panels"` is a tab WIDGET: bits-ui's `Tabs`, which owns the
8
+ `tablist`/`tab`/`tabpanel` roles, the roving tabindex (one Tab stop for the
9
+ whole strip), Arrow/Home/End movement between tabs, and the
10
+ `aria-controls`/`aria-labelledby` pairing between each tab and its panel.
11
+ None of that is worth hand-rolling and all of it is easy to get subtly
12
+ wrong.
13
+
14
+ `mode="links"` is NAVIGATION between sibling routes that happens to look
15
+ like tabs (First preferences / Two-candidate preferred / Polling places).
16
+ It must NOT be a tab widget: these are separate documents, each with its own
17
+ URL, and a `role="tab"` that navigates lies to a reader about what pressing
18
+ it does. So it is a labelled `<nav>` of ordinary anchors, every one of them
19
+ a Tab stop, with `aria-current="page"` on the one you are on — chosen by
20
+ `value` when the caller tracks it, and otherwise by the components context's
21
+ own current-page check.
22
+
23
+ ARIA contract: panels mode is bits-ui's, unmodified — `aria-selected` on the
24
+ tabs, `aria-controls` to the panel, arrows and Home/End moving selection.
25
+ Links mode is `<nav aria-label>` + `aria-current="page"`. A disabled item in
26
+ links mode is not a link at all (there is nothing to navigate to) but stays
27
+ in the strip as `aria-disabled` text, so the set of sections a reader can
28
+ see does not change as their permissions do.
29
+ -->
30
+ <script lang="ts">import { Tabs as BitsTabs } from "bits-ui";
31
+ import { getComponentsContext } from "../context.svelte.js";
32
+ import { tabsSize, tabsVariant } from "./types.js";
33
+ let { items, mode = "panels", value = $bindable(""), label = "Sections", variant = "border", size = "md", panel, class: className } = $props();
34
+ const context = getComponentsContext();
35
+ const stripClasses = $derived([
36
+ "tabs",
37
+ tabsVariant[variant],
38
+ tabsSize[size]
39
+ ]);
40
+ // A tab widget with nothing selected shows nothing, so panels need a
41
+ // selection from the start; the first ENABLED item, since a disabled one
42
+ // cannot be navigated back to.
43
+ const selected = $derived(value !== "" ? value : items.find((item) => item.disabled !== true)?.value ?? "");
44
+ const isCurrentLink = (item) => value !== "" ? value === item.value : item.href !== undefined && context.isCurrent(context.href(item.href));
45
+ </script>
46
+
47
+ {#if mode === 'links'}
48
+ <nav aria-label={label} class={[...stripClasses, className]}>
49
+ {#each items as item (item.value)}
50
+ {#if item.disabled === true}
51
+ <span class="tab tab-disabled" aria-disabled="true">{item.label}</span>
52
+ {:else}
53
+ {@const current = isCurrentLink(item)}
54
+ <a
55
+ href={context.href(item.href ?? '')}
56
+ class={['tab', current && 'tab-active']}
57
+ aria-current={current ? 'page' : undefined}
58
+ >
59
+ {item.label}
60
+ </a>
61
+ {/if}
62
+ {/each}
63
+ </nav>
64
+ {:else}
65
+ <!-- A function binding rather than `bind:value`: the value this renders at
66
+ is the DEFAULTED one, while what a write puts back is the caller's. -->
67
+ <BitsTabs.Root bind:value={() => selected, (next) => (value = next)} class={className}>
68
+ <BitsTabs.List class={stripClasses} aria-label={label}>
69
+ {#each items as item (item.value)}
70
+ <BitsTabs.Trigger
71
+ value={item.value}
72
+ disabled={item.disabled === true}
73
+ class={['tab', selected === item.value && 'tab-active']}
74
+ >
75
+ {item.label}
76
+ </BitsTabs.Trigger>
77
+ {/each}
78
+ </BitsTabs.List>
79
+ {#if panel}
80
+ {#each items as item (item.value)}
81
+ <BitsTabs.Content value={item.value} class="py-4">{@render panel(item)}</BitsTabs.Content>
82
+ {/each}
83
+ {/if}
84
+ </BitsTabs.Root>
85
+ {/if}
@@ -0,0 +1,42 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { Size } from '../ui/tones.ts';
3
+ import { type TabItem, type TabsMode, type TabsVariant } from './types.ts';
4
+ interface Props {
5
+ /** The tabs, in order: `value` and `label`, plus `href` in `links` mode. */
6
+ items: readonly TabItem[];
7
+ /**
8
+ * `panels` for a tab widget; `links` for navigation between routes.
9
+ * @defaultValue `'panels'`
10
+ */
11
+ mode?: TabsMode | undefined;
12
+ /**
13
+ * The selected value (panels) or the current one (links); `''` means
14
+ * unset — panels then select the first enabled item and links fall back to
15
+ * the context's current-page check. Bindable.
16
+ * @defaultValue `''`
17
+ */
18
+ value?: string | undefined;
19
+ /**
20
+ * Accessible name of the tab list / the navigation landmark.
21
+ * @defaultValue `'Sections'`
22
+ */
23
+ label?: string | undefined;
24
+ /**
25
+ * daisyUI tab style.
26
+ * @defaultValue `'border'`
27
+ */
28
+ variant?: TabsVariant | undefined;
29
+ /**
30
+ * daisyUI size step.
31
+ * @defaultValue `'md'`
32
+ */
33
+ size?: Size | undefined;
34
+ /** One panel's content, in `panels` mode. Without it, no panels render. */
35
+ panel?: Snippet<[TabItem]> | undefined;
36
+ /** Extra classes, merged last. */
37
+ class?: string | undefined;
38
+ }
39
+ /** A tab strip that is either a tab widget over panels (`mode="panels"`) or navigation between sibling routes (`mode="links"`). */
40
+ declare const Tabs: import("svelte").Component<Props, {}, "value">;
41
+ type Tabs = ReturnType<typeof Tabs>;
42
+ export default Tabs;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * layout — page chrome: the landmarks a page is assembled from, and the
3
+ * blocks that sit inside them.
4
+ *
5
+ * The family is structure, never copy. Every one of these takes the app's
6
+ * content as snippets and owns only the element that carries the semantics —
7
+ * the `<main>` a reader jumps to, the named `<nav>`s, the `banner` and
8
+ * `contentinfo` at the two ends of the page, the `<section aria-labelledby>`
9
+ * a long page is cut into. Import from the package barrel rather than from
10
+ * here.
11
+ *
12
+ * Optional props are declared `T | undefined` for the reason `ui/`'s are: the
13
+ * workspace compiles with `exactOptionalPropertyTypes`, under which `prop?: T`
14
+ * rejects an explicitly passed `undefined` and a caller cannot forward its own
15
+ * optional prop straight through.
16
+ *
17
+ * @module
18
+ */
19
+ export { default as Breadcrumbs } from './Breadcrumbs.svelte';
20
+ export { default as DetailLayout } from './DetailLayout.svelte';
21
+ export { default as FilterBar } from './FilterBar.svelte';
22
+ export { default as Footer } from './Footer.svelte';
23
+ export { default as Main } from './Main.svelte';
24
+ export { default as Navbar } from './Navbar.svelte';
25
+ export { default as PageHeader } from './PageHeader.svelte';
26
+ export { default as Section } from './Section.svelte';
27
+ export { default as Sidebar } from './Sidebar.svelte';
28
+ export { default as Tabs } from './Tabs.svelte';
29
+ export * from './types.ts';
@@ -0,0 +1,29 @@
1
+ /**
2
+ * layout — page chrome: the landmarks a page is assembled from, and the
3
+ * blocks that sit inside them.
4
+ *
5
+ * The family is structure, never copy. Every one of these takes the app's
6
+ * content as snippets and owns only the element that carries the semantics —
7
+ * the `<main>` a reader jumps to, the named `<nav>`s, the `banner` and
8
+ * `contentinfo` at the two ends of the page, the `<section aria-labelledby>`
9
+ * a long page is cut into. Import from the package barrel rather than from
10
+ * here.
11
+ *
12
+ * Optional props are declared `T | undefined` for the reason `ui/`'s are: the
13
+ * workspace compiles with `exactOptionalPropertyTypes`, under which `prop?: T`
14
+ * rejects an explicitly passed `undefined` and a caller cannot forward its own
15
+ * optional prop straight through.
16
+ *
17
+ * @module
18
+ */
19
+ export { default as Breadcrumbs } from './Breadcrumbs.svelte';
20
+ export { default as DetailLayout } from './DetailLayout.svelte';
21
+ export { default as FilterBar } from './FilterBar.svelte';
22
+ export { default as Footer } from './Footer.svelte';
23
+ export { default as Main } from './Main.svelte';
24
+ export { default as Navbar } from './Navbar.svelte';
25
+ export { default as PageHeader } from './PageHeader.svelte';
26
+ export { default as Section } from './Section.svelte';
27
+ export { default as Sidebar } from './Sidebar.svelte';
28
+ export { default as Tabs } from './Tabs.svelte';
29
+ export * from "./types.js";
@@ -0,0 +1,52 @@
1
+ /**
2
+ * The vocabulary the `layout/` family's list-shaped props are written in, and
3
+ * the literal daisyUI class tables its variants look up.
4
+ *
5
+ * The tables are local to this family rather than added to `ui/tones.ts`
6
+ * because `tabs-*` is a layout word: no `ui/` component renders a tab strip,
7
+ * and a table nobody outside one family reads is a table that belongs beside
8
+ * that family. The reason they are tables at all is the repo-wide one —
9
+ * Tailwind generates only the classes it can see verbatim in source, so a
10
+ * `tabs-${variant}` template string emits no CSS whatsoever.
11
+ *
12
+ * @module
13
+ */
14
+ import type { Size } from '../ui/tones.ts';
15
+ /** One step of a {@link Breadcrumbs} trail. */
16
+ export interface Crumb {
17
+ readonly label: string;
18
+ /**
19
+ * Where the crumb points. The TRAILING crumb is rendered as text whether or
20
+ * not it carries one — it is the page you are already on.
21
+ */
22
+ readonly href?: string | undefined;
23
+ }
24
+ /** One entry of a {@link Tabs} strip, in either mode. */
25
+ export interface TabItem {
26
+ /** Stable key, and the value `Tabs` selects on in `panels` mode. */
27
+ readonly value: string;
28
+ readonly label: string;
29
+ /** The route, in `links` mode. Ignored by `panels`. */
30
+ readonly href?: string | undefined;
31
+ readonly disabled?: boolean | undefined;
32
+ }
33
+ /** One option of a {@link FilterBar}. */
34
+ export interface FilterOption {
35
+ /** Stable key for the keyed `{#each}`. */
36
+ readonly key: string;
37
+ readonly label: string;
38
+ readonly href: string;
39
+ /**
40
+ * Whether this option is the view currently shown. The caller's to decide:
41
+ * only the page knows which axis the row is filtering on.
42
+ */
43
+ readonly active: boolean;
44
+ }
45
+ /** `panels` is a tab widget; `links` is navigation between sibling routes. */
46
+ export type TabsMode = 'panels' | 'links';
47
+ /** The three daisyUI tab treatments. */
48
+ export type TabsVariant = 'border' | 'box' | 'lift';
49
+ /** Literal daisyUI class per `TabsVariant` for `Tabs`; a lookup table so Tailwind's scanner sees every class. */
50
+ export declare const tabsVariant: Record<TabsVariant, string>;
51
+ /** Literal daisyUI class per `Size` for `Tabs`; a lookup table so Tailwind's scanner sees every class. */
52
+ export declare const tabsSize: Record<Size, string>;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * The vocabulary the `layout/` family's list-shaped props are written in, and
3
+ * the literal daisyUI class tables its variants look up.
4
+ *
5
+ * The tables are local to this family rather than added to `ui/tones.ts`
6
+ * because `tabs-*` is a layout word: no `ui/` component renders a tab strip,
7
+ * and a table nobody outside one family reads is a table that belongs beside
8
+ * that family. The reason they are tables at all is the repo-wide one —
9
+ * Tailwind generates only the classes it can see verbatim in source, so a
10
+ * `tabs-${variant}` template string emits no CSS whatsoever.
11
+ *
12
+ * @module
13
+ */
14
+ /** Literal daisyUI class per `TabsVariant` for `Tabs`; a lookup table so Tailwind's scanner sees every class. */
15
+ export const tabsVariant = {
16
+ border: 'tabs-border',
17
+ box: 'tabs-box',
18
+ lift: 'tabs-lift',
19
+ };
20
+ /** Literal daisyUI class per `Size` for `Tabs`; a lookup table so Tailwind's scanner sees every class. */
21
+ export const tabsSize = {
22
+ xs: 'tabs-xs',
23
+ sm: 'tabs-sm',
24
+ md: 'tabs-md',
25
+ lg: 'tabs-lg',
26
+ xl: 'tabs-xl',
27
+ };
@@ -0,0 +1,28 @@
1
+ <!-- @component
2
+ The "About: Rosa canina, Bed 4" row under a piece of content: a leading label, then a link per subject.
3
+ -->
4
+ <!--
5
+ ContextLinks — the "About: Rosa canina, Bed 4" row under a piece of content:
6
+ a leading label, then the things the content is about, each a link.
7
+
8
+ Renders NOTHING when there are no links — the common case, since most
9
+ content names no context, and an empty "About:" would be noise. Each href is
10
+ resolved through the components context, like every app-relative link here.
11
+
12
+ ARIA contract: a plain paragraph of links. The label is visible text read
13
+ before the links, so no `aria-label` is needed; each link's own text is its
14
+ accessible name.
15
+ -->
16
+ <script lang="ts">import { getComponentsContext } from "../context.svelte.js";
17
+ let { links, label = "About", class: className, ...rest } = $props();
18
+ const context = getComponentsContext();
19
+ </script>
20
+
21
+ {#if links.length > 0}
22
+ <p {...rest} class={['text-base-content/70 flex flex-wrap gap-x-3 gap-y-1 text-sm', className]}>
23
+ <span>{label}:</span>
24
+ {#each links as entry, index (index)}
25
+ <a class="link link-hover" href={context.href(entry.href)}>{entry.label}</a>
26
+ {/each}
27
+ </p>
28
+ {/if}
@@ -0,0 +1,20 @@
1
+ import type { HTMLAttributes } from 'svelte/elements';
2
+ /** One thing the content is about. */
3
+ export interface ContextLinkItem {
4
+ /** App-relative path, resolved through the components context. */
5
+ readonly href: string;
6
+ readonly label: string;
7
+ }
8
+ interface Props extends HTMLAttributes<HTMLParagraphElement> {
9
+ /** The subjects, each rendered as a link. */
10
+ links: readonly ContextLinkItem[];
11
+ /**
12
+ * The leading word, rendered as `"<label>:"`.
13
+ * @defaultValue `'About'`
14
+ */
15
+ label?: string | undefined;
16
+ }
17
+ /** The "About: Rosa canina, Bed 4" row under a piece of content: a leading label, then a link per subject. */
18
+ declare const ContextLinks: import("svelte").Component<Props, {}, "">;
19
+ type ContextLinks = ReturnType<typeof ContextLinks>;
20
+ export default ContextLinks;