shelving 1.222.1 → 1.222.3

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.
@@ -2,9 +2,11 @@ import { type FileElementProps } from "../util/element.js";
2
2
  import { FileExtractor } from "./FileExtractor.js";
3
3
  /**
4
4
  * File extractor for Markdown files.
5
- * - Stores the raw markdown text as `content`; rendering happens at output time via `<Markup>`.
5
+ * - Stores the markdown text as `content`; rendering happens at output time via `<Markup>`.
6
6
  * - Sets `title` from the first `# h1` heading if one is present — otherwise leaves it undefined
7
7
  * (a confident title only).
8
+ * - When a `title` is found, strips the leading `# h1` from `content` so renderers (which show
9
+ * `title` separately) don't display the heading twice.
8
10
  * - Sets `description` to the first prose paragraph as a plain-text summary (used for card listings and `<meta>`).
9
11
  */
10
12
  export declare class MarkupExtractor extends FileExtractor {
@@ -3,9 +3,11 @@ import { getElementText, walkElements } from "../util/element.js";
3
3
  import { FileExtractor } from "./FileExtractor.js";
4
4
  /**
5
5
  * File extractor for Markdown files.
6
- * - Stores the raw markdown text as `content`; rendering happens at output time via `<Markup>`.
6
+ * - Stores the markdown text as `content`; rendering happens at output time via `<Markup>`.
7
7
  * - Sets `title` from the first `# h1` heading if one is present — otherwise leaves it undefined
8
8
  * (a confident title only).
9
+ * - When a `title` is found, strips the leading `# h1` from `content` so renderers (which show
10
+ * `title` separately) don't display the heading twice.
9
11
  * - Sets `description` to the first prose paragraph as a plain-text summary (used for card listings and `<meta>`).
10
12
  */
11
13
  export class MarkupExtractor extends FileExtractor {
@@ -13,7 +15,8 @@ export class MarkupExtractor extends FileExtractor {
13
15
  priority = 10;
14
16
  extractProps(name, text) {
15
17
  const { title, description } = extractMarkdownProps(text);
16
- return { name, title, description, content: text };
18
+ // The title `# h1` is surfaced separately as `title`, so strip it from the body to avoid rendering it twice.
19
+ return { name, title, description, content: title ? _stripTitle(text) : text };
17
20
  }
18
21
  }
19
22
  /**
@@ -43,3 +46,7 @@ export function extractMarkdownProps(text) {
43
46
  function _plain(element) {
44
47
  return getElementText(element).replace(/\s+/g, " ").trim() || undefined;
45
48
  }
49
+ /** Strip a leading `# h1` heading (and any blank lines after it) from markdown text. */
50
+ function _stripTitle(text) {
51
+ return text.replace(/^\s*#[^\n\S]+\S[^\n]*(?:\n+|$)/, "");
52
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shelving",
3
- "version": "1.222.1",
3
+ "version": "1.222.3",
4
4
  "author": "Dave Houlbrooke <dave@shax.com>",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Prose } from "../block/Prose.js";
3
+ import { Title } from "../block/Title.js";
3
4
  import { Markup } from "../misc/Markup.js";
4
5
  import { requireMeta } from "../misc/MetaContext.js";
5
6
  import { Page } from "../page/Page.js";
@@ -8,5 +9,5 @@ import { TreeCards } from "../tree/TreeCards.js";
8
9
  export function DirectoryPage({ title, name, description, content, children }) {
9
10
  const { url } = requireMeta();
10
11
  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 })] }));
12
+ return (_jsxs(Page, { title: title ?? name, description: description, children: [_jsx(Title, { children: title ?? name }), content && (_jsx(Prose, { children: _jsx(Markup, { children: content }) })), _jsx(TreeCards, { path: path, children: children })] }));
12
13
  }
@@ -1,6 +1,7 @@
1
1
  import type { ReactNode } from "react";
2
2
  import type { DirectoryElementProps } from "../../util/element.js";
3
3
  import { Prose } from "../block/Prose.js";
4
+ import { Title } from "../block/Title.js";
4
5
  import { Markup } from "../misc/Markup.js";
5
6
  import { requireMeta } from "../misc/MetaContext.js";
6
7
  import { Page } from "../page/Page.js";
