shelving 1.236.2 → 1.237.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 (219) hide show
  1. package/extract/IndexExtractor.js +9 -2
  2. package/extract/MergingExtractor.d.ts +3 -1
  3. package/extract/MergingExtractor.js +41 -3
  4. package/extract/TypescriptExtractor.d.ts +1 -0
  5. package/extract/TypescriptExtractor.js +12 -2
  6. package/package.json +1 -1
  7. package/ui/README.md +19 -274
  8. package/ui/app/App.d.ts +1 -0
  9. package/ui/app/App.js +1 -0
  10. package/ui/app/App.md +58 -0
  11. package/ui/app/App.tsx +1 -0
  12. package/ui/block/Card.d.ts +1 -0
  13. package/ui/block/Card.js +1 -0
  14. package/ui/block/Card.md +85 -0
  15. package/ui/block/Card.tsx +1 -0
  16. package/ui/block/Heading.d.ts +1 -0
  17. package/ui/block/Heading.js +1 -0
  18. package/ui/block/Heading.md +70 -0
  19. package/ui/block/Heading.tsx +1 -0
  20. package/ui/block/List.d.ts +1 -0
  21. package/ui/block/List.js +1 -0
  22. package/ui/block/List.md +51 -0
  23. package/ui/block/List.tsx +1 -0
  24. package/ui/block/Panel.d.ts +1 -0
  25. package/ui/block/Panel.js +1 -0
  26. package/ui/block/Panel.md +50 -0
  27. package/ui/block/Panel.tsx +1 -0
  28. package/ui/block/Paragraph.d.ts +1 -0
  29. package/ui/block/Paragraph.js +1 -0
  30. package/ui/block/Paragraph.md +48 -0
  31. package/ui/block/Paragraph.tsx +1 -0
  32. package/ui/block/Prose.d.ts +1 -0
  33. package/ui/block/Prose.js +1 -0
  34. package/ui/block/Prose.md +49 -0
  35. package/ui/block/Prose.tsx +1 -0
  36. package/ui/block/Section.d.ts +6 -0
  37. package/ui/block/Section.js +6 -0
  38. package/ui/block/Section.md +56 -0
  39. package/ui/block/Section.tsx +6 -0
  40. package/ui/block/Subheading.d.ts +1 -0
  41. package/ui/block/Subheading.js +1 -0
  42. package/ui/block/Subheading.md +58 -0
  43. package/ui/block/Subheading.tsx +1 -0
  44. package/ui/block/Table.d.ts +1 -0
  45. package/ui/block/Table.js +1 -0
  46. package/ui/block/Table.md +54 -0
  47. package/ui/block/Table.tsx +1 -0
  48. package/ui/block/Title.d.ts +1 -0
  49. package/ui/block/Title.js +1 -0
  50. package/ui/block/Title.md +57 -0
  51. package/ui/block/Title.tsx +1 -0
  52. package/ui/dialog/Dialog.d.ts +1 -0
  53. package/ui/dialog/Dialog.js +1 -0
  54. package/ui/dialog/Dialog.md +73 -0
  55. package/ui/dialog/Dialog.tsx +1 -0
  56. package/ui/dialog/Modal.d.ts +1 -0
  57. package/ui/dialog/Modal.js +1 -0
  58. package/ui/dialog/Modal.md +40 -0
  59. package/ui/dialog/Modal.tsx +1 -0
  60. package/ui/docs/DocumentationButtons.d.ts +2 -0
  61. package/ui/docs/DocumentationButtons.js +2 -0
  62. package/ui/docs/DocumentationButtons.md +38 -0
  63. package/ui/docs/DocumentationButtons.tsx +2 -0
  64. package/ui/docs/DocumentationCard.d.ts +1 -0
  65. package/ui/docs/DocumentationCard.js +1 -0
  66. package/ui/docs/DocumentationCard.md +35 -0
  67. package/ui/docs/DocumentationCard.tsx +1 -0
  68. package/ui/docs/DocumentationKind.d.ts +1 -1
  69. package/ui/docs/DocumentationKind.js +9 -4
  70. package/ui/docs/DocumentationKind.tsx +10 -5
  71. package/ui/docs/DocumentationPage.d.ts +1 -0
  72. package/ui/docs/DocumentationPage.js +2 -0
  73. package/ui/docs/DocumentationPage.md +46 -0
  74. package/ui/docs/DocumentationPage.tsx +2 -0
  75. package/ui/form/Button.d.ts +1 -0
  76. package/ui/form/Button.js +1 -0
  77. package/ui/form/Button.md +88 -0
  78. package/ui/form/Button.tsx +1 -0
  79. package/ui/form/Field.d.ts +6 -1
  80. package/ui/form/Field.js +6 -1
  81. package/ui/form/Field.md +59 -0
  82. package/ui/form/Field.tsx +6 -1
  83. package/ui/form/Form.d.ts +1 -0
  84. package/ui/form/Form.md +118 -0
  85. package/ui/form/Form.tsx +1 -0
  86. package/ui/form/FormStore.md +47 -0
  87. package/ui/form/SchemaInput.d.ts +1 -0
  88. package/ui/form/SchemaInput.md +64 -0
  89. package/ui/form/SchemaInput.tsx +1 -0
  90. package/ui/inline/Code.d.ts +1 -0
  91. package/ui/inline/Code.js +1 -0
  92. package/ui/inline/Code.md +58 -0
  93. package/ui/inline/Code.tsx +1 -0
  94. package/ui/inline/Link.d.ts +1 -0
  95. package/ui/inline/Link.js +1 -0
  96. package/ui/inline/Link.md +47 -0
  97. package/ui/inline/Link.tsx +1 -0
  98. package/ui/inline/Mark.d.ts +1 -0
  99. package/ui/inline/Mark.js +1 -0
  100. package/ui/inline/Mark.md +40 -0
  101. package/ui/inline/Mark.tsx +1 -0
  102. package/ui/inline/Strong.d.ts +1 -0
  103. package/ui/inline/Strong.js +1 -0
  104. package/ui/inline/Strong.md +34 -0
  105. package/ui/inline/Strong.tsx +1 -0
  106. package/ui/layout/CenteredLayout.d.ts +1 -0
  107. package/ui/layout/CenteredLayout.js +1 -0
  108. package/ui/layout/CenteredLayout.md +38 -0
  109. package/ui/layout/CenteredLayout.tsx +1 -0
  110. package/ui/layout/SidebarLayout.d.ts +1 -0
  111. package/ui/layout/SidebarLayout.js +1 -0
  112. package/ui/layout/SidebarLayout.md +65 -0
  113. package/ui/layout/SidebarLayout.tsx +1 -0
  114. package/ui/menu/Menu.d.ts +2 -0
  115. package/ui/menu/Menu.js +2 -0
  116. package/ui/menu/Menu.md +51 -0
  117. package/ui/menu/Menu.tsx +2 -0
  118. package/ui/menu/MenuItem.md +54 -0
  119. package/ui/misc/Catcher.d.ts +1 -0
  120. package/ui/misc/Catcher.js +1 -0
  121. package/ui/misc/Catcher.md +41 -0
  122. package/ui/misc/Catcher.tsx +1 -0
  123. package/ui/misc/Loading.d.ts +1 -0
  124. package/ui/misc/Loading.js +1 -0
  125. package/ui/misc/Loading.md +28 -0
  126. package/ui/misc/Loading.tsx +1 -0
  127. package/ui/misc/Mapper.md +40 -0
  128. package/ui/misc/Markup.d.ts +1 -0
  129. package/ui/misc/Markup.js +1 -0
  130. package/ui/misc/Markup.md +34 -0
  131. package/ui/misc/Markup.tsx +1 -0
  132. package/ui/misc/StatusIcon.d.ts +1 -0
  133. package/ui/misc/StatusIcon.js +1 -0
  134. package/ui/misc/StatusIcon.md +25 -0
  135. package/ui/misc/StatusIcon.tsx +1 -0
  136. package/ui/misc/Tag.d.ts +1 -0
  137. package/ui/misc/Tag.js +1 -0
  138. package/ui/misc/Tag.md +47 -0
  139. package/ui/misc/Tag.tsx +1 -0
  140. package/ui/notice/Notice.d.ts +1 -0
  141. package/ui/notice/Notice.js +1 -0
  142. package/ui/notice/Notice.md +53 -0
  143. package/ui/notice/Notice.tsx +1 -0
  144. package/ui/notice/Notices.d.ts +1 -0
  145. package/ui/notice/Notices.js +1 -0
  146. package/ui/notice/Notices.md +59 -0
  147. package/ui/notice/Notices.tsx +1 -0
  148. package/ui/page/HTML.d.ts +1 -0
  149. package/ui/page/HTML.js +1 -0
  150. package/ui/page/HTML.md +36 -0
  151. package/ui/page/HTML.tsx +1 -0
  152. package/ui/page/Head.d.ts +1 -0
  153. package/ui/page/Head.js +1 -0
  154. package/ui/page/Head.md +26 -0
  155. package/ui/page/Head.tsx +1 -0
  156. package/ui/page/Page.d.ts +1 -0
  157. package/ui/page/Page.js +1 -0
  158. package/ui/page/Page.md +42 -0
  159. package/ui/page/Page.tsx +1 -0
  160. package/ui/router/Navigation.d.ts +1 -0
  161. package/ui/router/Navigation.js +1 -0
  162. package/ui/router/Navigation.md +41 -0
  163. package/ui/router/Navigation.tsx +1 -0
  164. package/ui/router/NavigationStore.md +34 -0
  165. package/ui/router/Router.d.ts +1 -0
  166. package/ui/router/Router.js +1 -0
  167. package/ui/router/Router.md +143 -0
  168. package/ui/router/Router.tsx +1 -0
  169. package/ui/style/TINT_CLASS.md +55 -0
  170. package/ui/transition/CollapseTransition.d.ts +1 -0
  171. package/ui/transition/CollapseTransition.js +1 -0
  172. package/ui/transition/CollapseTransition.md +34 -0
  173. package/ui/transition/CollapseTransition.tsx +1 -0
  174. package/ui/transition/FadeTransition.d.ts +1 -0
  175. package/ui/transition/FadeTransition.js +1 -0
  176. package/ui/transition/FadeTransition.md +36 -0
  177. package/ui/transition/FadeTransition.tsx +1 -0
  178. package/ui/transition/HorizontalTransition.d.ts +1 -0
  179. package/ui/transition/HorizontalTransition.js +1 -0
  180. package/ui/transition/HorizontalTransition.md +44 -0
  181. package/ui/transition/HorizontalTransition.tsx +1 -0
  182. package/ui/transition/Transition.d.ts +1 -0
  183. package/ui/transition/Transition.js +1 -0
  184. package/ui/transition/Transition.md +70 -0
  185. package/ui/transition/Transition.tsx +1 -0
  186. package/ui/transition/VerticalTransition.d.ts +1 -0
  187. package/ui/transition/VerticalTransition.js +1 -0
  188. package/ui/transition/VerticalTransition.md +34 -0
  189. package/ui/transition/VerticalTransition.tsx +1 -0
  190. package/ui/tree/TreeApp.d.ts +1 -0
  191. package/ui/tree/TreeApp.js +1 -0
  192. package/ui/tree/TreeApp.md +59 -0
  193. package/ui/tree/TreeApp.tsx +1 -0
  194. package/ui/tree/TreeMenu.d.ts +1 -0
  195. package/ui/tree/TreeMenu.js +1 -0
  196. package/ui/tree/TreeMenu.md +35 -0
  197. package/ui/tree/TreeMenu.tsx +1 -0
  198. package/ui/tree/TreeSidebar.d.ts +1 -0
  199. package/ui/tree/TreeSidebar.js +1 -0
  200. package/ui/tree/TreeSidebar.md +24 -0
  201. package/ui/tree/TreeSidebar.tsx +1 -0
  202. package/ui/util/getClass.md +55 -0
  203. package/ui/util/notify.md +50 -0
  204. package/ui/util/requireContext.md +24 -0
  205. package/ui/app/README.md +0 -32
  206. package/ui/block/README.md +0 -144
  207. package/ui/dialog/README.md +0 -80
  208. package/ui/docs/README.md +0 -71
  209. package/ui/form/README.md +0 -165
  210. package/ui/inline/README.md +0 -86
  211. package/ui/layout/README.md +0 -71
  212. package/ui/menu/README.md +0 -33
  213. package/ui/misc/README.md +0 -121
  214. package/ui/notice/README.md +0 -94
  215. package/ui/page/README.md +0 -56
  216. package/ui/router/README.md +0 -186
  217. package/ui/transition/README.md +0 -80
  218. package/ui/tree/README.md +0 -78
  219. package/ui/util/README.md +0 -153
