@nanisoft/prism-ui 0.16.0 → 0.16.1

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.
@@ -188,17 +188,11 @@ export type DocsShellProps = {
188
188
  * The accessible name of the rail. Required whenever `nav` is passed, because
189
189
  * it is a word a reader hears and a Page that ships no copy ships no
190
190
  * reader-facing copy either.
191
- *
192
- * It is also the visible word on the disclosure that stands in for the rail
193
- * below `lg`, because it is already this navigation's name and a Page cannot
194
- * invent a second one. A consumer that files its navigation in another language
195
- * gets the control in that language by having done this once.
196
191
  */
197
192
  navLabel: string;
198
193
  /**
199
194
  * The accessible name of the contents rail. Required whenever `toc` is passed,
200
- * for the same reason `navLabel` is, and the contents disclosure below `lg`
201
- * carries it for the same reason too.
195
+ * for the same reason `navLabel` is.
202
196
  */
203
197
  tocLabel: string;
204
198
  /**
@@ -347,32 +341,51 @@ export type DocsShellProps = {
347
341
  * a fact about ink, and announcing it would put a sentence in the middle of a
348
342
  * list of a consumer's own pages.
349
343
  *
350
- * **Below `lg` there was no navigation at all, and the fix is a native
351
- * disclosure.** At 768 and at 1024 both rails were `hidden` and the only
352
- * navigation left inside `<main>` was the two-item pager at the foot of the
353
- * article, so a reader on a thirty-one document reference at tablet width had no
354
- * contents, no on-this-page and no way to a sibling page except Previous and
355
- * Next. The disclosure is `<details>` and `<summary>`, which is the one
356
- * disclosure widget that needs no runtime at all: it is expanded and collapsed by
357
- * the platform, it is a real control in the Tab order with a real expanded state,
358
- * and adding a client boundary to a server Component to reinvent it would put
359
- * bytes on every documentation page in the family to save a reader one click.
344
+ * **The tree is in the document once, at every width, and the price of that is a
345
+ * phone reader crossing the whole navigation to reach the article.** At 768 and
346
+ * at 1024 both rails used to be `hidden`, so the only navigation left inside
347
+ * `<main>` was the two-item pager at the foot of the article, and a reader on a
348
+ * twenty-seven document reference at tablet width had no contents, no
349
+ * on-this-page and no way to a sibling page except Previous and Next. 0.16.0
350
+ * closed that gap by drawing the tree a second time behind a `<details>`, one
351
+ * copy for the rail and one for the narrow frame, and it shipped a doubled
352
+ * document to every documentation page in the family with it: two
353
+ * `aria-current` markers for one page, two lists of a consumer's own pages, two
354
+ * `docs-nav-page` rows for every document, and a second `<nav>` carrying the
355
+ * rail's own accessible name, which is the thing a consumer's suite reaches the
356
+ * rail by. Three consumer test files failed against the published package: two on
357
+ * a count that came back doubled, and two on a `getByRole('navigation', { name })`
358
+ * that had two answers where it expects one. So there is one copy now, and it
359
+ * shows at every width.
360
+ *
361
+ * **What that costs, with the number.** A consumer's rail measured 1,318 pixels
362
+ * of content in a built export at 1280 by 680, and those rows wrap on a phone, so
363
+ * a reader arriving at the top of a documentation page scrolls past a thousand
364
+ * pixels of navigation before the article begins. That is a real regression for
365
+ * that reader and it is the reason a disclosure was reached for in the first
366
+ * place. It is paid rather than hidden, because every arrangement that avoids it
367
+ * is worse: a rail at `lg` and nothing below it reopens the gap this change
368
+ * closes, and drawing the tree twice to keep the scroll short is what broke three
369
+ * consumer test files in the first place.
360
370
  *
361
- * The tree is rendered twice, once in each arrangement, and only one of them is
362
- * in the document at any width: the rail is `hidden lg:block` and the disclosure
363
- * is `lg:hidden`, so the other one is `display: none` and is out of the
364
- * accessibility tree and out of the tab order rather than a second copy a reader
365
- * meets. The summary carries `navLabel` or `tocLabel`, which is the caller's own
366
- * word for that navigation and therefore the one word on the control that cannot
367
- * be wrong in a language the consumer did not write in.
371
+ * **What would actually remove the scroll.** A collapsed rail below `lg` needs an
372
+ * open state. A server Component cannot hold one, and `<details>` is the only
373
+ * disclosure the platform holds on the Page's behalf, so the control that opens
374
+ * it has to be a client island inside the Page. That is a separate piece of work
375
+ * with its own budget, and it is not built here: a Page that ships a client
376
+ * boundary to save one scroll is making a different trade than the one stated
377
+ * above, and it should be made deliberately rather than smuggled in as the side
378
+ * effect of fixing a duplicate.
368
379
  *
369
380
  * **The frame is three columns from `lg`, and the third is the consumer's to
370
381
  * fill.** The rail is 15rem, the document takes the rest, and the contents rail
371
382
  * is 13rem. The third track exists only when `toc` is passed, because the
372
383
  * document takes the second track by auto-placement and a template that named a
373
384
  * track no child occupies would leave the document in the 15rem one. Below `lg`
374
- * the frame is a single column: the document fills it and the two navigations sit
375
- * above it behind their disclosures.
385
+ * the frame is a single column and the children flow in the order they are
386
+ * written: the rail, then the document, then the contents rail. The rail is the
387
+ * first child for that reason, so a reader below `lg` meets the navigation before
388
+ * the text rather than after it, and one arrangement serves both widths.
376
389
  *
377
390
  * It is a Page rather than a Block because it is a whole screen and it is the
378
391
  * screen a content pipeline targets: a route that reads one document and hands
@@ -383,10 +396,9 @@ export type DocsShellProps = {
383
396
  *
384
397
  * It is a server Component. It fetches nothing, it holds no state and it imports
385
398
  * no router, so a consumer renders it from whichever route their framework names
386
- * and hands it the document their pipeline produced. The sub-`lg` disclosure is
387
- * the reason that stays true under pressure: it is the one feature on this Page
388
- * that a hand would be tempted to write as a client Component, and it is written
389
- * as markup instead.
399
+ * and hands it the document their pipeline produced. Nothing here needs a client
400
+ * boundary, and the one feature that would want one is named above as work not
401
+ * done rather than quietly added.
390
402
  */
391
403
  export declare function DocsShell({ title, description, nav, toc, currentHref, navLabel, tocLabel, pagerLabel, pagerLabels, header, footer, className, children, }: DocsShellProps): import("react").JSX.Element;
392
404
  export default DocsShell;
@@ -1 +1 @@
1
- {"version":3,"file":"docs-shell.d.ts","sourceRoot":"","sources":["../../../src/pages/docs-shell/docs-shell.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAOtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAA;IACb,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,OAAO,CAAA;IACb;;;;;;;;OAQG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;;;;;;;;;OAUG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,0EAA0E;IAC1E,KAAK,EAAE,SAAS,YAAY,EAAE,CAAA;CAC/B,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,SAAS,CAAA;IACf,4DAA4D;IAC5D,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,YAAY,GAAG,cAAc,CAAA;AAEtE;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAA;IAChB,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B;;;;;;;;OAQG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;OAIG;IACH,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB;;;;OAIG;IACH,GAAG,CAAC,EAAE,SAAS,YAAY,EAAE,CAAA;IAC7B;;;;;;;OAOG;IACH,GAAG,CAAC,EAAE,SAAS,YAAY,EAAE,CAAA;IAC7B;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;;;;;;OASG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,WAAW,EAAE,eAAe,CAAA;IAC5B;;;;;OAKG;IACH,QAAQ,EAAE,SAAS,CAAA;IACnB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsJG;AACH,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,WAAW,EACX,GAAG,EACH,GAAG,EACH,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,WAAW,EACX,MAAM,EACN,MAAM,EACN,SAAS,EACT,QAAQ,GACT,EAAE,cAAc,+BA6GhB;AAsgBD,eAAe,SAAS,CAAA"}
1
+ {"version":3,"file":"docs-shell.d.ts","sourceRoot":"","sources":["../../../src/pages/docs-shell/docs-shell.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAOtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAA;IACb,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,OAAO,CAAA;IACb;;;;;;;;OAQG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;;;;;;;;;OAUG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,0EAA0E;IAC1E,KAAK,EAAE,SAAS,YAAY,EAAE,CAAA;CAC/B,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,SAAS,CAAA;IACf,4DAA4D;IAC5D,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,YAAY,GAAG,cAAc,CAAA;AAEtE;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAA;IAChB,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B;;;;;;;;OAQG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;OAIG;IACH,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB;;;;OAIG;IACH,GAAG,CAAC,EAAE,SAAS,YAAY,EAAE,CAAA;IAC7B;;;;;;;OAOG;IACH,GAAG,CAAC,EAAE,SAAS,YAAY,EAAE,CAAA;IAC7B;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,WAAW,EAAE,eAAe,CAAA;IAC5B;;;;;OAKG;IACH,QAAQ,EAAE,SAAS,CAAA;IACnB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwKG;AACH,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,WAAW,EACX,GAAG,EACH,GAAG,EACH,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,WAAW,EACX,MAAM,EACN,MAAM,EACN,SAAS,EACT,QAAQ,GACT,EAAE,cAAc,+BAiFhB;AA+fD,eAAe,SAAS,CAAA"}
@@ -113,32 +113,51 @@ import { cn } from '../../lib/utils.js';
113
113
  * a fact about ink, and announcing it would put a sentence in the middle of a
114
114
  * list of a consumer's own pages.
115
115
  *
116
- * **Below `lg` there was no navigation at all, and the fix is a native
117
- * disclosure.** At 768 and at 1024 both rails were `hidden` and the only
118
- * navigation left inside `<main>` was the two-item pager at the foot of the
119
- * article, so a reader on a thirty-one document reference at tablet width had no
120
- * contents, no on-this-page and no way to a sibling page except Previous and
121
- * Next. The disclosure is `<details>` and `<summary>`, which is the one
122
- * disclosure widget that needs no runtime at all: it is expanded and collapsed by
123
- * the platform, it is a real control in the Tab order with a real expanded state,
124
- * and adding a client boundary to a server Component to reinvent it would put
125
- * bytes on every documentation page in the family to save a reader one click.
126
- *
127
- * The tree is rendered twice, once in each arrangement, and only one of them is
128
- * in the document at any width: the rail is `hidden lg:block` and the disclosure
129
- * is `lg:hidden`, so the other one is `display: none` and is out of the
130
- * accessibility tree and out of the tab order rather than a second copy a reader
131
- * meets. The summary carries `navLabel` or `tocLabel`, which is the caller's own
132
- * word for that navigation and therefore the one word on the control that cannot
133
- * be wrong in a language the consumer did not write in.
116
+ * **The tree is in the document once, at every width, and the price of that is a
117
+ * phone reader crossing the whole navigation to reach the article.** At 768 and
118
+ * at 1024 both rails used to be `hidden`, so the only navigation left inside
119
+ * `<main>` was the two-item pager at the foot of the article, and a reader on a
120
+ * twenty-seven document reference at tablet width had no contents, no
121
+ * on-this-page and no way to a sibling page except Previous and Next. 0.16.0
122
+ * closed that gap by drawing the tree a second time behind a `<details>`, one
123
+ * copy for the rail and one for the narrow frame, and it shipped a doubled
124
+ * document to every documentation page in the family with it: two
125
+ * `aria-current` markers for one page, two lists of a consumer's own pages, two
126
+ * `docs-nav-page` rows for every document, and a second `<nav>` carrying the
127
+ * rail's own accessible name, which is the thing a consumer's suite reaches the
128
+ * rail by. Three consumer test files failed against the published package: two on
129
+ * a count that came back doubled, and two on a `getByRole('navigation', { name })`
130
+ * that had two answers where it expects one. So there is one copy now, and it
131
+ * shows at every width.
132
+ *
133
+ * **What that costs, with the number.** A consumer's rail measured 1,318 pixels
134
+ * of content in a built export at 1280 by 680, and those rows wrap on a phone, so
135
+ * a reader arriving at the top of a documentation page scrolls past a thousand
136
+ * pixels of navigation before the article begins. That is a real regression for
137
+ * that reader and it is the reason a disclosure was reached for in the first
138
+ * place. It is paid rather than hidden, because every arrangement that avoids it
139
+ * is worse: a rail at `lg` and nothing below it reopens the gap this change
140
+ * closes, and drawing the tree twice to keep the scroll short is what broke three
141
+ * consumer test files in the first place.
142
+ *
143
+ * **What would actually remove the scroll.** A collapsed rail below `lg` needs an
144
+ * open state. A server Component cannot hold one, and `<details>` is the only
145
+ * disclosure the platform holds on the Page's behalf, so the control that opens
146
+ * it has to be a client island inside the Page. That is a separate piece of work
147
+ * with its own budget, and it is not built here: a Page that ships a client
148
+ * boundary to save one scroll is making a different trade than the one stated
149
+ * above, and it should be made deliberately rather than smuggled in as the side
150
+ * effect of fixing a duplicate.
134
151
  *
135
152
  * **The frame is three columns from `lg`, and the third is the consumer's to
136
153
  * fill.** The rail is 15rem, the document takes the rest, and the contents rail
137
154
  * is 13rem. The third track exists only when `toc` is passed, because the
138
155
  * document takes the second track by auto-placement and a template that named a
139
156
  * track no child occupies would leave the document in the 15rem one. Below `lg`
140
- * the frame is a single column: the document fills it and the two navigations sit
141
- * above it behind their disclosures.
157
+ * the frame is a single column and the children flow in the order they are
158
+ * written: the rail, then the document, then the contents rail. The rail is the
159
+ * first child for that reason, so a reader below `lg` meets the navigation before
160
+ * the text rather than after it, and one arrangement serves both widths.
142
161
  *
143
162
  * It is a Page rather than a Block because it is a whole screen and it is the
144
163
  * screen a content pipeline targets: a route that reads one document and hands
@@ -149,10 +168,9 @@ import { cn } from '../../lib/utils.js';
149
168
  *
150
169
  * It is a server Component. It fetches nothing, it holds no state and it imports
151
170
  * no router, so a consumer renders it from whichever route their framework names
152
- * and hands it the document their pipeline produced. The sub-`lg` disclosure is
153
- * the reason that stays true under pressure: it is the one feature on this Page
154
- * that a hand would be tempted to write as a client Component, and it is written
155
- * as markup instead.
171
+ * and hands it the document their pipeline produced. Nothing here needs a client
172
+ * boundary, and the one feature that would want one is named above as work not
173
+ * done rather than quietly added.
156
174
  */
157
175
  export function DocsShell({ title, description, nav, toc, currentHref, navLabel, tocLabel, pagerLabel, pagerLabels, header, footer, className, children, }) {
158
176
  readTree(nav, 'nav');
@@ -177,10 +195,10 @@ export function DocsShell({ title, description, nav, toc, currentHref, navLabel,
177
195
  // contents rail landed in an implicit `auto` track rather than the
178
196
  // 13rem one. `check-breakpoint-variants.mjs` is the gate that says so
179
197
  // to the next class written against a screen the theme does not emit.
180
- contents ? 'lg:grid lg:grid-cols-[15rem_minmax(0,1fr)_13rem]' : 'lg:grid lg:grid-cols-[15rem_minmax(0,1fr)]'), children: [rail || contents ? (_jsxs("div", { "data-slot": "docs-nav-compact", className: "flex flex-col gap-4 lg:hidden", children: [rail ? (_jsx(Disclosure, { label: navLabel, unnamed: unnamedNav, children: _jsx(NavList, { entries: rail, currentHref: currentHref, depth: 0 }) })) : null, contents ? (_jsx(Disclosure, { label: tocLabel, unnamed: unnamedToc, children: _jsx(NavList, { entries: contents, currentHref: currentHref, depth: 0 }) })) : null] })) : null, rail ? (_jsx("aside", { "data-slot": "docs-rail", className: "hidden lg:col-start-1 lg:row-start-1 lg:block", children: _jsx(Rail, { label: navLabel, entries: rail, currentHref: currentHref, unnamed: unnamedNav }) })) : null, _jsxs("article", { "data-slot": "docs-article", className: "flex min-w-0 flex-col gap-8", children: [title ? (_jsxs("header", { className: "flex flex-col gap-3", children: [_jsx(Heading, { as: "h1", className: headingSizeClass('h1'), children: title }), description ? (_jsx(Text, { size: "lg", tone: "muted", className: "max-w-measure", children: description })) : null] })) : description ? (_jsx(Text, { size: "lg", tone: "muted", className: "max-w-measure", children: description })) : null, _jsx(Prose, { fullWidth: true, children: children }), neighbours ? (_jsx(Pager, { previous: neighbours.previous, next: neighbours.next, label: pagerLabel, labels: pagerLabels })) : null] }), contents ? (_jsx("aside", { "data-slot": "docs-contents", className: "hidden lg:col-start-3 lg:row-start-1 lg:block", children: _jsx(Rail, { label: tocLabel, entries: contents, currentHref: currentHref, unnamed: unnamedToc }) })) : null] }), footer] }));
198
+ contents ? 'lg:grid lg:grid-cols-[15rem_minmax(0,1fr)_13rem]' : 'lg:grid lg:grid-cols-[15rem_minmax(0,1fr)]'), children: [rail ? (_jsx("aside", { "data-slot": "docs-rail", className: "lg:col-start-1 lg:row-start-1", children: _jsx(Rail, { label: navLabel, entries: rail, currentHref: currentHref, unnamed: unnamedNav }) })) : null, _jsxs("article", { "data-slot": "docs-article", className: "flex min-w-0 flex-col gap-8", children: [title ? (_jsxs("header", { className: "flex flex-col gap-3", children: [_jsx(Heading, { as: "h1", className: headingSizeClass('h1'), children: title }), description ? (_jsx(Text, { size: "lg", tone: "muted", className: "max-w-measure", children: description })) : null] })) : description ? (_jsx(Text, { size: "lg", tone: "muted", className: "max-w-measure", children: description })) : null, _jsx(Prose, { fullWidth: true, children: children }), neighbours ? (_jsx(Pager, { previous: neighbours.previous, next: neighbours.next, label: pagerLabel, labels: pagerLabels })) : null] }), contents ? (_jsx("aside", { "data-slot": "docs-contents", className: "lg:col-start-3 lg:row-start-1", children: _jsx(Rail, { label: tocLabel, entries: contents, currentHref: currentHref, unnamed: unnamedToc }) })) : null] }), footer] }));
181
199
  }
