@nanisoft/prism-ui 0.15.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.
- package/dist/.tsbuildinfo +1 -1
- package/dist/blocks/data-table-01/data-table.d.ts +10 -0
- package/dist/blocks/data-table-01/data-table.d.ts.map +1 -1
- package/dist/blocks/data-table-01/data-table.js +2 -1
- package/dist/blocks/page-header-01/page-header.d.ts +7 -0
- package/dist/blocks/page-header-01/page-header.d.ts.map +1 -1
- package/dist/blocks/page-header-01/page-header.js +9 -1
- package/dist/blocks/run-console-01/run-console.d.ts.map +1 -1
- package/dist/blocks/run-console-01/run-console.js +2 -1
- package/dist/blocks/site-footer/site-footer.d.ts +16 -0
- package/dist/blocks/site-footer/site-footer.d.ts.map +1 -1
- package/dist/blocks/site-footer/site-footer.js +17 -1
- package/dist/blocks/stack-grid-01/stack-grid.d.ts +13 -0
- package/dist/blocks/stack-grid-01/stack-grid.d.ts.map +1 -1
- package/dist/blocks/stack-grid-01/stack-grid.js +14 -1
- package/dist/components/ui/diagram.d.ts +38 -7
- package/dist/components/ui/diagram.d.ts.map +1 -1
- package/dist/components/ui/diagram.js +134 -52
- package/dist/components/ui/fact-list.d.ts +17 -0
- package/dist/components/ui/fact-list.d.ts.map +1 -1
- package/dist/components/ui/fact-list.js +18 -1
- package/dist/components/ui/prose.d.ts +11 -0
- package/dist/components/ui/prose.d.ts.map +1 -1
- package/dist/components/ui/prose.js +12 -1
- package/dist/components/ui/pulse-graph.d.ts +36 -4
- package/dist/components/ui/pulse-graph.d.ts.map +1 -1
- package/dist/components/ui/pulse-graph.js +174 -60
- package/dist/components/ui/section.d.ts +33 -31
- package/dist/components/ui/section.d.ts.map +1 -1
- package/dist/components/ui/section.js +33 -31
- package/dist/lib/figure.d.ts +149 -0
- package/dist/lib/figure.d.ts.map +1 -0
- package/dist/lib/figure.js +242 -0
- package/dist/live/run-stream-01/run-stream.d.ts.map +1 -1
- package/dist/live/run-stream-01/run-stream.js +2 -1
- package/dist/pages/blog-post-page/index.d.ts +36 -15
- package/dist/pages/blog-post-page/index.d.ts.map +1 -1
- package/dist/pages/blog-post-page/index.js +35 -10
- package/dist/pages/docs-shell/docs-shell.d.ts +131 -17
- package/dist/pages/docs-shell/docs-shell.d.ts.map +1 -1
- package/dist/pages/docs-shell/docs-shell.js +230 -24
- package/dist/pages/error-page/index.d.ts.map +1 -1
- package/dist/pages/error-page/index.js +7 -3
- package/dist/pages/not-found-page/index.d.ts.map +1 -1
- package/dist/pages/not-found-page/index.js +4 -3
- package/dist/styles.css +131 -12
- package/package.json +2 -2
|
@@ -15,15 +15,36 @@ import type { ReactNode } from 'react';
|
|
|
15
15
|
* block used to make was true only of the group arm; it is now true of what the
|
|
16
16
|
* Page renders, and it says which of the two is doing the work.
|
|
17
17
|
*
|
|
18
|
-
* `title` may be the empty string, and an entry
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
18
|
+
* `title` may be the empty string, and an entry the Page cannot name is not
|
|
19
|
+
* rendered at all. It used to render as a label on the same rule that makes a
|
|
20
|
+
* group with no index a label, and that produced `<li><span></span></li>`: a
|
|
21
|
+
* row of nothing inside a `<nav>`, which one consumer measured at 102 across 25
|
|
22
|
+
* of its 31 documentation pages. A blank row is not a destination and it is not
|
|
23
|
+
* a label either, because a label is words. So the Page drops the entry and
|
|
24
|
+
* counts the drop on the rail as `data-unnamed-entries`, which is the same
|
|
25
|
+
* answer `Diagram` gives a relation it cannot resolve.
|
|
26
|
+
*
|
|
27
|
+
* **The page is not lost, and one thing is.** The address still resolves, the
|
|
28
|
+
* document still renders at it, and every link into it still works; what the rail
|
|
29
|
+
* loses is one row. The pager does lose that page, because the pager walks the
|
|
30
|
+
* same list and the row is no longer in it, so a reader who arrives at the address
|
|
31
|
+
* directly finds a document and no pager. That was already the answer before the
|
|
32
|
+
* row was dropped, and it is the cost of dropping rather than of this change:
|
|
33
|
+
* keeping it would mean publishing the nameless link a second time.
|
|
34
|
+
*
|
|
35
|
+
* **A blank `title` and a blank `href` are answered differently, and the reason
|
|
36
|
+
* is what each one has left.** A page with an address and no words is a real page
|
|
37
|
+
* with one unrenderable field, so dropping the row costs a reader nothing and
|
|
38
|
+
* taking the whole screen down over it would cost them everything. A page with
|
|
39
|
+
* words and no address is a row whose entire content is a route that does not
|
|
40
|
+
* exist, and there is nothing to render in its place, so `readTree` refuses it.
|
|
23
41
|
*/
|
|
24
42
|
export type DocsNavPage = {
|
|
25
43
|
type: 'page';
|
|
26
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* The words the reader meets. An empty or blank string names nothing, and the
|
|
46
|
+
* Page renders no row for the entry and counts the drop.
|
|
47
|
+
*/
|
|
27
48
|
title: string;
|
|
28
49
|
/** The address the page is read at. An empty string is refused, by name. */
|
|
29
50
|
href: string;
|
|
@@ -47,7 +68,15 @@ export type DocsNavPage = {
|
|
|
47
68
|
*/
|
|
48
69
|
export type DocsNavGroup = {
|
|
49
70
|
type: 'group';
|
|
50
|
-
/**
|
|
71
|
+
/**
|
|
72
|
+
* The words on the label. A status inside them stays inside them.
|
|
73
|
+
*
|
|
74
|
+
* An empty or blank string renders no label, and the pages under the group are
|
|
75
|
+
* still rendered: a group whose title cannot be rendered has lost a heading and
|
|
76
|
+
* not a section, so dropping the whole entry would delete pages the reader can
|
|
77
|
+
* otherwise reach. A group with no words and no children has nothing left to
|
|
78
|
+
* draw and is dropped whole.
|
|
79
|
+
*/
|
|
51
80
|
title: string;
|
|
52
81
|
/**
|
|
53
82
|
* The group's own index page, where it has one. Omit it for a group that is
|
|
@@ -259,21 +288,104 @@ export type DocsShellProps = {
|
|
|
259
288
|
* author filed it. A Page that sorted its rail would flatten the one thing the
|
|
260
289
|
* three sites disagree about and cannot both be right about.
|
|
261
290
|
*
|
|
262
|
-
* **The rail is bounded in height
|
|
263
|
-
*
|
|
264
|
-
*
|
|
265
|
-
*
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
* sidebar.
|
|
291
|
+
* **The rail is bounded in height, and the bound is what the reader has to be
|
|
292
|
+
* able to see.** Atlas files nineteen pages and AlphaLens files twenty-seven, so
|
|
293
|
+
* the taller tree is half again as long, and an unbounded rail on a tall tree is
|
|
294
|
+
* a rail that pushes the document below the fold before the reader has read a
|
|
295
|
+
* line of it. The rail and the contents rail are each capped against the viewport
|
|
296
|
+
* and scroll inside it, so a nineteen-page tree and a twenty-seven-page tree are
|
|
297
|
+
* both a full screen and neither is a page-long sidebar.
|
|
298
|
+
*
|
|
299
|
+
* **A cap the reader cannot see is a defect, and this one was invisible for 344
|
|
300
|
+
* and 750 pixels.** Measured in two consumers' built exports at 1280 by 680, the
|
|
301
|
+
* rail's content stood at 912 and 1318 pixels against a 568 pixel box, so more
|
|
302
|
+
* than half of one site's documentation navigation sat below the fold with
|
|
303
|
+
* `mask-image: none`, no scrollbar Chrome would draw until the reader scrolled,
|
|
304
|
+
* no fade and no count. Chrome's overlay scrollbars are the reason this is not
|
|
305
|
+
* caught by looking: they appear on scroll, so the first render of a rail that
|
|
306
|
+
* hides half its content is indistinguishable from a rail that has all of it, and
|
|
307
|
+
* the last visible row was cut mid-word above dead space, which reads as a
|
|
308
|
+
* rendering fault rather than as a scroll region.
|
|
309
|
+
*
|
|
310
|
+
* **The affordance is a fade across the foot of the scroll region, with the space
|
|
311
|
+
* it covers reserved rather than borrowed.** Three answers were available and the
|
|
312
|
+
* other two were rejected for stated reasons. A persistent themed scrollbar is
|
|
313
|
+
* truthful at both ends and costs nothing to legibility, and it is still here in
|
|
314
|
+
* the sense that the region is a real scroll region rather than a clipped box,
|
|
315
|
+
* but it is a single hairline whose length says "there is more" without saying
|
|
316
|
+
* which way, it needs `scrollbar-gutter` reserved in a 15rem rail to stop the
|
|
317
|
+
* content shifting when a short tree becomes a tall one, and in Chrome it is the
|
|
318
|
+
* least reliable of the three to reason about because the property that makes it
|
|
319
|
+
* persistent is the same one whose default is an overlay. A collapse control needs
|
|
320
|
+
* a disclosure whose state a server Component cannot hold. An "N more" control is
|
|
321
|
+
* copy this Page does not ship and it needs the count the Page cannot compute
|
|
322
|
+
* without measuring, which is the one thing a server Component cannot do.
|
|
323
|
+
*
|
|
324
|
+
* So the fade, and it is painted on a wrapper that does not scroll rather than on
|
|
325
|
+
* the scroll region itself: a mask or a gradient inside the scrollport moves with
|
|
326
|
+
* the content and marks nothing. The wrapper carries the sticky offset, the
|
|
327
|
+
* scroll region keeps the cap and the scrolling, and the gradient is pinned to
|
|
328
|
+
* the wrapper's foot. The region carries `padding-bottom` of the same height, and
|
|
329
|
+
* that is the half that makes it honest: at rest the gradient falls on reserved
|
|
330
|
+
* space and the last row is fully legible, and only while there is more below
|
|
331
|
+
* does it fall on content. Without the padding the same gradient washes the last
|
|
332
|
+
* row permanently, which is the usual cost of this answer and the reason the
|
|
333
|
+
* padding is not optional.
|
|
334
|
+
*
|
|
335
|
+
* **The fade is paint, and it is on the accessibility tree's terms.** It is an
|
|
336
|
+
* empty element with `aria-hidden` and `pointer-events-none`, inside the `<nav>`
|
|
337
|
+
* and outside the `<ul>`, so it is not a list item, it is not announced, it never
|
|
338
|
+
* takes a press and it never reaches a Tab stop. A keyboard reader scrolls the
|
|
339
|
+
* region with the arrow keys exactly as before and reaches every entry, and a
|
|
340
|
+
* screen-reader user is told nothing at all, which is the right answer: the cut is
|
|
341
|
+
* a fact about ink, and announcing it would put a sentence in the middle of a
|
|
342
|
+
* list of a consumer's own pages.
|
|
343
|
+
*
|
|
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.
|
|
370
|
+
*
|
|
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.
|
|
269
379
|
*
|
|
270
380
|
* **The frame is three columns from `lg`, and the third is the consumer's to
|
|
271
381
|
* fill.** The rail is 15rem, the document takes the rest, and the contents rail
|
|
272
382
|
* is 13rem. The third track exists only when `toc` is passed, because the
|
|
273
383
|
* document takes the second track by auto-placement and a template that named a
|
|
274
384
|
* track no child occupies would leave the document in the 15rem one. Below `lg`
|
|
275
|
-
* the frame is a single column
|
|
276
|
-
*
|
|
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.
|
|
277
389
|
*
|
|
278
390
|
* It is a Page rather than a Block because it is a whole screen and it is the
|
|
279
391
|
* screen a content pipeline targets: a route that reads one document and hands
|
|
@@ -284,7 +396,9 @@ export type DocsShellProps = {
|
|
|
284
396
|
*
|
|
285
397
|
* It is a server Component. It fetches nothing, it holds no state and it imports
|
|
286
398
|
* no router, so a consumer renders it from whichever route their framework names
|
|
287
|
-
* and hands it the document their pipeline produced.
|
|
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.
|
|
288
402
|
*/
|
|
289
403
|
export declare function DocsShell({ title, description, nav, toc, currentHref, navLabel, tocLabel, pagerLabel, pagerLabels, header, footer, className, children, }: DocsShellProps): import("react").JSX.Element;
|
|
290
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;
|
|
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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Prose } from '../../components/ui/prose.js';
|
|
3
|
+
import { headingSizeClass } from '../../components/ui/section.js';
|
|
3
4
|
import { Heading, Text } from '../../components/ui/typography.js';
|
|
4
5
|
import { cn } from '../../lib/utils.js';
|
|
5
6
|
/**
|
|
@@ -59,21 +60,104 @@ import { cn } from '../../lib/utils.js';
|
|
|
59
60
|
* author filed it. A Page that sorted its rail would flatten the one thing the
|
|
60
61
|
* three sites disagree about and cannot both be right about.
|
|
61
62
|
*
|
|
62
|
-
* **The rail is bounded in height
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* sidebar.
|
|
63
|
+
* **The rail is bounded in height, and the bound is what the reader has to be
|
|
64
|
+
* able to see.** Atlas files nineteen pages and AlphaLens files twenty-seven, so
|
|
65
|
+
* the taller tree is half again as long, and an unbounded rail on a tall tree is
|
|
66
|
+
* a rail that pushes the document below the fold before the reader has read a
|
|
67
|
+
* line of it. The rail and the contents rail are each capped against the viewport
|
|
68
|
+
* and scroll inside it, so a nineteen-page tree and a twenty-seven-page tree are
|
|
69
|
+
* both a full screen and neither is a page-long sidebar.
|
|
70
|
+
*
|
|
71
|
+
* **A cap the reader cannot see is a defect, and this one was invisible for 344
|
|
72
|
+
* and 750 pixels.** Measured in two consumers' built exports at 1280 by 680, the
|
|
73
|
+
* rail's content stood at 912 and 1318 pixels against a 568 pixel box, so more
|
|
74
|
+
* than half of one site's documentation navigation sat below the fold with
|
|
75
|
+
* `mask-image: none`, no scrollbar Chrome would draw until the reader scrolled,
|
|
76
|
+
* no fade and no count. Chrome's overlay scrollbars are the reason this is not
|
|
77
|
+
* caught by looking: they appear on scroll, so the first render of a rail that
|
|
78
|
+
* hides half its content is indistinguishable from a rail that has all of it, and
|
|
79
|
+
* the last visible row was cut mid-word above dead space, which reads as a
|
|
80
|
+
* rendering fault rather than as a scroll region.
|
|
81
|
+
*
|
|
82
|
+
* **The affordance is a fade across the foot of the scroll region, with the space
|
|
83
|
+
* it covers reserved rather than borrowed.** Three answers were available and the
|
|
84
|
+
* other two were rejected for stated reasons. A persistent themed scrollbar is
|
|
85
|
+
* truthful at both ends and costs nothing to legibility, and it is still here in
|
|
86
|
+
* the sense that the region is a real scroll region rather than a clipped box,
|
|
87
|
+
* but it is a single hairline whose length says "there is more" without saying
|
|
88
|
+
* which way, it needs `scrollbar-gutter` reserved in a 15rem rail to stop the
|
|
89
|
+
* content shifting when a short tree becomes a tall one, and in Chrome it is the
|
|
90
|
+
* least reliable of the three to reason about because the property that makes it
|
|
91
|
+
* persistent is the same one whose default is an overlay. A collapse control needs
|
|
92
|
+
* a disclosure whose state a server Component cannot hold. An "N more" control is
|
|
93
|
+
* copy this Page does not ship and it needs the count the Page cannot compute
|
|
94
|
+
* without measuring, which is the one thing a server Component cannot do.
|
|
95
|
+
*
|
|
96
|
+
* So the fade, and it is painted on a wrapper that does not scroll rather than on
|
|
97
|
+
* the scroll region itself: a mask or a gradient inside the scrollport moves with
|
|
98
|
+
* the content and marks nothing. The wrapper carries the sticky offset, the
|
|
99
|
+
* scroll region keeps the cap and the scrolling, and the gradient is pinned to
|
|
100
|
+
* the wrapper's foot. The region carries `padding-bottom` of the same height, and
|
|
101
|
+
* that is the half that makes it honest: at rest the gradient falls on reserved
|
|
102
|
+
* space and the last row is fully legible, and only while there is more below
|
|
103
|
+
* does it fall on content. Without the padding the same gradient washes the last
|
|
104
|
+
* row permanently, which is the usual cost of this answer and the reason the
|
|
105
|
+
* padding is not optional.
|
|
106
|
+
*
|
|
107
|
+
* **The fade is paint, and it is on the accessibility tree's terms.** It is an
|
|
108
|
+
* empty element with `aria-hidden` and `pointer-events-none`, inside the `<nav>`
|
|
109
|
+
* and outside the `<ul>`, so it is not a list item, it is not announced, it never
|
|
110
|
+
* takes a press and it never reaches a Tab stop. A keyboard reader scrolls the
|
|
111
|
+
* region with the arrow keys exactly as before and reaches every entry, and a
|
|
112
|
+
* screen-reader user is told nothing at all, which is the right answer: the cut is
|
|
113
|
+
* a fact about ink, and announcing it would put a sentence in the middle of a
|
|
114
|
+
* list of a consumer's own pages.
|
|
115
|
+
*
|
|
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.
|
|
69
151
|
*
|
|
70
152
|
* **The frame is three columns from `lg`, and the third is the consumer's to
|
|
71
153
|
* fill.** The rail is 15rem, the document takes the rest, and the contents rail
|
|
72
154
|
* is 13rem. The third track exists only when `toc` is passed, because the
|
|
73
155
|
* document takes the second track by auto-placement and a template that named a
|
|
74
156
|
* track no child occupies would leave the document in the 15rem one. Below `lg`
|
|
75
|
-
* the frame is a single column
|
|
76
|
-
*
|
|
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.
|
|
77
161
|
*
|
|
78
162
|
* It is a Page rather than a Block because it is a whole screen and it is the
|
|
79
163
|
* screen a content pipeline targets: a route that reads one document and hands
|
|
@@ -84,7 +168,9 @@ import { cn } from '../../lib/utils.js';
|
|
|
84
168
|
*
|
|
85
169
|
* It is a server Component. It fetches nothing, it holds no state and it imports
|
|
86
170
|
* no router, so a consumer renders it from whichever route their framework names
|
|
87
|
-
* and hands it the document their pipeline produced.
|
|
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.
|
|
88
174
|
*/
|
|
89
175
|
export function DocsShell({ title, description, nav, toc, currentHref, navLabel, tocLabel, pagerLabel, pagerLabels, header, footer, className, children, }) {
|
|
90
176
|
readTree(nav, 'nav');
|
|
@@ -92,6 +178,8 @@ export function DocsShell({ title, description, nav, toc, currentHref, navLabel,
|
|
|
92
178
|
const rail = nav && nav.length > 0 ? nav : undefined;
|
|
93
179
|
const contents = toc && toc.length > 0 ? toc : undefined;
|
|
94
180
|
const neighbours = currentHref === undefined ? undefined : deriveNeighbours(nav ?? [], currentHref);
|
|
181
|
+
const unnamedNav = unnamedIn(nav);
|
|
182
|
+
const unnamedToc = unnamedIn(toc);
|
|
95
183
|
return (_jsxs("div", { "data-slot": "docs-shell", className: cn('mx-auto w-full max-w-page px-6 py-10 lg:px-8', className), children: [header, _jsxs("div", { "data-slot": "docs-shell-frame", className: cn('flex flex-col gap-8 lg:flex-row lg:gap-10',
|
|
96
184
|
// One track for the rail, one for the document, and a third for the
|
|
97
185
|
// contents rail when there is one. The template names exactly the
|
|
@@ -107,7 +195,73 @@ export function DocsShell({ title, description, nav, toc, currentHref, navLabel,
|
|
|
107
195
|
// contents rail landed in an implicit `auto` track rather than the
|
|
108
196
|
// 13rem one. `check-breakpoint-variants.mjs` is the gate that says so
|
|
109
197
|
// to the next class written against a screen the theme does not emit.
|
|
110
|
-
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: "
|
|
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] }));
|
|
199
|
+
}
|
|
200
|
+
/* ------------------------------------------------------------------ *
|
|
201
|
+
* The two rails
|
|
202
|
+
* ------------------------------------------------------------------ */
|
|
203
|
+
/**
|
|
204
|
+
* One rail: a region that scrolls inside a bound against the viewport, with the
|
|
205
|
+
* cut at its foot marked so the rows below it are discoverable.
|
|
206
|
+
*
|
|
207
|
+
* **The sticky offset is on this wrapper and not on the scroll region, and the
|
|
208
|
+
* reason is the fade.** The fade has to be pinned to the foot of the region while
|
|
209
|
+
* the region scrolls, and nothing inside a scroll container stays put while that
|
|
210
|
+
* container scrolls: a gradient or a mask written into the scrollport travels with
|
|
211
|
+
* the content and so marks nothing once the reader has scrolled. The wrapper is
|
|
212
|
+
* the element that travels, so the fade is absolutely positioned against it and
|
|
213
|
+
* the `<nav>` inside is free to be nothing but the scroll region.
|
|
214
|
+
*
|
|
215
|
+
* The cap is `100svh` less the sticky offset plus the gap under it, and `svh` is
|
|
216
|
+
* the smallest viewport height rather than the largest, which is the direction that
|
|
217
|
+
* matters here. `dvh` would grow to the full height the moment a mobile browser's
|
|
218
|
+
* URL bar retracted, and a sticky region measured against a viewport taller than
|
|
219
|
+
* the one on screen is a region whose foot is below the bottom of the screen
|
|
220
|
+
* while it is pinned, which is the one state the bound exists to prevent. `svh`
|
|
221
|
+
* is never taller than what is visible, so `top` plus `max-h` is always inside the
|
|
222
|
+
* viewport and the rail's foot always clears it. `top-20` is 5rem and the cap is
|
|
223
|
+
* the viewport less 7rem, so the foot sits 2rem above the bottom edge at every
|
|
224
|
+
* window height; a short window makes the rail shorter and does not make it
|
|
225
|
+
* taller than the space it is pinned in.
|
|
226
|
+
*
|
|
227
|
+
* `padding-bottom` is the same height as the fade, and it is what makes the fade
|
|
228
|
+
* honest. The gradient falls on the last 2rem of whatever the scrollport is
|
|
229
|
+
* showing, so with the padding reserved it falls on empty space once the reader
|
|
230
|
+
* has reached the end and on content only while there is more below. Without it
|
|
231
|
+
* the same gradient permanently washes the bottom of the last row, which is the
|
|
232
|
+
* usual cost of a fade and the reason the padding is part of the answer rather
|
|
233
|
+
* than a detail.
|
|
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
|
+
*
|
|
260
|
+
* `unnamed` is carried on the `<nav>` rather than logged, for the reason
|
|
261
|
+
* `unnamedIn` gives.
|
|
262
|
+
*/
|
|
263
|
+
function Rail({ label, entries, currentHref, unnamed, }) {
|
|
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" })] }));
|
|
111
265
|
}
|
|
112
266
|
/* ------------------------------------------------------------------ *
|
|
113
267
|
* The tree
|
|
@@ -124,6 +278,21 @@ export function DocsShell({ title, description, nav, toc, currentHref, navLabel,
|
|
|
124
278
|
function addressOf(href) {
|
|
125
279
|
return href !== undefined && href.trim() !== '' ? href : undefined;
|
|
126
280
|
}
|
|
281
|
+
/**
|
|
282
|
+
* Whether an entry has words to be called by.
|
|
283
|
+
*
|
|
284
|
+
* Blank counts as none, for the same reason `addressOf` counts it: all three
|
|
285
|
+
* consumer adapters build a title out of whatever their content pipeline produced,
|
|
286
|
+
* and one of them maps a heading whose title arrives as a React element to the
|
|
287
|
+
* empty string. A row is rendered from a string, and a string of spaces is not a
|
|
288
|
+
* name. It is read here rather than at each use because `destinationOf` decides
|
|
289
|
+
* between a link and a label, the renderer decides between a row and nothing, and
|
|
290
|
+
* the counter decides how many rows went missing, and three answers to one
|
|
291
|
+
* question is how a fourth grows.
|
|
292
|
+
*/
|
|
293
|
+
function named(entry) {
|
|
294
|
+
return entry.title.trim() !== '';
|
|
295
|
+
}
|
|
127
296
|
/**
|
|
128
297
|
* The address an entry is reachable at, or `undefined` when it is not a
|
|
129
298
|
* destination at all.
|
|
@@ -136,7 +305,35 @@ function addressOf(href) {
|
|
|
136
305
|
* `Next` link under it.
|
|
137
306
|
*/
|
|
138
307
|
function destinationOf(entry) {
|
|
139
|
-
return entry
|
|
308
|
+
return named(entry) ? addressOf(entry.href) : undefined;
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* How many entries in a tree the Page cannot name, and therefore did not draw.
|
|
312
|
+
*
|
|
313
|
+
* **It is counted rather than swallowed, and the place it is counted on is the
|
|
314
|
+
* rail itself.** `Diagram` answers a dropped relation the same way, with
|
|
315
|
+
* `data-unresolved-relations` on the drawing, and the argument is the same one: a
|
|
316
|
+
* row that did not draw is a fact about the caller's data, and a fact that leaves
|
|
317
|
+
* no trace is a defect the next reader has to rediscover from a screenshot. The
|
|
318
|
+
* number is on the element rather than in a console because a caller reads the
|
|
319
|
+
* element and does not read the console.
|
|
320
|
+
*
|
|
321
|
+
* Three things are counted, because three things go missing rather than two:
|
|
322
|
+
* a page with no words, which is dropped whole; a group with no words, whose
|
|
323
|
+
* label is not rendered while its pages still are; and a group with neither words
|
|
324
|
+
* nor children, which has nothing left to draw and is dropped whole.
|
|
325
|
+
*/
|
|
326
|
+
function unnamedIn(entries) {
|
|
327
|
+
let count = 0;
|
|
328
|
+
for (const entry of entries ?? []) {
|
|
329
|
+
if (entry.type === 'divider')
|
|
330
|
+
continue;
|
|
331
|
+
if (!named(entry))
|
|
332
|
+
count += 1;
|
|
333
|
+
if (entry.type === 'group')
|
|
334
|
+
count += unnamedIn(entry.items);
|
|
335
|
+
}
|
|
336
|
+
return count;
|
|
140
337
|
}
|
|
141
338
|
/**
|
|
142
339
|
* Reads a tree before any of it renders, and refuses the one shape it cannot
|
|
@@ -205,15 +402,23 @@ function NavNode({ entry, currentHref, depth, }) {
|
|
|
205
402
|
}
|
|
206
403
|
const href = destinationOf(entry);
|
|
207
404
|
if (entry.type === 'group') {
|
|
208
|
-
|
|
405
|
+
// A group with no words and no pages has nothing left to draw, and a `<li>`
|
|
406
|
+
// holding an empty `<div>` is the same empty row the page arm used to render.
|
|
407
|
+
// Dropping it costs nothing, because there was nothing in it.
|
|
408
|
+
if (!named(entry) && entry.items.length === 0)
|
|
409
|
+
return null;
|
|
410
|
+
return (_jsx("li", { "data-slot": "docs-nav-group", children: _jsxs("div", { className: "flex flex-col gap-1", children: [!named(entry) ? null : href === undefined ? (_jsx("span", { "data-slot": "docs-nav-label", className: cn('rounded-sm text-sm font-semibold tracking-tight', containsHref(entry, currentHref) ? 'text-foreground' : 'text-muted-foreground'), children: entry.title })) : (_jsx("a", { "data-slot": "docs-nav-heading", href: href, "aria-current": currentHref === href ? 'page' : undefined, className: cn('hover:text-foreground rounded-sm text-sm font-semibold tracking-tight transition-colors duration-fast ease-out', under(href, currentHref) ? 'text-foreground' : 'text-muted-foreground'), children: entry.title })), entry.items.length > 0 ? (_jsx(NavList, { entries: entry.items, currentHref: currentHref, depth: depth + 1 })) : null] }) }));
|
|
209
411
|
}
|
|
210
|
-
// The page arm
|
|
211
|
-
// named the entry, so
|
|
212
|
-
//
|
|
213
|
-
// with no accessible name is announced as "link" and nothing
|
|
214
|
-
|
|
412
|
+
// The page arm, and there is one shape of it left. `readTree` refused a page
|
|
413
|
+
// with no address above and named the entry, so every page that reaches here has
|
|
414
|
+
// one, and a page with no words is not rendered at all rather than rendered as
|
|
415
|
+
// a label: a link with no accessible name is announced as "link" and nothing
|
|
416
|
+
// else, and a blank row is not a label either because a label is words.
|
|
417
|
+
if (!named(entry))
|
|
418
|
+
return null;
|
|
419
|
+
return (_jsx("li", { "data-slot": "docs-nav-page", children: _jsx("a", { "data-slot": "docs-nav-link", href: href, "aria-current": currentHref === href ? 'page' : undefined, className: cn('-ms-px block border-l-2 py-1 ps-3 text-sm transition-colors duration-fast ease-out', currentHref === href
|
|
215
420
|
? 'text-foreground border-primary font-medium'
|
|
216
|
-
: 'text-muted-foreground hover:text-foreground border-transparent'), children: entry.title })
|
|
421
|
+
: 'text-muted-foreground hover:text-foreground border-transparent'), children: entry.title }) }));
|
|
217
422
|
}
|
|
218
423
|
/**
|
|
219
424
|
* Every page the tree holds, in the order a reader meets them.
|
|
@@ -225,11 +430,12 @@ function NavNode({ entry, currentHref, depth, }) {
|
|
|
225
430
|
* the pager to reach either. A divider contributes nothing at all.
|
|
226
431
|
*
|
|
227
432
|
* The row a reader can click and the row the pager can reach are decided by the
|
|
228
|
-
* SAME function, `destinationOf
|
|
229
|
-
*
|
|
230
|
-
* in the rail
|
|
231
|
-
*
|
|
232
|
-
*
|
|
433
|
+
* SAME function, `destinationOf`, and a row with no words is now dropped from the
|
|
434
|
+
* rail as well, so the two surfaces agree twice over rather than once by accident.
|
|
435
|
+
* The defect this replaced was a nameless anchor in the rail and a `Next` link
|
|
436
|
+
* under it carrying the text of whichever entry happened to follow, published
|
|
437
|
+
* from one malformed row. Deriving without asking produced the first and a
|
|
438
|
+
* separate opinion produced the second; asking once produces neither.
|
|
233
439
|
*/
|
|
234
440
|
function flatten(entries, into = []) {
|
|
235
441
|
for (const entry of entries) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/pages/error-page/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAItC,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/pages/error-page/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAItC,OAAO,EAAyC,KAAK,YAAY,EAAE,MAAM,6BAA6B,CAAA;AAItG;;;;;;;;;GASG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,6BAA6B;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,CAAA;AAED;;;;;;;;GAQG;AACH,KAAK,eAAe,GAAG;IACrB;;;;;;;OAOG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;;;;OAKG;IACH,KAAK,EAAE,MAAM,CAAA;IACb,0FAA0F;IAC1F,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB;;;OAGG;IACH,KAAK,EAAE,SAAS,aAAa,EAAE,CAAA;IAC/B;;;;;;;OAOG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB,wFAAwF;IACxF,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B,6GAA6G;IAC7G,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,cAAc,GAAG,eAAe,GAC1C,CACI;IACE;;;;;;;OAOG;IACH,SAAS,EAAE,MAAM,CAAA;IACjB;;;;;;OAMG;IACH,cAAc,EAAE,MAAM,CAAA;CACvB,GACD;IACE,mCAAmC;IACnC,SAAS,CAAC,EAAE,KAAK,CAAA;IACjB,4DAA4D;IAC5D,cAAc,CAAC,EAAE,KAAK,CAAA;CACvB,CACJ,CAAA;AAqBH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgEG;AACH,wBAAgB,SAAS,CAAC,EACxB,IAAI,EACJ,KAAK,EACL,WAAW,EACX,KAAK,EACL,KAAK,EACL,UAAU,EACV,SAAS,EACT,cAAc,EACd,QAAQ,EACR,YAAmB,EACnB,SAAS,GACV,EAAE,cAAc,+BAqEhB;AAED,eAAe,SAAS,CAAA"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { CtaLink } from '../../components/ui/cta-link.js';
|
|
3
3
|
import { Prose } from '../../components/ui/prose.js';
|
|
4
|
-
import { Section, childLevel } from '../../components/ui/section.js';
|
|
4
|
+
import { Section, childLevel, headingSizeClass } from '../../components/ui/section.js';
|
|
5
5
|
import { Heading, Text } from '../../components/ui/typography.js';
|
|
6
6
|
import { cn } from '../../lib/utils.js';
|
|
7
7
|
/**
|
|
@@ -90,9 +90,13 @@ export function ErrorPage({ code, title, description, retry, links, linksLabel,
|
|
|
90
90
|
assertReference(reference, referenceLabel);
|
|
91
91
|
/*
|
|
92
92
|
The headline sits one step below the code, which is the same derivation every
|
|
93
|
-
Block uses and the reason a hardcoded `h2` would be right exactly once.
|
|
93
|
+
Block uses and the reason a hardcoded `h2` would be right exactly once. The
|
|
94
|
+
size is asked of the same table rather than passed to `Heading`'s `size`, which
|
|
95
|
+
is a step of the scale and not a rung of the ladder, so the code and the
|
|
96
|
+
headline were drawn at fixed sizes that the ladder's ceiling has since left
|
|
97
|
+
behind.
|
|
94
98
|
*/
|
|
95
99
|
const TitleHeading = childLevel(headingLevel);
|
|
96
|
-
return (_jsx(Section, { "data-slot": "error-page", className: cn(className), children: _jsxs("div", { "data-slot": "error-page-body", className: "flex flex-col items-start gap-6", children: [_jsx(Heading, { as: headingLevel,
|
|
100
|
+
return (_jsx(Section, { "data-slot": "error-page", className: cn(className), children: _jsxs("div", { "data-slot": "error-page-body", className: "flex flex-col items-start gap-6", children: [_jsx(Heading, { as: headingLevel, className: cn('text-muted-foreground font-mono', headingSizeClass(headingLevel)), children: code }), _jsxs("div", { className: "flex flex-col gap-3", children: [_jsx(Heading, { as: TitleHeading, className: headingSizeClass(TitleHeading), children: title }), description ? _jsx(Text, { size: "lg", children: description }) : null] }), retry === undefined ? null : (_jsx("div", { "data-slot": "error-page-retry", children: retry })), links.length > 0 ? (_jsx("nav", { "aria-label": linksLabel, className: "flex flex-wrap items-center gap-3", children: links.map((link, index) => (_jsx(CtaLink, { href: link.href, newTab: link.newTab, variant: index === 0 ? 'default' : 'outline', children: link.label }, link.href))) })) : null, reference === undefined ? null : (_jsxs("dl", { "data-slot": "error-page-reference", className: "flex flex-col items-start gap-1", children: [_jsx("dt", { className: "text-muted-foreground text-xs", children: referenceLabel }), _jsx("dd", { className: "font-mono text-sm", children: reference })] })), children ? _jsx(Prose, { className: "mt-2", children: children }) : null] }) }));
|
|
97
101
|
}
|
|
98
102
|
export default ErrorPage;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/pages/not-found-page/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/pages/not-found-page/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAQtC;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,6BAA6B;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,KAAK,EAAE,SAAS,YAAY,EAAE,CAAA;IAC9B;;;;;OAKG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB;;;OAGG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAgB,YAAY,CAAC,EAC3B,IAAI,EACJ,KAAK,EACL,WAAW,EACX,KAAK,EACL,UAAU,EACV,QAAQ,EACR,SAAS,GACV,EAAE,iBAAiB,+BA+BnB;AAED,eAAe,YAAY,CAAA"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { CtaLink } from '../../components/ui/cta-link.js';
|
|
3
|
-
import { Heading, Text } from '../../components/ui/typography.js';
|
|
4
3
|
import { Prose } from '../../components/ui/prose.js';
|
|
5
|
-
import { Section } from '../../components/ui/section.js';
|
|
4
|
+
import { Section, headingSizeClass } from '../../components/ui/section.js';
|
|
5
|
+
import { Heading, Text } from '../../components/ui/typography.js';
|
|
6
|
+
import { cn } from '../../lib/utils.js';
|
|
6
7
|
/**
|
|
7
8
|
* A complete not-found screen: the code, what happened, and the ways out.
|
|
8
9
|
*
|
|
@@ -41,6 +42,6 @@ import { Section } from '../../components/ui/section.js';
|
|
|
41
42
|
* route their framework names.
|
|
42
43
|
*/
|
|
43
44
|
export function NotFoundPage({ code, title, description, links, linksLabel, children, className, }) {
|
|
44
|
-
return (_jsx(Section, { className: className, children: _jsxs("div", { className: "flex flex-col items-start gap-6", children: [_jsx(Heading, { as: "h1",
|
|
45
|
+
return (_jsx(Section, { className: className, children: _jsxs("div", { className: "flex flex-col items-start gap-6", children: [_jsx(Heading, { as: "h1", className: cn('text-muted-foreground font-mono', headingSizeClass('h1')), children: code }), _jsxs("div", { className: "flex flex-col gap-3", children: [_jsx(Heading, { as: "h2", className: headingSizeClass('h2'), children: title }), description ? _jsx(Text, { size: "lg", children: description }) : null] }), links.length > 0 ? (_jsx("nav", { "aria-label": linksLabel, className: "flex flex-wrap items-center gap-3", children: links.map((link, index) => (_jsx(CtaLink, { href: link.href, newTab: link.newTab, variant: index === 0 ? 'default' : 'outline', children: link.label }, link.href))) })) : null, children ? _jsx(Prose, { className: "mt-2", children: children }) : null] }) }));
|
|
45
46
|
}
|
|
46
47
|
export default NotFoundPage;
|