@@ -0,0 +1,35 @@
1
+ # DocumentationCard
2
+
3
+ A compact link tile summarising a documented symbol — the default card renderer for `tree-documentation` elements in [`TreeCards`](/ui/TreeCards) directory listings. Each card links straight to the symbol's own page.
4
+
5
+ **Things to know:**
6
+
7
+ - It leads with the symbol's signature(s) via [`DocumentationSignatures`](/ui/DocumentationSignatures) (the same calm code blocks as [`DocumentationPage`](/ui/DocumentationPage)). The signature already carries the name (and `readonly` for properties), so there is no separate title or kind tag — the card's *colour* carries the kind. Symbols with no signature (classes, interfaces, modules) fall back to a plain-name heading.
8
+ - Below the heading it renders the symbol's [`DocumentationButtons`](/ui/DocumentationButtons) relations, then a prose lead-in. The `member of` relation is dropped — a member card almost always sits on its own class's page already.
9
+ - The card links to the element's stamped `path` (the canonical URL set by `flattenTree()` — see [`TreeProvider`](/ui/TreeProvider)).
10
+
11
+ ## Usage
12
+
13
+ Used automatically via [`TreeCards`](/ui/TreeCards) (which [`DocumentationPage`](/ui/DocumentationPage) uses for its child sections). To render a single card manually, spread the element's flattened props.
14
+
15
+ ```tsx
16
+ import { DocumentationCard } from "shelving/ui";
17
+
18
+ // `element` is a `tree-documentation` element from DirectoryExtractor (see /extract).
19
+ <DocumentationCard {...element.props} />
20
+ ```
21
+
22
+ To replace this renderer across the whole site, wrap the app in [`TreeCardMapping`](/ui/TreeCards).
23
+
24
+ ## Styling
25
+
26
+ `DocumentationCard` has no own CSS hooks — it composes [`Card`](/ui/Card), [`Subheading`](/ui/Subheading), and [`Paragraph`](/ui/Paragraph). The card is tinted by `kind` via [`DocumentationKind`](/ui/DocumentationKind)'s colour map; retheme through `Card`'s `--card-*` hooks.
27
+
28
+ ## See also
29
+
30
+ - [`DocumentationPage`](/ui/DocumentationPage) — the full detail page these cards link to.
31
+ - [`DocumentationButtons`](/ui/DocumentationButtons) — the relations nav rendered inside the card.
32
+ - [`DocumentationKind`](/ui/DocumentationKind) — supplies the colour that tints the card by kind.
33
+ - [`TreeCards`](/ui/TreeCards) — the listing that dispatches cards, and the `*Mapping` override mechanism.
34
+ - [`Card`](/ui/Card) — the surface this card is painted on.
35
+ - [extract](/extract) — produces the `TreeElement` tree whose props this renderer consumes.
@@ -13,6 +13,7 @@ import { DocumentationSignatures } from "./DocumentationSignatures.js";
13
13
  * - Leads with the symbol's signature(s) as calm code blocks (`<DocumentationSignatures>`, same as the detail page), which already carry the name; falls back to the bare name for symbols with no signature (classes, interfaces, modules).
