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
package/ui/misc/README.md DELETED
@@ -1,121 +0,0 @@
1
- # Misc
2
-
3
- Cross-cutting utilities and components that don't belong to a single content category. These are the primitives other components in [ui](/ui) are built from — error handling, status colouring, markdown rendering, element dispatch, and page metadata.
4
-
5
- ## Error boundaries
6
-
7
- `Catcher` is a React class component that catches errors thrown anywhere in its subtree and replaces the failed region with a fallback UI. Pass `as` to supply a custom error renderer; it defaults to `ErrorNotice` (an inline error notice with a retry button). `PageCatcher` is a convenience wrapper that uses `ErrorPage` instead — a full-page error display inside a `<CenteredLayout>`.
8
-
9
- `RetryButton` reads the retry callback from the nearest `Catcher` via context and renders a `<Button>`. Returns `null` when there is no parent catcher.
10
-
11
- `ErrorNotice` and `ErrorPage` can be used standalone when you need to display a known error without a boundary.
12
-
13
- ```tsx
14
- import { PageCatcher, Catcher, ErrorNotice } from "shelving/ui";
15
-
16
- // Catch and display errors for a whole page
17
- <PageCatcher>
18
- <MyPage />
19
- </PageCatcher>
20
-
21
- // Localised error boundary inside a panel
22
- <Catcher as={ErrorNotice}>
23
- <LiveFeed />
24
- </Catcher>
25
- ```
26
-
27
- ## Status and colour
28
-
29
- `Status` is the type (`"loading" | "info" | "success" | "warning" | "danger" | "error"`) and `StatusProps` is the matching props interface — a `status="error"` prop plus boolean aliases (`<Notice error>`). Use these as the canonical vocabulary for component state everywhere in the UI.
30
-
31
- `getStatusClass` maps a `Status` string or `StatusProps` object to a CSS module class. Compose it with other class helpers when building components that need status colouring.
32
-
33
- `Color` (from [ui/style](../style/)) exports `ColorProps` — a `color` prop taking a raw hue (`"red"`, `"blue"`, `"purple"`, `"green"`, etc.) — and `getColorClass`. Use `status` for semantic meaning and `color` for purely decorative differentiation.
34
-
35
- `getTypographyClass` (from `Typography`) returns a class for the `size` prop (`size="small"` … `size="xxlarge"`), the `tint` prop, and the font-family (`code`, `sans`, `serif`, …) and alignment variants. Compose into components that need typography overrides without wrapping in an extra element.
36
-
37
- ## Loading spinner
38
-
39
- `Loading` renders an animated SVG spinner. `LOADING` is a pre-keyed `<Loading />` constant — use it directly to avoid unnecessary reconciliation overhead.
40
-
41
- ```tsx
42
- import { LOADING } from "shelving/ui";
43
-
44
- {busy ? LOADING : children}
45
- ```
46
-
47
- ## Status icon
48
-
49
- `StatusIcon` picks the right icon for a given status and sizes it via the `size` prop (`"small"`, `"normal"`, `"large"`, `"xlarge"`, or `"xxlarge"`; defaults to the current line height). `info` is the default when no `status` prop is set.
50
-
51
- ```tsx
52
- import { StatusIcon } from "shelving/ui";
53
-
54
- <StatusIcon status="success" size="large" />
55
- <StatusIcon status="error" />
56
- <StatusIcon status="loading" size="small" />
57
- ```
58
-
59
- ## Tag
60
-
61
- `Tag` is a small inline label. It accepts both `StatusProps` and `ColorProps`, plus `href` or `onClick` from `ClickableProps`, so it can be static or interactive.
62
-
63
- ```tsx
64
- import { Tag } from "shelving/ui";
65
-
66
- <Tag success>Active</Tag>
67
- <Tag warning href="/billing">Overdue</Tag>
68
- <Tag color="purple" size="small">Beta</Tag>
69
- ```
70
-
71
- ## Markup renderer
72
-
73
- `Markup` parses a markup string and renders the resulting React nodes. It defaults to the full block + inline rule set and resolves links against the current `<Meta>` context. Wrap in `<Prose>` for longform typography.
74
-
75
- ```tsx
76
- import { Prose, Markup } from "shelving/ui";
77
-
78
- <Prose>
79
- <Markup>{article.body}</Markup>
80
- </Prose>
81
- ```
82
-
83
- Override any `MarkupOptions` prop directly on `<Markup>` when you need a custom rule set or a specific base URL.
84
-
85
- ## Element dispatch: `createMapper`
86
-
87
- `createMapper` creates a `[Mapping, Mapper]` component pair backed by a private React context. `Mapper` walks a pre-walked element tree and replaces each matching element type with the registered component. `Mapping` lets a subtree override or extend the dispatch table.
88
-
89
- This is the right tool when a component renders a tree of typed elements and callers need to swap in their own renderers for specific types.
90
-
91
- ```tsx
92
- import { createMapper } from "shelving/ui";
93
-
94
- const [TreeMapping, TreeMapper] = createMapper({
95
- "tree-element": TreeRow,
96
- });
97
-
98
- // In a consumer:
99
- <TreeMapper>{walkElements(children)}</TreeMapper>
100
-
101
- // Override one entry in a subtree:
102
- <TreeMapping mapping={{ "tree-element": SpecialTreeRow }}>
103
- <TreeMapper>{walkElements(children)}</TreeMapper>
104
- </TreeMapping>
105
- ```
106
-
107
- ## Page metadata context
108
-
109
- `MetaContext` is the raw React context holding the current `Meta` (URL, base root, and other page-level properties). It is published by `<HTML>` and consumed internally by `<Markup>`, `<Link>`, `<Router>`, and similar components.
110
-
111
- `requireMeta` reads the context and optionally merges in override props — use this in components that need to resolve URLs against the current page.
112
-
113
- `requireMetaURL` resolves the current `url` against the meta `root` and returns the meta extended with the site-root-relative `path` and the extracted query `params`. Throws if `url` is unset or sits on a different origin to `root`.
114
-
115
- ## See also
116
-
117
- - [ui/block](/ui/block) — block content components that compose with `Tag`, `Markup`, and `Prose`
118
- - [ui/inline](/ui/inline) — inline content components
119
- - [ui/notice](/ui/notice) — `Notice` component used inside `ErrorNotice`
120
- - [ui/router](/ui/router) — `<Router>` and `<Navigation>` that publish into `MetaContext`
121
- - [markup](/markup) — the markup parser and rule set underlying `<Markup>`
@@ -1,94 +0,0 @@
1
- # Notices
2
-
3
- Inline and global toast-style notices for user feedback. `<Notice>` is a standalone status banner; `<Notices>` is the global list that listens for dispatched events and shows them automatically.
4
-
5
- ## Concepts
6
-
7
- **`<Notice>`** renders an `<aside>` with a status icon and a message. It accepts a `status` prop (`"info"`, `"success"`, `"error"`, `"danger"`, `"loading"`, etc.) and maps it to the appropriate colour and ARIA role. The icon defaults to `<StatusIcon>` but can be replaced or hidden.
8
-
9
- **`<Message>`** is a lighter variant — a `<p>` tag with the same status colours, for short inline feedback inside a form or card rather than a banner.
10
-
11
- **`<Notices>`** renders the global list of active notices. It subscribes to `"notice"` events on `window` (dispatched by the `notify` helpers in [ui/util](/ui/util)) and shows each one as a `<Notice>`. Notices auto-dismiss after 5 seconds unless they carry a `"loading"` status.
12
-
13
- **`NoticeStore` and `NoticesStore`** are the reactive stores behind `<Notices>`. `NoticesStore` is an `ArrayStore<NoticeStore>` that manages the list. Each `NoticeStore` is a `DataStore` holding one notice's message and status, and removes itself from the list when it closes.
14
-
15
- ## Basic usage
16
-
17
- Place `<Notice>` anywhere to show inline status feedback.
18
-
19
- ```tsx
20
- import { Notice } from "shelving/ui";
21
-
22
- <Notice status="success">Your changes have been saved.</Notice>
23
- <Notice status="error">Something went wrong.</Notice>
24
- <Notice status="loading" />
25
- ```
26
-
27
- When `status` is omitted, `<Notice>` defaults to `"info"` if `children` is present, or `"loading"` if not.
28
-
29
- Use `<Message>` for shorter inline feedback inside paragraphs or forms.
30
-
31
- ```tsx
32
- import { Message } from "shelving/ui";
33
-
34
- <Message status="error">This field is required.</Message>
35
- ```
36
-
37
- ## Global notices
38
-
39
- Mount `<Notices>` once near the root of your app. It renders at that point in the DOM and listens automatically.
40
-
41
- ```tsx
42
- import { Notices } from "shelving/ui";
43
-
44
- export function AppLayout({ children }) {
45
- return (
46
- <>
47
- {children}
48
- <Notices />
49
- </>
50
- );
51
- }
52
- ```
53
-
54
- Dispatch notices from anywhere — no context required:
55
-
56
- ```tsx
57
- import { notifySuccess, notifyError, callNotified } from "shelving/ui";
58
-
59
- // Direct dispatch.
60
- notifySuccess("Profile updated.");
61
- notifyError("Could not connect.");
62
-
63
- // Wrap an async callback — dispatches success or error automatically.
64
- callNotified(async () => {
65
- await saveProfile(data);
66
- return "Profile updated.";
67
- });
68
- ```
69
-
70
- ## Programmatic control via `NoticesStore`
71
-
72
- The global `NOTICES` singleton is exported for advanced use — for example, keeping a reference to a specific notice so you can update or close it manually.
73
-
74
- ```tsx
75
- import { NOTICES } from "shelving/ui";
76
-
77
- // Show a loading notice and hold a reference to it.
78
- const notice = NOTICES.show(undefined, "loading");
79
-
80
- await uploadFile(file);
81
-
82
- // Update the same notice in place.
83
- notice.show("Upload complete.", "success");
84
-
85
- // Or close it immediately.
86
- notice.close();
87
- ```
88
-
89
- `NoticeStore` implements `AsyncDisposable`, so it can be used in an `await using` block to close automatically when the scope exits.
90
-
91
- ## See also
92
-
93
- - [ui/util](/ui/util) — `notify`, `notifySuccess`, `notifyError`, `callNotified`, and `subscribeNotices`
94
- - [store](/store) — `ArrayStore` and `DataStore` that `NoticesStore` and `NoticeStore` extend
package/ui/page/README.md DELETED
@@ -1,56 +0,0 @@
1
- # Page
2
-
3
- Document-level components for the HTML shell and per-page metadata. These three components own the `<html>`, `<head>`, and per-page `<title>` / `<meta>` output for a shelving app.
4
-
5
- ## Components
6
-
7
- | Component | Purpose |
8
- |---|---|
9
- | `<HTML>` | Renders the full `<html>` document shell with `<head>` and `<body>`. Use this as the outermost wrapper for SSR. |
10
- | `<Page>` | Wraps one page inside the app. Merges per-page meta props into context and emits hoistable head tags (title, description, meta, links, scripts) that React 19 lifts into `<head>`. Also updates `window.history` to match the page URL. |
11
- | `<Head>` | Low-level: emits the hoistable tags from the current `Meta` context. `<Page>` renders it automatically — you rarely need it directly. |
12
-
13
- `<HTML>` and `<Page>` both accept `PossibleMeta` props (`app`, `root`, `url`, `title`, `description`, `language`, `tags`, `links`, `stylesheets`, `modules`, `scripts`) and merge them into the context they provide to children.
14
-
15
- ## SSR usage
16
-
17
- ```tsx
18
- import { HTML, Page } from "shelving/ui";
19
- import { Navigation, Router } from "shelving/ui";
20
-
21
- // Server-side render — pass the request URL to <HTML>.
22
- renderToString(
23
- <HTML app="My App" root="https://example.com/" url={requestUrl} language="en">
24
- <Navigation>
25
- <Router routes={{
26
- "/": HomePage,
27
- "/about": AboutPage,
28
- }}/>
29
- </Navigation>
30
- </HTML>
31
- );
32
- ```
33
-
34
- ## Per-page metadata
35
-
36
- ```tsx
37
- function UserPage({ id }: { id: string }) {
38
- return (
39
- <Page title="User profile" url={`/users/${id}`} description="View user details.">
40
- <Section>…</Section>
41
- </Page>
42
- );
43
- }
44
- ```
45
-
46
- The title is composed with the app name from the surrounding context: `"User profile - My App"`.
47
-
48
- ## How hoisting works
49
-
50
- `<Page>` renders `<Head>` inline. React 19 automatically hoists `<title>`, `<meta>`, `<link>`, and `<script>` elements into the document `<head>`, so you don't need a portal. `<base>` is the exception — it is not hoistable and lives only in `<HTML>`.
51
-
52
- ## See also
53
-
54
- - [`app`](/ui/app) — `<App>` for client-side-only roots (no `<html>` shell needed)
55
- - [`router`](/ui/router) — `<Navigation>` and `<Router>` for URL-driven rendering
56
- - [`layout`](/ui/layout) — layouts that go inside `<Page>`
@@ -1,186 +0,0 @@
1
- # Router
2
-
3
- Client-side routing for shelving apps.
4
-
5
- Two pieces:
6
-
7
- | Component | Job |
8
- | --------------- | ---------------------------------------------------------------------------------------------- |
9
- | `<Navigation>` | One per app. Owns URL state, intercepts link clicks, listens for `popstate`. |
10
- | `<Router>` | Pure matcher. Reads URL from `<Meta>`, matches `routes`, renders the matched element. |
11
-
12
- Plus `requireNavigation()` for imperative `forward()` / `redirect()` calls from anywhere in the tree.
13
-
14
- `<Router>` reads URL state from `<Meta>`, so it works with no `<Navigation>` at all (SSR, static rendering, tests). `<Navigation>` is what publishes a *live* URL into `<Meta>` on the client.
15
-
16
- ## Basic setup
17
-
18
- ```tsx
19
- <HTML url={initialUrl} root="https://example.com/">
20
- <Navigation>
21
- <Router routes={{
22
- "/": HomePage,
23
- "/users/{id}": UserPage,
24
- "/about": AboutPage,
25
- }}/>
26
- </Navigation>
27
- </HTML>
28
- ```
29
-
30
- - Route keys are `AbsolutePath` strings starting with `/`.
31
- - Placeholders (`{id}`, `:id`, `[id]`, `${id}`, `{{id}}`) are passed to function/component routes as props (merged with URL `?query` params; placeholders win on conflict).
32
- - A string value (e.g. `"/users/123"`) is a redirect — visiting the key path navigates to the target.
33
- - `<Router>` itself accepts `PossibleMeta` props (`url`, `base`, etc.) to override the surrounding context.
34
-
35
- ## Route value types
36
-
37
- | Value | Behaviour |
38
- | --------------------- | ---------------------------------------------------------------------- |
39
- | `RouteComponent` | Rendered as `<Component {...params}/>` with merged placeholder + query. |
40
- | `AbsolutePath` string | Redirects to that path (placeholders resolved against the source). |
41
- | `ReactElement` | Rendered as-is — use for layout wrapping or composing inner routers. |
42
-
43
- ## Placeholder syntax
44
-
45
- All forms produce the same matched value — pick whichever reads best:
46
-
47
- | Form | Single segment | Catchall (one+ segments, also matches empty) |
48
- | ----------------- | ---------------------- | -------------------------------------------- |
49
- | Anonymous | `*` (named `"0"`) | `**` / `***` / `****` (named `"0"`) |
50
- | Colon | `:name` | `:name*` / `:name**` |
51
- | Single brace | `{name}` | `{...name}` / `{name*}` / `{....name}` |
52
- | Square bracket | `[name]` | `[...name]` / `[name*]` |
53
- | Dollar brace | `${name}` | `${...name}` / `${name*}` |
54
- | Double brace | `{{name}}` | `{{...name}}` / `{{name*}}` |
55
-
56
- Modifier chars are tolerant: one-or-more stars and three-or-more dots are all equivalent. So `{path*}`, `{path**}`, `{...path}`, and `{....path}` all behave the same.
57
-
58
- Catchall placeholders allow empty values, so a trailing catchall matches the trailing-slash-absent variant too — `/files/{...path}` matches both `/files`, `/files/`, and `/files/a/b/c`.
59
-
60
- ## Layout wrapping
61
-
62
- Put layout JSX as the route value with another `<Router>` inside.
63
-
64
- ```tsx
65
- const SIDEBARRED_ROUTES = {
66
- "/users": <UsersPage/>,
67
- "/users/{id}": <UserPage/>,
68
- "/settings": <SettingsPage/>,
69
- };
70
-
71
- <Router routes={{
72
- "/": <HomePage/>,
73
- "/{...path}": (
74
- <SidebarLayout>
75
- <Router routes={SIDEBARRED_ROUTES}/>
76
- </SidebarLayout>
77
- ),
78
- }}/>
79
- ```
80
-
81
- The outer router matches everything, wraps in `<SidebarLayout>`, and hands off to the inner router. Since `<Router>` reads its URL from `<Meta>`, the inner router sees the same URL.
82
-
83
- ## Section / microsite pattern
84
-
85
- A self-contained "section" of the app — its own URL prefix, its own routes — composes via a catchall + a function route value that hands the captured sub-path to a nested router.
86
-
87
- ```tsx
88
- <Router routes={{
89
- "/": <HomePage/>,
90
- "/users/{...path}": ({ path = "/" }) => (
91
- <Router routes={{
92
- "/": UsersPage,
93
- "/{id}": UserPage,
94
- }} url={path}/>
95
- ),
96
- }}/>
97
- ```
98
-
99
- The outer router captures everything under `/users` into the `path` placeholder, then the inner router treats `path` as its starting URL. The inner router's `"/"` matches the bare `/users`; `/{id}` matches `/users/123`.
100
-
101
- Pull that out into a dedicated component for readability:
102
-
103
- ```tsx
104
- const USER_ROUTES = {
105
- "/": UsersPage,
106
- "/{id}": UserPage,
107
- "/{id}/edit": UserEditPage,
108
- };
109
-
110
- export function UserRouter({ path = "/" }: { path?: AbsolutePath }) {
111
- return <Router routes={USER_ROUTES} url={path}/>;
112
- }
113
-
114
- // then at the call site:
115
- <Router routes={{
116
- "/": <HomePage/>,
117
- "/users/{...path}": ({ path }) => <UserRouter path={path}/>,
118
- "/blog/{...path}": ({ path }) => <BlogRouter path={path}/>,
119
- }}/>
120
- ```
121
-
122
- Each section module owns its routes and exposes one component. The top-level router stays a flat list of section prefixes.
123
-
124
- ## Stacking layouts and sections
125
-
126
- The two patterns compose. Wrap a bunch of routes in a layout, then route further inside it:
127
-
128
- ```tsx
129
- const SIDEBARRED_ROUTES = {
130
- "/": <Dashboard/>,
131
- "/users/{...path}": ({ path }) => <UserRouter path={path}/>,
132
- "/blog/{...path}": ({ path }) => <BlogRouter path={path}/>,
133
- "/settings": <SettingsPage/>,
134
- };
135
-
136
- <Router routes={{
137
- "/login": <LoginPage/>, // no sidebar
138
- "/{...path}": ( // everything else wrapped
139
- <SidebarLayout>
140
- <Router routes={SIDEBARRED_ROUTES}/>
141
- </SidebarLayout>
142
- ),
143
- }}/>
144
- ```
145
-
146
- `/login` skips the sidebar. Every other path goes through `<SidebarLayout>` and then the inner router decides what to render — including handing off to section routers via the catchall pattern.
147
-
148
- ## Navigation
149
-
150
- Inside a component, get the navigation store for imperative URL changes:
151
-
152
- ```tsx
153
- const nav = requireNavigation();
154
- nav.forward("/users/123"); // push history
155
- nav.redirect("/login"); // replace history
156
- ```
157
-
158
- Same-origin anchor clicks are intercepted automatically and turned into `forward()` calls. Add a `download` attribute to opt out.
159
-
160
- ## `<NavigationIsolate>`
161
-
162
- Force a full remount of children whenever the URL changes:
163
-
164
- ```tsx
165
- <NavigationIsolate>
166
- <ExpensiveStatefulThing/>
167
- </NavigationIsolate>
168
- ```
169
-
170
- ## SSR / static rendering
171
-
172
- `<Router>` has no client requirements — it reads from `<Meta>` and re-renders when context changes. For static rendering, set `url` and `root` on the outer wrapper and skip `<Navigation>`:
173
-
174
- ```tsx
175
- renderToString(
176
- <HTML url={path} root="https://example.com/">
177
- <Router routes={…}/>
178
- </HTML>
179
- );
180
- ```
181
-
182
- For client-side SPAs, wrap the same tree in `<Navigation>` for live URL updates.
183
-
184
- ## Base paths
185
-
186
- `root="https://example.com/app/"` is supported. The base path prefix is stripped from the URL before route matching via `matchURLPrefix`. URLs that fall outside the base render as `null` from the router.
@@ -1,80 +0,0 @@
1
- # Transition
2
-
3
- React 19 View Transition wrappers for animated enter and leave effects. Each component wraps its children in React's `<ViewTransition>` and applies a named CSS transition class, so swapping content between renders produces a smooth animation.
4
-
5
- ## Components
6
-
7
- | Component | Default transition | Forward / back |
8
- |---|---|---|
9
- | `<FadeTransition>` | `fade` | — |
10
- | `<CollapseTransition>` | `collapse` | — |
11
- | `<VerticalTransition>` | `slideDown` | forward: `slideDown`, back: `slideUp` |
12
- | `<HorizontalTransition>` | `slideRight` | forward: `slideRight`, back: `slideLeft` |
13
- | `<Transition>` | configurable | configurable |
14
-
15
- `<VerticalTransition>` and `<HorizontalTransition>` are direction-aware: they read the transition type set by `setTransitionType()` and choose the correct slide direction.
16
-
17
- ## Basic usage
18
-
19
- Wrap any content that should animate when it mounts or unmounts:
20
-
21
- ```tsx
22
- import { FadeTransition } from "shelving/ui";
23
-
24
- function Panel({ visible }: { visible: boolean }) {
25
- return visible ? (
26
- <FadeTransition>
27
- <div className="panel">…</div>
28
- </FadeTransition>
29
- ) : null;
30
- }
31
- ```
32
-
33
- ## Direction-aware routing transitions
34
-
35
- Set the transition type before a navigation, then wrap routed content in the appropriate transition:
36
-
37
- ```tsx
38
- import { HorizontalTransition, setTransitionType } from "shelving/ui";
39
-
40
- function navigate(direction: "forward" | "back") {
41
- startTransition(() => {
42
- setTransitionType(direction);
43
- nav.forward(nextUrl);
44
- });
45
- }
46
-
47
- // In the layout:
48
- <HorizontalTransition>
49
- <Router routes={ROUTES}/>
50
- </HorizontalTransition>
51
- ```
52
-
53
- When `direction` is `"forward"` the content slides right; when `"back"` it slides left.
54
-
55
- ## Overlay variant
56
-
57
- Add `overlay` to raise the transition group above surrounding content during animation (`z-index: 100`):
58
-
59
- ```tsx
60
- <FadeTransition overlay>
61
- <Notification/>
62
- </FadeTransition>
63
- ```
64
-
65
- ## Custom transitions
66
-
67
- Use `<Transition>` directly to specify any transition class names:
68
-
69
- ```tsx
70
- <Transition default="zoom" forward="zoomIn" back="zoomOut">
71
- {children}
72
- </Transition>
73
- ```
74
-
75
- Class names must correspond to `::view-transition-class()` rules in your CSS.
76
-
77
- ## See also
78
-
79
- - [`router`](/ui/router) — `<Navigation>` triggers route changes that transitions animate
80
- - [`dialog`](/ui/dialog) — animate dialog enter and leave
package/ui/tree/README.md DELETED
@@ -1,78 +0,0 @@
1
- # Tree components
2
-
3
- Shell components for a tree-based documentation site. Given a `TreeElement` from [extract](/extract), these components produce a complete site: a sidebar menu, client-side routing, and a rendered page for every element.
4
-
5
- ## Concepts
6
-
7
- **`<TreeApp>` is the entry point.** It wraps `<App>` with error catching and a sidebar layout, then wires `<Navigation>` and a `<Router>` covering two routes: `/` renders the root via `<TreePage>`, and `/{...path}` passes every deeper URL to `<TreePage>` as well. The sidebar is always a `<TreeSidebar>`.
8
-
9
- **`<TreeRouter>` resolves and dispatches.** It resolves the current URL to an element with a single `map.get(path)` against the flattened tree (provided by `<TreeProvider>`), then hands the matched element to the right page renderer via `<TreeRouterMapper>`. It throws `NotFoundError` if nothing matches and no `fallback` is given.
10
-
11
- **`<TreeMenu>` and `<TreeSidebar>` build navigation.** `<TreeSidebar>` renders a single home link for the root, then its children via `<TreeMenuMapper>`. `<TreeMenu>` renders a menu from a tree element's children directly. Only generic `tree-element` nodes appear — code symbols are kept off the navigation.
12
-
13
- **`<TreeCards>` renders a card list.** It dispatches each child element to a card renderer via `<TreeCardMapper>`; each card links straight to its element's stamped `path`. Used by the page renderers in [ui/docs](/ui/docs) to fill out directory and file pages.
14
-
15
- **`<TreeProvider>` flattens the tree — the one transform the UI runs on.** It flattens the tree once (via `flattenTree()`), which stamps a canonical `path` on every element and indexes them into a map keyed by both flat name and canonical path, then shares it on `TreeContext`. Descendants read it with `useTreeMap()`: the router resolves a URL with `map.get(path)`, and cross-references (`<TreeButton>`, breadcrumbs) resolve by flat key (`"Store"`, `"Store.get"`) or canonical path (`"/schema/BooleanSchema"`) and link to the resolved element's `path`. Nested providers merge their maps, so links resolve across a combined set of trees.
16
-
17
- **`<TreeBreadcrumbs>` renders an ancestor trail.** Given a page's `path`, it looks each ancestor prefix up in the tree map (so it needs a `<TreeProvider>` above) and renders a `<nav>` of links separated by `›` icons, with section-level block spacing (`BLOCK_CLASS`, overridable via the `space` prop). Works with any tree — the current page is omitted (the page title already names it).
18
-
19
- **Mappings — override any renderer.** Each dispatch layer is backed by a `[Mapping, Mapper]` pair created by `createMapper()`. Wrap any subtree with a `*Mapping` component to swap the renderer for a specific element type without touching anything else.
20
-
21
- | Exported pair | Element types covered | What it overrides |
22
- |---|---|---|
23
- | `TreePageMapping` / `TreePageMapper` | `tree-element`, `tree-documentation` | Full-page renderer |
24
- | `TreeMenuMapping` / `TreeMenuMapper` | `tree-element`, `tree-documentation` | Sidebar menu item |
25
- | `TreeCardMapping` / `TreeCardMapper` | `tree-element`, `tree-documentation` | Card in a listing |
26
-
27
- ## Basic usage
28
-
29
- ```tsx
30
- import { TreeApp } from "shelving/ui";
31
-
32
- // tree is a TreeElement returned by DirectoryExtractor.
33
- <TreeApp tree={tree} />
34
- ```
35
-
36
- That single line produces a complete documentation site.
37
-
38
- ## Adding custom routes
39
-
40
- Pass extra routes to `<TreeApp>`. They are merged before the tree routes, so they take precedence on conflicts.
41
-
42
- ```tsx
43
- <TreeApp tree={tree} routes={{ "/changelog": ChangelogPage }} />
44
- ```
45
-
46
- ## Overriding a renderer
47
-
48
- Wrap the app (or any subtree) with a `*Mapping` component to replace the renderer for one element type.
49
-
50
- ```tsx
51
- import { TreeApp, TreePageMapping } from "shelving/ui";
52
-
53
- <TreePageMapping mapping={{ "tree-element": MyTreePage }}>
54
- <TreeApp tree={tree} />
55
- </TreePageMapping>
56
- ```
57
-
58
- The same pattern works for `TreeMenuMapping` (sidebar items) and `TreeCardMapping` (cards inside directory listings).
59
-
60
- ## Using menu and sidebar components directly
61
-
62
- For finer layout control, use `<TreeSidebar>` or `<TreeMenu>` outside `<TreeApp>`.
63
-
64
- ```tsx
65
- import { TreeMenu, TreeSidebar } from "shelving/ui";
66
-
67
- // A home link + children menu combined — the default sidebar.
68
- <TreeSidebar tree={root} />
69
-
70
- // Just the navigation menu from a subtree's children.
71
- <TreeMenu tree={section} path="/docs" />
72
- ```
73
-
74
- ## See also
75
-
76
- - [extract](/extract) — builds the `TreeElement` tree that `<TreeApp>` consumes
77
- - [ui/docs](/ui/docs) — the default page and card renderers dispatched by the mappers
78
- - [ui/router](/ui/router) — `<Navigation>` and `<Router>` wired inside `<TreeApp>`