shelving 1.236.1 → 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.
- package/extract/IndexExtractor.js +9 -2
- package/extract/MergingExtractor.d.ts +3 -1
- package/extract/MergingExtractor.js +41 -3
- package/extract/TypescriptExtractor.d.ts +1 -0
- package/extract/TypescriptExtractor.js +12 -2
- package/markup/rule/inline.d.ts +1 -1
- package/markup/rule/inline.js +2 -2
- package/package.json +1 -1
- package/ui/README.md +19 -274
- package/ui/app/App.d.ts +1 -0
- package/ui/app/App.js +1 -0
- package/ui/app/App.md +58 -0
- package/ui/app/App.tsx +1 -0
- package/ui/block/Card.d.ts +1 -0
- package/ui/block/Card.js +1 -0
- package/ui/block/Card.md +85 -0
- package/ui/block/Card.tsx +1 -0
- package/ui/block/Heading.d.ts +1 -0
- package/ui/block/Heading.js +1 -0
- package/ui/block/Heading.md +70 -0
- package/ui/block/Heading.tsx +1 -0
- package/ui/block/List.d.ts +1 -0
- package/ui/block/List.js +1 -0
- package/ui/block/List.md +51 -0
- package/ui/block/List.tsx +1 -0
- package/ui/block/Panel.d.ts +1 -0
- package/ui/block/Panel.js +1 -0
- package/ui/block/Panel.md +50 -0
- package/ui/block/Panel.tsx +1 -0
- package/ui/block/Paragraph.d.ts +1 -0
- package/ui/block/Paragraph.js +1 -0
- package/ui/block/Paragraph.md +48 -0
- package/ui/block/Paragraph.tsx +1 -0
- package/ui/block/Prose.d.ts +1 -0
- package/ui/block/Prose.js +1 -0
- package/ui/block/Prose.md +49 -0
- package/ui/block/Prose.tsx +1 -0
- package/ui/block/Section.d.ts +6 -0
- package/ui/block/Section.js +6 -0
- package/ui/block/Section.md +56 -0
- package/ui/block/Section.tsx +6 -0
- package/ui/block/Subheading.d.ts +1 -0
- package/ui/block/Subheading.js +1 -0
- package/ui/block/Subheading.md +58 -0
- package/ui/block/Subheading.tsx +1 -0
- package/ui/block/Table.d.ts +1 -0
- package/ui/block/Table.js +1 -0
- package/ui/block/Table.md +54 -0
- package/ui/block/Table.tsx +1 -0
- package/ui/block/Title.d.ts +1 -0
- package/ui/block/Title.js +1 -0
- package/ui/block/Title.md +57 -0
- package/ui/block/Title.tsx +1 -0
- package/ui/dialog/Dialog.d.ts +1 -0
- package/ui/dialog/Dialog.js +1 -0
- package/ui/dialog/Dialog.md +73 -0
- package/ui/dialog/Dialog.tsx +1 -0
- package/ui/dialog/Modal.d.ts +1 -0
- package/ui/dialog/Modal.js +1 -0
- package/ui/dialog/Modal.md +40 -0
- package/ui/dialog/Modal.tsx +1 -0
- package/ui/docs/DocumentationButtons.d.ts +2 -0
- package/ui/docs/DocumentationButtons.js +2 -0
- package/ui/docs/DocumentationButtons.md +38 -0
- package/ui/docs/DocumentationButtons.tsx +2 -0
- package/ui/docs/DocumentationCard.d.ts +1 -0
- package/ui/docs/DocumentationCard.js +1 -0
- package/ui/docs/DocumentationCard.md +35 -0
- package/ui/docs/DocumentationCard.tsx +1 -0
- package/ui/docs/DocumentationKind.d.ts +1 -1
- package/ui/docs/DocumentationKind.js +9 -4
- package/ui/docs/DocumentationKind.tsx +10 -5
- package/ui/docs/DocumentationPage.d.ts +1 -0
- package/ui/docs/DocumentationPage.js +2 -0
- package/ui/docs/DocumentationPage.md +46 -0
- package/ui/docs/DocumentationPage.tsx +2 -0
- package/ui/form/Button.d.ts +1 -0
- package/ui/form/Button.js +1 -0
- package/ui/form/Button.md +88 -0
- package/ui/form/Button.tsx +1 -0
- package/ui/form/Field.d.ts +6 -1
- package/ui/form/Field.js +6 -1
- package/ui/form/Field.md +59 -0
- package/ui/form/Field.tsx +6 -1
- package/ui/form/Form.d.ts +1 -0
- package/ui/form/Form.md +118 -0
- package/ui/form/Form.tsx +1 -0
- package/ui/form/FormStore.md +47 -0
- package/ui/form/SchemaInput.d.ts +1 -0
- package/ui/form/SchemaInput.md +64 -0
- package/ui/form/SchemaInput.tsx +1 -0
- package/ui/inline/Code.d.ts +1 -0
- package/ui/inline/Code.js +1 -0
- package/ui/inline/Code.md +58 -0
- package/ui/inline/Code.tsx +1 -0
- package/ui/inline/Link.d.ts +1 -0
- package/ui/inline/Link.js +1 -0
- package/ui/inline/Link.md +47 -0
- package/ui/inline/Link.tsx +1 -0
- package/ui/inline/Mark.d.ts +1 -0
- package/ui/inline/Mark.js +1 -0
- package/ui/inline/Mark.md +40 -0
- package/ui/inline/Mark.tsx +1 -0
- package/ui/inline/Strong.d.ts +1 -0
- package/ui/inline/Strong.js +1 -0
- package/ui/inline/Strong.md +34 -0
- package/ui/inline/Strong.tsx +1 -0
- package/ui/layout/CenteredLayout.d.ts +1 -0
- package/ui/layout/CenteredLayout.js +1 -0
- package/ui/layout/CenteredLayout.md +38 -0
- package/ui/layout/CenteredLayout.tsx +1 -0
- package/ui/layout/SidebarLayout.d.ts +1 -0
- package/ui/layout/SidebarLayout.js +1 -0
- package/ui/layout/SidebarLayout.md +65 -0
- package/ui/layout/SidebarLayout.tsx +1 -0
- package/ui/menu/Menu.d.ts +2 -0
- package/ui/menu/Menu.js +2 -0
- package/ui/menu/Menu.md +51 -0
- package/ui/menu/Menu.tsx +2 -0
- package/ui/menu/MenuItem.md +54 -0
- package/ui/misc/Catcher.d.ts +1 -0
- package/ui/misc/Catcher.js +1 -0
- package/ui/misc/Catcher.md +41 -0
- package/ui/misc/Catcher.tsx +1 -0
- package/ui/misc/Loading.d.ts +1 -0
- package/ui/misc/Loading.js +1 -0
- package/ui/misc/Loading.md +28 -0
- package/ui/misc/Loading.tsx +1 -0
- package/ui/misc/Mapper.md +40 -0
- package/ui/misc/Markup.d.ts +1 -0
- package/ui/misc/Markup.js +1 -0
- package/ui/misc/Markup.md +34 -0
- package/ui/misc/Markup.tsx +1 -0
- package/ui/misc/StatusIcon.d.ts +1 -0
- package/ui/misc/StatusIcon.js +1 -0
- package/ui/misc/StatusIcon.md +25 -0
- package/ui/misc/StatusIcon.tsx +1 -0
- package/ui/misc/Tag.d.ts +1 -0
- package/ui/misc/Tag.js +1 -0
- package/ui/misc/Tag.md +47 -0
- package/ui/misc/Tag.tsx +1 -0
- package/ui/notice/Notice.d.ts +1 -0
- package/ui/notice/Notice.js +1 -0
- package/ui/notice/Notice.md +53 -0
- package/ui/notice/Notice.tsx +1 -0
- package/ui/notice/Notices.d.ts +1 -0
- package/ui/notice/Notices.js +1 -0
- package/ui/notice/Notices.md +59 -0
- package/ui/notice/Notices.tsx +1 -0
- package/ui/page/HTML.d.ts +1 -0
- package/ui/page/HTML.js +1 -0
- package/ui/page/HTML.md +36 -0
- package/ui/page/HTML.tsx +1 -0
- package/ui/page/Head.d.ts +1 -0
- package/ui/page/Head.js +1 -0
- package/ui/page/Head.md +26 -0
- package/ui/page/Head.tsx +1 -0
- package/ui/page/Page.d.ts +1 -0
- package/ui/page/Page.js +1 -0
- package/ui/page/Page.md +42 -0
- package/ui/page/Page.tsx +1 -0
- package/ui/router/Navigation.d.ts +1 -0
- package/ui/router/Navigation.js +1 -0
- package/ui/router/Navigation.md +41 -0
- package/ui/router/Navigation.tsx +1 -0
- package/ui/router/NavigationStore.md +34 -0
- package/ui/router/Router.d.ts +1 -0
- package/ui/router/Router.js +1 -0
- package/ui/router/Router.md +143 -0
- package/ui/router/Router.tsx +1 -0
- package/ui/style/TINT_CLASS.md +55 -0
- package/ui/transition/CollapseTransition.d.ts +1 -0
- package/ui/transition/CollapseTransition.js +1 -0
- package/ui/transition/CollapseTransition.md +34 -0
- package/ui/transition/CollapseTransition.tsx +1 -0
- package/ui/transition/FadeTransition.d.ts +1 -0
- package/ui/transition/FadeTransition.js +1 -0
- package/ui/transition/FadeTransition.md +36 -0
- package/ui/transition/FadeTransition.tsx +1 -0
- package/ui/transition/HorizontalTransition.d.ts +1 -0
- package/ui/transition/HorizontalTransition.js +1 -0
- package/ui/transition/HorizontalTransition.md +44 -0
- package/ui/transition/HorizontalTransition.tsx +1 -0
- package/ui/transition/Transition.d.ts +1 -0
- package/ui/transition/Transition.js +1 -0
- package/ui/transition/Transition.md +70 -0
- package/ui/transition/Transition.tsx +1 -0
- package/ui/transition/VerticalTransition.d.ts +1 -0
- package/ui/transition/VerticalTransition.js +1 -0
- package/ui/transition/VerticalTransition.md +34 -0
- package/ui/transition/VerticalTransition.tsx +1 -0
- package/ui/tree/TreeApp.d.ts +1 -0
- package/ui/tree/TreeApp.js +1 -0
- package/ui/tree/TreeApp.md +59 -0
- package/ui/tree/TreeApp.tsx +1 -0
- package/ui/tree/TreeMenu.d.ts +1 -0
- package/ui/tree/TreeMenu.js +1 -0
- package/ui/tree/TreeMenu.md +35 -0
- package/ui/tree/TreeMenu.tsx +1 -0
- package/ui/tree/TreeSidebar.d.ts +1 -0
- package/ui/tree/TreeSidebar.js +1 -0
- package/ui/tree/TreeSidebar.md +24 -0
- package/ui/tree/TreeSidebar.tsx +1 -0
- package/ui/util/getClass.md +55 -0
- package/ui/util/notify.md +50 -0
- package/ui/util/requireContext.md +24 -0
- package/ui/app/README.md +0 -32
- package/ui/block/README.md +0 -144
- package/ui/dialog/README.md +0 -80
- package/ui/docs/README.md +0 -71
- package/ui/form/README.md +0 -165
- package/ui/inline/README.md +0 -86
- package/ui/layout/README.md +0 -71
- package/ui/menu/README.md +0 -33
- package/ui/misc/README.md +0 -121
- package/ui/notice/README.md +0 -94
- package/ui/page/README.md +0 -56
- package/ui/router/README.md +0 -186
- package/ui/transition/README.md +0 -80
- package/ui/tree/README.md +0 -78
- package/ui/util/README.md +0 -153
|
@@ -62,8 +62,15 @@ function _absorbIndex(element, index) {
|
|
|
62
62
|
// Recurse first so nested levels absorb their own indexes before we look at this one.
|
|
63
63
|
// Only descend into elements that actually have children — leaving childless leaves (e.g. files) untouched, including their `undefined` children.
|
|
64
64
|
const recursed = Array.from(walkElements(element.props.children)).map(child => notNullish(child.props.children) ? _absorbIndex(child, index) : child);
|
|
65
|
-
// Find the index child by
|
|
66
|
-
|
|
65
|
+
// Find the index child by pattern priority: the earliest `index` pattern with a matching child wins, so a
|
|
66
|
+
// README.md is preferred over an index.ts barrel even when the barrel is listed first on disk (a barrel carries
|
|
67
|
+
// no prose, so absorbing it instead of the README would silently drop the directory's documentation).
|
|
68
|
+
let indexChild;
|
|
69
|
+
for (const matcher of index) {
|
|
70
|
+
indexChild = recursed.find(child => anyMatch(child.key, matcher));
|
|
71
|
+
if (indexChild)
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
67
74
|
if (!indexChild)
|
|
68
75
|
return { ...element, props: { ...element.props, children: recursed } };
|
|
69
76
|
// Fold the index child into the parent, and drop it from children.
|
|
@@ -20,9 +20,11 @@ export interface MergingExtractorOptions {
|
|
|
20
20
|
/**
|
|
21
21
|
* Through extractor that walks a tree of `tree-element` nodes and merges sibling tree elements whose keys match a `merges` template pair.
|
|
22
22
|
* - Purely key-based: it doesn't care whether siblings are directories or files — any element with children is processed, at every level.
|
|
23
|
+
* - **Token-first:** a secondary (e.g. `Card.md`) is preferentially folded into the same-named documentation token declared by a sibling file (the `Card` symbol inside `Card.tsx`), not the file element. Exported names are unique across the package, so this is unambiguous — and it lands the prose on the published symbol page, which survives the module flatten (file-element content does not).
|
|
24
|
+
* - **File fallback:** when no same-named token exists, the secondary folds into a sibling *file* whose key matches a `merges` candidate (whole-file prose like `template.md` → `template.ts`).
|
|
23
25
|
* - The primary (winning) element keeps its `key`, `source`, and `type`; the secondary's `title`, `description`,
|
|
24
26
|
* `content`, and `children` are folded in via `mergeTreeElements()`.
|
|
25
|
-
* - A secondary with no matching
|
|
27
|
+
* - A secondary with no matching token or file is left in place — pure prose files (e.g. `concepts.md` with no `concepts.ts`) stand alone.
|
|
26
28
|
*
|
|
27
29
|
* @example
|
|
28
30
|
* ```ts
|
|
@@ -15,9 +15,11 @@ const DEFAULT_MERGES = {
|
|
|
15
15
|
/**
|
|
16
16
|
* Through extractor that walks a tree of `tree-element` nodes and merges sibling tree elements whose keys match a `merges` template pair.
|
|
17
17
|
* - Purely key-based: it doesn't care whether siblings are directories or files — any element with children is processed, at every level.
|
|
18
|
+
* - **Token-first:** a secondary (e.g. `Card.md`) is preferentially folded into the same-named documentation token declared by a sibling file (the `Card` symbol inside `Card.tsx`), not the file element. Exported names are unique across the package, so this is unambiguous — and it lands the prose on the published symbol page, which survives the module flatten (file-element content does not).
|
|
19
|
+
* - **File fallback:** when no same-named token exists, the secondary folds into a sibling *file* whose key matches a `merges` candidate (whole-file prose like `template.md` → `template.ts`).
|
|
18
20
|
* - The primary (winning) element keeps its `key`, `source`, and `type`; the secondary's `title`, `description`,
|
|
19
21
|
* `content`, and `children` are folded in via `mergeTreeElements()`.
|
|
20
|
-
* - A secondary with no matching
|
|
22
|
+
* - A secondary with no matching token or file is left in place — pure prose files (e.g. `concepts.md` with no `concepts.ts`) stand alone.
|
|
21
23
|
*
|
|
22
24
|
* @example
|
|
23
25
|
* ```ts
|
|
@@ -70,10 +72,24 @@ function _mergeElement(element, merges) {
|
|
|
70
72
|
}
|
|
71
73
|
/** Merge same-template siblings at one directory level. */
|
|
72
74
|
function _mergeChildren(children, merges) {
|
|
73
|
-
// Index children by key so we can look up primary candidates quickly.
|
|
75
|
+
// Index children by key so we can look up primary file candidates quickly.
|
|
74
76
|
const byKey = new Map();
|
|
75
77
|
for (const child of children)
|
|
76
78
|
byKey.set(child.key, child);
|
|
79
|
+
// Index exported documentation tokens by name, recording the key of the file element that declares each.
|
|
80
|
+
// Exported names are unique across the package, so a `Foo.md` can target the symbol `Foo` directly.
|
|
81
|
+
const tokensByName = new Map();
|
|
82
|
+
for (const child of children) {
|
|
83
|
+
if (child.type !== "tree-element")
|
|
84
|
+
continue;
|
|
85
|
+
for (const token of walkElements(child.props.children)) {
|
|
86
|
+
const t = token;
|
|
87
|
+
if (t.type === "tree-documentation")
|
|
88
|
+
tokensByName.set(t.props.name, { fileKey: child.key, token: t });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Accumulate token replacements per declaring file: fileKey → (tokenKey → merged token).
|
|
92
|
+
const tokenUpdates = new Map();
|
|
77
93
|
// Walk in original order, deciding for each whether it's a secondary that should fold into a primary.
|
|
78
94
|
const skip = new Set();
|
|
79
95
|
for (const secondary of children) {
|
|
@@ -81,6 +97,18 @@ function _mergeChildren(children, merges) {
|
|
|
81
97
|
const matches = matchTemplate(lhs, secondary.key);
|
|
82
98
|
if (!matches)
|
|
83
99
|
continue;
|
|
100
|
+
// Prefer folding a `.md` into the same-named documentation token (e.g. `Card.md` → the `Card` component) so the
|
|
101
|
+
// prose lands on the published symbol page — the module flatten keeps tokens but discards file-element content.
|
|
102
|
+
const base = Object.values(matches)[0];
|
|
103
|
+
const hit = base ? tokensByName.get(base) : undefined;
|
|
104
|
+
if (hit && hit.token !== secondary) {
|
|
105
|
+
const fileMap = tokenUpdates.get(hit.fileKey) ?? new Map();
|
|
106
|
+
fileMap.set(hit.token.key, mergeTreeElements(fileMap.get(hit.token.key) ?? hit.token, secondary));
|
|
107
|
+
tokenUpdates.set(hit.fileKey, fileMap);
|
|
108
|
+
skip.add(secondary);
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
// Otherwise fall back to merging into a sibling file (whole-file prose like `template.md` → `template.ts`).
|
|
84
112
|
for (const rhs of candidates) {
|
|
85
113
|
const primaryKey = renderTemplate(rhs, matches);
|
|
86
114
|
const primary = byKey.get(primaryKey);
|
|
@@ -94,5 +122,15 @@ function _mergeChildren(children, merges) {
|
|
|
94
122
|
break;
|
|
95
123
|
}
|
|
96
124
|
}
|
|
97
|
-
|
|
125
|
+
// Rebuild: drop merged `.md` secondaries, apply file-level merges, and fold token updates into their file elements.
|
|
126
|
+
return children
|
|
127
|
+
.filter(c => !skip.has(c))
|
|
128
|
+
.map(c => {
|
|
129
|
+
const updated = byKey.get(c.key) ?? c;
|
|
130
|
+
const fileMap = tokenUpdates.get(c.key);
|
|
131
|
+
if (!fileMap)
|
|
132
|
+
return updated;
|
|
133
|
+
const merged = Array.from(walkElements(updated.props.children), child => fileMap.get(child.key) ?? child);
|
|
134
|
+
return { ...updated, props: { ...updated.props, children: merged } };
|
|
135
|
+
});
|
|
98
136
|
}
|
|
@@ -6,6 +6,7 @@ import { FileExtractor } from "./FileExtractor.js";
|
|
|
6
6
|
* - Extracts exported, public, non-`_`-prefixed declarations as `tree-documentation` children.
|
|
7
7
|
* - Overloaded declarations sharing a name are merged into a single `tree-documentation` with multiple `signatures`.
|
|
8
8
|
* - Class declarations synthesise their `signatures`, `params`, and `returns` from the constructor — `new ClassName<…>(…)` including generics, one signature per constructor overload, with `returns` set to the class type. Param descriptions come from the constructor's `@param` first, then the class's `@param`.
|
|
9
|
+
* - A `@kind` tag in a symbol's JSDoc overrides the inferred kind — e.g. `@kind component` relabels a React component (otherwise a `function`) so the docs site groups and colours it as a component. The override also drops the trailing `()` from the title, since a non-function kind reads as a bare name.
|
|
9
10
|
* - Top-of-file JSDoc comment becomes the file's `content`.
|
|
10
11
|
* - Sets `description` (a plain-text summary from the first JSDoc paragraph) on the file and every `tree-documentation` child.
|
|
11
12
|
* - Sets `title` on every `tree-documentation` child — `name()` for functions and methods, bare `name` for other kinds. Parent class context comes from the `class` prop ("member of …" affordance), never the title.
|
|
@@ -7,6 +7,7 @@ import { extractMarkdownProps } from "./MarkupExtractor.js";
|
|
|
7
7
|
* - Extracts exported, public, non-`_`-prefixed declarations as `tree-documentation` children.
|
|
8
8
|
* - Overloaded declarations sharing a name are merged into a single `tree-documentation` with multiple `signatures`.
|
|
9
9
|
* - Class declarations synthesise their `signatures`, `params`, and `returns` from the constructor — `new ClassName<…>(…)` including generics, one signature per constructor overload, with `returns` set to the class type. Param descriptions come from the constructor's `@param` first, then the class's `@param`.
|
|
10
|
+
* - A `@kind` tag in a symbol's JSDoc overrides the inferred kind — e.g. `@kind component` relabels a React component (otherwise a `function`) so the docs site groups and colours it as a component. The override also drops the trailing `()` from the title, since a non-function kind reads as a bare name.
|
|
10
11
|
* - Top-of-file JSDoc comment becomes the file's `content`.
|
|
11
12
|
* - Sets `description` (a plain-text summary from the first JSDoc paragraph) on the file and every `tree-documentation` child.
|
|
12
13
|
* - Sets `title` on every `tree-documentation` child — `name()` for functions and methods, bare `name` for other kinds. Parent class context comes from the `class` prop ("member of …" affordance), never the title.
|
|
@@ -127,7 +128,8 @@ function _extractStatement(statement, source) {
|
|
|
127
128
|
if (name.startsWith("_"))
|
|
128
129
|
return;
|
|
129
130
|
const jsDoc = _getJSDoc(statement, source);
|
|
130
|
-
|
|
131
|
+
// A `@kind` tag overrides the AST-inferred kind (e.g. `@kind component` for a React component declared as a function).
|
|
132
|
+
const kind = jsDoc?.kind ?? _getKind(statement);
|
|
131
133
|
if (!kind)
|
|
132
134
|
return;
|
|
133
135
|
const signatures = _getSignatures(statement, source, name);
|
|
@@ -442,10 +444,11 @@ function _getClassMembers(statement, source, className) {
|
|
|
442
444
|
}
|
|
443
445
|
/**
|
|
444
446
|
* `@rule` names handled (parsed or deliberately discarded) — everything else is appended to `unhandled` as raw markup.
|
|
447
|
+
* - `@kind` is parsed by `_parseJSDocKind` to override the AST-inferred kind, so it must not also leak into `unhandled`.
|
|
445
448
|
* - `@see` is recognised here purely to strip it: it's a VS Code hover affordance (a link back to the docs site) and must
|
|
446
449
|
* never leak into the rendered page content. It has no dedicated parser; it's simply discarded from the `unhandled` bucket.
|
|
447
450
|
*/
|
|
448
|
-
const _HANDLED_RULES = new Set(["param", "params", "return", "returns", "throw", "throws", "example", "examples", "see"]);
|
|
451
|
+
const _HANDLED_RULES = new Set(["kind", "param", "params", "return", "returns", "throw", "throws", "example", "examples", "see"]);
|
|
449
452
|
/** Extract JSDoc from a node. */
|
|
450
453
|
function _getJSDoc(node, source) {
|
|
451
454
|
const ranges = ts.getLeadingCommentRanges(source.text, node.pos);
|
|
@@ -460,6 +463,7 @@ function _getJSDoc(node, source) {
|
|
|
460
463
|
if (!text.startsWith("/**"))
|
|
461
464
|
continue;
|
|
462
465
|
const description = _parseJSDocComment(text);
|
|
466
|
+
const kind = _parseJSDocKind(text);
|
|
463
467
|
const params = _parseJSDocParams(text);
|
|
464
468
|
const returns = _parseJSDocReturns(text);
|
|
465
469
|
const throws = _parseJSDocThrows(text);
|
|
@@ -467,6 +471,7 @@ function _getJSDoc(node, source) {
|
|
|
467
471
|
const unhandled = _parseJSDocUnhandled(text);
|
|
468
472
|
return {
|
|
469
473
|
description: description || undefined,
|
|
474
|
+
kind,
|
|
470
475
|
params: params.length ? params : undefined,
|
|
471
476
|
returns: returns.length ? returns : undefined,
|
|
472
477
|
throws: throws.length ? throws : undefined,
|
|
@@ -529,6 +534,11 @@ function _parseJSDocComment(text) {
|
|
|
529
534
|
const result = description.join("\n").trim();
|
|
530
535
|
return result || undefined;
|
|
531
536
|
}
|
|
537
|
+
/** Parse a single `@kind` override from a JSDoc comment (e.g. `@kind component`), or `undefined` when absent. */
|
|
538
|
+
function _parseJSDocKind(text) {
|
|
539
|
+
// `@kind name` — a single identifier-ish token (letters, digits, hyphens).
|
|
540
|
+
return text.match(/@kind\s+([\w-]+)/)?.[1];
|
|
541
|
+
}
|
|
532
542
|
/** Parse `@param` tags from a JSDoc comment. Duplicates are kept (overloads). */
|
|
533
543
|
function _parseJSDocParams(text) {
|
|
534
544
|
const results = [];
|
package/markup/rule/inline.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* - Inline strong text wrapped in one or more `*` asterisks.
|
|
4
4
|
* - Inline emphasis text wrapped in one or more `_` underscores.
|
|
5
5
|
* - Inline inserted text wrapped in one or more `+` pluses.
|
|
6
|
-
* - Inline deleted text wrapped in one or more
|
|
6
|
+
* - Inline deleted text wrapped in one or more `~` tildes.
|
|
7
7
|
* - Inline highlighted text wrapped in one or more `=` equals or `:` colons.
|
|
8
8
|
* - Whitespace cannot be the first or last character of the element (e.g. `* abc *` will not work).
|
|
9
9
|
* - Closing chars must match opening characters.
|
package/markup/rule/inline.js
CHANGED
|
@@ -2,13 +2,13 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { createMarkupRule } from "../MarkupRule.js";
|
|
3
3
|
import { createWordRegExp } from "../util/regexp.js";
|
|
4
4
|
/** Map characters, e.g. `*`, to their coresponding HTML tag, e.g. `strong` */
|
|
5
|
-
const INLINE_CHARS = { "
|
|
5
|
+
const INLINE_CHARS = { "~": "del", "+": "ins", "*": "strong", _: "em", "=": "mark" };
|
|
6
6
|
/**
|
|
7
7
|
* Inline strong, emphasis, insert, delete, highlight.
|
|
8
8
|
* - Inline strong text wrapped in one or more `*` asterisks.
|
|
9
9
|
* - Inline emphasis text wrapped in one or more `_` underscores.
|
|
10
10
|
* - Inline inserted text wrapped in one or more `+` pluses.
|
|
11
|
-
* - Inline deleted text wrapped in one or more
|
|
11
|
+
* - Inline deleted text wrapped in one or more `~` tildes.
|
|
12
12
|
* - Inline highlighted text wrapped in one or more `=` equals or `:` colons.
|
|
13
13
|
* - Whitespace cannot be the first or last character of the element (e.g. `* abc *` will not work).
|
|
14
14
|
* - Closing chars must match opening characters.
|
package/package.json
CHANGED
package/ui/README.md
CHANGED
|
@@ -8,299 +8,44 @@ The `ui` module exists so an app never hand-rolls the same form field, card, or
|
|
|
8
8
|
|
|
9
9
|
## How components work
|
|
10
10
|
|
|
11
|
-
A few conventions run through every component
|
|
11
|
+
A few conventions run through every component:
|
|
12
12
|
|
|
13
13
|
- **Styling props, not CSS.** Visual options are props on the component — enumerated props for the scales (`color="red"`, `size="large"`, `space="none"`) and boolean props for on/off variants (`<Button strong>`, `<Section narrow>`, `<Flex wrap>`). Each maps to a class in a CSS Module. You never pass `style` or raw `className`.
|
|
14
|
-
- **Composition.** Higher-level components — a `*Page`, a `*Card` — take their identity from library components like `Card
|
|
14
|
+
- **Composition.** Higher-level components — a `*Page`, a `*Card` — take their identity from library components like [`Card`](/ui/Card), [`Section`](/ui/Section), [`Button`](/ui/Button), and [`Tag`](/ui/Tag) rather than shipping their own styling.
|
|
15
15
|
- **Sentence case.** Titles, headings, and button labels capitalise only the first word.
|
|
16
16
|
- **Theming via CSS variables.** Colour and spacing come from CSS custom properties with fallback chains, so a theme is a small set of variable overrides.
|
|
17
17
|
|
|
18
|
-
##
|
|
18
|
+
## The styling system
|
|
19
19
|
|
|
20
|
-
The styling system has four moving parts
|
|
20
|
+
The styling system lives in `style/` and has four moving parts: design tokens, the tint scale, cascade layers, and the styling props. Components compose them in a predictable shape; consumers theme by overriding CSS custom properties at `:root`.
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
**Design tokens.** `style/base.css` defines every design-token constant at `:root` — colours (`--color-*`), font sizes (`--size-*`), spacing (`--space-*`), radii (`--radius-*`), strokes (`--stroke-*`), shadows (`--shadow-*`), durations (`--duration-*`), font weights (`--weight-*`), and font faces (`--font-*`) — plus semantic aliases themes usually target instead (`--color-primary`, `--color-link`, `--color-success`, `--space-paragraph`, …). Components read these via `var(--token)`; `base.css` is `@import`ed at the top of every `*.module.css`, so the tokens and the cascade-layer order reach every component regardless of bundle order.
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
**The tint scale.** All colour flows from one anchor variable, `--tint-50`, from which a 21-step ladder is computed and *recomputed* under [`TINT_CLASS`](/ui/TINT_CLASS) — the heart of how `color=` and `status=` retint a whole subtree. The ladder, the recompute trick, the painting conventions, and the theming guide all live on the [`TINT_CLASS`](/ui/TINT_CLASS) page.
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
**Cascade layers.** Styles are ordered by `@layer`, lowest to highest priority: `defaults` (`:root` tokens, the tint ladder, body baseline) → `components` (the bulk of the CSS: `.card`, `.button`, …) → `variants` (cross-cutting opt-in modifiers, which always beat components) → `overrides` (top-priority structural fixes like `:first-child` / `:last-child` margin collapses). Unlayered rules beat all layered rules, so a theme should set tokens at `:root` or wrap its rules in `@layer`.
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
**Styling props.** The cross-cutting visual options are props, each backed by a helper in `style/` that maps the prop to a class. Colour and status move the tint anchor — [`getColorClass`](/ui/getColorClass) and [`getStatusClass`](/ui/getStatusClass); size, alignment, and font family come from [`getTypographyClass`](/ui/getTypographyClass); spacing, padding, and gap from [`getSpaceClass`](/ui/getSpaceClass), [`getPaddingClass`](/ui/getPaddingClass), and [`getGapClass`](/ui/getGapClass); width constraints from [`getWidthClass`](/ui/getWidthClass); flex layout from [`getFlexClass`](/ui/getFlexClass); and opt-in scrolling from [`getScrollClass`](/ui/getScrollClass). Each helper's page lists its exact prop values and what they set. A component opts into the props it wants by extending the matching `*Props` interfaces and composing the `getXxxClass(props)` calls.
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
Each painting component also exposes its own theme hooks — a single tint hook (`--card-tint`) to recolour the whole component, plus per-property hooks (`--card-background`, `--card-radius`, …) for surgical overrides. Those are documented in each component's own **Styling** section (see [`Card`](/ui/Card) for the precedent).
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
## Finding your way around
|
|
33
33
|
|
|
34
|
-
The
|
|
34
|
+
The components below are listed in the index following this page; this is the short version of where to start reading.
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
**Content.** Block-level structure starts with [`Card`](/ui/Card), [`Section`](/ui/Section), and the [`Heading`](/ui/Heading) / [`Title`](/ui/Title) family, with [`Table`](/ui/Table), [`List`](/ui/List), and [`Figure`](/ui/Figure) for specific shapes; wrap longform copy in [`Prose`](/ui/Prose). Inline pieces — [`Link`](/ui/Link), [`Code`](/ui/Code), [`Strong`](/ui/Strong), [`Mark`](/ui/Mark) — live inside that block content. To render a Markdown string as components, use [`Markup`](/ui/Markup).
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
/* Color.module.css — a colour variant just moves the anchor. */
|
|
40
|
-
.red {
|
|
41
|
-
--tint-50: var(--color-red);
|
|
42
|
-
}
|
|
38
|
+
**Structure.** Mount a client app with [`App`](/ui/App), or render a full server document with [`HTML`](/ui/HTML) and [`Page`](/ui/Page). Arrange the screen with [`CenteredLayout`](/ui/CenteredLayout) or [`SidebarLayout`](/ui/SidebarLayout), and drive URLs with [`Navigation`](/ui/Navigation) and [`Router`](/ui/Router).
|
|
43
39
|
|
|
44
|
-
|
|
45
|
-
.success {
|
|
46
|
-
--tint-50: var(--color-success);
|
|
47
|
-
}
|
|
48
|
-
```
|
|
40
|
+
**Interaction.** Forms start at [`Form`](/ui/Form), which wires [`Field`](/ui/Field) and the typed inputs to a [`FormStore`](/ui/FormStore); [`Button`](/ui/Button) is the standalone action. Overlays are [`Dialog`](/ui/Dialog) and [`Modal`](/ui/Modal); navigation menus are [`Menu`](/ui/Menu) and [`MenuItem`](/ui/MenuItem); transient feedback is [`Notice`](/ui/Notice) (and the global [`Notices`](/ui/Notices) list); animate enter/leave with [`Transition`](/ui/Transition).
|
|
49
41
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
Components paint from the ladder by convention:
|
|
53
|
-
|
|
54
|
-
| Step | Used for |
|
|
55
|
-
|---|---|
|
|
56
|
-
| `--tint-00` | Body text, headings — maximum contrast |
|
|
57
|
-
| `--tint-50` | The hue itself — accents, labels, `Tag` backgrounds, `strong` button backgrounds |
|
|
58
|
-
| `--tint-80` | Borders |
|
|
59
|
-
| `--tint-90` | Surfaces — `Card`, `Preformatted`, `Button` backgrounds |
|
|
60
|
-
| `--tint-95` | Hover state of those surfaces |
|
|
61
|
-
| `--tint-100` | The page background; text on `--tint-50` backgrounds |
|
|
62
|
-
|
|
63
|
-
Pairings follow contrast: long text reads at `00`-on-`90` or `00`-on-`100`; short labels read at `100`-on-`50`.
|
|
64
|
-
|
|
65
|
-
### Cascade layers
|
|
66
|
-
|
|
67
|
-
Order, lowest to highest priority:
|
|
68
|
-
|
|
69
|
-
| Layer | What's in it |
|
|
70
|
-
|---|---|
|
|
71
|
-
| `defaults` | `:root` design tokens, the tint ladder, body baseline typography, low-priority opt-in defaults |
|
|
72
|
-
| `components` | Component-defining CSS — the bulk of the codebase: `.card`, `.button`, `.notice`, `.heading`, etc. |
|
|
73
|
-
| `variants` | Cross-cutting opt-in modifiers (Color, Status, Spacing, Padding, Gap, Width, Typography, Flex, Scroll). Always beat components. |
|
|
74
|
-
| `overrides` | Top-priority structural overrides — `:first-child` / `:last-child` margin collapses, which need to beat variant-set margins |
|
|
75
|
-
|
|
76
|
-
**Unlayered rules beat all layered rules.** A consumer theme that wraps its overrides in `@layer theme { … }` or just sets tokens at `:root` is fine; one that writes raw class selectors without participating in the layer system will silently dominate variants.
|
|
77
|
-
|
|
78
|
-
### Styling props
|
|
79
|
-
|
|
80
|
-
[`style/`](./style/) exports the cross-cutting styling props. Each module has the same shape: a `.module.css` with classes inside `@layer variants`, and a `.tsx` exporting a `getXxxClass(props)` helper plus a props interface that components extend.
|
|
81
|
-
|
|
82
|
-
Scales — anything with mutually-exclusive options — are enumerated props:
|
|
83
|
-
|
|
84
|
-
| Prop | Module | Values | Sets |
|
|
85
|
-
|---|---|---|---|
|
|
86
|
-
| `color=` | [`Color`](./style/Color.tsx) | `"primary"`, `"secondary"`, `"tertiary"`, `"red"`, `"orange"`, `"yellow"`, `"green"`, `"aqua"`, `"blue"`, `"purple"`, `"pink"`, `"gray"` | The tint anchor — recolours the whole scope |
|
|
87
|
-
| `status=` | [`Status`](./style/Status.tsx) | `"info"`, `"success"`, `"warning"`, `"danger"`, `"error"`, `"loading"` | The tint anchor, via a semantic name |
|
|
88
|
-
| `size=` | [`Typography`](./style/Typography.tsx) | `"xxsmall"` … `"xxlarge"` | `font-size` |
|
|
89
|
-
| `tint=` | [`Typography`](./style/Typography.tsx) | `"00"`, `"05"`, … `"100"` | Text `color`, as a step of the current ladder |
|
|
90
|
-
| `space=` | [`Spacing`](./style/Spacing.tsx) | `"none"`, `"xxsmall"` … `"xxlarge"` | `margin-block` (top + bottom) |
|
|
91
|
-
| `padding=` | [`Padding`](./style/Padding.tsx) | `"none"`, `"xxsmall"` … `"xxlarge"` | `padding-block` (top + bottom) |
|
|
92
|
-
| `gap=` | [`Gap`](./style/Gap.tsx) | `"none"`, `"xxsmall"` … `"xxlarge"` | `gap` between children |
|
|
93
|
-
|
|
94
|
-
On/off options stay boolean props:
|
|
95
|
-
|
|
96
|
-
| Props | Module | Purpose |
|
|
97
|
-
|---|---|---|
|
|
98
|
-
| `narrow`, `wide`, `full` | [`Width`](./style/Width.tsx) | Constrain (or unconstrain) `max-width` |
|
|
99
|
-
| `body`, `code`, `monospace`, `sans`, `serif` | [`Typography`](./style/Typography.tsx) | Font family |
|
|
100
|
-
| `left`, `center`, `right` | [`Typography`](./style/Typography.tsx) | Text alignment |
|
|
101
|
-
| `wrap`, `column`, `reverse`, justify/align (`left`, `middle`, `between`, …) | [`Flex`](./style/Flex.tsx) | Flex layout (composes `gap=`) |
|
|
102
|
-
| `horizontal`, `vertical` | [`Scroll`](./style/Scroll.tsx) | Opt-in scrolling (combinable) |
|
|
103
|
-
|
|
104
|
-
Status also keeps boolean aliases (`<Notice error>` ≡ `<Notice status="error">`) because they read naturally at call sites that hard-code one status.
|
|
105
|
-
|
|
106
|
-
A component using styling props looks like:
|
|
107
|
-
|
|
108
|
-
```tsx
|
|
109
|
-
export interface CardProps extends ColorProps, StatusProps, PaddingProps, SpacingProps, WidthVariants /* … */ {}
|
|
110
|
-
|
|
111
|
-
export function Card({ children, ...props }: CardProps): ReactElement {
|
|
112
|
-
return (
|
|
113
|
-
<article
|
|
114
|
-
className={getClass(
|
|
115
|
-
getModuleClass(CARD_CSS, "card"),
|
|
116
|
-
getStatusClass(props),
|
|
117
|
-
getColorClass(props),
|
|
118
|
-
getPaddingClass(props),
|
|
119
|
-
getSpacingClass(props),
|
|
120
|
-
getWidthClass(props),
|
|
121
|
-
)}
|
|
122
|
-
>
|
|
123
|
-
{children}
|
|
124
|
-
</article>
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
```tsx
|
|
130
|
-
// At a call site:
|
|
131
|
-
<Card color="purple" padding="large" space="none">…</Card>
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
### Component theme hooks
|
|
135
|
-
|
|
136
|
-
Each component exposes per-component CSS custom properties for its overridable values, read with a `var(--component-hook, default)` fallback chain. A consumer overrides the hook at `:root` to retheme that one component without touching the rest of the design system.
|
|
137
|
-
|
|
138
|
-
Every painting component exposes two kinds of hook:
|
|
139
|
-
|
|
140
|
-
- **A tint hook** — the component rebinds the scale anchor once, at the top of its rule: `--tint-50: var(--card-tint, inherit);`. Setting `--card-tint: var(--color-purple)` recolours every card (and everything nested inside cards) while leaving the rest of the page alone. The `inherit` fallback is what lets `color=` / `status=` variants and parent scopes flow through when the hook is unset.
|
|
141
|
-
- **Per-property hooks** — `--card-background`, `--card-border`, `--card-padding`, `--card-radius`, `--card-shadow`, and so on, for surgical overrides of a single painted property: `background: var(--card-background, var(--tint-90))`.
|
|
142
|
-
|
|
143
|
-
Naming follows the file-prefix rule from [AGENTS.md](/AGENTS.md): hooks owned by a module file start with that file's kebab-case name — `Card.module.css` owns `--card-*`, `Button.module.css` owns `--button-*`. Design tokens declared at `:root` in `base.css` and the tint ladder itself are exempt — they're the global palette, not file-owned.
|
|
144
|
-
|
|
145
|
-
### Theming
|
|
146
|
-
|
|
147
|
-
A theme is a CSS file of custom-property overrides at `:root`, imported after the base styles. Work from broadest to narrowest:
|
|
148
|
-
|
|
149
|
-
1. **Move a palette colour.** Overriding `--color-gray` moves the default anchor, retinting every neutral ladder in the app — the broadest possible change. Overriding `--color-red`, `--color-primary`, etc. re-aims every variant and status that maps to it.
|
|
150
|
-
2. **Retint one component family.** Set its tint hook: `--card-tint: var(--color-purple)` makes all cards (and their nested content) purple-tinted, with text, border, surface, and hover shades all derived for free.
|
|
151
|
-
3. **Override one property.** Per-property hooks are the scalpel: `--button-radius: 999px`, `--card-border: none`, `--tag-case: none`.
|
|
152
|
-
|
|
153
|
-
**Don't override individual ladder steps (`--tint-90`, etc.) at `:root`.** The ladder is *recomputed* from the anchor inside every `.tint` scope — which includes every component that accepts `color=` or `status=` — so a step override at `:root` only reaches untinted regions and produces inconsistent surfaces. Move the anchor (option 1 or 2) instead, and the steps follow.
|
|
154
|
-
|
|
155
|
-
### How `:first-child` / `:last-child` margin overrides work
|
|
156
|
-
|
|
157
|
-
Every paragraph-level component zeros its outer margins when it's the first or last child of its container — otherwise a Heading at the top of a Card would leave a strip of unwanted space. These rules live in `@layer overrides`, which beats every other layer including `variants`, so a `<Paragraph space="large">` still collapses its abutting edges correctly.
|
|
158
|
-
|
|
159
|
-
Pattern:
|
|
160
|
-
|
|
161
|
-
```css
|
|
162
|
-
@layer components {
|
|
163
|
-
.paragraph { margin-block: var(--paragraph-space, var(--space-paragraph)); }
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
@layer overrides {
|
|
167
|
-
.paragraph {
|
|
168
|
-
&:first-child { margin-block-start: 0; }
|
|
169
|
-
&:last-child { margin-block-end: 0; }
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
### Writing a new component
|
|
175
|
-
|
|
176
|
-
A typical new block-level component looks like:
|
|
177
|
-
|
|
178
|
-
```tsx
|
|
179
|
-
// Address.tsx
|
|
180
|
-
import { type ColorProps, getColorClass } from "../style/Color.js";
|
|
181
|
-
import { getSpacingClass, type SpacingProps } from "../style/Spacing.js";
|
|
182
|
-
import { getTypographyClass, type TypographyProps } from "../style/Typography.js";
|
|
183
|
-
|
|
184
|
-
export interface AddressProps extends ColorProps, SpacingProps, TypographyProps, ChildProps {}
|
|
185
|
-
|
|
186
|
-
export function Address({ children, ...props }: AddressProps) {
|
|
187
|
-
return (
|
|
188
|
-
<address
|
|
189
|
-
className={getClass(
|
|
190
|
-
getModuleClass(styles, "address"),
|
|
191
|
-
getColorClass(props),
|
|
192
|
-
getSpacingClass(props),
|
|
193
|
-
getTypographyClass(props),
|
|
194
|
-
)}
|
|
195
|
-
>
|
|
196
|
-
{children}
|
|
197
|
-
</address>
|
|
198
|
-
);
|
|
199
|
-
}
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
```css
|
|
203
|
-
/* Address.module.css */
|
|
204
|
-
@import "../style/base.css";
|
|
205
|
-
|
|
206
|
-
@layer components {
|
|
207
|
-
.address {
|
|
208
|
-
/* Theme — rebind the tint anchor so `--address-tint` (and parent scopes) flow through. */
|
|
209
|
-
--tint-50: var(--address-tint, inherit);
|
|
210
|
-
|
|
211
|
-
/* Box */
|
|
212
|
-
display: block;
|
|
213
|
-
margin-inline: 0;
|
|
214
|
-
margin-block: var(--address-space, var(--space-paragraph));
|
|
215
|
-
|
|
216
|
-
/* Text — paint from the ladder, with a per-property hook in front. */
|
|
217
|
-
color: var(--address-color, var(--tint-00));
|
|
218
|
-
font-family: var(--address-font, inherit);
|
|
219
|
-
font-size: var(--address-size, inherit);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
@layer overrides {
|
|
224
|
-
.address {
|
|
225
|
-
&:first-child { margin-block-start: 0; }
|
|
226
|
-
&:last-child { margin-block-end: 0; }
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
Checklist:
|
|
232
|
-
|
|
233
|
-
- [ ] `@import "../style/base.css";` at the top.
|
|
234
|
-
- [ ] All rules inside `@layer components { … }`.
|
|
235
|
-
- [ ] All custom properties owned by this file start with the file name (`--address-*`, etc.), per [AGENTS.md](/AGENTS.md).
|
|
236
|
-
- [ ] If the component paints colour, rebind the tint anchor at the top of the rule (`--tint-50: var(--address-tint, inherit);`) and paint from ladder steps with per-property hooks in front.
|
|
237
|
-
- [ ] `:first-child` / `:last-child` overrides in a separate `@layer overrides { … }` block.
|
|
238
|
-
- [ ] TSX extends the styling-prop interfaces (`ColorProps`, `SpacingProps`, `TypographyProps`, etc.) you want to expose; composes the matching `getXxxClass(props)` calls.
|
|
239
|
-
|
|
240
|
-
## Module map
|
|
241
|
-
|
|
242
|
-
### Content
|
|
243
|
-
|
|
244
|
-
| Folder | What's inside |
|
|
245
|
-
|---|---|
|
|
246
|
-
| [block](/ui/block) | Block-level content — `Card`, `Section`, `Title`, `Heading`, `Table`, `List`, `Prose`, `Figure` |
|
|
247
|
-
| [inline](/ui/inline) | Inline content — `Code`, `Strong`, `Emphasis`, `Link`, `Mark`, `Small` |
|
|
248
|
-
| [misc](/ui/misc) | Cross-cutting pieces — `Markup`, `Tag`, `StatusIcon`, `Loading`, `Catcher`, `Mapper` |
|
|
249
|
-
| [style](./style/) | The styling system — design tokens, the tint scale, styling props, `Flex`, `Scroll` |
|
|
250
|
-
|
|
251
|
-
### Structure
|
|
252
|
-
|
|
253
|
-
| Folder | What's inside |
|
|
254
|
-
|---|---|
|
|
255
|
-
| [app](/ui/app) | The `<App>` root component |
|
|
256
|
-
| [page](/ui/page) | Document-level components — `<HTML>`, `<Head>`, `<Page>` |
|
|
257
|
-
| [layout](/ui/layout) | Page layouts — `SidebarLayout`, `CenteredLayout` |
|
|
258
|
-
| [router](/ui/router) | Client-side routing — `<Navigation>`, `<Router>` |
|
|
259
|
-
|
|
260
|
-
### Interaction
|
|
261
|
-
|
|
262
|
-
| Folder | What's inside |
|
|
263
|
-
|---|---|
|
|
264
|
-
| [form](/ui/form) | Forms and inputs — `<Form>`, `<Field>`, typed inputs, `<Button>`, `FormStore` |
|
|
265
|
-
| [dialog](/ui/dialog) | `<Dialog>` and `<Modal>` overlays |
|
|
266
|
-
| [menu](/ui/menu) | `<Menu>` and `<MenuItem>` |
|
|
267
|
-
| [notice](/ui/notice) | Inline and global notices |
|
|
268
|
-
| [transition](/ui/transition) | CSS enter / leave transitions |
|
|
269
|
-
|
|
270
|
-
### Documentation site
|
|
271
|
-
|
|
272
|
-
| Folder | What's inside |
|
|
273
|
-
|---|---|
|
|
274
|
-
| [tree](/ui/tree) | `<TreeApp>` and the components that turn a tree into a site |
|
|
275
|
-
| [docs](/ui/docs) | Page and card renderers for directories, files, and code symbols |
|
|
276
|
-
| [util](/ui/util) | UI helper functions — context, meta, CSS class composition |
|
|
277
|
-
|
|
278
|
-
## Quick start
|
|
279
|
-
|
|
280
|
-
A minimal single-screen app:
|
|
281
|
-
|
|
282
|
-
```tsx
|
|
283
|
-
import { App, CenteredLayout, Section, Title, Paragraph } from "shelving/ui";
|
|
284
|
-
|
|
285
|
-
function HelloApp() {
|
|
286
|
-
return (
|
|
287
|
-
<App app="My app">
|
|
288
|
-
<CenteredLayout>
|
|
289
|
-
<Section narrow>
|
|
290
|
-
<Title>Hello</Title>
|
|
291
|
-
<Paragraph>Welcome to the app.</Paragraph>
|
|
292
|
-
</Section>
|
|
293
|
-
</CenteredLayout>
|
|
294
|
-
</App>
|
|
295
|
-
);
|
|
296
|
-
}
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
For a routed, multi-page app, wrap the tree in [`<Navigation>` and `<Router>`](/ui/router). For a documentation site, hand an extracted tree to [`<TreeApp>`](/ui/tree) — see the [extract](/extract) guide.
|
|
42
|
+
**Documentation site.** Hand an extracted tree to [`TreeApp`](/ui/TreeApp) and you get a complete site — sidebar, routing, and a rendered page per element — using the renderers in `docs/`.
|
|
300
43
|
|
|
301
44
|
## See also
|
|
302
45
|
|
|
303
46
|
- [extract](/extract) — builds the tree that the documentation components render
|
|
304
|
-
- [markup](/markup) — Markdown rendering used by
|
|
305
|
-
- [store](/store) — reactive state behind `FormStore
|
|
47
|
+
- [markup](/markup) — Markdown rendering used by [`Markup`](/ui/Markup) and [`Prose`](/ui/Prose)
|
|
48
|
+
- [store](/store) — reactive state behind [`FormStore`](/ui/FormStore), `NavigationStore`, and notices
|
|
306
49
|
- [react](/react) — store and provider hooks used alongside these components
|
|
50
|
+
|
|
51
|
+
> Building or extending a component? The contributor walkthrough (file layout, the tint-anchor + per-property-hook pattern, `:first-child` / `:last-child` overrides, and the checklist) lives in the **React Components** section of `AGENTS.md`.
|
package/ui/app/App.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export interface AppProps extends PossibleMeta, ChildProps {
|
|
|
17
17
|
* @param children The application content.
|
|
18
18
|
* @param meta The root meta (app name, root URL, language, etc.).
|
|
19
19
|
* @returns The app root element wrapping `children`.
|
|
20
|
+
* @kind component
|
|
20
21
|
* @example <App app="My App" root="https://example.com/"><Navigation>…</Navigation></App>
|
|
21
22
|
* @see https://dhoulb.github.io/shelving/ui/app/App/App
|
|
22
23
|
*/
|
package/ui/app/App.js
CHANGED
|
@@ -9,6 +9,7 @@ import "../style/base.css";
|
|
|
9
9
|
* @param children The application content.
|
|
10
10
|
* @param meta The root meta (app name, root URL, language, etc.).
|
|
11
11
|
* @returns The app root element wrapping `children`.
|
|
12
|
+
* @kind component
|
|
12
13
|
* @example <App app="My App" root="https://example.com/"><Navigation>…</Navigation></App>
|
|
13
14
|
* @see https://dhoulb.github.io/shelving/ui/app/App/App
|
|
14
15
|
*/
|
package/ui/app/App.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# App
|
|
2
|
+
|
|
3
|
+
Root component for a client-side Shelving app. `<App>` applies the theme CSS class to `document.body` and provides a `Meta` context so every descendant can read or update page metadata.
|
|
4
|
+
|
|
5
|
+
Use `<App>` when mounting into an existing HTML page on the client. For server-side rendering where you need the full `<html>` document shell, use [`HTML`](/ui/HTML) instead.
|
|
6
|
+
|
|
7
|
+
## A minimal app
|
|
8
|
+
|
|
9
|
+
The smallest single-screen app — `<App>` wraps a layout and some content:
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import { App, CenteredLayout, Section, Title, Paragraph } from "shelving/ui";
|
|
13
|
+
|
|
14
|
+
function HelloApp() {
|
|
15
|
+
return (
|
|
16
|
+
<App app="My app">
|
|
17
|
+
<CenteredLayout>
|
|
18
|
+
<Section narrow>
|
|
19
|
+
<Title>Hello</Title>
|
|
20
|
+
<Paragraph>Welcome to the app.</Paragraph>
|
|
21
|
+
</Section>
|
|
22
|
+
</CenteredLayout>
|
|
23
|
+
</App>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## A routed app
|
|
29
|
+
|
|
30
|
+
For a multi-page app, wrap the routes in [`Navigation`](/ui/Navigation) and [`Router`](/ui/Router):
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
import { App, Navigation, Router } from "shelving/ui";
|
|
34
|
+
|
|
35
|
+
export function MyApp() {
|
|
36
|
+
return (
|
|
37
|
+
<App app="My app" root="https://example.com/" url="/">
|
|
38
|
+
<Navigation>
|
|
39
|
+
<Router routes={{
|
|
40
|
+
"/": HomePage,
|
|
41
|
+
"/about": AboutPage,
|
|
42
|
+
}} />
|
|
43
|
+
</Navigation>
|
|
44
|
+
</App>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`<App>` accepts all `PossibleMeta` props (`app`, `root`, `url`, `title`, `language`, `tags`, etc.) and merges them into the context it provides to children. On mount it adds the theme class to `document.body`, which activates the CSS custom property tokens defined in `App.module.css`; on unmount it removes it.
|
|
50
|
+
|
|
51
|
+
For a documentation site, hand an extracted tree to [`TreeApp`](/ui/TreeApp) instead — see the [extract](/extract) guide.
|
|
52
|
+
|
|
53
|
+
## See also
|
|
54
|
+
|
|
55
|
+
- [`HTML`](/ui/HTML) — the full `<html>` document shell for server-side rendering (vs. `<App>` for client mounts).
|
|
56
|
+
- [`Navigation`](/ui/Navigation) and [`Router`](/ui/Router) — client-side routing wrapped inside the app.
|
|
57
|
+
- [`CenteredLayout`](/ui/CenteredLayout) and [`SidebarLayout`](/ui/SidebarLayout) — the page layouts that go inside an app.
|
|
58
|
+
- [`TreeApp`](/ui/TreeApp) — a ready-made documentation-site root built on the same pieces.
|
package/ui/app/App.tsx
CHANGED
|
@@ -19,6 +19,7 @@ export interface AppProps extends PossibleMeta, ChildProps {}
|
|
|
19
19
|
* @param children The application content.
|
|
20
20
|
* @param meta The root meta (app name, root URL, language, etc.).
|
|
21
21
|
* @returns The app root element wrapping `children`.
|
|
22
|
+
* @kind component
|
|
22
23
|
* @example <App app="My App" root="https://example.com/"><Navigation>…</Navigation></App>
|
|
23
24
|
* @see https://dhoulb.github.io/shelving/ui/app/App/App
|
|
24
25
|
*/
|