14
14
  * - The card is tinted by `kind` (colour carries the method/property/etc. distinction — no separate tag).
15
15
  *
16
+ * @kind component
16
17
  * @param props The documentation element's flattened props (`path`, `title`, `name`, `kind`, `description`, `signatures`, plus relational metadata); the `class` relation is dropped so member cards omit the redundant "member of" link.
17
18
  * @returns A `<Card>` linking to the symbol's own page.
18
19
  * @example <DocumentationCard {...element.props} />
@@ -7,7 +7,7 @@ import type { UIColor } from "../style/Color.js";
7
7
  * @see https://dhoulb.github.io/shelving/ui/docs/DocumentationKind/DocumentationKindProps
8
8
  */
9
9
  export interface DocumentationKindProps extends TagProps {
10
- /** The documentation kind (e.g. `"function"`, `"class"`, `"interface"`, `"type"`, `"constant"`, `"method"`, `"property"`). */
10
+ /** The documentation kind (e.g. `"component"`, `"function"`, `"class"`, `"interface"`, `"type"`, `"constant"`, `"method"`, `"property"`). */
11
11
  readonly kind: string;
12
12
  }
13
13
  /**
@@ -1,14 +1,19 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Tag } from "../misc/Tag.js";
3
- /** Mapping from a documented symbol's `kind` to its raw colour variant. */
3
+ /**
4
+ * Mapping from a documented symbol's `kind` to its raw colour variant.
5
+ * - Related kinds share a hue: component/class (purple), function/method (blue), interface/type (aqua).
6
+ * - Leaves `orange`, `pink`, and the brand aliases free for future kinds.
7
+ */
4
8
  const KIND_COLOR = {
5
9
  module: "red",
6
- function: "blue",
10
+ component: "purple",
7
11
  class: "purple",
12
+ function: "blue",
13
+ method: "blue",
8
14
  interface: "aqua",
9
- type: "pink",
15
+ type: "aqua",
10
16
  constant: "green",
11
- method: "orange",
12
17
  property: "yellow",
13
18
  };
14
19
  /**
@@ -8,19 +8,24 @@ import type { UIColor } from "../style/Color.js";
8
8
  * @see https://dhoulb.github.io/shelving/ui/docs/DocumentationKind/DocumentationKindProps
9
9
  */
