shelving 1.242.1 → 1.244.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/extract/TypescriptExtractor.js +7 -5
  2. package/package.json +1 -1
  3. package/ui/README.md +1 -1
  4. package/ui/app/App.md +1 -1
  5. package/ui/block/Block.d.ts +1 -1
  6. package/ui/block/Block.js +1 -1
  7. package/ui/block/Block.tsx +1 -1
  8. package/ui/block/Card.js +1 -1
  9. package/ui/block/Card.tsx +3 -1
  10. package/ui/block/Image.d.ts +1 -1
  11. package/ui/block/Image.js +1 -1
  12. package/ui/block/Image.tsx +1 -1
  13. package/ui/block/Panel.d.ts +1 -1
  14. package/ui/block/Panel.js +1 -1
  15. package/ui/block/Panel.md +3 -3
  16. package/ui/block/Panel.tsx +1 -1
  17. package/ui/block/Prose.js +2 -2
  18. package/ui/block/Prose.tsx +25 -25
  19. package/ui/block/Section.d.ts +1 -1
  20. package/ui/block/Section.js +1 -1
  21. package/ui/block/Section.md +4 -4
  22. package/ui/block/Section.module.css +2 -1
  23. package/ui/block/Section.tsx +1 -1
  24. package/ui/block/Table.d.ts +4 -3
  25. package/ui/block/Table.js +4 -3
  26. package/ui/block/Table.md +1 -0
  27. package/ui/block/Table.module.css +1 -0
  28. package/ui/block/Table.tsx +6 -4
  29. package/ui/block/Title.md +1 -1
  30. package/ui/dialog/Dialog.js +1 -1
  31. package/ui/dialog/Dialog.tsx +2 -2
  32. package/ui/dialog/Modal.js +2 -1
  33. package/ui/dialog/Modal.tsx +2 -1
  34. package/ui/docs/DocumentationHomePage.js +1 -1
  35. package/ui/docs/DocumentationHomePage.tsx +2 -2
  36. package/ui/docs/DocumentationPage.d.ts +1 -1
  37. package/ui/docs/DocumentationPage.js +4 -5
  38. package/ui/docs/DocumentationPage.md +1 -1
  39. package/ui/docs/DocumentationPage.test.tsx +26 -0
  40. package/ui/docs/DocumentationPage.tsx +77 -47
  41. package/ui/form/ButtonInput.js +2 -2
  42. package/ui/form/ButtonInput.tsx +7 -2
  43. package/ui/form/CheckboxInput.js +2 -2
  44. package/ui/form/CheckboxInput.tsx +8 -3
  45. package/ui/form/DateInput.js +2 -2
  46. package/ui/form/DateInput.tsx +2 -2
  47. package/ui/form/Field.js +2 -2
  48. package/ui/form/Field.tsx +4 -4
  49. package/ui/form/Form.js +2 -1
  50. package/ui/form/Form.tsx +3 -2
  51. package/ui/form/Input.d.ts +3 -3
  52. package/ui/form/Input.js +4 -4
  53. package/ui/form/Input.tsx +6 -6
  54. package/ui/form/NumberInput.js +2 -2
  55. package/ui/form/NumberInput.tsx +2 -2
  56. package/ui/form/OutputInput.js +2 -2
  57. package/ui/form/OutputInput.tsx +5 -2
  58. package/ui/form/Popover.js +3 -2
  59. package/ui/form/Popover.tsx +3 -2
  60. package/ui/form/Progress.js +3 -3
  61. package/ui/form/Progress.tsx +15 -5
  62. package/ui/form/RadioInput.js +2 -2
  63. package/ui/form/RadioInput.tsx +10 -3
  64. package/ui/form/SelectInput.js +2 -2
  65. package/ui/form/SelectInput.tsx +4 -4
  66. package/ui/form/TextInput.js +3 -3
  67. package/ui/form/TextInput.tsx +3 -3
  68. package/ui/layout/CenteredLayout.js +2 -2
  69. package/ui/layout/CenteredLayout.md +1 -1
  70. package/ui/layout/CenteredLayout.tsx +3 -3
  71. package/ui/layout/SidebarLayout.js +5 -5
  72. package/ui/layout/SidebarLayout.tsx +16 -7
  73. package/ui/misc/Loading.js +2 -1
  74. package/ui/misc/Loading.tsx +10 -3
  75. package/ui/notice/Message.js +2 -2
  76. package/ui/notice/Message.tsx +2 -2
  77. package/ui/style/Scroll.d.ts +3 -4
  78. package/ui/style/Scroll.js +1 -1
  79. package/ui/style/Scroll.tsx +3 -4
  80. package/ui/style/Width.d.ts +17 -20
  81. package/ui/style/Width.js +6 -6
  82. package/ui/style/Width.module.css +7 -2
  83. package/ui/style/Width.tsx +18 -21
  84. package/ui/style/getWidthClass.md +5 -4
  85. package/ui/tree/TreeIndexPage.js +1 -1
  86. package/ui/tree/TreeIndexPage.tsx +4 -4
  87. package/ui/tree/TreePage.js +1 -1
  88. package/ui/tree/TreePage.tsx +3 -3
  89. package/util/tree.d.ts +2 -0