182
200
  /* ------------------------------------------------------------------ *
183
- * The two rails at lg
201
+ * The two rails
184
202
  * ------------------------------------------------------------------ */
185
203
  /**
186
204
  * One rail: a region that scrolls inside a bound against the viewport, with the
@@ -214,32 +232,36 @@ export function DocsShell({ title, description, nav, toc, currentHref, navLabel,
214
232
  * usual cost of a fade and the reason the padding is part of the answer rather
215
233
  * than a detail.
216
234
  *
235
+ * **The bound, the sticky offset, the band and the fade are all written against
236
+ * the same `lg:`, so below `lg` this rail is an ordinary block in the flow: no
237
+ * scroll region, no cut, no reservation, no fade.** That is the right shape for a
238
+ * rail that is the first thing in a single column, because a sticky region a full
239
+ * viewport tall above the article would be worse than a long one above it.
240
+ *
241
+ * **The fade and the band are bound to the cut rather than to the rail, and the
242
+ * reason is what a fade is for.** A fade marks a cut, so it may only exist where
243
+ * there is one, and the cut is the `overflow-y` at `lg`: the scroll region, the
244
+ * cap, the sticky offset, the reserved band and the gradient are one arrangement
245
+ * or none of them. The fade shipped unprefixed, which put the arrangement out of
246
+ * step with itself at the one width that has no cut to mark. Below `lg` the region
247
+ * is an ordinary block, so the `pb-8` reserving the band is inert there and the
248
+ * gradient fell on the last row or two of a rail that was simply running on. The
249
+ * band and the fade still measured equal and the reader still lost nothing
250
+ * legible, which is why looking did not catch it: a gradient painted over content
251
+ * is a defect, and it is not a legibility one.
252
+ *
253
+ * **The limit bought here is stated rather than left to be found.** Below `lg` the
254
+ * rail is bounded by its content rather than by the viewport, so a long tree runs
255
+ * past the fold of a phone screen with nothing marking where it ends: no cut to
256
+ * mark, no band to reserve and no scroll region to scroll inside. That is the
257
+ * honest price of one copy of the tree at every width, and the measurement behind
258
+ * it is stated once on the Page above rather than repeated here.
259
+ *
217
260
  * `unnamed` is carried on the `<nav>` rather than logged, for the reason
218
261
  * `unnamedIn` gives.
219
262
  */