10
10
  export interface DocumentationKindProps extends TagProps {
11
- /** The documentation kind (e.g. `"function"`, `"class"`, `"interface"`, `"type"`, `"constant"`, `"method"`, `"property"`). */
11
+ /** The documentation kind (e.g. `"component"`, `"function"`, `"class"`, `"interface"`, `"type"`, `"constant"`, `"method"`, `"property"`). */
12
12
  readonly kind: string;
13
13
  }
14
14
 
15
- /** Mapping from a documented symbol's `kind` to its raw colour variant. */
15
+ /**
16
+ * Mapping from a documented symbol's `kind` to its raw colour variant.
17
+ * - Related kinds share a hue: component/class (purple), function/method (blue), interface/type (aqua).
18
+ * - Leaves `orange`, `pink`, and the brand aliases free for future kinds.
19
+ */
16
20
  const KIND_COLOR: { readonly [K in string]?: UIColor } = {
17
21
  module: "red",
18
- function: "blue",
22
+ component: "purple",
19
23
  class: "purple",
24
+ function: "blue",
25
+ method: "blue",
20
26
  interface: "aqua",
21
- type: "pink",
27
+ type: "aqua",
22
28
  constant: "green",
23
- method: "orange",
24
29
  property: "yellow",
25
30
  };
26
31
 
@@ -6,6 +6,7 @@ import type { DocumentationElementProps } from "../../util/tree.js";
6
6
  * - Child symbols are grouped by `kind` into card sections (Functions, Classes, Methods, Properties, …), each under its own heading.
7
7
  * - All sections are conditional — only render when they have entries.
8
8
  *
9
+ * @kind component
9
10
  * @param props The documentation element's flattened props (`title`, `name`, `kind`, `description`, `content`, `signatures`, `params`, `returns`, `throws`, `examples`, `children`, plus relational metadata).
10
11
  * @returns A `<Page>` containing the symbol's full documentation.
11
12
  * @example <DocumentationPage {...element.props} />
@@ -22,6 +22,7 @@ import { DocumentationSignatures } from "./DocumentationSignatures.js";
22
22
  const DEFAULT_TYPE = "unknown";
23
23
  /** Documentation `kind`s grouped into card sections, in display order — pluralised, sentence-case headings. */