@@ -56,9 +56,9 @@ function _mergeOverloads(existing, next) {
56
56
  // Keep first content encountered; fill in if `existing` had none.
57
57
  content: a.content ?? b.content,
58
58
  // Append incoming entries, skipping any already present (by field identity), preserving insertion order.
59
- // Identity: signatures/examples/throws by rendered string; params by (name, type, description, optional); returns by (type, description).
59
+ // Identity: signatures/examples/throws by rendered string; params by (name, type, description, optional, default); returns by (type, description).
60
60
  signatures: _concatUnique(a.signatures, b.signatures, s => s),
61
- params: _concatUnique(a.params, b.params, p => `${p.name}\0${p.type}\0${p.description}\0${p.optional}`),
61
+ params: _concatUnique(a.params, b.params, p => `${p.name}\0${p.type}\0${p.description}\0${p.optional}\0${p.default}`),
62
62
  returns: _concatUnique(a.returns, b.returns, r => `${r.type}\0${r.description}`),
63
63
  throws: _concatUnique(a.throws, b.throws, t => `${t.type}\0${t.description}`),
64
64
  examples: _concatUnique(a.examples, b.examples, e => e.description ?? ""),
@@ -260,7 +260,8 @@ function _getParams(statement, source, jsDocParams) {
260
260
  const type = p.type?.getText(source);
261
261
  const optional = !!p.questionToken || !!p.initializer;
262
262
  const description = jsDocParams?.find(d => d.name === name)?.description;
263
- return { name, type, description, optional };
263
+ const def = p.initializer?.getText(source);
264
+ return { name, type, description, optional, default: def };
264
265
  });
265
266
  return params.length ? params : undefined;
266
267
  }
@@ -279,9 +280,10 @@ function _getConstructorParams(statement, source, classJsDocParams) {
279
280
  const optional = !!p.questionToken || !!p.initializer;
280
281
  // Constructor-level `@param` wins over the class-level `@param` on collision.
281
282
  const description = ctorJsDocParams?.find(d => d.name === name)?.description ?? classJsDocParams?.find(d => d.name === name)?.description;
282
- return { name, type, description, optional };
283
+ const def = p.initializer?.getText(source);
284
+ return { name, type, description, optional, default: def };
283
285
  });
284
- params = _concatUnique(params, next, p => `${p.name}\0${p.type}\0${p.description}\0${p.optional}`);
286
+ params = _concatUnique(params, next, p => `${p.name}\0${p.type}\0${p.description}\0${p.optional}\0${p.default}`);
285
287
  }
286
288
  return params?.length ? params : undefined;
287
289
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shelving",
3
- "version": "1.242.1",
3
+ "version": "1.244.0",
4
4
  "author": "Dave Houlbrooke <dave@shax.com>",