220
263
  function Rail({ label, entries, currentHref, unnamed, }) {
221
- return (_jsxs("div", { className: "relative lg:sticky lg:top-20", children: [_jsx("nav", { "aria-label": label, "data-unnamed-entries": unnamed, className: "lg:max-h-[calc(100svh-7rem)] lg:overflow-y-auto lg:pe-4 lg:pb-8", children: _jsx(NavList, { entries: entries, currentHref: currentHref, depth: 0 }) }), _jsx("div", { "aria-hidden": "true", "data-slot": "docs-rail-fade", className: "from-background pointer-events-none absolute inset-x-0 bottom-0 h-8 bg-gradient-to-t to-transparent" })] }));
222
- }
223
- /**
224
- * One tree behind a native disclosure, for the widths where there is no rail.
225
- *
226
- * `<details>` rather than a Component, and the whole argument is that it needs no
227
- * runtime: the platform holds the expanded state, the control is in the Tab order
228
- * with a real expanded state, and the Page stays a server Component. A Page that
229
- * shipped a client disclosure for this would put JavaScript on every documentation
230
- * page in the family to replace a browser feature that has been in the platform
231
- * since 2018.
232
- *
233
- * **The summary's word is the caller's.** `navLabel` and `tocLabel` are already
234
- * required props and already name these two navigations for a screen reader, so
235
- * the control that opens one says the same thing the region inside it is called
236
- * and the Page ships no word of its own. Nothing suppresses the browser's own
237
- * disclosure marker or its own focus ring: the marker is the cheapest honest
238
- * signal that the row is a disclosure, and `py-3` puts the target at 44 pixels for
239
- * a coarse pointer without a variant.
240
- */
241
- function Disclosure({ label, unnamed, children, }) {
242
- return (_jsxs("details", { "data-slot": "docs-nav-disclosure", children: [_jsx("summary", { className: "text-foreground cursor-pointer py-3 text-sm font-medium", children: label }), _jsx("nav", { "aria-label": label, "data-unnamed-entries": unnamed, className: "pb-4", children: children })] }));
264
+ return (_jsxs("div", { className: "relative lg:sticky lg:top-20", children: [_jsx("nav", { "aria-label": label, "data-unnamed-entries": unnamed, className: "lg:max-h-[calc(100svh-7rem)] lg:overflow-y-auto lg:pe-4 lg:pb-8", children: _jsx(NavList, { entries: entries, currentHref: currentHref, depth: 0 }) }), _jsx("div", { "aria-hidden": "true", "data-slot": "docs-rail-fade", className: "pointer-events-none lg:absolute lg:inset-x-0 lg:bottom-0 lg:h-8 lg:bg-gradient-to-t lg:from-background lg:to-transparent" })] }));
243
265
  }