24
24
  const KIND_SECTIONS = {
25
+ component: "Components",
25
26
  function: "Functions",
26
27
  class: "Classes",
27
28
  interface: "Interfaces",
@@ -36,6 +37,7 @@ const KIND_SECTIONS = {
36
37
  * - Child symbols are grouped by `kind` into card sections (Functions, Classes, Methods, Properties, …), each under its own heading.
37
38
  * - All sections are conditional — only render when they have entries.
38
39
  *
40
+ * @kind component
39
41
  * @param props The documentation element's flattened props (`title`, `name`, `kind`, `description`, `content`, `signatures`, `params`, `returns`, `throws`, `examples`, `children`, plus relational metadata).
40
42
  * @returns A `<Page>` containing the symbol's full documentation.
41
43
  * @example <DocumentationPage {...element.props} />
@@ -0,0 +1,46 @@
1
+ # DocumentationPage
2
+
3
+ The full detail page for a documented symbol — the default renderer for `tree-documentation` elements dispatched by [`TreeApp`](/ui/TreeApp). It is the most detailed page renderer in the tree shell; render it directly only when you need a symbol page outside the tree, or replace it for one element type via [`TreePageMapping`](/ui/TreeRouter).
4
+
5
+ **Things to know:**
6
+
7
+ - Above the title it renders an ancestor trail via [`TreeBreadcrumbs`](/ui/TreeBreadcrumbs), so it needs a [`TreeProvider`](/ui/TreeProvider) above it to resolve the ancestors.
8
+ - The title carries a [`DocumentationKind`](/ui/DocumentationKind) tag, and below it [`DocumentationButtons`](/ui/DocumentationButtons) lists the symbol's relations (`member of`, `extends`, `implements`) as links.
9
+ - It renders the signature(s) via [`DocumentationSignatures`](/ui/DocumentationSignatures) (one block per overload, each carrying the symbol's name), then prose content, then conditional `Parameters` / `Returns` / `Throws` / `Examples` sections — each only appears when it has entries.
10
+ - Child symbols follow, grouped by `kind` into card sections (`Components`, `Functions`, `Classes`, `Interfaces`, `Types`, `Constants`, `Methods`, `Properties`) rendered as [`DocumentationCard`](/ui/DocumentationCard)s inside a [`TreeCards`](/ui/TreeCards) listing. A new documented kind needs an entry in `KIND_SECTIONS` here (and a colour in [`DocumentationKind`](/ui/DocumentationKind)).
11
+
12
+ ## Usage
13
+
14
+ Used automatically by [`TreeApp`](/ui/TreeApp). To render a single page manually, spread the element's flattened props.
15
+
16
+ ```tsx
17
+ import { DocumentationPage } from "shelving/ui";
18
+
19
+ // `element` is a `tree-documentation` element from DirectoryExtractor (see /extract).
20
+ <DocumentationPage {...element.props} />
21
+ ```
22
+
23
+ To replace this renderer across the whole site, wrap the app in [`TreePageMapping`](/ui/TreeRouter).
24
+
25
+ ```tsx
26
+ import { TreeApp, TreePageMapping } from "shelving/ui";
27
+
28
+ <TreePageMapping mapping={{ "tree-documentation": MyDocumentationPage }}>
29
+ <TreeApp tree={tree} />
30
+ </TreePageMapping>
31
+ ```
32
+
33
+ ## Styling
34
+
35
+ `DocumentationPage` has no own CSS hooks — it composes [`Page`](/ui/Page), [`Panel`](/ui/Panel), [`Section`](/ui/Section), and the other block components, which carry their own themeable surfaces. Retheme through those.
36
+
37
+ ## See also
38
+
39
+ - [`DocumentationCard`](/ui/DocumentationCard) — the compact card form of a symbol, used for the child sections here.
40
+ - [`DocumentationButtons`](/ui/DocumentationButtons) — the relations nav rendered below the title.
41
+ - [`DocumentationKind`](/ui/DocumentationKind) — the colour-coded kind tag carried by the title.
42
+ - [`DocumentationSignatures`](/ui/DocumentationSignatures) — renders the symbol's signature blocks.
43
+ - [`TreeApp`](/ui/TreeApp) — wires this renderer into a complete site via the page mappers.
44
+ - [`TreeBreadcrumbs`](/ui/TreeBreadcrumbs) — the ancestor trail rendered above the title.
45
+ - [extract](/extract) — produces the `TreeElement` tree whose props this renderer consumes.
46
+ - [markup](/markup) — renders the Markdown `content` field carried by each element.
@@ -25,6 +25,7 @@ const DEFAULT_TYPE = "unknown";
25
25
 
26
26
  /** Documentation `kind`s grouped into card sections, in display order — pluralised, sentence-case headings. */
27
27
  const KIND_SECTIONS = {
28
+ component: "Components",
28
29
  function: "Functions",
29
30
  class: "Classes",
30
31
  interface: "Interfaces",
@@ -40,6 +41,7 @@ const KIND_SECTIONS = {
40
41
  * - Child symbols are grouped by `kind` into card sections (Functions, Classes, Methods, Properties, …), each under its own heading.
41
42
  * - All sections are conditional — only render when they have entries.
42
43
  *
44
+ * @kind component
43
45
  * @param props The documentation element's flattened props (`title`, `name`, `kind`, `description`, `content`, `signatures`, `params`, `returns`, `throws`, `examples`, `children`, plus relational metadata).
44
46
  * @returns A `<Page>` containing the symbol's full documentation.
45
47
  * @example <DocumentationPage {...element.props} />
@@ -37,6 +37,7 @@ interface ButtonProps extends ButtonVariants, ClickableProps {
37
37
  * - Content-width by default (never grows); it won't shrink below its label. Pass `full` to fill the available width.
38
38
  * - Accepts all `ButtonVariants` styling props plus the `ClickableProps` (`onClick`, `href`, `disabled`, etc.).
39
39
  *
40
+ * @kind component
40
41
  * @example <Button onClick={save} color="primary">Save</Button>
41
42
  * @example <Button href="/about">About</Button>
42
43
  * @see https://dhoulb.github.io/shelving/ui/form/Button/Button
package/ui/form/Button.js CHANGED
@@ -22,6 +22,7 @@ export function getButtonClass(variants) {
22
22
  * - Content-width by default (never grows); it won't shrink below its label. Pass `full` to fill the available width.
23
23
  * - Accepts all `ButtonVariants` styling props plus the `ClickableProps` (`onClick`, `href`, `disabled`, etc.).
24
24
  *
25
+ * @kind component
25
26
  * @example <Button onClick={save} color="primary">Save</Button>
26
27
  * @example <Button href="/about">About</Button>
27
28
  * @see https://dhoulb.github.io/shelving/ui/form/Button/Button
@@ -0,0 +1,88 @@
1
+ # Button
2
+
3
+ A clickable styled as a solid button. Renders an `<a href="">` when given `href`, or a `<button>` when given `onClick` — the shared `Clickable` primitive picks the element, so a button is always the right semantics for what it does.
4
+
5
+ **Things to know:**
6
+
7
+ - Content-width by default: it sizes to its label and never grows. Pass `full` to fill the available width (it then shrinks to share a row, down to the content floor).
8
+ - `strong` marks the default action in a form — a filled background instead of an outline. `plain` and `outline` drop the background until hover/focus.
9
+ - `color=` / `status=` move the tint anchor, so the background, border and label re-derive from the same ladder; `small` tightens the padding.
10
+ - `getButtonClass(variants)` returns the same `className` the component composes — use it to style a non-`<button>` element as a button when `Button` itself doesn't fit.
11
+
12
+ ## Usage
13
+
14
+ ### Actions and links
15
+
16
+ ```tsx
17
+ import { Button } from "shelving/ui";
18
+
19
+ <Button onClick={save} color="primary" strong>Save</Button>
20
+ <Button href="/about">About</Button>
21
+ <Button onClick={remove} status="error">Delete</Button>
22
+ ```
23
+
24
+ ### A row of buttons
25
+
26
+ ```tsx
27
+ import { Button } from "shelving/ui";
28
+ import { Row } from "shelving/ui";
29
+
30
+ <Row gap="small" right>
31
+ <Button plain onClick={cancel}>Cancel</Button>
32
+ <Button strong onClick={submit}>Continue</Button>
33
+ </Row>
34
+ ```
35
+
36
+ ### Reusing the button class
37
+
38
+ ```tsx
39
+ import { getButtonClass } from "shelving/ui";
40
+
41
+ // Style an arbitrary element as a button.
42
+ <label className={getButtonClass({ color: "primary", small: true })}>
43
+ Upload<input type="file" hidden />
44
+ </label>
45
+ ```
46
+
47
+ ## Styling
48
+
49
+ `Button` paints from the [tint ladder](/ui/TINT_CLASS). Override these hooks at `:root` or any ancestor scope; move `--button-tint` to recolour the whole button, or use a per-property hook for one change.
50
+
51
+ | Variable | Styles | Default |
52
+ |---|---|---|
53
+ | `--button-tint` | Tint anchor for the button scope | `inherit` (flows from `color=` / `status=` / parent) |
54
+ | `--button-background` | Surface fill | `var(--tint-90)` |
55
+ | `--button-hover-background` | Surface fill on hover / focus | `var(--tint-95)` |
56
+ | `--button-text` | Label colour | `var(--tint-50)` |
57
+ | `--button-border` | Border shorthand | `var(--button-stroke) solid var(--tint-80)` |
58
+ | `--button-stroke` | Border / outline thickness | `var(--stroke-normal)` (2px) |
59
+ | `--button-radius` | Corner radius | `var(--radius-xsmall)` (8px) |
60
+ | `--button-padding` | Inner padding | `var(--space-small)` (12px) |
61
+ | `--button-small-padding` | Inner padding when `small` | `var(--space-xxsmall)` (4px) |
62
+ | `--button-space` | Outer block margin | `var(--space-small)` (12px) |
63
+ | `--button-font` | Font family | `var(--font-body)` |
64
+ | `--button-weight` | Font weight | `var(--weight-strong)` (700) |
65
+ | `--button-size` | Font size | `var(--size-normal)` |
66
+ | `--button-leading` | Line height | `var(--leading)` |
67
+ | `--button-transition` | Transition | `all var(--duration-fast)` (150ms) |
68
+ | `--button-focus-border` | Focus outline | `var(--stroke-focus) solid var(--color-focus)` |
69
+ | `--button-disabled-opacity` | Opacity when disabled | `0.5` |
70
+ | `--button-strong-background` | Fill when `strong` | `var(--tint-50)` |
71
+ | `--button-strong-text` | Label colour when `strong` | `var(--tint-100)` |
72
+ | `--button-strong-border` | Border when `strong` | `var(--button-stroke) solid transparent` |
73
+ | `--button-strong-hover-background` | Hover fill when `strong` | `var(--tint-55)` |
74
+
75
+ **Global tokens it reads:** the tint ladder `--tint-50` / `--tint-80` / `--tint-90` / `--tint-95` / `--tint-100` / `--tint-55`, plus `--space-small`, `--space-xxsmall`, `--radius-xsmall`, `--stroke-normal`, `--stroke-focus`, `--color-focus`, `--font-body`, `--weight-strong`, `--size-normal`, `--leading`, and `--duration-fast`.
76
+
77
+ ```css
78
+ /* Theme: pill-shaped buttons. */
79
+ :root {
80
+ --button-radius: 999px;
81
+ }
82
+ ```
83
+
84
+ ## See also
85
+
86
+ - [`Clickable`](/ui/Clickable) — the unstyled click/press primitive `Button` delegates to.
87
+ - [`Link`](/ui/Link) — an inline text link (vs. a button-styled `<a>`).
88
+ - [`ui`](/ui) — the styling system: tint ladder, cascade layers, and theming.
@@ -50,6 +50,7 @@ interface ButtonProps extends ButtonVariants, ClickableProps {}
50
50
  * - Content-width by default (never grows); it won't shrink below its label. Pass `full` to fill the available width.
51
51
  * - Accepts all `ButtonVariants` styling props plus the `ClickableProps` (`onClick`, `href`, `disabled`, etc.).
52
52
  *
53
+ * @kind component
53
54
  * @example <Button onClick={save} color="primary">Save</Button>
54
55
  * @example <Button href="/about">About</Button>
55
56
  * @see https://dhoulb.github.io/shelving/ui/form/Button/Button
@@ -13,5 +13,10 @@ export interface FieldProps extends ChildProps {
13
13
  /** Render at half width (50%) so two fields sit side-by-side; defaults to full width (one per row). */
14
14
  half?: boolean | undefined;
15
15
  }
16
- /** A `<Field>` wraps around a form control/input, to shows a small `<label>` above it. */
16
+ /**
17
+ * A `<Field>` wraps around a form control/input, to shows a small `<label>` above it.
18
+ *
19
+ * @kind component
20
+ * @see https://dhoulb.github.io/shelving/ui/form/Field/Field
21
+ */
17
22
  export declare function Field({ title, description, message, half, children }: FieldProps): ReactElement;
package/ui/form/Field.js CHANGED
@@ -2,7 +2,12 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Message } from "../notice/Message.js";
3
3
  import { getClass } from "../util/css.js";
4
4
  import styles from "./Field.module.css";
5
- /** A `<Field>` wraps around a form control/input, to shows a small `<label>` above it. */
5
+ /**
6
+ * A `<Field>` wraps around a form control/input, to shows a small `<label>` above it.
7
+ *
8
+ * @kind component
9
+ * @see https://dhoulb.github.io/shelving/ui/form/Field/Field
10
+ */
6
11
  export function Field({ title, description, message, half, children }) {
7
12
  return (_jsxs("label", { className: getClass(styles.field, half && styles.half), children: [(title || description) && (_jsxs("div", { children: [title ? _jsx("div", { className: styles.title, children: title }) : null, description && _jsx("div", { className: styles.description, children: description })] })), children, message && (_jsx(Message, { status: "error", right: true, children: message }))] }));
8
13
  }
@@ -0,0 +1,59 @@
1
+ # Field
2
+
3
+ The visual wrapper for a single form control. `Field` renders a `<label>` with an optional title and description above the input, and an inline error message below it. Use it when composing inputs by hand rather than relying on the automatic fields rendered by [`Form`](/ui/Form).
4
+
5
+ **Things to know:**
6
+
7
+ - Full width by default (one field per row). Pass `half` to render at 50% so two fields sit side-by-side.
8
+ - The `message` prop renders below the input as an error `Message` — wire it to the field's error string.
9
+ - `FormInput name="…"` combines a field's value, error, and schema lookup from the surrounding `FormContext`; reach for `Field` directly when you want explicit control over the label and layout.
10
+
11
+ ## Usage
12
+
13
+ ### Standalone field
14
+
15
+ ```tsx
16
+ import { Field, TextInput } from "shelving/ui";
17
+
18
+ <Field title="Email address" message={emailError}>
19
+ <TextInput name="email" value={email} onValue={setEmail} required />
20
+ </Field>
21
+ ```
22
+
23
+ ### Two-up layout
24
+
25
+ ```tsx
26
+ import { Field, TextInput } from "shelving/ui";
27
+
28
+ <Field title="First name" half>
29
+ <TextInput name="first" value={first} onValue={setFirst} />
30
+ </Field>
31
+ <Field title="Last name" half>
32
+ <TextInput name="last" value={last} onValue={setLast} />
33
+ </Field>
34
+ ```
35
+
36
+ ## Styling
37
+
38
+ `Field` paints its label, description, and message text. Override these hooks at `:root` or any ancestor scope.
39
+
40
+ | Variable | Styles | Default |
41
+ |---|---|---|
42
+ | `--field-space` | Outer block margin (top + bottom) | `var(--space-paragraph)` (16px) |
43
+ | `--field-gap` | Gap between label, control, and message | `var(--space-xsmall)` |
44
+ | `--field-title-size` | Title font size | `var(--size-normal)` |
45
+ | `--field-title-weight` | Title font weight | `var(--weight-strong)` |
46
+ | `--field-color-title` | Title colour | `var(--tint-00)` |
47
+ | `--field-description-size` | Description font size | `var(--size-normal)` |
48
+ | `--field-description-weight` | Description font weight | `var(--weight-normal)` |
49
+ | `--field-color-description` | Description colour | `var(--shade-dark)` |
50
+ | `--field-message-weight` | Message font weight | `var(--weight-strong)` |
51
+ | `--field-color-message` | Message colour | `var(--color-red)` |
52
+
53
+ **Global tokens it reads:** the tint ladder `--tint-00`, plus `--space-paragraph`, `--space-xsmall`, `--size-normal`, `--weight-strong`, `--weight-normal`, `--shade-dark`, and `--color-red`.
54
+
55
+ ## See also
56
+
57
+ - [`Form`](/ui/Form) — renders fields automatically from a schema.
58
+ - [`SchemaInput`](/ui/SchemaInput) — the control `SchemaField` drops inside a `Field`.
59
+ - [ui](/ui) — top-level UI module index.
package/ui/form/Field.tsx CHANGED
@@ -18,7 +18,12 @@ export interface FieldProps extends ChildProps {
18
18
  half?: boolean | undefined;
19
19
  }
20
20
 
21
- /** A `<Field>` wraps around a form control/input, to shows a small `<label>` above it. */
21
+ /**
22
+ * A `<Field>` wraps around a form control/input, to shows a small `<label>` above it.
23
+ *
24
+ * @kind component
25
+ * @see https://dhoulb.github.io/shelving/ui/form/Field/Field
26
+ */
22
27
  export function Field({ title, description, message, half, children }: FieldProps): ReactElement {
23
28
  return (
24
29
  // biome-ignore lint/a11y/noLabelWithoutControl: Generally `children` will contain a field.
package/ui/form/Form.d.ts CHANGED
@@ -38,6 +38,7 @@ export interface FormProps<T extends Data> extends OptionalChildProps {
38
38
  *
39
39
  * @param props Props including `schema`, initial `data`, `onSubmit`, `submit` content, and initial `messages`.
40
40
  * @returns A `<form>` element wrapping the fields in a `FormContext` provider.
41
+ * @kind component
41
42
  * @example <Form schema={USER_SCHEMA} onSubmit={save} />
42
43
  * @see https://dhoulb.github.io/shelving/ui/form/Form/Form
43
44
  */
@@ -0,0 +1,118 @@
1
+ # Form
2
+
3
+ The entry point for shelving forms. `Form` creates a [`FormStore`](/ui/FormStore) from a `schema` prop, wraps everything in an HTML `<form>`, disables the whole fieldset while busy, and calls `onSubmit` on a valid submit. Build validated, schema-driven forms from a handful of composable pieces, or drop in a single `<Form>` for a fully automatic experience.
4
+
5
+ **Things to know:**
6
+
7
+ - If you provide no `children`, `Form` renders `<FormFields>` (one auto-input per schema property) followed by `<FormFooter>` (submit button + error message), so a usable form is one prop away.
8
+ - Pass `data` to pre-populate an edit form. Pass `messages` (a string or dictionary) to seed initial field errors — useful when a server returns validation failures.
9
+ - The whole `<fieldset>` is disabled while a submit is in flight, so inputs and buttons lock automatically.
10
+ - A successful submit inside a `<dialog>` closes the dialog automatically.
11
+ - Notices are surfaced from the `onSubmit` return/throw — see [Notices and error surfacing](#notices-and-error-surfacing) below.
12
+
13
+ ## Usage
14
+
15
+ ### Automatic form
16
+
17
+ With no `children`, `Form` renders one input per schema property plus a footer.
18
+
19
+ ```tsx
20
+ import { Form } from "shelving/ui";
21
+ import { DATA, StringSchema, NumberSchema } from "shelving/schema";
22
+
23
+ const PRODUCT_SCHEMA = DATA({
24
+ name: new StringSchema({ title: "Name", min: 1, max: 100 }),
25
+ price: new NumberSchema({ title: "Price", min: 0 }),
26
+ });
27
+
28
+ export function NewProductForm() {
29
+ return (
30
+ <Form
31
+ schema={PRODUCT_SCHEMA}
32
+ submit="Create product"
33
+ onSubmit={async data => {
34
+ await createProduct(data);
35
+ return "Product created"; // dispatched as a success notice
36
+ }}
37
+ />
38
+ );
39
+ }
40
+ ```
41
+
42
+ ### Edit form with seeded data
43
+
44
+ ```tsx
45
+ import { Form } from "shelving/ui";
46
+ import { DATA, StringSchema, NumberSchema, BOOLEAN } from "shelving/schema";
47
+
48
+ const LISTING_SCHEMA = DATA({
49
+ title: new StringSchema({ title: "Title", min: 1, max: 80 }),
50
+ price: new NumberSchema({ title: "Price", min: 0 }),
51
+ published: BOOLEAN,
52
+ });
53
+
54
+ export function ListingForm({ listing }: { listing?: typeof LISTING_SCHEMA.type }) {
55
+ return (
56
+ <Form
57
+ schema={LISTING_SCHEMA}
58
+ data={listing}
59
+ submit={listing ? "Save changes" : "Publish listing"}
60
+ onSubmit={async data => {
61
+ await saveListing(data);
62
+ return listing ? "Listing updated" : "Listing published";
63
+ }}
64
+ />
65
+ );
66
+ }
67
+ ```
68
+
69
+ ### Custom layout
70
+
71
+ Provide explicit `children` when you need control over field order, groupings, or extra buttons. `<FormInput name="…">` uses `useField()` to pull the current value, error, and schema from context, then delegates to [`SchemaInput`](/ui/SchemaInput) so each field renders the correct control type.
72
+
73
+ ```tsx
74
+ import { Form, Field, FormInput, SubmitButton, Button, FormMessage } from "shelving/ui";
75
+
76
+ <Form schema={LISTING_SCHEMA} data={listing} onSubmit={handleSubmit}>
77
+ <Field title="Title" required>
78
+ <FormInput name="title" />
79
+ </Field>
80
+ <Field title="Price">
81
+ <FormInput name="price" />
82
+ </Field>
83
+ <FormInput name="published" />
84
+ <footer>
85
+ <SubmitButton>Save changes</SubmitButton>
86
+ <Button plain onClick={onCancel}>Cancel</Button>
87
+ <FormMessage />
88
+ </footer>
89
+ </Form>
90
+ ```
91
+
92
+ ## Notices and error surfacing
93
+
94
+ When an `onSubmit` callback returns a non-empty `ReactNode`, `Form` dispatches it as a success notice. When it throws a **string**, the string is parsed into field messages — any line matching `"fieldName: message"` maps to that field's error display; an unmatched remainder appears as the form-wide message shown by `<FormMessage>`. Non-string throws become global error notices. The string-splitting rule comes from [schema](/schema).
95
+
96
+ - `<FormMessage>` renders the top-level `""` message inline as a `<Message>`.
97
+ - `<FormNotice>` renders it as a larger `<Notice>` block.
98
+ - `<FormNotify>` (no JSX output) forwards the message to the global notice system via a side effect instead.
99
+
100
+ ## Styling
101
+
102
+ `Form` only lays out its block flow — it exposes a single spacing hook and otherwise inherits styling from the components inside it.
103
+
104
+ | Variable | Styles | Default |
105
+ |---|---|---|
106
+ | `--form-space` | Outer block margin (top + bottom) | `var(--space-paragraph)` (16px) |
107
+
108
+ **Global tokens it reads:** `--space-paragraph`.
109
+
110
+ ## See also
111
+
112
+ - [`FormStore`](/ui/FormStore) — the reactive state class underlying every form.
113
+ - [`Field`](/ui/Field) — the label + input + error wrapper for a single control.
114
+ - [`SchemaInput`](/ui/SchemaInput) — the schema-to-input dispatch component.
115
+ - [`SubmitButton`](/ui/SubmitButton) — submit button that reads the surrounding form's busy state.
116
+ - [schema](/schema) — `DataSchema`, `StringSchema`, `NumberSchema`, and the other schema types that drive automatic input selection.
117
+ - [react](/react) — `useStore`, `useInstance`, and other hooks used internally.
118
+ - [ui](/ui) — top-level UI module index.
package/ui/form/Form.tsx CHANGED
@@ -51,6 +51,7 @@ export interface FormProps<T extends Data> extends OptionalChildProps {
51
51
  *
52
52
  * @param props Props including `schema`, initial `data`, `onSubmit`, `submit` content, and initial `messages`.
53
53
  * @returns A `<form>` element wrapping the fields in a `FormContext` provider.
54
+ * @kind component
54
55
  * @example <Form schema={USER_SCHEMA} onSubmit={save} />
55
56
  * @see https://dhoulb.github.io/shelving/ui/form/Form/Form
56
57
  */
@@ -0,0 +1,47 @@
1
+ # FormStore
2
+
3
+ The reactive brain behind every form. `FormStore` extends `DataStore` from [store](/store) and owns the current (partial) field values, a `messages` dictionary of per-field errors, and the validate/submit helpers that drive a [`Form`](/ui/Form).
4
+
5
+ **Things to know:**
6
+
7
+ - It holds the current (possibly partial and invalid) field values plus a `messages` dictionary — error strings keyed by field name, with a top-level `""` key for form-wide messages.
8
+ - `validated` is a getter that runs the schema and returns fully-typed data or throws a string on failure.
9
+ - `publish(name, value)` validates a single field, writes the result, and stores any per-field error (it persists the raw value even when invalid, so nothing is lost on the way to submit).
10
+ - `submit(callback)` validates the whole form and, if valid, runs the callback.
11
+ - Assigning a string to `reason` splits it into per-field messages (using the `"fieldName: message"` line format from [schema](/schema)) instead of recording a global failure; any non-string reason is surfaced as-is.
12
+ - You rarely construct `FormStore` directly — [`Form`](/ui/Form) does it for you — but you can grab it from context with `requireForm()` when you need it.
13
+
14
+ ## Usage
15
+
16
+ ### Direct construction
17
+
18
+ ```tsx
19
+ import { FormStore } from "shelving/ui";
20
+ import { DATA, StringSchema } from "shelving/schema";
21
+
22
+ const USER_SCHEMA = DATA({ name: new StringSchema({ title: "Name", min: 1 }) });
23
+
24
+ const store = new FormStore(USER_SCHEMA, { name: "Dave" });
25
+
26
+ store.publish("name", "Dave Houlbrooke"); // Validate + write a single field.
27
+ const data = store.validated; // Fully-typed data, or throws a string message.
28
+ ```
29
+
30
+ ### Reading the store from context
31
+
32
+ ```tsx
33
+ import { requireForm } from "shelving/ui";
34
+
35
+ function ResetButton() {
36
+ const store = requireForm();
37
+ return <Button plain onClick={() => store.set("name", "")}>Clear name</Button>;
38
+ }
39
+ ```
40
+
41
+ ## See also
42
+
43
+ - [`Form`](/ui/Form) — the component that creates and provides a `FormStore`.
44
+ - [`Field`](/ui/Field) — renders a single field's value and message from the store.
45
+ - [store](/store) — `DataStore` and the reactive store family `FormStore` builds on.
46
+ - [schema](/schema) — schema validation and the `"fieldName: message"` split format.
47
+ - [react](/react) — `useStore`, `useInstance`, and other hooks used to subscribe to the store.
@@ -37,6 +37,7 @@ export interface SchemaInputProps<T extends Schema, I = never> extends ValueInpu
37
37
  * @param props Props including the `schema` plus value input props.
38
38
  * @returns The matching input element for the schema.
39
39
  * @throws `UnexpectedError` if no input matches the schema type.
40
+ * @kind component
40
41
  * @example <SchemaInput name="email" schema={EMAIL} /> // Outputs a `<TextInput>` for the "email" property.
41
42
  * @example <SchemaInput name="age" schema={AGE} /> // Outputs a `<NumberInput>` for the "age" property.
42
43
  * @see https://dhoulb.github.io/shelving/ui/form/SchemaInput/SchemaInput