@waveso/docs 0.9.1 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +539 -0
- package/README.md +99 -3
- package/dist/code-frame.d.ts +28 -1
- package/dist/code-frame.js +36 -1
- package/dist/frontmatter.d.ts +5 -0
- package/dist/frontmatter.js +5 -0
- package/dist/nav-order.d.ts +43 -0
- package/dist/nav-order.js +72 -0
- package/dist/next.d.ts +10 -0
- package/dist/next.js +33 -0
- package/dist/plugins/rehype-code-frame.js +41 -11
- package/dist/react/explore.d.ts +53 -0
- package/dist/react/explore.js +86 -0
- package/dist/react/markdown-components.js +14 -0
- package/dist/react/pager.d.ts +42 -0
- package/dist/react/pager.js +91 -0
- package/dist/react/shell-labels.d.ts +25 -1
- package/dist/react/shell-labels.js +4 -0
- package/dist/react/toc.js +34 -5
- package/dist/styles.css +944 -146
- package/dist/types.d.ts +31 -1
- package/package.json +9 -1
|
@@ -110,6 +110,20 @@ function createImage(Image) {
|
|
|
110
110
|
* "no tabindex on non-interactive elements", not a violation of it. A labelled
|
|
111
111
|
* `<section>` is a `region` landmark, so the tab stop announces itself instead
|
|
112
112
|
* of being a mystery stop in the tab order.
|
|
113
|
+
*
|
|
114
|
+
* ⚠️ ONE FRAME, AND IT WORE `.wave-docs-panel` FOR A WHILE.
|
|
115
|
+
*
|
|
116
|
+
* The panel — an outer frame, a header band, an inset card — exists to separate
|
|
117
|
+
* *chrome* from *content*. "Where to go next" and a code frame both have chrome
|
|
118
|
+
* to put in that band: a title, a language, a copy button. A table's header row
|
|
119
|
+
* is not chrome, it is data, and setting the body into a card away from its own
|
|
120
|
+
* header cost three vertical rules down each side, stopped the row dividers
|
|
121
|
+
* short of the box, and narrowed the reading width — on the densest element on
|
|
122
|
+
* a page, for nothing gained. Full-width dividers are what let an eye track a
|
|
123
|
+
* row across.
|
|
124
|
+
*
|
|
125
|
+
* It keeps the panel's outer radius, so a table and a code block still read as
|
|
126
|
+
* two of one family without the table pretending to have chrome it has not got.
|
|
113
127
|
*/
|
|
114
128
|
function createTable(label) {
|
|
115
129
|
return function MarkdownTable({ className, ...rest }) {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { NavStop } from "../nav-order.js";
|
|
2
|
+
import { DocsLinkComponent } from "./markdown-components.js";
|
|
3
|
+
import { ReactNode } from "react";
|
|
4
|
+
//#region src/react/pager.d.ts
|
|
5
|
+
interface DocsPagerProps {
|
|
6
|
+
/** The stop before this page in the reading order. Omit at the beginning. */
|
|
7
|
+
previous?: NavStop | undefined;
|
|
8
|
+
/** The stop after it. Omit at the end. */
|
|
9
|
+
next?: NavStop | undefined;
|
|
10
|
+
/** Client-side router link, e.g. `next/link`. Falls back to `<a>`. */
|
|
11
|
+
Link?: DocsLinkComponent | undefined;
|
|
12
|
+
/** Above the previous page's title. Defaults to `'Previous'`. */
|
|
13
|
+
previousLabel?: string | undefined;
|
|
14
|
+
/** Above the next page's title. Defaults to `'Next'`. */
|
|
15
|
+
nextLabel?: string | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Accessible name for the landmark. Defaults to `'Pagination'`.
|
|
18
|
+
*
|
|
19
|
+
* Named because a page can hold more than one navigation landmark — this,
|
|
20
|
+
* the sidebar and the table of contents — and "navigation" three times is
|
|
21
|
+
* not a list anyone can steer by.
|
|
22
|
+
*/
|
|
23
|
+
label?: string | undefined;
|
|
24
|
+
className?: string | undefined;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Links to the pages either side of this one in the reading order.
|
|
28
|
+
*
|
|
29
|
+
* Derived from the same tree `DocsSidebar` renders, so it cannot disagree with
|
|
30
|
+
* the column beside it — see `nav-order.ts`. Nothing here is authored: a page
|
|
31
|
+
* gets a pager by being in the navigation.
|
|
32
|
+
*
|
|
33
|
+
* ⚠️ NOTHING RENDERS AT ALL WHEN THERE IS NO NEIGHBOUR EITHER SIDE. A single
|
|
34
|
+
* page site, or a route outside the tree, would otherwise get an empty
|
|
35
|
+
* landmark — announced by a screen reader as a navigation region containing
|
|
36
|
+
* nothing, which is worse than the absence it is standing in for.
|
|
37
|
+
*
|
|
38
|
+
* No client JavaScript: two links and a heading, rendered on the server.
|
|
39
|
+
*/
|
|
40
|
+
declare function DocsPager({ previous, next, Link, previousLabel, nextLabel, label, className }: DocsPagerProps): ReactNode;
|
|
41
|
+
//#endregion
|
|
42
|
+
export { DocsPager, DocsPagerProps };
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
//#region src/react/pager.tsx
|
|
3
|
+
/**
|
|
4
|
+
* Links to the pages either side of this one in the reading order.
|
|
5
|
+
*
|
|
6
|
+
* Derived from the same tree `DocsSidebar` renders, so it cannot disagree with
|
|
7
|
+
* the column beside it — see `nav-order.ts`. Nothing here is authored: a page
|
|
8
|
+
* gets a pager by being in the navigation.
|
|
9
|
+
*
|
|
10
|
+
* ⚠️ NOTHING RENDERS AT ALL WHEN THERE IS NO NEIGHBOUR EITHER SIDE. A single
|
|
11
|
+
* page site, or a route outside the tree, would otherwise get an empty
|
|
12
|
+
* landmark — announced by a screen reader as a navigation region containing
|
|
13
|
+
* nothing, which is worse than the absence it is standing in for.
|
|
14
|
+
*
|
|
15
|
+
* No client JavaScript: two links and a heading, rendered on the server.
|
|
16
|
+
*/
|
|
17
|
+
function DocsPager({ previous, next, Link, previousLabel = "Previous", nextLabel = "Next", label = "Pagination", className }) {
|
|
18
|
+
if (previous === void 0 && next === void 0) return null;
|
|
19
|
+
return /* @__PURE__ */ jsxs("nav", {
|
|
20
|
+
"aria-label": label,
|
|
21
|
+
className: ["wave-docs-pager", className].filter(Boolean).join(" "),
|
|
22
|
+
children: [/* @__PURE__ */ jsx(PagerLink, {
|
|
23
|
+
stop: previous,
|
|
24
|
+
direction: "previous",
|
|
25
|
+
caption: previousLabel,
|
|
26
|
+
Link
|
|
27
|
+
}), /* @__PURE__ */ jsx(PagerLink, {
|
|
28
|
+
stop: next,
|
|
29
|
+
direction: "next",
|
|
30
|
+
caption: nextLabel,
|
|
31
|
+
Link
|
|
32
|
+
})]
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
function PagerLink({ stop, direction, caption, Link }) {
|
|
36
|
+
if (stop === void 0) return /* @__PURE__ */ jsx("div", { className: "wave-docs-pager__gap" });
|
|
37
|
+
const body = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("span", {
|
|
38
|
+
className: "wave-docs-pager__caption",
|
|
39
|
+
children: [
|
|
40
|
+
direction === "previous" ? /* @__PURE__ */ jsx(PagerChevron, {}) : null,
|
|
41
|
+
caption,
|
|
42
|
+
direction === "next" ? /* @__PURE__ */ jsx(PagerChevron, {}) : null
|
|
43
|
+
]
|
|
44
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
45
|
+
className: "wave-docs-pager__title",
|
|
46
|
+
children: stop.title
|
|
47
|
+
})] });
|
|
48
|
+
const props = {
|
|
49
|
+
className: "wave-docs-pager__link",
|
|
50
|
+
href: stop.href,
|
|
51
|
+
"data-direction": direction,
|
|
52
|
+
"aria-label": `${caption}: ${stop.title}`
|
|
53
|
+
};
|
|
54
|
+
return Link === void 0 ? /* @__PURE__ */ jsx("a", {
|
|
55
|
+
...props,
|
|
56
|
+
children: body
|
|
57
|
+
}) : /* @__PURE__ */ jsx(Link, {
|
|
58
|
+
...props,
|
|
59
|
+
children: body
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The arrow on the outer edge of each link, pointing the way it goes.
|
|
64
|
+
*
|
|
65
|
+
* Decorative: the link is named "Previous: Installation" by `aria-label`, so
|
|
66
|
+
* this would only repeat a word already in the name — and `⌘`-style symbols
|
|
67
|
+
* read badly when they reach a screen reader at all.
|
|
68
|
+
*
|
|
69
|
+
* Which way it points is the stylesheet's, not this component's: it is a
|
|
70
|
+
* physical direction, and it mirrors under `dir="rtl"` where "previous" is on
|
|
71
|
+
* the right. Rotating it here would put that decision somewhere CSS cannot
|
|
72
|
+
* correct it.
|
|
73
|
+
*/
|
|
74
|
+
function PagerChevron() {
|
|
75
|
+
return /* @__PURE__ */ jsx("svg", {
|
|
76
|
+
className: "wave-docs-pager__chevron",
|
|
77
|
+
"aria-hidden": "true",
|
|
78
|
+
focusable: "false",
|
|
79
|
+
viewBox: "0 0 24 24",
|
|
80
|
+
width: "16",
|
|
81
|
+
height: "16",
|
|
82
|
+
fill: "none",
|
|
83
|
+
stroke: "currentColor",
|
|
84
|
+
strokeWidth: "2",
|
|
85
|
+
strokeLinecap: "round",
|
|
86
|
+
strokeLinejoin: "round",
|
|
87
|
+
children: /* @__PURE__ */ jsx("path", { d: "m9 18 6-6-6-6" })
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
//#endregion
|
|
91
|
+
export { DocsPager };
|
|
@@ -70,6 +70,30 @@ interface DocsLabels {
|
|
|
70
70
|
toc?: string | undefined;
|
|
71
71
|
/** The link at the end of the TOC. Default `'Back to top'`. */
|
|
72
72
|
backToTop?: string | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* Above the previous page's title in the pager. Defaults to `'Previous'`.
|
|
75
|
+
*
|
|
76
|
+
* The direction, not the destination: the page's own title is the name, and
|
|
77
|
+
* these two words are what say which way it lies.
|
|
78
|
+
*/
|
|
79
|
+
/**
|
|
80
|
+
* The "where to go next" block's heading. Defaults to `'Where to go next'`.
|
|
81
|
+
*
|
|
82
|
+
* A page opts into that block with `explore` in its frontmatter; this is the one
|
|
83
|
+
* string the package supplies for it, and the questions are the author's.
|
|
84
|
+
*/
|
|
85
|
+
explore?: string | undefined;
|
|
86
|
+
previousPage?: string | undefined;
|
|
87
|
+
/** The same for the next page. Defaults to `'Next'`. */
|
|
88
|
+
nextPage?: string | undefined;
|
|
89
|
+
/**
|
|
90
|
+
* Accessible name for the pager landmark. Defaults to `'Pagination'`.
|
|
91
|
+
*
|
|
92
|
+
* A page carries three navigation landmarks — the sidebar, the table of
|
|
93
|
+
* contents and this — and "navigation" three times is not a list anyone can
|
|
94
|
+
* steer by.
|
|
95
|
+
*/
|
|
96
|
+
pagination?: string | undefined;
|
|
73
97
|
/**
|
|
74
98
|
* Screen-reader suffix on a link that opens a new tab.
|
|
75
99
|
* Default `'(opens in a new tab)'`.
|
|
@@ -137,7 +161,7 @@ interface DocsLabels {
|
|
|
137
161
|
* failure being guarded against is a key that is declared, documented and never
|
|
138
162
|
* read, which type-checks perfectly.
|
|
139
163
|
*/
|
|
140
|
-
declare const DOCS_LABEL_KEYS: readonly ["nav", "openNav", "closeNav", "skipToContent", "expandGroup", "collapseGroup", "toc", "backToTop", "externalLink", "table", "calloutNote", "calloutTip", "calloutImportant", "calloutWarning", "calloutCaution", "youtubeTitle", "youtubePlay", "youtubeHide", "copyCode", "copyCodeFrom", "copied", "copyFailed"];
|
|
164
|
+
declare const DOCS_LABEL_KEYS: readonly ["nav", "openNav", "closeNav", "skipToContent", "expandGroup", "collapseGroup", "toc", "backToTop", "externalLink", "table", "calloutNote", "calloutTip", "calloutImportant", "calloutWarning", "calloutCaution", "youtubeTitle", "youtubePlay", "youtubeHide", "copyCode", "copyCodeFrom", "explore", "previousPage", "nextPage", "pagination", "copied", "copyFailed"];
|
|
141
165
|
/** The four the shell renders itself, resolved centrally. */
|
|
142
166
|
type ShellLabelKey = 'nav' | 'openNav' | 'closeNav' | 'skipToContent';
|
|
143
167
|
/**
|
package/dist/react/toc.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { DOCS_CONTENT_ID } from "../docs-content-id.js";
|
|
3
|
-
import { useEffect, useMemo, useRef, useState } from "react";
|
|
3
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
4
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
//#region src/react/toc.tsx
|
|
6
6
|
const DEFAULT_ROOT_MARGIN = "0px 0px -60% 0px";
|
|
@@ -48,14 +48,26 @@ function DocsToc({ entries, label = "On this page", rootMargin = DEFAULT_ROOT_MA
|
|
|
48
48
|
lastIds.current = ids;
|
|
49
49
|
setActiveId(void 0);
|
|
50
50
|
}
|
|
51
|
+
const inBand = useRef(/* @__PURE__ */ new Set());
|
|
52
|
+
const atBottom = useRef(false);
|
|
53
|
+
const resolveActive = useCallback(() => {
|
|
54
|
+
if (atBottom.current) {
|
|
55
|
+
const last = ids[ids.length - 1];
|
|
56
|
+
if (last !== void 0) {
|
|
57
|
+
setActiveId(last);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const next = ids.find((id) => inBand.current.has(id));
|
|
62
|
+
if (next !== void 0) setActiveId(next);
|
|
63
|
+
}, [ids]);
|
|
51
64
|
useEffect(() => {
|
|
52
65
|
if (ids.length === 0 || typeof IntersectionObserver === "undefined") return;
|
|
53
|
-
const visible =
|
|
66
|
+
const visible = inBand.current;
|
|
54
67
|
const observer = new IntersectionObserver((records) => {
|
|
55
68
|
for (const record of records) if (record.isIntersecting) visible.add(record.target.id);
|
|
56
69
|
else visible.delete(record.target.id);
|
|
57
|
-
|
|
58
|
-
if (next !== void 0) setActiveId(next);
|
|
70
|
+
resolveActive();
|
|
59
71
|
}, {
|
|
60
72
|
rootMargin,
|
|
61
73
|
threshold: 0
|
|
@@ -81,7 +93,24 @@ function DocsToc({ entries, label = "On this page", rootMargin = DEFAULT_ROOT_MA
|
|
|
81
93
|
if (frame !== void 0) cancelAnimationFrame(frame);
|
|
82
94
|
observer.disconnect();
|
|
83
95
|
};
|
|
84
|
-
}, [
|
|
96
|
+
}, [
|
|
97
|
+
ids,
|
|
98
|
+
rootMargin,
|
|
99
|
+
resolveActive
|
|
100
|
+
]);
|
|
101
|
+
useEffect(() => {
|
|
102
|
+
if (ids[ids.length - 1] === void 0 || typeof window === "undefined") return;
|
|
103
|
+
const onScroll = () => {
|
|
104
|
+
const scrollable = document.documentElement.scrollHeight - window.innerHeight;
|
|
105
|
+
const bottom = scrollable > 2 && window.scrollY >= scrollable - 2;
|
|
106
|
+
if (bottom === atBottom.current) return;
|
|
107
|
+
atBottom.current = bottom;
|
|
108
|
+
resolveActive();
|
|
109
|
+
};
|
|
110
|
+
window.addEventListener("scroll", onScroll, { passive: true });
|
|
111
|
+
onScroll();
|
|
112
|
+
return () => window.removeEventListener("scroll", onScroll);
|
|
113
|
+
}, [ids, resolveActive]);
|
|
85
114
|
if (entries.length === 0) return null;
|
|
86
115
|
return /* @__PURE__ */ jsxs("nav", {
|
|
87
116
|
"aria-label": label,
|