244
266
  /* ------------------------------------------------------------------ *
245
267
  * The tree
package/dist/styles.css CHANGED
@@ -3324,12 +3324,21 @@
3324
3324
  }
3325
3325
  }
3326
3326
  @media (width >= 64rem) {
3327
+ .lg\:absolute {
3328
+ position: absolute;
3329
+ }
3327
3330
  .lg\:sticky {
3328
3331
  position: sticky;
3329
3332
  }
3333
+ .lg\:inset-x-0 {
3334
+ inset-inline: var(--spacing-0);
3335
+ }
3330
3336
  .lg\:top-20 {
3331
3337
  top: var(--spacing-20);
3332
3338
  }
3339
+ .lg\:bottom-0 {
3340
+ bottom: var(--spacing-0);
3341
+ }
3333
3342
  .lg\:order-1 {
3334
3343
  order: 1;
3335
3344
  }
@@ -3372,6 +3381,9 @@
3372
3381
  .lg\:hidden {
3373
3382
  display: none;
3374
3383
  }
3384
+ .lg\:h-8 {
3385
+ height: var(--spacing-8);
3386
+ }
3375
3387
  .lg\:max-h-\[calc\(100svh-7rem\)\] {
3376
3388
  max-height: calc(100svh - 7rem);
3377
3389
  }
@@ -3461,6 +3473,18 @@
3461
3473
  border-left-style: var(--tw-border-style);
3462
3474
  border-left-width: 1px;
3463
3475
  }
3476
+ .lg\:bg-gradient-to-t {
3477
+ --tw-gradient-position: to top in oklab;
3478
+ background-image: linear-gradient(var(--tw-gradient-stops));
3479
+ }
3480
+ .lg\:from-background {
3481
+ --tw-gradient-from: var(--background);
3482
+ --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
3483
+ }
3484
+ .lg\:to-transparent {
3485
+ --tw-gradient-to: transparent;
3486
+ --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
3487
+ }
3464
3488
  .lg\:p-6 {
3465
3489
  padding: var(--spacing-6);
3466
3490
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nanisoft/prism-ui",
3
- "version": "0.16.0",
3
+ "version": "0.16.1",
4
4
  "type": "module",
5
5
  "description": "Prism's React component, block and page library.",
6
6
  "license": "MIT",