@@ -12,6 +13,7 @@ export function DirectoryPage({ title, name, description, content, children }: D
12
13
  const path = url?.pathname ?? "/";
13
14
  return (
14
15
  <Page title={title ?? name} description={description}>
16
+ <Title>{title ?? name}</Title>
15
17
  {content && (
16
18
  <Prose>
17
19
  <Markup>{content}</Markup>
@@ -10,5 +10,5 @@ import { DocumentationKind } from "./DocumentationKind.js";
10
10
  /** Card renderer for a `tree-documentation` element — a summary card showing the heading, signatures, and description. */
11
11
  export function DocumentationCard({ path, title, name, kind, description, signatures }) {
12
12
  const href = joinPath(path, name);
13
- 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))), description && _jsx(Paragraph, { children: description })] }));
13
+ return (_jsxs(Card, { href: href, children: [_jsx(Subheading, { children: _jsxs(Flex, { left: true, wrap: true, children: [_jsx(Code, { children: title ?? name }), kind && _jsx(DocumentationKind, { kind: kind })] }) }), signatures?.map(sig => (_jsx(Preformatted, { children: sig }, sig))), description && _jsx(Paragraph, { children: description })] }));
14
14
  }
@@ -19,7 +19,7 @@ export function DocumentationCard({ path, title, name, kind, description, signat
19
19
  return (
20
20
  <Card href={href}>
21
21
  <Subheading>
22
- <Flex left>
22
+ <Flex left wrap>
23
23
  <Code>{title ?? name}</Code>
24
24
  {kind && <DocumentationKind kind={kind} />}
25
25
  </Flex>
@@ -33,7 +33,7 @@ const KIND_SECTIONS = [
33
33
  export function DocumentationPage({ title, name, kind, description, content, signatures, params, returns, throws, examples, children, }) {
34
34
  const { url } = requireMeta();
35
35
  const path = (url?.pathname ?? "/");
36
- return (_jsxs(Page, { title: title ?? name, description: description, children: [_jsx(Title, { children: _jsxs(Flex, { left: true, children: [title ?? name, kind && _jsx(DocumentationKind, { kind: kind })] }) }), signatures?.map(sig => (_jsx(Preformatted, { children: sig }, sig))), content && (_jsx(Prose, { children: _jsx(Markup, { children: content }) })), params?.length && (_jsxs(Section, { children: [_jsx(Heading, { children: "Parameters" }), _jsx(Definitions, { row: true, children: params.map(({ name, type = DEFAULT_TYPE, description = "", optional }) => (_jsx(Definition, { term: _jsxs(_Fragment, { children: [_jsx(Code, { children: name }), ": ", _jsx(Code, { children: type }), optional && _jsx(_Fragment, { children: " (optional)" })] }), children: description }, `${name}-${type}-${description}`))) })] })), returns?.length && (_jsxs(Section, { children: [_jsx(Heading, { children: "Returns" }), _jsx(Definitions, { row: true, children: returns.map(({ type = DEFAULT_TYPE, description = "" }) => (_jsx(Definition, { term: _jsx(Code, { children: type }), children: description }, `${type}-${description}`))) })] })), throws?.length && (_jsxs(Section, { children: [_jsx(Heading, { children: "Throws" }), _jsx(Definitions, { row: true, children: throws.map(({ type = DEFAULT_TYPE, description = "" }) => (_jsx(Definition, { term: _jsx(Code, { children: type }), children: description }, `${type}-${description}`))) })] })), examples?.length && (_jsxs(Section, { children: [_jsx(Heading, { children: "Examples" }), examples.map(({ description }) => (_jsx(Preformatted, { children: description }, description)))] })), KIND_SECTIONS.map(([kind, label]) => {
36
+ return (_jsxs(Page, { title: title ?? name, description: description, children: [_jsx(Title, { children: _jsxs(Flex, { left: true, wrap: true, children: [title ?? name, kind && _jsx(DocumentationKind, { kind: kind })] }) }), signatures?.map(sig => (_jsx(Preformatted, { children: sig }, sig))), content && (_jsx(Prose, { children: _jsx(Markup, { children: content }) })), params?.length && (_jsxs(Section, { children: [_jsx(Heading, { children: "Parameters" }), _jsx(Definitions, { row: true, children: params.map(({ name, type = DEFAULT_TYPE, description = "", optional }) => (_jsx(Definition, { term: _jsxs(_Fragment, { children: [_jsx(Code, { children: name }), ": ", _jsx(Code, { children: type }), optional && _jsx(_Fragment, { children: " (optional)" })] }), children: description }, `${name}-${type}-${description}`))) })] })), returns?.length && (_jsxs(Section, { children: [_jsx(Heading, { children: "Returns" }), _jsx(Definitions, { row: true, children: returns.map(({ type = DEFAULT_TYPE, description = "" }) => (_jsx(Definition, { term: _jsx(Code, { children: type }), children: description }, `${type}-${description}`))) })] })), throws?.length && (_jsxs(Section, { children: [_jsx(Heading, { children: "Throws" }), _jsx(Definitions, { row: true, children: throws.map(({ type = DEFAULT_TYPE, description = "" }) => (_jsx(Definition, { term: _jsx(Code, { children: type }), children: description }, `${type}-${description}`))) })] })), examples?.length && (_jsxs(Section, { children: [_jsx(Heading, { children: "Examples" }), examples.map(({ description }) => (_jsx(Preformatted, { children: description }, description)))] })), KIND_SECTIONS.map(([kind, label]) => {
37
37
  // Pre-filter the children for this kind; only render the section when it has cards.
38
38
  const group = Array.from(queryElements(children, { "props.kind": kind }));
39
39
  return group.length ? (_jsxs(Section, { children: [_jsx(Heading, { children: label }), _jsx(TreeCards, { path: path, children: group })] }, kind)) : null;
@@ -53,7 +53,7 @@ export function DocumentationPage({
53
53
  return (
54
54
  <Page title={title ?? name} description={description}>
55
55
  <Title>
56
- <Flex left>
56
+ <Flex left wrap>
57
57
  {title ?? name}
58
58
  {kind && <DocumentationKind kind={kind} />}
59
59
  </Flex>
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Prose } from "../block/Prose.js";
3
+ import { Title } from "../block/Title.js";
3
4
  import { Markup } from "../misc/Markup.js";
4
5
  import { requireMeta } from "../misc/MetaContext.js";
5
6
  import { Page } from "../page/Page.js";
@@ -8,5 +9,5 @@ import { TreeCards } from "../tree/TreeCards.js";
8
9
  export function FilePage({ title, name, description, content, children }) {
9
10
  const { url } = requireMeta();
10
11
  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 })] }));
12
+ return (_jsxs(Page, { title: title ?? name, description: description, children: [_jsx(Title, { children: title ?? name }), content && (_jsx(Prose, { children: _jsx(Markup, { children: content }) })), _jsx(TreeCards, { path: path, children: children })] }));
12
13
  }
@@ -1,6 +1,7 @@
1
1
  import type { ReactNode } from "react";
2
2
  import type { FileElementProps } from "../../util/element.js";
3
3
  import { Prose } from "../block/Prose.js";
4
+ import { Title } from "../block/Title.js";
4
5
  import { Markup } from "../misc/Markup.js";
5
6
  import { requireMeta } from "../misc/MetaContext.js";
6
7
  import { Page } from "../page/Page.js";
@@ -12,6 +13,7 @@ export function FilePage({ title, name, description, content, children }: FileEl
12
13
  const path = url?.pathname ?? "/";
13
14
  return (
14
15
  <Page title={title ?? name} description={description}>
16
+ <Title>{title ?? name}</Title>
15
17
  {content && (
16
18
  <Prose>
17
19
  <Markup>{content}</Markup>
@@ -1,5 +1,11 @@
1
1
  .tag {
2
2
  display: inline-block;
3
+ flex: 0 0 fit-content; /* Content-width; never grow or shrink, like icons. */
4
+ /* Truncate overlong text instead of overflowing the container. */
5
+ max-width: 100%;
6
+ overflow: hidden;
7
+ text-overflow: ellipsis;
8
+ white-space: nowrap;
3
9
  padding: 0 var(--space-xxsmall);
4
10
  border: 0;
5
11
  border-radius: var(--radius-xxsmall);
package/util/element.d.ts CHANGED
@@ -41,7 +41,7 @@ export interface TreeElementProps extends ElementProps {
41
41
  /**
42
42
  * Markup source string that should be rendered as the element's visible body content.
43
43
  * - Rendered via the `<Markup>` component (typically inside a `<Prose>` wrapper).
44
- * - For Markdown files this is the file's text; for TypeScript symbols this is the JSDoc description.
44
+ * - For Markdown files this is the file's body (the title `# h1` is lifted into `title`); for TypeScript symbols this is the JSDoc description.
45
45
  */
46
46
  readonly content?: string | undefined;
47
47
  /** Children of a tree element must be other tree elements. */