shelving 1.215.1 → 1.216.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shelving",
3
- "version": "1.215.1",
3
+ "version": "1.216.0",
4
4
  "author": "Dave Houlbrooke <dave@shax.com>",
5
5
  "repository": {
6
6
  "type": "git",
package/ui/README.md CHANGED
@@ -21,7 +21,7 @@ A few conventions run through every component (see also the React Components sec
21
21
 
22
22
  | Folder | What's inside |
23
23
  |---|---|
24
- | [block](/ui/block) | Block-level content — `Card`, `Section`, `Heading`, `Table`, `List`, `Prose`, `Figure`, `Flex` |
24
+ | [block](/ui/block) | Block-level content — `Card`, `Section`, `Title`, `Heading`, `Table`, `List`, `Prose`, `Figure`, `Flex` |
25
25
  | [inline](/ui/inline) | Inline content — `Code`, `Strong`, `Emphasis`, `Link`, `Mark`, `Small` |
26
26
  | [misc](/ui/misc) | Cross-cutting pieces — `Markup`, `Tag`, `Status`, `Loading`, `Color`, `Catcher`, `Mapper` |
27
27
 
@@ -57,14 +57,14 @@ A few conventions run through every component (see also the React Components sec
57
57
  A minimal single-screen app:
58
58
 
59
59
  ```tsx
60
- import { App, CenteredLayout, Section, Heading, Paragraph } from "shelving/ui";
60
+ import { App, CenteredLayout, Section, Title, Paragraph } from "shelving/ui";
61
61
 
62
62
  function HelloApp() {
63
63
  return (
64
64
  <App app="My app">
65
65
  <CenteredLayout>
66
66
  <Section narrow>
67
- <Heading>Hello</Heading>
67
+ <Title>Hello</Title>
68
68
  <Paragraph>Welcome to the app.</Paragraph>
69
69
  </Section>
70
70
  </CenteredLayout>
@@ -12,7 +12,7 @@ export interface CardProps extends ClickableProps {
12
12
  * - When `href` or `onClick` is set the card becomes navigable: a stretched overlay `<a>` / `<button>` covers the entire card while the children render normally inside.
13
13
  * - Real interactive elements inside the card (e.g. inline `<a>` links) stay clickable thanks to `position: relative; z-index: 2` rules in the stylesheet.
14
14
  *
15
- * @example <Card><Heading>Static</Heading></Card>
16
- * @example <Card href="/foo" title="Open foo"><Heading>Clickable</Heading></Card>
15
+ * @example <Card><Subheading>Static</Subheading></Card>
16
+ * @example <Card href="/foo" title="Open foo"><Subheading>Clickable</Subheading></Card>
17
17
  */
18
18
  export declare function Card({ children, href, onClick, title, ...props }: CardProps): ReactElement;
package/ui/block/Card.js CHANGED
@@ -7,8 +7,8 @@ import CARD_CSS from "./Card.module.css";
7
7
  * - When `href` or `onClick` is set the card becomes navigable: a stretched overlay `<a>` / `<button>` covers the entire card while the children render normally inside.
8
8
  * - Real interactive elements inside the card (e.g. inline `<a>` links) stay clickable thanks to `position: relative; z-index: 2` rules in the stylesheet.
9
9
  *
10
- * @example <Card><Heading>Static</Heading></Card>
11
- * @example <Card href="/foo" title="Open foo"><Heading>Clickable</Heading></Card>
10
+ * @example <Card><Subheading>Static</Subheading></Card>
11
+ * @example <Card href="/foo" title="Open foo"><Subheading>Clickable</Subheading></Card>
12
12
  */
13
13
  export function Card({ children, href, onClick, title = "Open", ...props }) {
14
14
  const overlay = (href || onClick) && _jsx(Clickable, { title: title, href: href, onClick: onClick, ...props, className: CARD_CSS.overlay });
package/ui/block/Card.tsx CHANGED
@@ -18,8 +18,8 @@ export interface CardProps extends ClickableProps {
18
18
  * - When `href` or `onClick` is set the card becomes navigable: a stretched overlay `<a>` / `<button>` covers the entire card while the children render normally inside.
19
19
  * - Real interactive elements inside the card (e.g. inline `<a>` links) stay clickable thanks to `position: relative; z-index: 2` rules in the stylesheet.
20
20
  *
21
- * @example <Card><Heading>Static</Heading></Card>
22
- * @example <Card href="/foo" title="Open foo"><Heading>Clickable</Heading></Card>
21
+ * @example <Card><Subheading>Static</Subheading></Card>
22
+ * @example <Card href="/foo" title="Open foo"><Subheading>Clickable</Subheading></Card>
23
23
  */
24
24
  export function Card({ children, href, onClick, title = "Open", ...props }: CardProps): ReactElement {
25
25
  const overlay = (href || onClick) && <Clickable title={title} href={href} onClick={onClick} {...props} className={CARD_CSS.overlay} />;
@@ -1,6 +1,16 @@
1
- import type { ReactNode } from "react";
1
+ import type { ReactElement, ReactNode } from "react";
2
+ /** Props shared by `Title`, `Heading`, and `Subheading`. */
2
3
  export interface HeadingProps {
4
+ /**
5
+ * Heading level (`1`–`6`) — sets the rendered `<h1>`–`<h6>` tag.
6
+ * Avoid overriding this in practice: pick the component that matches the level — `Title` (`<h1>`), `Heading` (`<h2>`), or `Subheading` (`<h3>`) — so the visual size and the document outline stay in step.
7
+ */
3
8
  level?: "1" | "2" | "3" | "4" | "5" | "6" | 1 | 2 | 3 | 4 | 5 | 6;
9
+ /** Heading content. */
4
10
  children: ReactNode;
5
11
  }
6
- export declare function Heading({ level, children, ...variants }: HeadingProps): import("react/jsx-runtime").JSX.Element;
12
+ /**
13
+ * Section heading — renders an `<h2>`.
14
+ * - Sits between `Title` (`<h1>`) and `Subheading` (`<h3>`) in the heading hierarchy.
15
+ */
16
+ export declare function Heading({ level, children, ...variants }: HeadingProps): ReactElement;
@@ -1,7 +1,11 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { getModuleClass } from "../util/css.js";
3
3
  import styles from "./Heading.module.css";
4
- export function Heading({ level = "1", children, ...variants }) {
4
+ /**
5
+ * Section heading — renders an `<h2>`.
6
+ * - Sits between `Title` (`<h1>`) and `Subheading` (`<h3>`) in the heading hierarchy.
7
+ */
8
+ export function Heading({ level = "2", children, ...variants }) {
5
9
  const Element = `h${level}`;
6
10
  return _jsx(Element, { className: getModuleClass(styles, "heading", variants), children: children });
7
11
  }
@@ -1,22 +1,19 @@
1
1
  .heading,
2
- .prose h1 {
2
+ .prose h2 {
3
3
  /* Box */
4
4
  display: block;
5
5
  inline-size: 100%;
6
6
  margin-inline: 0;
7
- margin-block: var(--heading-spacing, var(--space-normal));
7
+ /* `em` top margin scales with font-size, so larger headings get proportionally more space above them. */
8
+ margin-block-start: var(--heading-spacing-before, 1.5em);
9
+ margin-block-end: var(--heading-spacing, var(--space-normal));
8
10
 
9
11
  /* Style */
10
12
  font-family: var(--heading-font, var(--font-body));
11
13
  font-weight: var(--heading-weight, var(--weight-strong));
12
14
  line-height: var(--heading-leading, var(--leading));
13
15
  color: var(--heading-color, var(--color-text));
14
-
15
- /*
16
- * Default font-size — applies to h1 (the `<Heading>` default) and to `.prose h1`.
17
- * Per-level rules below override for `<Heading level="2-6">` cases.
18
- */
19
- font-size: var(--heading-font-size, var(--size-xxxlarge));
16
+ font-size: var(--heading-font-size, var(--size-xxlarge));
20
17
 
21
18
  /* Psuedo-classes */
22
19
  &:first-child {
@@ -26,14 +23,3 @@
26
23
  margin-block-end: 0;
27
24
  }
28
25
  }
29
-
30
- /* Per-level font-size scaling — `<Heading level="N">` sizes itself by its tag. */
31
- .heading:is(h2) {
32
- font-size: var(--heading-font-size, var(--size-xxlarge));
33
- }
34
- .heading:is(h3) {
35
- font-size: var(--heading-font-size, var(--size-xlarge));
36
- }
37
- .heading:is(h4, h5, h6) {
38
- font-size: var(--heading-font-size, var(--size-large));
39
- }
@@ -1,13 +1,23 @@
1
- import type { ReactNode } from "react";
1
+ import type { ReactElement, ReactNode } from "react";
2
2
  import { getModuleClass } from "../util/css.js";
3
3
  import styles from "./Heading.module.css";
4
4
 
5
+ /** Props shared by `Title`, `Heading`, and `Subheading`. */
5
6
  export interface HeadingProps {
7
+ /**
8
+ * Heading level (`1`–`6`) — sets the rendered `<h1>`–`<h6>` tag.
9
+ * Avoid overriding this in practice: pick the component that matches the level — `Title` (`<h1>`), `Heading` (`<h2>`), or `Subheading` (`<h3>`) — so the visual size and the document outline stay in step.
10
+ */
6
11
  level?: "1" | "2" | "3" | "4" | "5" | "6" | 1 | 2 | 3 | 4 | 5 | 6;
12
+ /** Heading content. */
7
13
  children: ReactNode;
8
14
  }
9
15
 
10
- export function Heading({ level = "1", children, ...variants }: HeadingProps) {
16
+ /**
17
+ * Section heading — renders an `<h2>`.
18
+ * - Sits between `Title` (`<h1>`) and `Subheading` (`<h3>`) in the heading hierarchy.
19
+ */
20
+ export function Heading({ level = "2", children, ...variants }: HeadingProps): ReactElement {
11
21
  const Element: `h${typeof level}` = `h${level}`;
12
22
  return <Element className={getModuleClass(styles, "heading", variants)}>{children}</Element>;
13
23
  }
@@ -31,10 +31,10 @@ Some block components ship multiple pieces intended to compose:
31
31
  ### Content card with a heading
32
32
 
33
33
  ```tsx
34
- import { Card, Heading, Paragraph } from "shelving/ui";
34
+ import { Card, Paragraph, Subheading } from "shelving/ui";
35
35
 
36
36
  <Card href="/products/42" title="Open product">
37
- <Heading level={2}>Widget Pro</Heading>
37
+ <Subheading>Widget Pro</Subheading>
38
38
  <Paragraph>The best widget on the market.</Paragraph>
39
39
  </Card>
40
40
  ```
@@ -56,7 +56,7 @@ import { Section, Heading, Definitions, Definition } from "shelving/ui";
56
56
  </Section>
57
57
  ```
58
58
 
59
- `<Subheading>` uses the same `level` prop as `<Heading>` but applies secondary typography styles use it for in-section labels and panel titles.
59
+ `<Title>`, `<Heading>`, and `<Subheading>` render `<h1>`, `<h2>`, and `<h3>` respectively — pick the component that matches the level rather than overriding it with the `level` prop. Use `<Subheading>` for card titles, in-section labels, and panel titles.
60
60
 
61
61
  ### Prose content from a renderer
62
62
 
@@ -73,12 +73,12 @@ Wrap `<Markup>` (or any component that emits raw HTML elements) in `<Prose>` to
73
73
  ### Flex row of cards
74
74
 
75
75
  ```tsx
76
- import { Flex, Card, Heading } from "shelving/ui";
76
+ import { Card, Flex, Subheading } from "shelving/ui";
77
77
 
78
78
  <Flex wrap>
79
79
  {products.map(p => (
80
80
  <Card key={p.id} href={`/products/${p.id}`}>
81
- <Heading level={3}>{p.name}</Heading>
81
+ <Subheading>{p.name}</Subheading>
82
82
  </Card>
83
83
  ))}
84
84
  </Flex>
@@ -1,3 +1,9 @@
1
+ import type { ReactElement } from "react";
1
2
  import type { HeadingProps } from "./Heading.js";
3
+ /** Props for `Subheading` — identical to `HeadingProps`. */
2
4
  export type SubheadingProps = HeadingProps;
3
- export declare function Subheading({ level, children, ...variants }: SubheadingProps): import("react/jsx-runtime").JSX.Element;
5
+ /**
6
+ * Subsection heading — renders an `<h3>`.
7
+ * - Only marginally larger than body text; its bold weight is the main differentiator.
8
+ */
9
+ export declare function Subheading({ level, children, ...variants }: SubheadingProps): ReactElement;
@@ -1,7 +1,11 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { getModuleClass } from "../util/css.js";
3
3
  import styles from "./Subheading.module.css";
4
- export function Subheading({ level = "2", children, ...variants }) {
4
+ /**
5
+ * Subsection heading — renders an `<h3>`.
6
+ * - Only marginally larger than body text; its bold weight is the main differentiator.
7
+ */
8
+ export function Subheading({ level = "3", children, ...variants }) {
5
9
  const Element = `h${level}`;
6
10
  return _jsx(Element, { className: getModuleClass(styles, "subheading", variants), children: children });
7
11
  }
@@ -1,22 +1,19 @@
1
1
  .subheading,
2
- .prose :is(h2, h3, h4, h5, h6) {
2
+ .prose :is(h3, h4, h5, h6) {
3
3
  /* Box */
4
4
  display: block;
5
5
  inline-size: 100%;
6
6
  margin-inline: 0;
7
- margin-block: var(--subheading-spacing, var(--space-normal));
7
+ /* `em` top margin scales with font-size, so larger headings get proportionally more space above them. */
8
+ margin-block-start: var(--subheading-spacing-before, 1.5em);
9
+ margin-block-end: var(--subheading-spacing, var(--space-normal));
8
10
 
9
11
  /* Style */
10
12
  font-family: var(--subheading-font, var(--font-body));
11
13
  font-weight: var(--subheading-weight, var(--weight-strong));
12
14
  line-height: var(--subheading-leading, var(--leading));
13
15
  color: var(--subheading-color, var(--color-text));
14
-
15
- /*
16
- * Default font-size — applies to h2 (the `<Subheading>` default).
17
- * Per-level rules below override for `<Subheading level="3-6">` cases and for `.prose` headings.
18
- */
19
- font-size: var(--subheading-font-size, var(--size-xxlarge));
16
+ font-size: var(--subheading-font-size, var(--size-large));
20
17
 
21
18
  /* Psuedo-classes */
22
19
  &:first-child {
@@ -26,13 +23,3 @@
26
23
  margin-block-end: 0;
27
24
  }
28
25
  }
29
-
30
- /* Per-level font-size scaling — `<Subheading level="N">` (and prose headings) size by tag. */
31
- .subheading:is(h3),
32
- .prose h3 {
33
- font-size: var(--subheading-font-size, var(--size-xlarge));
34
- }
35
- .subheading:is(h4, h5, h6),
36
- .prose :is(h4, h5, h6) {
37
- font-size: var(--subheading-font-size, var(--size-large));
38
- }
@@ -1,10 +1,16 @@
1
+ import type { ReactElement } from "react";
1
2
  import { getModuleClass } from "../util/css.js";
2
3
  import type { HeadingProps } from "./Heading.js";
3
4
  import styles from "./Subheading.module.css";
4
5
 
6
+ /** Props for `Subheading` — identical to `HeadingProps`. */
5
7
  export type SubheadingProps = HeadingProps;
6
8
 
7
- export function Subheading({ level = "2", children, ...variants }: SubheadingProps) {
9
+ /**
10
+ * Subsection heading — renders an `<h3>`.
11
+ * - Only marginally larger than body text; its bold weight is the main differentiator.
12
+ */
13
+ export function Subheading({ level = "3", children, ...variants }: SubheadingProps): ReactElement {
8
14
  const Element: `h${typeof level}` = `h${level}`;
9
15
  return <Element className={getModuleClass(styles, "subheading", variants)}>{children}</Element>;
10
16
  }
@@ -0,0 +1,9 @@
1
+ import type { ReactElement } from "react";
2
+ import type { HeadingProps } from "./Heading.js";
3
+ /** Props for `Title` — identical to `HeadingProps`. */
4
+ export type TitleProps = HeadingProps;
5
+ /**
6
+ * Page title — renders an `<h1>`.
7
+ * - The most prominent heading on a page; there should normally be exactly one.
8
+ */
9
+ export declare function Title({ level, children, ...variants }: TitleProps): ReactElement;
@@ -0,0 +1,11 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { getModuleClass } from "../util/css.js";
3
+ import styles from "./Title.module.css";
4
+ /**
5
+ * Page title — renders an `<h1>`.
6
+ * - The most prominent heading on a page; there should normally be exactly one.
7
+ */
8
+ export function Title({ level = "1", children, ...variants }) {
9
+ const Element = `h${level}`;
10
+ return _jsx(Element, { className: getModuleClass(styles, "title", variants), children: children });
11
+ }
@@ -0,0 +1,25 @@
1
+ .title,
2
+ .prose h1 {
3
+ /* Box */
4
+ display: block;
5
+ inline-size: 100%;
6
+ margin-inline: 0;
7
+ /* `em` top margin scales with font-size, so larger headings get proportionally more space above them. */
8
+ margin-block-start: var(--title-spacing-before, 1.5em);
9
+ margin-block-end: var(--title-spacing, var(--space-normal));
10
+
11
+ /* Style */
12
+ font-family: var(--title-font, var(--font-body));
13
+ font-weight: var(--title-weight, var(--weight-strong));
14
+ line-height: var(--title-leading, var(--leading));
15
+ color: var(--title-color, var(--color-text));
16
+ font-size: var(--title-font-size, var(--size-xxxlarge));
17
+
18
+ /* Psuedo-classes */
19
+ &:first-child {
20
+ margin-block-start: 0;
21
+ }
22
+ &:last-child {
23
+ margin-block-end: 0;
24
+ }
25
+ }
@@ -0,0 +1,16 @@
1
+ import type { ReactElement } from "react";
2
+ import { getModuleClass } from "../util/css.js";
3
+ import type { HeadingProps } from "./Heading.js";
4
+ import styles from "./Title.module.css";
5
+
6
+ /** Props for `Title` — identical to `HeadingProps`. */
7
+ export type TitleProps = HeadingProps;
8
+
9
+ /**
10
+ * Page title — renders an `<h1>`.
11
+ * - The most prominent heading on a page; there should normally be exactly one.
12
+ */
13
+ export function Title({ level = "1", children, ...variants }: TitleProps): ReactElement {
14
+ const Element: `h${typeof level}` = `h${level}`;
15
+ return <Element className={getModuleClass(styles, "title", variants)}>{children}</Element>;
16
+ }
@@ -15,4 +15,5 @@ export * from "./Prose.js";
15
15
  export * from "./Section.js";
16
16
  export * from "./Subheading.js";
17
17
  export * from "./Table.js";
18
+ export * from "./Title.js";
18
19
  export * from "./Video.js";
package/ui/block/index.js CHANGED
@@ -15,4 +15,5 @@ export * from "./Prose.js";
15
15
  export * from "./Section.js";
16
16
  export * from "./Subheading.js";
17
17
  export * from "./Table.js";
18
+ export * from "./Title.js";
18
19
  export * from "./Video.js";
package/ui/block/index.ts CHANGED
@@ -15,4 +15,5 @@ export * from "./Prose.js";
15
15
  export * from "./Section.js";
16
16
  export * from "./Subheading.js";
17
17
  export * from "./Table.js";
18
+ export * from "./Title.js";
18
19
  export * from "./Video.js";
@@ -2,8 +2,8 @@ import type { ReactNode } from "react";
2
2
  import type { DirectoryElementProps } from "../../util/element.js";
3
3
  import { type AbsolutePath } from "../../util/path.js";
4
4
  interface DirectoryCardProps extends DirectoryElementProps {
5
- path?: AbsolutePath | undefined;
5
+ path: AbsolutePath;
6
6
  }
7
7
  /** Card renderer for a `tree-directory` element. */
8
- export declare function DirectoryCard({ path, title, name, content }: DirectoryCardProps): ReactNode;
8
+ export declare function DirectoryCard({ path, name, title, content }: DirectoryCardProps): ReactNode;
9
9
  export {};
@@ -1,11 +1,11 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { joinPath } from "../../util/path.js";
3
3
  import { Card } from "../block/Card.js";
4
- import { Heading } from "../block/Heading.js";
5
4
  import { Prose } from "../block/Prose.js";
5
+ import { Subheading } from "../block/Subheading.js";
6
6
  import { Markup } from "../misc/Markup.js";
7
7
  /** Card renderer for a `tree-directory` element. */
8
- export function DirectoryCard({ path = "/", title, name, content }) {
8
+ export function DirectoryCard({ path, name, title, content }) {
9
9
  const href = joinPath(path, name);
10
- return (_jsxs(Card, { href: href, children: [_jsx(Heading, { level: "3", children: title ?? name }), content && (_jsx(Prose, { children: _jsx(Markup, { children: content }) }))] }));
10
+ return (_jsxs(Card, { href: href, children: [_jsx(Subheading, { children: title ?? name }), content && (_jsx(Prose, { children: _jsx(Markup, { children: content }) }))] }));
11
11
  }
@@ -2,20 +2,20 @@ import type { ReactNode } from "react";
2
2
  import type { DirectoryElementProps } from "../../util/element.js";
3
3
  import { type AbsolutePath, joinPath } from "../../util/path.js";
4
4
  import { Card } from "../block/Card.js";
5
- import { Heading } from "../block/Heading.js";
6
5
  import { Prose } from "../block/Prose.js";
6
+ import { Subheading } from "../block/Subheading.js";
7
7
  import { Markup } from "../misc/Markup.js";
8
8
 
9
9
  interface DirectoryCardProps extends DirectoryElementProps {
10
- path?: AbsolutePath | undefined;
10
+ path: AbsolutePath;
11
11
  }
12
12
 
13
13
  /** Card renderer for a `tree-directory` element. */
14
- export function DirectoryCard({ path = "/", title, name, content }: DirectoryCardProps): ReactNode {
14
+ export function DirectoryCard({ path, name, title, content }: DirectoryCardProps): ReactNode {
15
15
  const href = joinPath(path, name);
16
16
  return (
17
17
  <Card href={href}>
18
- <Heading level="3">{title ?? name}</Heading>
18
+ <Subheading>{title ?? name}</Subheading>
19
19
  {content && (
20
20
  <Prose>
21
21
  <Markup>{content}</Markup>
@@ -1,9 +1,12 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Prose } from "../block/Prose.js";
3
3
  import { Markup } from "../misc/Markup.js";
4
+ import { requireMeta } from "../misc/MetaContext.js";
4
5
  import { Page } from "../page/Page.js";
5
6
  import { TreeCards } from "../tree/TreeCards.js";
6
7
  /** Page renderer for a `tree-directory` element — shows title, content, and child cards. */
7
8
  export function DirectoryPage({ title, name, description, content, children }) {
8
- return (_jsxs(Page, { title: title ?? name, description: description, children: [content && (_jsx(Prose, { children: _jsx(Markup, { children: content }) })), _jsx(TreeCards, { children: children })] }));
9
+ const { url } = requireMeta();
10
+ const path = url?.pathname ?? "/";
11
+ return (_jsxs(Page, { title: title ?? name, description: description, children: [content && (_jsx(Prose, { children: _jsx(Markup, { children: content }) })), _jsx(TreeCards, { path: path, children: children })] }));
9
12
  }
@@ -2,11 +2,14 @@ import type { ReactNode } from "react";
2
2
  import type { DirectoryElementProps } from "../../util/element.js";
3
3
  import { Prose } from "../block/Prose.js";
4
4
  import { Markup } from "../misc/Markup.js";
5
+ import { requireMeta } from "../misc/MetaContext.js";
5
6
  import { Page } from "../page/Page.js";
6
7
  import { TreeCards } from "../tree/TreeCards.js";
7
8
 
8
9
  /** Page renderer for a `tree-directory` element — shows title, content, and child cards. */
9
10
  export function DirectoryPage({ title, name, description, content, children }: DirectoryElementProps): ReactNode {
11
+ const { url } = requireMeta();
12
+ const path = url?.pathname ?? "/";
10
13
  return (
11
14
  <Page title={title ?? name} description={description}>
12
15
  {content && (
@@ -14,7 +17,7 @@ export function DirectoryPage({ title, name, description, content, children }: D
14
17
  <Markup>{content}</Markup>
15
18
  </Prose>
16
19
  )}
17
- <TreeCards>{children}</TreeCards>
20
+ <TreeCards path={path}>{children}</TreeCards>
18
21
  </Page>
19
22
  );
20
23
  }
@@ -2,7 +2,7 @@ import type { ReactNode } from "react";
2
2
  import type { DocumentationElementProps } from "../../util/element.js";
3
3
  import { type AbsolutePath } from "../../util/path.js";
4
4
  interface DocumentationCardProps extends DocumentationElementProps {
5
- path?: AbsolutePath | undefined;
5
+ path: AbsolutePath;
6
6
  }
7
7
  /** Card renderer for a `tree-documentation` element. */
8
8
  export declare function DocumentationCard({ path, title, name, kind, content, signatures }: DocumentationCardProps): ReactNode;
@@ -2,14 +2,14 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { joinPath } from "../../util/path.js";
3
3
  import { Card } from "../block/Card.js";
4
4
  import { Flex } from "../block/Flex.js";
5
- import { Heading } from "../block/Heading.js";
6
5
  import { Preformatted } from "../block/Preformatted.js";
7
6
  import { Prose } from "../block/Prose.js";
7
+ import { Subheading } from "../block/Subheading.js";
8
8
  import { Code } from "../inline/Code.js";
9
9
  import { Markup } from "../misc/Markup.js";
10
10
  import { DocumentationKind } from "./DocumentationKind.js";
11
11
  /** Card renderer for a `tree-documentation` element. */
12
- export function DocumentationCard({ path = "/", title, name, kind, content, signatures }) {
12
+ export function DocumentationCard({ path, title, name, kind, content, signatures }) {
13
13
  const href = joinPath(path, name);
14
- return (_jsxs(Card, { href: href, children: [_jsx(Heading, { level: "3", children: _jsxs(Flex, { left: true, children: [_jsx(Code, { children: title ?? name }), kind && _jsx(DocumentationKind, { kind: kind })] }) }), signatures?.map(sig => (_jsx(Preformatted, { children: sig }, sig))), content && (_jsx(Prose, { children: _jsx(Markup, { children: content }) }))] }));
14
+ return (_jsxs(Card, { href: href, children: [_jsx(Subheading, { children: _jsxs(Flex, { left: true, children: [_jsx(Code, { children: title ?? name }), kind && _jsx(DocumentationKind, { kind: kind })] }) }), signatures?.map(sig => (_jsx(Preformatted, { children: sig }, sig))), content && (_jsx(Prose, { children: _jsx(Markup, { children: content }) }))] }));
15
15
  }
@@ -3,28 +3,28 @@ import type { DocumentationElementProps } from "../../util/element.js";
3
3
  import { type AbsolutePath, joinPath } from "../../util/path.js";
4
4
  import { Card } from "../block/Card.js";
5
5
  import { Flex } from "../block/Flex.js";
6
- import { Heading } from "../block/Heading.js";
7
6
  import { Preformatted } from "../block/Preformatted.js";
8
7
  import { Prose } from "../block/Prose.js";
8
+ import { Subheading } from "../block/Subheading.js";
9
9
  import { Code } from "../inline/Code.js";
10
10
  import { Markup } from "../misc/Markup.js";
11
11
  import { DocumentationKind } from "./DocumentationKind.js";
12
12
 
13
13
  interface DocumentationCardProps extends DocumentationElementProps {
14
- path?: AbsolutePath | undefined;
14
+ path: AbsolutePath;
15
15
  }
16
16
 
17
17
  /** Card renderer for a `tree-documentation` element. */
18
- export function DocumentationCard({ path = "/", title, name, kind, content, signatures }: DocumentationCardProps): ReactNode {
18
+ export function DocumentationCard({ path, title, name, kind, content, signatures }: DocumentationCardProps): ReactNode {
19
19
  const href = joinPath(path, name);
20
20
  return (
21
21
  <Card href={href}>
22
- <Heading level="3">
22
+ <Subheading>
23
23
  <Flex left>
24
24
  <Code>{title ?? name}</Code>
25
25
  {kind && <DocumentationKind kind={kind} />}
26
26
  </Flex>
27
- </Heading>
27
+ </Subheading>
28
28
  {signatures?.map(sig => (
29
29
  <Preformatted key={sig}>{sig}</Preformatted>
30
30
  ))}
@@ -2,8 +2,8 @@ import type { ReactNode } from "react";
2
2
  import type { FileElementProps } from "../../util/element.js";
3
3
  import { type AbsolutePath } from "../../util/path.js";
4
4
  interface FileCardProps extends FileElementProps {
5
- path?: AbsolutePath | undefined;
5
+ path: AbsolutePath;
6
6
  }
7
7
  /** Card renderer for a `tree-file` element. */
8
- export declare function FileCard({ path, title, name, content }: FileCardProps): ReactNode;
8
+ export declare function FileCard({ path, name, title, content }: FileCardProps): ReactNode;
9
9
  export {};
@@ -1,11 +1,11 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { joinPath } from "../../util/path.js";
3
3
  import { Card } from "../block/Card.js";
4
- import { Heading } from "../block/Heading.js";
5
4
  import { Prose } from "../block/Prose.js";
5
+ import { Subheading } from "../block/Subheading.js";
6
6
  import { Markup } from "../misc/Markup.js";
7
7
  /** Card renderer for a `tree-file` element. */
8
- export function FileCard({ path = "/", title, name, content }) {
8
+ export function FileCard({ path, name, title, content }) {
9
9
  const href = joinPath(path, name);
10
- return (_jsxs(Card, { href: href, children: [_jsx(Heading, { level: "3", children: title ?? name }), content && (_jsx(Prose, { children: _jsx(Markup, { children: content }) }))] }));
10
+ return (_jsxs(Card, { href: href, children: [_jsx(Subheading, { children: title ?? name }), content && (_jsx(Prose, { children: _jsx(Markup, { children: content }) }))] }));
11
11
  }
@@ -2,20 +2,20 @@ import type { ReactNode } from "react";
2
2
  import type { FileElementProps } from "../../util/element.js";
3
3
  import { type AbsolutePath, joinPath } from "../../util/path.js";
4
4
  import { Card } from "../block/Card.js";
5
- import { Heading } from "../block/Heading.js";
6
5
  import { Prose } from "../block/Prose.js";
6
+ import { Subheading } from "../block/Subheading.js";
7
7
  import { Markup } from "../misc/Markup.js";
8
8
 
9
9
  interface FileCardProps extends FileElementProps {
10
- path?: AbsolutePath | undefined;
10
+ path: AbsolutePath;
11
11
  }
12
12
 
13
13
  /** Card renderer for a `tree-file` element. */
14
- export function FileCard({ path = "/", title, name, content }: FileCardProps): ReactNode {
14
+ export function FileCard({ path, name, title, content }: FileCardProps): ReactNode {
15
15
  const href = joinPath(path, name);
16
16
  return (
17
17
  <Card href={href}>
18
- <Heading level="3">{title ?? name}</Heading>
18
+ <Subheading>{title ?? name}</Subheading>
19
19
  {content && (
20
20
  <Prose>
21
21
  <Markup>{content}</Markup>
@@ -7,6 +7,6 @@ import { TreeCards } from "../tree/TreeCards.js";
7
7
  /** Page renderer for a `tree-file` element — shows title, content, and child code symbols. */
8
8
  export function FilePage({ title, name, description, content, children }) {
9
9
  const { url } = requireMeta();
10
- const path = (url?.pathname ?? "/");
10
+ const path = url?.pathname ?? "/";
11
11
  return (_jsxs(Page, { title: title ?? name, description: description, children: [content && (_jsx(Prose, { children: _jsx(Markup, { children: content }) })), _jsx(TreeCards, { path: path, children: children })] }));
12
12
  }
@@ -1,6 +1,5 @@
1
1
  import type { ReactNode } from "react";
2
2
  import type { FileElementProps } from "../../util/element.js";
3
- import type { AbsolutePath } from "../../util/path.js";
4
3
  import { Prose } from "../block/Prose.js";
5
4
  import { Markup } from "../misc/Markup.js";
6
5
  import { requireMeta } from "../misc/MetaContext.js";
@@ -10,7 +9,7 @@ import { TreeCards } from "../tree/TreeCards.js";
10
9
  /** Page renderer for a `tree-file` element — shows title, content, and child code symbols. */
11
10
  export function FilePage({ title, name, description, content, children }: FileElementProps): ReactNode {
12
11
  const { url } = requireMeta();
13
- const path = (url?.pathname ?? "/") as AbsolutePath;
12
+ const path = url?.pathname ?? "/";
14
13
  return (
15
14
  <Page title={title ?? name} description={description}>
16
15
  {content && (
@@ -3,21 +3,21 @@ import { type TreeElements } from "../../util/element.js";
3
3
  import type { AbsolutePath } from "../../util/path.js";
4
4
  /** Extras threaded through `TreeCardMapper` to every card — currently just the parent URL path. */
5
5
  export interface TreeCardExtras {
6
- /** URL path of the parent element. Each card computes its own path as `path + mapped.key`. Defaults to `/`. */
7
- readonly path?: AbsolutePath | undefined;
6
+ /** URL path of the parent element. Each card computes its own path as `path + mapped.name`. Defaults to `/`. */
7
+ readonly path: AbsolutePath;
8
8
  }
9
9
  /** Mapping + Mapper pair for tree cards — wrap children in `<TreeCardMapping>` to override. */
10
10
  export declare const TreeCardMapping: import("react").FunctionComponent<import("../misc/Mapper.js").MappingProps<TreeCardExtras>>, TreeCardMapper: import("react").FunctionComponent<import("../misc/Mapper.js").MapperProps<TreeCardExtras>>;
11
11
  export interface TreeCardsProps {
12
12
  /** The children to render as cards. */
13
13
  readonly children?: TreeElements;
14
- /** URL path of the parent element. Each card appends its own key to compute its href. */
14
+ /** URL path of the parent element. Each card appends its own name to compute its href. */
15
15
  readonly path?: AbsolutePath | undefined;
16
16
  }
17
17
  /**
18
18
  * Render a list of tree elements as a stack of cards.
19
19
  * - Each element is dispatched via `<TreeCardMapper>` to its registered renderer.
20
- * - `path` is threaded through to each card so it can compute its href as `path + key`.
20
+ * - `path` is threaded through to each card so it can compute its href as `path + name`.
21
21
  * - To override the renderer for a specific element type, wrap in `<TreeCardMapping mapping={…}>`.
22
22
  */
23
- export declare function TreeCards({ children, path }: TreeCardsProps): ReactNode;
23
+ export declare function TreeCards({ path, children }: TreeCardsProps): ReactNode;
@@ -13,9 +13,9 @@ export const [TreeCardMapping, TreeCardMapper] = createMapper({
13
13
  /**
14
14
  * Render a list of tree elements as a stack of cards.
15
15
  * - Each element is dispatched via `<TreeCardMapper>` to its registered renderer.
16
- * - `path` is threaded through to each card so it can compute its href as `path + key`.
16
+ * - `path` is threaded through to each card so it can compute its href as `path + name`.
17
17
  * - To override the renderer for a specific element type, wrap in `<TreeCardMapping mapping={…}>`.
18
18
  */
19
- export function TreeCards({ children, path }) {
19
+ export function TreeCards({ path = "/", children }) {
20
20
  return _jsx(TreeCardMapper, { path: path, children: walkElements(children) });
21
21
  }
@@ -8,8 +8,8 @@ import { createMapper } from "../misc/Mapper.js";
8
8
 
9
9
  /** Extras threaded through `TreeCardMapper` to every card — currently just the parent URL path. */
10
10
  export interface TreeCardExtras {
11
- /** URL path of the parent element. Each card computes its own path as `path + mapped.key`. Defaults to `/`. */
12
- readonly path?: AbsolutePath | undefined;
11
+ /** URL path of the parent element. Each card computes its own path as `path + mapped.name`. Defaults to `/`. */
12
+ readonly path: AbsolutePath;
13
13
  }
14
14
 
15
15
  /** Mapping + Mapper pair for tree cards — wrap children in `<TreeCardMapping>` to override. */
@@ -22,16 +22,16 @@ export const [TreeCardMapping, TreeCardMapper] = createMapper<TreeCardExtras>({
22
22
  export interface TreeCardsProps {
23
23
  /** The children to render as cards. */
24
24
  readonly children?: TreeElements;
25
- /** URL path of the parent element. Each card appends its own key to compute its href. */
25
+ /** URL path of the parent element. Each card appends its own name to compute its href. */
26
26
  readonly path?: AbsolutePath | undefined;
27
27
  }
28
28
 
29
29
  /**
30
30
  * Render a list of tree elements as a stack of cards.
31
31
  * - Each element is dispatched via `<TreeCardMapper>` to its registered renderer.
32
- * - `path` is threaded through to each card so it can compute its href as `path + key`.
32
+ * - `path` is threaded through to each card so it can compute its href as `path + name`.
33
33
  * - To override the renderer for a specific element type, wrap in `<TreeCardMapping mapping={…}>`.
34
34
  */
35
- export function TreeCards({ children, path }: TreeCardsProps): ReactNode {
35
+ export function TreeCards({ path = "/", children }: TreeCardsProps): ReactNode {
36
36
  return <TreeCardMapper path={path}>{walkElements(children)}</TreeCardMapper>;
37
37
  }
@@ -9,7 +9,7 @@ export declare const MENU_QUERY: Query<{
9
9
  /** Extras threaded through `TreeMenuMapper` to every menu item — the parent's URL path. */
10
10
  interface TreeMenuExtras {
11
11
  /** URL path of the parent element. Each item appends its own `name` to compute its own path. Defaults to `/`. */
12
- readonly path?: AbsolutePath | undefined;
12
+ readonly path: AbsolutePath;
13
13
  }
14
14
  /**
15
15
  * Default menu item renderer for any `tree-*` element.
@@ -31,5 +31,5 @@ export interface TreeMenuProps {
31
31
  * - To customise renderers for specific types, wrap in `<TreeMenuMapping mapping={…}>`.
32
32
  * - Only directories and files appear — code symbols are kept off the navigation.
33
33
  */
34
- export declare function TreeMenu({ tree, path }: TreeMenuProps): ReactNode;
34
+ export declare function TreeMenu({ path, tree }: TreeMenuProps): ReactNode;
35
35
  export {};
@@ -27,6 +27,6 @@ export const [TreeMenuMapping, TreeMenuMapper] = createMapper({
27
27
  * - To customise renderers for specific types, wrap in `<TreeMenuMapping mapping={…}>`.
28
28
  * - Only directories and files appear — code symbols are kept off the navigation.
29
29
  */
30
- export function TreeMenu({ tree, path = "/" }) {
30
+ export function TreeMenu({ path = "/", tree }) {
31
31
  return (_jsx(Menu, { children: _jsx(TreeMenuMapper, { path: path, children: queryElements(tree.props.children, MENU_QUERY) }) }));
32
32
  }
@@ -12,7 +12,7 @@ export const MENU_QUERY: Query<{ type: string }> = { type: ["tree-directory", "t
12
12
  /** Extras threaded through `TreeMenuMapper` to every menu item — the parent's URL path. */
13
13
  interface TreeMenuExtras {
14
14
  /** URL path of the parent element. Each item appends its own `name` to compute its own path. Defaults to `/`. */
15
- readonly path?: AbsolutePath | undefined;
15
+ readonly path: AbsolutePath;
16
16
  }
17
17
 
18
18
  /**
@@ -54,7 +54,7 @@ export interface TreeMenuProps {
54
54
  * - To customise renderers for specific types, wrap in `<TreeMenuMapping mapping={…}>`.
55
55
  * - Only directories and files appear — code symbols are kept off the navigation.
56
56
  */
57
- export function TreeMenu({ tree, path = "/" }: TreeMenuProps): ReactNode {
57
+ export function TreeMenu({ path = "/", tree }: TreeMenuProps): ReactNode {
58
58
  return (
59
59
  <Menu>
60
60
  <TreeMenuMapper path={path}>{queryElements(tree.props.children, MENU_QUERY)}</TreeMenuMapper>