5
5
  "repository": {
6
6
  "type": "git",
package/ui/README.md CHANGED
@@ -10,7 +10,7 @@ The `ui` module exists so an app never hand-rolls the same form field, card, or
10
10
 
11
11
  A few conventions run through every component:
12
12
 
13
- - **Styling props are for one-off overrides.** 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. Reach for them when a component needs to look different in *one place* — the way the docs site tints its accents purple — not as the way to dress a whole app. You never pass `style` or raw `className`.
13
+ - **Styling props are for one-off overrides.** Visual options are props on the component — enumerated props for the scales (`color="red"`, `size="large"`, `space="none"`, `width="narrow"`) and boolean props for on/off variants (`<Button strong>`, `<Title center>`, `<Flex wrap>`). Each maps to a class in a CSS Module. Reach for them when a component needs to look different in *one place* — the way the docs site tints its accents purple — not as the way to dress a whole app. You never pass `style` or raw `className`.
14
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
  - **Theme with CSS.** An app-wide custom look is a CSS file, not a wall of props. Write a `theme.css` that overrides the base design-token variables (and, where needed, per-component hooks) at `:root`, and import it after the library styles. The recommended workflow is to spend time tuning those variables to match your design — see [Theming](#theming) below.
package/ui/app/App.md CHANGED
@@ -15,7 +15,7 @@ function HelloApp() {
15
15
  return (
16
16
  <App app="My app">
17
17
  <CenteredLayout>
18
- <Section narrow>
18
+ <Section width="narrow">
19
19
  <Title>Hello</Title>
20
20
  <Paragraph>Welcome to the app.</Paragraph>
21
21
  </Section>
@@ -34,7 +34,7 @@ export declare function getBlockClass(variants: BlockProps): string;
34
34
  * - Pass `as` to render a different semantic element (`section`, `header`, `footer`, `nav`, `aside`, `figure`).
35
35
  *
36
36
  * @example <Block><Paragraph>Hello</Paragraph></Block>
37
- * @example <Block as="aside" narrow><Paragraph>Sidebar</Paragraph></Block>
37
+ * @example <Block as="aside" width="narrow"><Paragraph>Sidebar</Paragraph></Block>
38
38
  * @see https://dhoulb.github.io/shelving/ui/block/Block/Block
39
39
  */
40
40
  export declare function Block({ as: Component, children, ...props }: BlockProps): ReactElement;
package/ui/block/Block.js CHANGED
@@ -25,7 +25,7 @@ export function getBlockClass(variants) {
25
25
  * - Pass `as` to render a different semantic element (`section`, `header`, `footer`, `nav`, `aside`, `figure`).
26
26
  *
27
27
  * @example <Block><Paragraph>Hello</Paragraph></Block>
28
- * @example <Block as="aside" narrow><Paragraph>Sidebar</Paragraph></Block>
28
+ * @example <Block as="aside" width="narrow"><Paragraph>Sidebar</Paragraph></Block>
29
29
  * @see https://dhoulb.github.io/shelving/ui/block/Block/Block
30
30
  */
31
31
  export function Block({ as: Component = "div", children, ...props }) {
@@ -52,7 +52,7 @@ export function getBlockClass(variants: BlockProps): string {
52
52
  * - Pass `as` to render a different semantic element (`section`, `header`, `footer`, `nav`, `aside`, `figure`).
53
53
  *
54
54
  * @example <Block><Paragraph>Hello</Paragraph></Block>
55
- * @example <Block as="aside" narrow><Paragraph>Sidebar</Paragraph></Block>
55
+ * @example <Block as="aside" width="narrow"><Paragraph>Sidebar</Paragraph></Block>
56
56
  * @see https://dhoulb.github.io/shelving/ui/block/Block/Block
57
57
  */
58
58
  export function Block({ as: Component = "div", children, ...props }: BlockProps): ReactElement {
package/ui/block/Card.js CHANGED
@@ -21,6 +21,6 @@ import CARD_CSS from "./Card.module.css";
21
21
  * @see https://dhoulb.github.io/shelving/ui/block/Card/Card
22
22
  */
23
23
  export function Card({ children, href, onClick, title = "Open", ...props }) {
24
- const overlay = (href || onClick) && _jsx(Clickable, { title: title, href: href, onClick: onClick, ...props, className: CARD_CSS.overlay });
24
+ const overlay = (href || onClick) && (_jsx(Clickable, { title: title, href: href, onClick: onClick, ...props, className: getModuleClass(CARD_CSS, "overlay") }));
25
25
  return (_jsxs("article", { className: getClass(getModuleClass(CARD_CSS, "card"), getStatusClass(props), getColorClass(props), getPaddingClass(props), getSpaceClass(props), getTypographyClass(props), getWidthClass(props)), children: [overlay, overlay ? _jsx("div", { children: children }) : children] }));
26
26
  }
package/ui/block/Card.tsx CHANGED
@@ -36,7 +36,9 @@ export interface CardProps
36
36
  * @see https://dhoulb.github.io/shelving/ui/block/Card/Card
37
37
  */
38
38
  export function Card({ children, href, onClick, title = "Open", ...props }: CardProps): ReactElement {
39
- const overlay = (href || onClick) && <Clickable title={title} href={href} onClick={onClick} {...props} className={CARD_CSS.overlay} />;
39
+ const overlay = (href || onClick) && (
40
+ <Clickable title={title} href={href} onClick={onClick} {...props} className={getModuleClass(CARD_CSS, "overlay")} />
41
+ );
40
42
  return (
41
43
  <article
42
44
  className={getClass(
@@ -15,7 +15,7 @@ export interface ImageProps extends SpaceVariants, WidthVariants {
15
15
  *
16
16
  * @param props The image `src`, optional `alt` text, plus space and width variants.
17
17
  * @returns Rendered `<img>` element.
18
- * @example <Image src="/logo.png" alt="Logo" width="medium" />
18
+ * @example <Image src="/logo.png" alt="Logo" width="narrow" />
19
19
  * @see https://dhoulb.github.io/shelving/ui/block/Image/Image
20
20
  */
21
21
  export declare function Image({ src, alt, ...variants }: ImageProps): ReactElement;
package/ui/block/Image.js CHANGED
@@ -9,7 +9,7 @@ const IMAGE_CLASS = getModuleClass(styles, "image");
9
9
  *
10
10
  * @param props The image `src`, optional `alt` text, plus space and width variants.
11
11
  * @returns Rendered `<img>` element.
12
- * @example <Image src="/logo.png" alt="Logo" width="medium" />
12
+ * @example <Image src="/logo.png" alt="Logo" width="narrow" />
13
13
  * @see https://dhoulb.github.io/shelving/ui/block/Image/Image
14
14
  */
15
15
  export function Image({ src, alt, ...variants }) {
@@ -21,7 +21,7 @@ export interface ImageProps extends SpaceVariants, WidthVariants {
21
21
  *
22
22
  * @param props The image `src`, optional `alt` text, plus space and width variants.
23
23
  * @returns Rendered `<img>` element.
24
- * @example <Image src="/logo.png" alt="Logo" width="medium" />
24
+ * @example <Image src="/logo.png" alt="Logo" width="narrow" />
25
25
  * @see https://dhoulb.github.io/shelving/ui/block/Image/Image
26
26
  */
27
27
  export function Image({ src, alt, ...variants }: ImageProps): ReactElement {
@@ -27,7 +27,7 @@ export interface PanelProps extends ColorVariants, PaddingVariants, StatusVarian
27
27
  * @kind component
28
28
  * @param props Colour, padding, status, and typography variants plus `children`.
29
29
  * @returns Rendered full-width panel region.
30
- * @example <Panel><Block narrow><Title>Welcome</Title></Block></Panel>
30
+ * @example <Panel><Block width="narrow"><Title>Welcome</Title></Block></Panel>
31
31
  * @example <Panel padding="xlarge" color="primary"><Title>Welcome</Title></Panel>
32
32
  * @see https://dhoulb.github.io/shelving/ui/block/Panel/Panel
33
33
  */
package/ui/block/Panel.js CHANGED
@@ -16,7 +16,7 @@ const PANEL_CLASS = getModuleClass(PANEL_CSS, "panel");
16
16
  * @kind component
17
17
  * @param props Colour, padding, status, and typography variants plus `children`.
18
18
  * @returns Rendered full-width panel region.
19
- * @example <Panel><Block narrow><Title>Welcome</Title></Block></Panel>
19
+ * @example <Panel><Block width="narrow"><Title>Welcome</Title></Block></Panel>
20
20
  * @example <Panel padding="xlarge" color="primary"><Title>Welcome</Title></Panel>
21
21
  * @see https://dhoulb.github.io/shelving/ui/block/Panel/Panel
22
22
  */
package/ui/block/Panel.md CHANGED
@@ -4,7 +4,7 @@ A full-width vertical region that paints the current surface colour. Use panels
4
4
 
5
5
  **Things to know:**
6
6
 
7
- - A panel always spans the full width of its container. To constrain the content inside, compose a [`Block`](/ui/Block) `narrow` (or `wide`) within it.
7
+ - A panel always spans the full width of its container. To constrain the content inside, compose a [`Block`](/ui/Block) `width="narrow"` (or `width="wide"`) within it.
8
8
  - Block margin is always zero so panels stack flush; control the vertical breathing room with the `padding` variant (`<Panel padding="large">`, `<Panel padding="none">`). Inline padding is fixed.
9
9
  - `color=` / `status=` move the tint anchor for the whole panel scope, so the surface, border, and text re-derive together and cascade into nested content.
10
10
  - The top and bottom borders are dropped on the first and last panel so the page doesn't gain stray edge lines.
@@ -17,12 +17,12 @@ A full-width vertical region that paints the current surface colour. Use panels
17
17
  import { Panel, Block, Title, Paragraph } from "shelving/ui";
18
18
 
19
19
  <Panel as="header" color="primary">
20
- <Block narrow>
20
+ <Block width="narrow">
21
21
  <Title>Welcome</Title>
22
22
  </Block>
23
23
  </Panel>
24
24
  <Panel padding="large">
25
- <Block narrow>
25
+ <Block width="narrow">
26
26
  <Paragraph>Each panel is a full-width band; the inner block constrains the content.</Paragraph>
27
27
  </Block>
28
28
  </Panel>
@@ -33,7 +33,7 @@ export interface PanelProps extends ColorVariants, PaddingVariants, StatusVarian
33
33
  * @kind component
34
34
  * @param props Colour, padding, status, and typography variants plus `children`.
35
35
  * @returns Rendered full-width panel region.
36
- * @example <Panel><Block narrow><Title>Welcome</Title></Block></Panel>
36
+ * @example <Panel><Block width="narrow"><Title>Welcome</Title></Block></Panel>
37
37
  * @example <Panel padding="xlarge" color="primary"><Title>Welcome</Title></Panel>
38
38
  * @see https://dhoulb.github.io/shelving/ui/block/Panel/Panel
39
39
  */
package/ui/block/Prose.js CHANGED
@@ -9,7 +9,7 @@ import SMALL_CSS from "../inline/Small.module.css";
9
9
  import STRONG_CSS from "../inline/Strong.module.css";
10
10
  import SUBSCRIPT_CSS from "../inline/Subscript.module.css";
11
11
  import SUPERSCRIPT_CSS from "../inline/Superscript.module.css";
12
- import { getClass } from "../util/css.js";
12
+ import { getClass, getModuleClass } from "../util/css.js";
13
13
  import ADDRESS_CSS from "./Address.module.css";
14
14
  import BLOCKQUOTE_CSS from "./Blockquote.module.css";
15
15
  import CAPTION_CSS from "./Caption.module.css";
@@ -25,7 +25,7 @@ import SUBHEADING_CSS from "./Subheading.module.css";
25
25
  import TABLE_CSS from "./Table.module.css";
26
26
  import TITLE_CSS from "./Title.module.css";
27
27
  // Combine the `.prose` class from every block and inline component's CSS module into a single string.
28
- const PROSE_STYLES = getClass(PARAGRAPH_CSS.prose, HEADING_CSS.prose, SUBHEADING_CSS.prose, ADDRESS_CSS.prose, BLOCKQUOTE_CSS.prose, SECTION_CSS.prose, CODE_CSS.prose, DEFINITIONS_CSS.prose, DELETED_CSS.prose, EMPHASIS_CSS.prose, IMAGE_CSS.prose, INSERTED_CSS.prose, CAPTION_CSS.prose, LIST_CSS.prose, TITLE_CSS.prose, LINK_CSS.prose, MARK_CSS.prose, PREFORMATTED_CSS.prose, SMALL_CSS.prose, STRONG_CSS.prose, SUBSCRIPT_CSS.prose, SUPERSCRIPT_CSS.prose, TABLE_CSS.prose, DIVIDER_CSS.prose);
28
+ const PROSE_STYLES = getClass(getModuleClass(PARAGRAPH_CSS, "prose"), getModuleClass(HEADING_CSS, "prose"), getModuleClass(SUBHEADING_CSS, "prose"), getModuleClass(ADDRESS_CSS, "prose"), getModuleClass(BLOCKQUOTE_CSS, "prose"), getModuleClass(SECTION_CSS, "prose"), getModuleClass(CODE_CSS, "prose"), getModuleClass(DEFINITIONS_CSS, "prose"), getModuleClass(DELETED_CSS, "prose"), getModuleClass(EMPHASIS_CSS, "prose"), getModuleClass(IMAGE_CSS, "prose"), getModuleClass(INSERTED_CSS, "prose"), getModuleClass(CAPTION_CSS, "prose"), getModuleClass(LIST_CSS, "prose"), getModuleClass(TITLE_CSS, "prose"), getModuleClass(LINK_CSS, "prose"), getModuleClass(MARK_CSS, "prose"), getModuleClass(PREFORMATTED_CSS, "prose"), getModuleClass(SMALL_CSS, "prose"), getModuleClass(STRONG_CSS, "prose"), getModuleClass(SUBSCRIPT_CSS, "prose"), getModuleClass(SUPERSCRIPT_CSS, "prose"), getModuleClass(TABLE_CSS, "prose"), getModuleClass(DIVIDER_CSS, "prose"));
29
29
  /**
30
30
  * A section of longform text containing lots of `<p>` or `<ul>` style elements.
31
31
  * - Applies the prose variant of every block and inline component so nested content picks up the right longform spacing and typography.
@@ -9,7 +9,7 @@ import SMALL_CSS from "../inline/Small.module.css";
9
9
  import STRONG_CSS from "../inline/Strong.module.css";
10
10
  import SUBSCRIPT_CSS from "../inline/Subscript.module.css";
11
11
  import SUPERSCRIPT_CSS from "../inline/Superscript.module.css";
12
- import { getClass } from "../util/css.js";
12
+ import { getClass, getModuleClass } from "../util/css.js";
13
13
  import type { OptionalChildProps } from "../util/props.js";
14
14
  import ADDRESS_CSS from "./Address.module.css";
15
15
  import BLOCKQUOTE_CSS from "./Blockquote.module.css";
@@ -28,30 +28,30 @@ import TITLE_CSS from "./Title.module.css";
28
28
 
29
29
  // Combine the `.prose` class from every block and inline component's CSS module into a single string.
30
30
  const PROSE_STYLES = getClass(
31
- PARAGRAPH_CSS.prose,
32
- HEADING_CSS.prose,
33
- SUBHEADING_CSS.prose,
34
- ADDRESS_CSS.prose,
35
- BLOCKQUOTE_CSS.prose,
36
- SECTION_CSS.prose,
37
- CODE_CSS.prose,
38
- DEFINITIONS_CSS.prose,
39
- DELETED_CSS.prose,
40
- EMPHASIS_CSS.prose,
41
- IMAGE_CSS.prose,
42
- INSERTED_CSS.prose,
43
- CAPTION_CSS.prose,
44
- LIST_CSS.prose,
45
- TITLE_CSS.prose,
46
- LINK_CSS.prose,
47
- MARK_CSS.prose,
48
- PREFORMATTED_CSS.prose,
49
- SMALL_CSS.prose,
50
- STRONG_CSS.prose,
51
- SUBSCRIPT_CSS.prose,
52
- SUPERSCRIPT_CSS.prose,
53
- TABLE_CSS.prose,
54
- DIVIDER_CSS.prose,
31
+ getModuleClass(PARAGRAPH_CSS, "prose"),
32
+ getModuleClass(HEADING_CSS, "prose"),
33
+ getModuleClass(SUBHEADING_CSS, "prose"),
34
+ getModuleClass(ADDRESS_CSS, "prose"),
35
+ getModuleClass(BLOCKQUOTE_CSS, "prose"),
36
+ getModuleClass(SECTION_CSS, "prose"),
37
+ getModuleClass(CODE_CSS, "prose"),
38
+ getModuleClass(DEFINITIONS_CSS, "prose"),
39
+ getModuleClass(DELETED_CSS, "prose"),
40
+ getModuleClass(EMPHASIS_CSS, "prose"),
41
+ getModuleClass(IMAGE_CSS, "prose"),
42
+ getModuleClass(INSERTED_CSS, "prose"),
43
+ getModuleClass(CAPTION_CSS, "prose"),
44
+ getModuleClass(LIST_CSS, "prose"),
45
+ getModuleClass(TITLE_CSS, "prose"),
46
+ getModuleClass(LINK_CSS, "prose"),
47
+ getModuleClass(MARK_CSS, "prose"),
48
+ getModuleClass(PREFORMATTED_CSS, "prose"),
49
+ getModuleClass(SMALL_CSS, "prose"),
50
+ getModuleClass(STRONG_CSS, "prose"),
51
+ getModuleClass(SUBSCRIPT_CSS, "prose"),
52
+ getModuleClass(SUPERSCRIPT_CSS, "prose"),
53
+ getModuleClass(TABLE_CSS, "prose"),
54
+ getModuleClass(DIVIDER_CSS, "prose"),
55
55
  );
56
56
 
57
57
  /**
@@ -76,7 +76,7 @@ export declare function Nav(props: SectionProps): ReactElement;
76
76
  * @kind component
77
77
  * @param props Colour, space, typography, and width variants plus optional `as` override and `children`.
78
78
  * @returns Rendered `<aside>` element.
79
- * @example <Aside narrow><Paragraph>Sidebar</Paragraph></Aside>
79
+ * @example <Aside width="narrow"><Paragraph>Sidebar</Paragraph></Aside>
80
80
  * @see https://dhoulb.github.io/shelving/ui/block/Section/Aside
81
81
  */
82
82
  export declare function Aside(props: SectionProps): ReactElement;
@@ -77,7 +77,7 @@ export function Nav(props) {
77
77
  * @kind component
78
78
  * @param props Colour, space, typography, and width variants plus optional `as` override and `children`.
79
79
  * @returns Rendered `<aside>` element.
80
- * @example <Aside narrow><Paragraph>Sidebar</Paragraph></Aside>
80
+ * @example <Aside width="narrow"><Paragraph>Sidebar</Paragraph></Aside>
81
81
  * @see https://dhoulb.github.io/shelving/ui/block/Section/Aside
82
82
  */
83
83
  export function Aside(props) {
@@ -6,7 +6,7 @@ A landmark content region — renders a `<section>` with block-level spacing and
6
6
 
7
7
  - Pick the component whose HTML element matches the semantic meaning rather than reaching for a generic [`Block`](/ui/Block). `<Section>` is a `<section>`, `<Nav>` a `<nav>`, `<Figure>` a `<figure>`, and so on.
8
8
  - Every section centres its content and caps the line length so text never touches the viewport edges. Nested sections relax that cap so they can fill their parent.
9
- - Pass `narrow` / `wide` / `full` to constrain or unconstrain the width, and the usual `color` / `space` / typography variants to retint and respace.
9
+ - Sections default to the `--width-normal` content width, so most of the time you set no width at all. Pass `width="narrow"` / `"wide"` / `"full"` (or `"fit"`) to change that, and the usual `color` / `space` / typography variants to retint and respace.
10
10
  - Pair [`Figure`](/ui/Section) with [`Caption`](/ui/Caption) for a `<figure>` / `<figcaption>` pair.
11
11
 
12
12
  ## Usage
@@ -16,7 +16,7 @@ A landmark content region — renders a `<section>` with block-level spacing and
16
16
  ```tsx
17
17
  import { Section, Heading, Definitions } from "shelving/ui";
18
18
 
19
- <Section narrow>
19
+ <Section width="narrow">
20
20
  <Heading>Account details</Heading>
21
21
  <Definitions>
22
22
  <dt>Name</dt><dd>Alice Smith</dd>
@@ -42,11 +42,11 @@ import { Header, Nav, Footer } from "shelving/ui";
42
42
 
43
43
  | Variable | Styles | Default |
44
44
  |---|---|---|
45
- | `--section-width` | Content width | `100%` |
45
+ | `--section-width` | Content width | `var(--width-normal)` (55rem) |
46
46
  | `--section-indent` | Inline gutter kept on each side so text doesn't touch the edges | `var(--space-normal)` (16px) |
47
47
  | `--section-space` | Outer block margin (top + bottom) | `var(--space-section)` (2rem) |
48
48
 
49
- **Global tokens it reads:** [`--space-normal`](/ui/getSpaceClass) and [`--space-section`](/ui/getSpaceClass). The `narrow` / `wide` / `full` width variants come from the shared [`ui`](/ui) styling system.
49
+ **Global tokens it reads:** [`--space-normal`](/ui/getSpaceClass), [`--space-section`](/ui/getSpaceClass), and [`--width-normal`](/ui/getWidthClass) (the default content width). The `width` variant (`narrow` / `normal` / `wide` / `full` / `fit`) comes from the shared [`ui`](/ui) styling system.
50
50
 
51
51
  ## See also
52
52
 
@@ -1,5 +1,6 @@
1
1
  @import "../style/layers.css";
2
2
  @import "../style/Space.module.css";
3
+ @import "../style/Width.module.css";
3
4
 
4
5
  @layer components {
5
6
  .prose :where(section, article, aside, nav, header, footer, figure),
@@ -9,7 +10,7 @@
9
10
  display: block;
10
11
  box-sizing: border-box;
11
12
  max-inline-size: calc(100% - (var(--section-indent, var(--space-normal)) * 2)); /* Stop text touching the sides. */
12
- inline-size: var(--section-width, 100%);
13
+ inline-size: var(--section-width, var(--width-normal)); /* Default to the normal content width; override with the `width` variant. */
13
14
  margin-inline: auto;
14
15
  margin-block: var(--section-space, var(--space-section));
15
16
 
@@ -105,7 +105,7 @@ export function Nav(props: SectionProps): ReactElement {
105
105
  * @kind component
106
106
  * @param props Colour, space, typography, and width variants plus optional `as` override and `children`.
107
107
  * @returns Rendered `<aside>` element.
108
- * @example <Aside narrow><Paragraph>Sidebar</Paragraph></Aside>
108
+ * @example <Aside width="narrow"><Paragraph>Sidebar</Paragraph></Aside>
109
109
  * @see https://dhoulb.github.io/shelving/ui/block/Section/Aside
110
110
  */
111
111
  export function Aside(props: SectionProps): ReactElement {
@@ -2,13 +2,14 @@ import type { ReactElement } from "react";
2
2
  import { type ColorVariants } from "../style/Color.js";
3
3
  import { type SpaceVariants } from "../style/Space.js";
4
4
  import { type TypographyVariants } from "../style/Typography.js";
5
+ import { type WidthVariants } from "../style/Width.js";
5
6
  import type { ChildProps } from "../util/props.js";
6
7
  /**
7
- * Props for `Table` — colour, space, and typography variants plus `children`.
8
+ * Props for `Table` — colour, space, typography, and width variants plus `children`.
8
9
  *
9
10
  * @see https://dhoulb.github.io/shelving/ui/block/Table/TableProps
10
11
  */
11
- export interface TableProps extends ColorVariants, SpaceVariants, TypographyVariants, ChildProps {
12
+ export interface TableProps extends ColorVariants, SpaceVariants, TypographyVariants, WidthVariants, ChildProps {
12
13
  }
13
14
  /**
14
15
  * Table block — rendered as `<table>`.
@@ -16,7 +17,7 @@ export interface TableProps extends ColorVariants, SpaceVariants, TypographyVari
16
17
  * - `<th>` / `<td>` cells draw the borders (the `<table>` element itself has none); override their weight via the `--table-border` / `--table-stroke` hooks.
17
18
  *
18
19
  * @kind component
19
- * @param props Colour, space, and typography variants plus `children`.
20
+ * @param props Colour, space, typography, and width variants plus `children`.
20
21
  * @returns Rendered `<table>` element.
21
22
  * @example <Table><tbody><tr><td>Cell</td></tr></tbody></Table>
22
23
  * @see https://dhoulb.github.io/shelving/ui/block/Table/Table
package/ui/block/Table.js CHANGED
@@ -2,21 +2,22 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { getColorClass } from "../style/Color.js";
3
3
  import { getSpaceClass } from "../style/Space.js";
4
4
  import { getTypographyClass } from "../style/Typography.js";
5
+ import { getWidthClass } from "../style/Width.js";
5
6
  import { getClass, getModuleClass } from "../util/css.js";
6
7
  import TABLE_CSS from "./Table.module.css";
7
- const TABLE_CLASS = getModuleClass(TABLE_CSS, "divider");
8
+ const TABLE_CLASS = getModuleClass(TABLE_CSS, "table");
8
9
  /**
9
10
  * Table block — rendered as `<table>`.
10
11
  * - Wrap in a `<Scroll horizontal>` if the table may exceed the container width on small screens.
11
12
  * - `<th>` / `<td>` cells draw the borders (the `<table>` element itself has none); override their weight via the `--table-border` / `--table-stroke` hooks.
12
13
  *
13
14
  * @kind component
14
- * @param props Colour, space, and typography variants plus `children`.
15
+ * @param props Colour, space, typography, and width variants plus `children`.
15
16
  * @returns Rendered `<table>` element.
16
17
  * @example <Table><tbody><tr><td>Cell</td></tr></tbody></Table>
17
18
  * @see https://dhoulb.github.io/shelving/ui/block/Table/Table
18
19
  */
19
20
  export function Table({ children, ...props }) {
20
21
  return (_jsx("table", { className: getClass(TABLE_CLASS, //
21
- getColorClass(props), getSpaceClass(props), getTypographyClass(props)), children: children }));
22
+ getColorClass(props), getSpaceClass(props), getTypographyClass(props), getWidthClass(props)), children: children }));
22
23
  }
package/ui/block/Table.md CHANGED
@@ -8,6 +8,7 @@ A data table — renders a `<table>`. Compose the usual `<thead>` / `<tbody>` /
8
8
  - First and last cells in a row drop their outer inline padding so the table aligns flush with the surrounding text column.
9
9
  - Wrap a wide table in a horizontally scrollable container if it may exceed the content width on small screens.
10
10
  - Like the other block components it collapses its outer block margin when it is the first or last child.
11
+ - Spans the full width of its container by default; set the `width` variant (`narrow` / `normal` / `wide` / `full` / `fit`) to constrain it.
11
12
  - Inside [`Prose`](/ui/Prose) a raw `<table>` picks up the same styling, so Markdown-rendered tables match component ones.
12
13
 
13
14
  ## Usage
@@ -11,6 +11,7 @@
11
11
  .prose table {
12
12
  /* Box */
13
13
  display: table;
14
+ inline-size: 100%;
14
15
  margin-inline: 0;
15
16
  margin-block: var(--table-space, var(--space-paragraph));
16
17
  text-indent: 0;
@@ -2,18 +2,19 @@ import type { ReactElement } from "react";
2
2
  import { type ColorVariants, getColorClass } from "../style/Color.js";
3
3
  import { getSpaceClass, type SpaceVariants } from "../style/Space.js";
4
4
  import { getTypographyClass, type TypographyVariants } from "../style/Typography.js";
5
+ import { getWidthClass, type WidthVariants } from "../style/Width.js";
5
6
  import { getClass, getModuleClass } from "../util/css.js";
6
7
  import type { ChildProps } from "../util/props.js";
7
8
  import TABLE_CSS from "./Table.module.css";
8
9
 
9
- const TABLE_CLASS = getModuleClass(TABLE_CSS, "divider");
10
+ const TABLE_CLASS = getModuleClass(TABLE_CSS, "table");
10
11
 
11
12
  /**
12
- * Props for `Table` — colour, space, and typography variants plus `children`.
13
+ * Props for `Table` — colour, space, typography, and width variants plus `children`.
13
14
  *
14
15
  * @see https://dhoulb.github.io/shelving/ui/block/Table/TableProps
15
16
  */
16
- export interface TableProps extends ColorVariants, SpaceVariants, TypographyVariants, ChildProps {}
17
+ export interface TableProps extends ColorVariants, SpaceVariants, TypographyVariants, WidthVariants, ChildProps {}
17
18
 
18
19
  /**
19
20
  * Table block — rendered as `<table>`.
@@ -21,7 +22,7 @@ export interface TableProps extends ColorVariants, SpaceVariants, TypographyVari
21
22
  * - `<th>` / `<td>` cells draw the borders (the `<table>` element itself has none); override their weight via the `--table-border` / `--table-stroke` hooks.
22
23
  *
23
24
  * @kind component
24
- * @param props Colour, space, and typography variants plus `children`.
25
+ * @param props Colour, space, typography, and width variants plus `children`.
25
26
  * @returns Rendered `<table>` element.
26
27
  * @example <Table><tbody><tr><td>Cell</td></tr></tbody></Table>
27
28
  * @see https://dhoulb.github.io/shelving/ui/block/Table/Table
@@ -34,6 +35,7 @@ export function Table({ children, ...props }: TableProps): ReactElement {
34
35
  getColorClass(props),
35
36
  getSpaceClass(props),
36
37
  getTypographyClass(props),
38
+ getWidthClass(props),
37
39
  )}
38
40
  >
39
41
  {children}
package/ui/block/Title.md CHANGED
@@ -26,7 +26,7 @@ import { Title, Paragraph } from "shelving/ui";
26
26
  import { Panel, Block, Title } from "shelving/ui";
27
27
 
28
28
  <Panel as="header" color="primary">
29
- <Block narrow>
29
+ <Block width="narrow">
30
30
  <Title>Welcome</Title>
31
31
  </Block>
32
32
  </Panel>
@@ -18,7 +18,7 @@ export const Dialog = memo(({ children, onClose, ...props }) => {
18
18
  useEffect(() => {
19
19
  ref.current?.showModal();
20
20
  }, []);
21
- return (_jsx(Suspense, { fallback: null, children: _jsxs("dialog", { ref: ref, className: styles.dialog, onClick: _closeOnBackdropClick, onClose: onClose, ...props, children: [children, _jsx("div", { className: styles.close, children: _jsx(DialogCloseButton, { plain: true }) })] }) }));
21
+ return (_jsx(Suspense, { fallback: null, children: _jsxs("dialog", { ref: ref, className: getModuleClass(styles, "dialog"), onClick: _closeOnBackdropClick, onClose: onClose, ...props, children: [children, _jsx("div", { className: getModuleClass(styles, "close"), children: _jsx(DialogCloseButton, { plain: true }) })] }) }));
22
22
  });
23
23
  /** When the user clicks anywhere on a `<dialog>` element (and the click isn't on a link etc), then close the dialog. */
24
24
  function _closeOnBackdropClick({ currentTarget, target }) {
@@ -35,9 +35,9 @@ export const Dialog = memo(({ children, onClose, ...props }: DialogProps) => {
35
35
  return (
36
36
  <Suspense fallback={null}>
37
37
  {/** biome-ignore lint/a11y/useKeyWithClickEvents: Dialogs also show a close button. */}
38
- <dialog ref={ref} className={styles.dialog} onClick={_closeOnBackdropClick} onClose={onClose} {...props}>
38
+ <dialog ref={ref} className={getModuleClass(styles, "dialog")} onClick={_closeOnBackdropClick} onClose={onClose} {...props}>
39
39
  {children}
40
- <div className={styles.close}>
40
+ <div className={getModuleClass(styles, "close")}>
41
41
  <DialogCloseButton plain />
42
42
  </div>
43
43
  </dialog>
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { getModuleClass } from "../util/css.js";
2
3
  import styles from "./Modal.module.css";
3
4
  /**
4
5
  * Styled `<aside>` overlay container for modal content.
@@ -10,5 +11,5 @@ import styles from "./Modal.module.css";
10
11
  * @see https://dhoulb.github.io/shelving/ui/dialog/Modal/Modal
11
12
  */
12
13
  export function Modal({ children }) {
13
- return _jsx("aside", { className: styles.modal, children: children });
14
+ return _jsx("aside", { className: getModuleClass(styles, "modal"), children: children });
14
15
  }
@@ -1,4 +1,5 @@
1
1
  import type { ReactElement } from "react";
2
+ import { getModuleClass } from "../util/css.js";
2
3
  import type { OptionalChildProps } from "../util/props.js";
3
4
  import styles from "./Modal.module.css";
4
5
 
@@ -19,5 +20,5 @@ export interface ModalProps extends OptionalChildProps {}
19
20
  * @see https://dhoulb.github.io/shelving/ui/dialog/Modal/Modal
20
21
  */
21
22
  export function Modal({ children }: ModalProps): ReactElement {
22
- return <aside className={styles.modal}>{children}</aside>;
23
+ return <aside className={getModuleClass(styles, "modal")}>{children}</aside>;
23
24
  }
@@ -20,5 +20,5 @@ import { TreeCards } from "../tree/TreeCards.js";
20
20
  * @see https://dhoulb.github.io/shelving/ui/docs/DocumentationHomePage/DocumentationHomePage
21
21
  */
22
22
  export function DocumentationHomePage({ title, name, description, content, children }) {
23
- return (_jsx(Page, { title: title ?? name, description: description, children: _jsxs(Block, { color: "red", children: [_jsx(Panel, { padding: "5x", children: _jsx(Title, { center: true, children: title ?? name }) }), content && (_jsx(Section, { wide: true, children: _jsx(Prose, { children: _jsx(Markup, { children: content }) }) })), _jsx(Section, { wide: true, children: _jsx(TreeCards, { children: children }) })] }) }));
23
+ return (_jsx(Page, { title: title ?? name, description: description, children: _jsxs(Block, { color: "red", children: [_jsx(Panel, { padding: "5x", children: _jsx(Title, { center: true, children: title ?? name }) }), content && (_jsx(Section, { children: _jsx(Prose, { children: _jsx(Markup, { children: content }) }) })), _jsx(Section, { children: _jsx(TreeCards, { children: children }) })] }) }));
24
24
  }
@@ -29,13 +29,13 @@ export function DocumentationHomePage({ title, name, description, content, child
29
29
  <Title center>{title ?? name}</Title>
30
30
  </Panel>
31
31
  {content && (
32
- <Section wide>
32
+ <Section>
33
33
  <Prose>
34
34
  <Markup>{content}</Markup>
35
35
  </Prose>
36
36
  </Section>
37
37
  )}
38
- <Section wide>
38
+ <Section>
39
39
  <TreeCards>{children}</TreeCards>
40
40
  </Section>
41
41
  </Block>
@@ -1,4 +1,4 @@
1
- import { type ReactNode } from "react";
1
+ import type { ReactNode } from "react";
2
2
  import type { DocumentationElementProps } from "../../util/tree.js";
3
3
  /**
4
4
  * Page renderer for a `tree-documentation` element — the full detail page for a documented symbol.