@tenphi/renderer 0.23.0 → 0.25.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/dist/client/client-navigation.d.ts +1 -0
- package/dist/client/client-navigation.js +41 -0
- package/dist/client/client-navigation.js.map +1 -0
- package/dist/client/navigation-router.d.ts +2 -0
- package/dist/client/navigation-router.js +36 -0
- package/dist/client/navigation-router.js.map +1 -0
- package/dist/client/prefetch-focus.d.ts +9 -0
- package/dist/client/prefetch-focus.d.ts.map +1 -0
- package/dist/client/prefetch-focus.js +26 -0
- package/dist/client/prefetch-focus.js.map +1 -0
- package/dist/client/search.d.ts.map +1 -1
- package/dist/client/search.js +15 -1
- package/dist/client/search.js.map +1 -1
- package/dist/components/AppearanceInit.astro +6 -0
- package/dist/components/Document.styles.js +13 -0
- package/dist/components/SelectPopover.astro +12 -3
- package/dist/components/appearance-bootstrap.js +21 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/overrides/Search.astro +15 -8
- package/dist/routes/Page.astro +6 -1
- package/package.json +2 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "./navigation-router.js";
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
//#region src/client/client-navigation.ts
|
|
2
|
+
let pageLoadNotified = false;
|
|
3
|
+
document.addEventListener("astro:page-load", () => {
|
|
4
|
+
pageLoadNotified = true;
|
|
5
|
+
}, { once: true });
|
|
6
|
+
window.addEventListener("load", () => {
|
|
7
|
+
window.setTimeout(() => {
|
|
8
|
+
if (!pageLoadNotified) document.dispatchEvent(new Event("astro:page-load"));
|
|
9
|
+
}, 0);
|
|
10
|
+
}, { once: true });
|
|
11
|
+
let router;
|
|
12
|
+
function loadRouter() {
|
|
13
|
+
return router ??= import("./navigation-router.js").catch((error) => {
|
|
14
|
+
router = void 0;
|
|
15
|
+
throw error;
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
function navigationLink(target) {
|
|
19
|
+
const link = target instanceof Element ? target.closest("a[href]") : null;
|
|
20
|
+
if (!(link instanceof HTMLAnchorElement) || link.hasAttribute("download") || link.hasAttribute("data-astro-reload") || link.target && link.target !== "_self") return;
|
|
21
|
+
const url = new URL(link.href);
|
|
22
|
+
if (url.origin !== location.origin || !router && url.pathname === location.pathname && url.search === location.search && url.hash) return;
|
|
23
|
+
return link;
|
|
24
|
+
}
|
|
25
|
+
for (const name of ["pointerover", "focusin"]) document.addEventListener(name, (event) => {
|
|
26
|
+
if (navigationLink(event.composedPath()[0])) loadRouter().catch(() => {});
|
|
27
|
+
});
|
|
28
|
+
document.addEventListener("click", (event) => {
|
|
29
|
+
if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
|
|
30
|
+
const link = navigationLink(event.composedPath()[0]);
|
|
31
|
+
if (!link) return;
|
|
32
|
+
event.preventDefault();
|
|
33
|
+
loadRouter().then(({ navigate }) => navigate(link.href, {
|
|
34
|
+
sourceElement: link,
|
|
35
|
+
history: link.dataset.astroHistory === "replace" ? "replace" : "auto"
|
|
36
|
+
})).catch(() => location.assign(link.href));
|
|
37
|
+
});
|
|
38
|
+
//#endregion
|
|
39
|
+
export {};
|
|
40
|
+
|
|
41
|
+
//# sourceMappingURL=client-navigation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-navigation.js","names":[],"sources":["../../src/client/client-navigation.ts"],"sourcesContent":["// Use Astro's public router without ClientRouter's vendor stylesheet. Cookbook\n// owns link interception and extracted accessibility styles; Astro owns fetch,\n// stylesheet readiness, script execution, history, and route announcements.\n// Prefetch expects an initial page-load event before later route swaps. When\n// the router is still lazy, supply it after all native load listeners finish.\nlet pageLoadNotified = false;\ndocument.addEventListener(\n \"astro:page-load\",\n () => {\n pageLoadNotified = true;\n },\n { once: true },\n);\nwindow.addEventListener(\n \"load\",\n () => {\n window.setTimeout(() => {\n if (!pageLoadNotified)\n document.dispatchEvent(new Event(\"astro:page-load\"));\n }, 0);\n },\n { once: true },\n);\n\nlet router: Promise<typeof import(\"./navigation-router.js\")> | undefined;\nfunction loadRouter() {\n return (router ??= import(\"./navigation-router.js\").catch(\n (error: unknown) => {\n router = undefined;\n throw error;\n },\n ));\n}\n\nfunction navigationLink(target: EventTarget | undefined) {\n const link = target instanceof Element ? target.closest(\"a[href]\") : null;\n if (\n !(link instanceof HTMLAnchorElement) ||\n link.hasAttribute(\"download\") ||\n link.hasAttribute(\"data-astro-reload\") ||\n (link.target && link.target !== \"_self\")\n )\n return;\n const url = new URL(link.href);\n if (\n url.origin !== location.origin ||\n (!router &&\n url.pathname === location.pathname &&\n url.search === location.search &&\n url.hash)\n )\n return;\n // Heading links stay native until a page-navigation intent loads the router.\n return link;\n}\n\n// Download the router on navigation intent, rather than for every reader.\nfor (const name of [\"pointerover\", \"focusin\"]) {\n document.addEventListener(name, (event) => {\n if (navigationLink(event.composedPath()[0]))\n void loadRouter().catch(() => {\n // A later click can retry; native navigation remains the fallback.\n });\n });\n}\n\ndocument.addEventListener(\"click\", (event) => {\n if (\n event.defaultPrevented ||\n event.button !== 0 ||\n event.metaKey ||\n event.ctrlKey ||\n event.shiftKey ||\n event.altKey\n )\n return;\n const link = navigationLink(event.composedPath()[0]);\n if (!link) return;\n event.preventDefault();\n void loadRouter()\n .then(({ navigate }) =>\n navigate(link.href, {\n sourceElement: link,\n history: link.dataset.astroHistory === \"replace\" ? \"replace\" : \"auto\",\n }),\n )\n .catch(() => location.assign(link.href));\n});\n"],"mappings":";AAKA,IAAI,mBAAmB;AACvB,SAAS,iBACP,yBACM;CACJ,mBAAmB;AACrB,GACA,EAAE,MAAM,KAAK,CACf;AACA,OAAO,iBACL,cACM;CACJ,OAAO,iBAAiB;EACtB,IAAI,CAAC,kBACH,SAAS,cAAc,IAAI,MAAM,iBAAiB,CAAC;CACvD,GAAG,CAAC;AACN,GACA,EAAE,MAAM,KAAK,CACf;AAEA,IAAI;AACJ,SAAS,aAAa;CACpB,OAAQ,WAAW,OAAO,yBAAyB,CAAC,OACjD,UAAmB;EAClB,SAAS,KAAA;EACT,MAAM;CACR,CACF;AACF;AAEA,SAAS,eAAe,QAAiC;CACvD,MAAM,OAAO,kBAAkB,UAAU,OAAO,QAAQ,SAAS,IAAI;CACrE,IACE,EAAE,gBAAgB,sBAClB,KAAK,aAAa,UAAU,KAC5B,KAAK,aAAa,mBAAmB,KACpC,KAAK,UAAU,KAAK,WAAW,SAEhC;CACF,MAAM,MAAM,IAAI,IAAI,KAAK,IAAI;CAC7B,IACE,IAAI,WAAW,SAAS,UACvB,CAAC,UACA,IAAI,aAAa,SAAS,YAC1B,IAAI,WAAW,SAAS,UACxB,IAAI,MAEN;CAEF,OAAO;AACT;AAGA,KAAK,MAAM,QAAQ,CAAC,eAAe,SAAS,GAC1C,SAAS,iBAAiB,OAAO,UAAU;CACzC,IAAI,eAAe,MAAM,aAAa,CAAC,CAAC,EAAE,GACxC,WAAgB,CAAC,CAAC,YAAY,CAE9B,CAAC;AACL,CAAC;AAGH,SAAS,iBAAiB,UAAU,UAAU;CAC5C,IACE,MAAM,oBACN,MAAM,WAAW,KACjB,MAAM,WACN,MAAM,WACN,MAAM,YACN,MAAM,QAEN;CACF,MAAM,OAAO,eAAe,MAAM,aAAa,CAAC,CAAC,EAAE;CACnD,IAAI,CAAC,MAAM;CACX,MAAM,eAAe;CACrB,WAAgB,CAAC,CACd,MAAM,EAAE,eACP,SAAS,KAAK,MAAM;EAClB,eAAe;EACf,SAAS,KAAK,QAAQ,iBAAiB,YAAY,YAAY;CACjE,CAAC,CACH,CAAC,CACA,YAAY,SAAS,OAAO,KAAK,IAAI,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { initializeTabs } from "./tabs.js";
|
|
2
|
+
import { navigate } from "astro:transitions/client";
|
|
3
|
+
//#region src/client/navigation-router.ts
|
|
4
|
+
document.addEventListener("astro:before-swap", (event) => {
|
|
5
|
+
const transition = event;
|
|
6
|
+
transition.viewTransition.skipTransition();
|
|
7
|
+
for (const name of ["data-theme", "data-contrast"]) {
|
|
8
|
+
const value = document.documentElement.getAttribute(name);
|
|
9
|
+
if (value === null) transition.newDocument.documentElement.removeAttribute(name);
|
|
10
|
+
else transition.newDocument.documentElement.setAttribute(name, value);
|
|
11
|
+
}
|
|
12
|
+
const sidebar = document.querySelector("#cookbook__sidebar");
|
|
13
|
+
const key = sidebar?.querySelector("cookbook-sidebar")?.dataset.storageKey;
|
|
14
|
+
const scroll = sidebar?.scrollTop ?? 0;
|
|
15
|
+
const swap = transition.swap;
|
|
16
|
+
transition.swap = () => {
|
|
17
|
+
swap();
|
|
18
|
+
const next = document.querySelector("#cookbook__sidebar");
|
|
19
|
+
if (next && key && next.querySelector("cookbook-sidebar")?.dataset.storageKey === key && matchMedia("(min-width: 50rem)").matches) next.scrollTop = scroll;
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
document.addEventListener("astro:after-swap", () => {
|
|
23
|
+
initializeTabs();
|
|
24
|
+
if (!location.hash) {
|
|
25
|
+
window.scrollTo({
|
|
26
|
+
top: 0,
|
|
27
|
+
left: 0,
|
|
28
|
+
behavior: "instant"
|
|
29
|
+
});
|
|
30
|
+
document.getElementById("main-content")?.focus({ preventScroll: true });
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
//#endregion
|
|
34
|
+
export { navigate };
|
|
35
|
+
|
|
36
|
+
//# sourceMappingURL=navigation-router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigation-router.js","names":[],"sources":["../../src/client/navigation-router.ts"],"sourcesContent":["import type { TransitionBeforeSwapEvent } from \"astro:transitions/client\";\nimport { initializeTabs } from \"./tabs.js\";\nexport { navigate } from \"astro:transitions/client\";\n\n// Load swap behavior with the router, before the first client navigation.\ndocument.addEventListener(\"astro:before-swap\", (event) => {\n const transition = event as TransitionBeforeSwapEvent;\n // Instant swaps avoid the browser's default full-page crossfade.\n transition.viewTransition.skipTransition();\n for (const name of [\"data-theme\", \"data-contrast\"]) {\n const value = document.documentElement.getAttribute(name);\n if (value === null)\n transition.newDocument.documentElement.removeAttribute(name);\n else transition.newDocument.documentElement.setAttribute(name, value);\n }\n const sidebar = document.querySelector<HTMLElement>(\"#cookbook__sidebar\");\n const key =\n sidebar?.querySelector<HTMLElement>(\"cookbook-sidebar\")?.dataset.storageKey;\n const scroll = sidebar?.scrollTop ?? 0;\n const swap = transition.swap;\n transition.swap = () => {\n swap();\n const next = document.querySelector<HTMLElement>(\"#cookbook__sidebar\");\n if (\n next &&\n key &&\n next.querySelector<HTMLElement>(\"cookbook-sidebar\")?.dataset\n .storageKey === key &&\n matchMedia(\"(min-width: 50rem)\").matches\n )\n next.scrollTop = scroll;\n };\n});\n\ndocument.addEventListener(\"astro:after-swap\", () => {\n // Enhance incoming panels synchronously, before a frame can show every\n // no-JavaScript panel and then jump when page-load scripts hide them.\n initializeTabs();\n // Keep fragment navigation intact, but reset article scroll on page changes,\n // including Back/Forward. Sidebar scroll is independent of the document.\n if (!location.hash) {\n window.scrollTo({ top: 0, left: 0, behavior: \"instant\" });\n document.getElementById(\"main-content\")?.focus({ preventScroll: true });\n }\n});\n"],"mappings":";;;AAKA,SAAS,iBAAiB,sBAAsB,UAAU;CACxD,MAAM,aAAa;CAEnB,WAAW,eAAe,eAAe;CACzC,KAAK,MAAM,QAAQ,CAAC,cAAc,eAAe,GAAG;EAClD,MAAM,QAAQ,SAAS,gBAAgB,aAAa,IAAI;EACxD,IAAI,UAAU,MACZ,WAAW,YAAY,gBAAgB,gBAAgB,IAAI;OACxD,WAAW,YAAY,gBAAgB,aAAa,MAAM,KAAK;CACtE;CACA,MAAM,UAAU,SAAS,cAA2B,oBAAoB;CACxE,MAAM,MACJ,SAAS,cAA2B,kBAAkB,CAAC,EAAE,QAAQ;CACnE,MAAM,SAAS,SAAS,aAAa;CACrC,MAAM,OAAO,WAAW;CACxB,WAAW,aAAa;EACtB,KAAK;EACL,MAAM,OAAO,SAAS,cAA2B,oBAAoB;EACrE,IACE,QACA,OACA,KAAK,cAA2B,kBAAkB,CAAC,EAAE,QAClD,eAAe,OAClB,WAAW,oBAAoB,CAAC,CAAC,SAEjC,KAAK,YAAY;CACrB;AACF,CAAC;AAED,SAAS,iBAAiB,0BAA0B;CAGlD,eAAe;CAGf,IAAI,CAAC,SAAS,MAAM;EAClB,OAAO,SAAS;GAAE,KAAK;GAAG,MAAM;GAAG,UAAU;EAAU,CAAC;EACxD,SAAS,eAAe,cAAc,CAAC,EAAE,MAAM,EAAE,eAAe,KAAK,CAAC;CACxE;AACF,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region src/client/prefetch-focus.d.ts
|
|
2
|
+
/** Keep Astro's hover strategy working for keyboard focus after body swaps. */
|
|
3
|
+
declare function initializePrefetchFocus(options: {
|
|
4
|
+
prefetchAll?: boolean;
|
|
5
|
+
defaultStrategy?: string;
|
|
6
|
+
}): void;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { initializePrefetchFocus };
|
|
9
|
+
//# sourceMappingURL=prefetch-focus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prefetch-focus.d.ts","names":[],"sources":["../../src/client/prefetch-focus.ts"],"mappings":";;iBAGgB,wBAAwB;EACtC;EACA"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { prefetch } from "astro:prefetch";
|
|
2
|
+
//#region src/client/prefetch-focus.ts
|
|
3
|
+
/** Keep Astro's hover strategy working for keyboard focus after body swaps. */
|
|
4
|
+
function initializePrefetchFocus(options) {
|
|
5
|
+
let swapped = false;
|
|
6
|
+
document.addEventListener("astro:after-swap", () => {
|
|
7
|
+
swapped = true;
|
|
8
|
+
}, { once: true });
|
|
9
|
+
let timeout;
|
|
10
|
+
document.addEventListener("focusin", (event) => {
|
|
11
|
+
if (!swapped) return;
|
|
12
|
+
const link = event.target instanceof Element ? event.target.closest("a") : null;
|
|
13
|
+
if (!(link instanceof HTMLAnchorElement)) return;
|
|
14
|
+
const strategy = link.dataset.astroPrefetch;
|
|
15
|
+
if (!(strategy === "hover" || (strategy === "" || strategy === void 0 && options.prefetchAll) && (options.defaultStrategy ?? "hover") === "hover")) return;
|
|
16
|
+
window.clearTimeout(timeout);
|
|
17
|
+
timeout = window.setTimeout(() => {
|
|
18
|
+
if (link.isConnected) prefetch(link.href);
|
|
19
|
+
}, 80);
|
|
20
|
+
});
|
|
21
|
+
document.addEventListener("focusout", () => window.clearTimeout(timeout));
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
|
24
|
+
export { initializePrefetchFocus };
|
|
25
|
+
|
|
26
|
+
//# sourceMappingURL=prefetch-focus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prefetch-focus.js","names":[],"sources":["../../src/client/prefetch-focus.ts"],"sourcesContent":["import { prefetch } from \"astro:prefetch\";\n\n/** Keep Astro's hover strategy working for keyboard focus after body swaps. */\nexport function initializePrefetchFocus(options: {\n prefetchAll?: boolean;\n defaultStrategy?: string;\n}): void {\n // Astro 7.3 binds focus listeners to the initial body. Its page-load refresh\n // handles mouse listeners on new anchors, but does not rebind keyboard focus.\n // Use the public prefetch API only after swaps; Astro still owns\n // requests, cache reuse, deduplication, and connection checks.\n let swapped = false;\n document.addEventListener(\n \"astro:after-swap\",\n () => {\n swapped = true;\n },\n { once: true },\n );\n let timeout: number | undefined;\n document.addEventListener(\"focusin\", (event) => {\n if (!swapped) return;\n const link =\n event.target instanceof Element ? event.target.closest(\"a\") : null;\n if (!(link instanceof HTMLAnchorElement)) return;\n const strategy = link.dataset.astroPrefetch;\n const hover =\n strategy === \"hover\" ||\n ((strategy === \"\" || (strategy === undefined && options.prefetchAll)) &&\n (options.defaultStrategy ?? \"hover\") === \"hover\");\n if (!hover) return;\n window.clearTimeout(timeout);\n timeout = window.setTimeout(() => {\n if (link.isConnected) prefetch(link.href);\n }, 80);\n });\n document.addEventListener(\"focusout\", () => window.clearTimeout(timeout));\n}\n"],"mappings":";;;AAGA,SAAgB,wBAAwB,SAG/B;CAKP,IAAI,UAAU;CACd,SAAS,iBACP,0BACM;EACJ,UAAU;CACZ,GACA,EAAE,MAAM,KAAK,CACf;CACA,IAAI;CACJ,SAAS,iBAAiB,YAAY,UAAU;EAC9C,IAAI,CAAC,SAAS;EACd,MAAM,OACJ,MAAM,kBAAkB,UAAU,MAAM,OAAO,QAAQ,GAAG,IAAI;EAChE,IAAI,EAAE,gBAAgB,oBAAoB;EAC1C,MAAM,WAAW,KAAK,QAAQ;EAK9B,IAAI,EAHF,aAAa,YACX,aAAa,MAAO,aAAa,KAAA,KAAa,QAAQ,iBACrD,QAAQ,mBAAmB,aAAa,UACjC;EACZ,OAAO,aAAa,OAAO;EAC3B,UAAU,OAAO,iBAAiB;GAChC,IAAI,KAAK,aAAa,SAAS,KAAK,IAAI;EAC1C,GAAG,EAAE;CACP,CAAC;CACD,SAAS,iBAAiB,kBAAkB,OAAO,aAAa,OAAO,CAAC;AAC1E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","names":[],"sources":["../../src/client/search.ts"],"mappings":";KAAK;EAAiB;EAAa,cAAc;;
|
|
1
|
+
{"version":3,"file":"search.d.ts","names":[],"sources":["../../src/client/search.ts"],"mappings":";KAAK;EAAiB;EAAa,cAAc;;KAE5C,kBAAkB;EACrB,iBAAiB,QAAQ,iBAAiB;;;iBAI5B,iBACd,SAAS,aACT,SAAS,iBACT,sBACA"}
|
package/dist/client/search.js
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
function initializeSearch(element, options, development, base) {
|
|
4
4
|
if (element.dataset.initialized) return;
|
|
5
5
|
element.dataset.initialized = "true";
|
|
6
|
+
const listeners = new AbortController();
|
|
7
|
+
const persistenceKey = element.dataset.searchKey;
|
|
8
|
+
if (persistenceKey) element.setAttribute("data-astro-transition-persist", persistenceKey);
|
|
6
9
|
const open = element.querySelector("[data-open-modal]");
|
|
7
10
|
const close = element.querySelector("[data-close-modal]");
|
|
8
11
|
const dialog = element.querySelector("dialog");
|
|
@@ -118,13 +121,24 @@ function initializeSearch(element, options, development, base) {
|
|
|
118
121
|
document.body.removeAttribute("data-search-modal-open");
|
|
119
122
|
returnFocus?.focus();
|
|
120
123
|
});
|
|
124
|
+
document.addEventListener("astro:before-swap", (event) => {
|
|
125
|
+
generation += 1;
|
|
126
|
+
returnFocus = null;
|
|
127
|
+
if (dialog.open) dialog.close();
|
|
128
|
+
dialog.removeAttribute("data-open");
|
|
129
|
+
document.body.removeAttribute("data-search-modal-open");
|
|
130
|
+
const next = event.newDocument;
|
|
131
|
+
const nextRoot = persistenceKey ? [...next.querySelectorAll("site-search")].find((root) => root.dataset.searchKey === persistenceKey) : void 0;
|
|
132
|
+
if (nextRoot) nextRoot.setAttribute("data-astro-transition-persist", persistenceKey);
|
|
133
|
+
else listeners.abort();
|
|
134
|
+
}, { signal: listeners.signal });
|
|
121
135
|
window.addEventListener("keydown", (event) => {
|
|
122
136
|
if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "k") {
|
|
123
137
|
event.preventDefault();
|
|
124
138
|
if (dialog.open && !closing) hide();
|
|
125
139
|
else show();
|
|
126
140
|
}
|
|
127
|
-
});
|
|
141
|
+
}, { signal: listeners.signal });
|
|
128
142
|
}
|
|
129
143
|
//#endregion
|
|
130
144
|
export { initializeSearch };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.js","names":[],"sources":["../../src/client/search.ts"],"sourcesContent":["type SearchResult = { url: string; sub_results?: SearchResult[] };\ntype PagefindOptions = Record<string, unknown> & {\n processResult?: (result: SearchResult) => SearchResult | void;\n};\n\n/** Own the dialog lifecycle; Pagefind owns indexing, filtering and result rendering. */\nexport function initializeSearch(\n element: HTMLElement,\n options: PagefindOptions,\n development: boolean,\n base: string,\n): void {\n if (element.dataset.initialized) return;\n element.dataset.initialized = \"true\";\n const open = element.querySelector<HTMLButtonElement>(\"[data-open-modal]\")!;\n const close = element.querySelector<HTMLButtonElement>(\"[data-close-modal]\")!;\n const dialog = element.querySelector(\"dialog\")!;\n const frame = element.querySelector(\"[data-element=Frame]\")!;\n const status = element.querySelector<HTMLElement>(\"[data-search-status]\");\n const input = element.querySelector<HTMLInputElement>(\"[data-search-input]\");\n const clear = element.querySelector<HTMLButtonElement>(\"[data-clear-search]\");\n const shortcut = open.querySelector(\"kbd\")!;\n if (/(Mac|iPhone|iPod|iPad)/i.test(navigator.platform)) {\n shortcut.querySelector(\"kbd\")!.textContent = \"⌘\";\n open.setAttribute(\"aria-keyshortcuts\", \"Meta+K\");\n }\n delete shortcut.dataset.pending;\n let initialized: Promise<void> | undefined;\n let engineInput: HTMLInputElement | null = null;\n let returnFocus: HTMLElement | null = null;\n let closing = false;\n let generation = 0;\n const updateSearch = () => {\n if (clear) clear.hidden = !input?.value;\n if (engineInput) {\n engineInput.value = input?.value ?? \"\";\n engineInput.dispatchEvent(new Event(\"input\", { bubbles: true }));\n }\n };\n input?.addEventListener(\"input\", updateSearch);\n clear?.addEventListener(\"click\", () => {\n if (!input) return;\n input.value = \"\";\n updateSearch();\n input.focus();\n });\n const initialize = () => {\n if (development) return Promise.resolve();\n return (initialized ??= (async () => {\n // @ts-expect-error Pagefind publishes no declarations for its default UI.\n const { PagefindUI } = await import(\"@pagefind/default-ui\");\n const translations = JSON.parse(element.dataset.translations ?? \"{}\");\n const format = (url: string) =>\n element.hasAttribute(\"data-strip-trailing-slash\")\n ? url.replace(/(.)\\/(#.*)?$/, \"$1$2\")\n : url;\n new PagefindUI({\n ...options,\n element: element.querySelector(\"[data-search-results]\"),\n baseUrl: base,\n bundlePath: `${base.replace(/\\/$/, \"\")}/pagefind/`,\n showImages: false,\n showSubResults: true,\n translations,\n processResult(result: SearchResult) {\n result = options.processResult?.(result) ?? result;\n result.url = format(result.url);\n result.sub_results?.forEach((child) => {\n child.url = format(child.url);\n });\n return result;\n },\n });\n // Pagefind generates and controls these nodes; its UI API exposes only classes.\n engineInput = element.querySelector(\".pagefind-ui__search-input\");\n element.querySelector(\".pagefind-ui__form\")?.removeAttribute(\"role\");\n // Cookbook owns the field so focus stays within the opening tap on mobile.\n // Pagefind still owns query processing and its lazily rendered results.\n element\n .querySelectorAll<HTMLElement>(\n \".pagefind-ui__search-input, .pagefind-ui__search-clear\",\n )\n .forEach((control) => {\n control.hidden = true;\n control.tabIndex = -1;\n });\n updateSearch();\n })().catch((error: unknown) => {\n initialized = undefined;\n if (status) {\n status.hidden = false;\n // Reuse the localized Pagefind error, with a plain fallback.\n const translations = JSON.parse(element.dataset.translations ?? \"{}\");\n status.textContent =\n translations.error ?? \"Search could not load. Close and try again.\";\n }\n throw error;\n }));\n };\n const show = (trigger?: HTMLElement) => {\n if (dialog.open && !closing) return;\n generation += 1;\n closing = false;\n if (!dialog.open) {\n returnFocus =\n trigger ??\n (document.activeElement instanceof HTMLElement &&\n document.activeElement !== document.body\n ? document.activeElement\n : open);\n dialog.removeAttribute(\"data-open\");\n dialog.showModal();\n }\n // Do this synchronously, before the lazy import releases user activation.\n input?.focus({ preventScroll: true });\n // Establish the initial state after entering the top layer. The global\n // style renderer does not preserve @starting-style in server output.\n dialog.getBoundingClientRect();\n dialog.setAttribute(\"data-open\", \"\");\n document.body.setAttribute(\"data-search-modal-open\", \"\");\n if (!development && status) status.hidden = true;\n void initialize().catch(() => {\n /* Keep the close control usable when the search bundle fails. */\n });\n };\n const hide = async () => {\n if (!dialog.open || closing) return;\n closing = true;\n const current = ++generation;\n dialog.removeAttribute(\"data-open\");\n // Keep the modal in the top layer until its exit transition has finished.\n // This also works in browsers without discrete display/overlay transitions.\n await Promise.allSettled(\n dialog\n .getAnimations()\n .filter((animation) =>\n Number.isFinite(animation.effect?.getComputedTiming().endTime),\n )\n .map((animation) => animation.finished),\n );\n if (current === generation && dialog.open) dialog.close();\n };\n open.addEventListener(\"click\", () => {\n show(open);\n });\n open.disabled = false;\n close.addEventListener(\"click\", () => void hide());\n dialog.addEventListener(\"cancel\", (event) => {\n event.preventDefault();\n void hide();\n });\n dialog.addEventListener(\"click\", (event) => {\n if (!(event.target instanceof Element)) return;\n if (event.target.closest(\"a[href]\") || !frame.contains(event.target))\n void hide();\n });\n dialog.addEventListener(\"close\", () => {\n dialog.removeAttribute(\"data-open\");\n closing = false;\n document.body.removeAttribute(\"data-search-modal-open\");\n returnFocus?.focus();\n });\n window.addEventListener(\"keydown\", (event) => {\n if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === \"k\") {\n event.preventDefault();\n if (dialog.open && !closing) void hide();\n else void show();\n }\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"search.js","names":[],"sources":["../../src/client/search.ts"],"sourcesContent":["type SearchResult = { url: string; sub_results?: SearchResult[] };\nimport type { TransitionBeforeSwapEvent } from \"astro:transitions/client\";\ntype PagefindOptions = Record<string, unknown> & {\n processResult?: (result: SearchResult) => SearchResult | void;\n};\n\n/** Own the dialog lifecycle; Pagefind owns indexing, filtering and result rendering. */\nexport function initializeSearch(\n element: HTMLElement,\n options: PagefindOptions,\n development: boolean,\n base: string,\n): void {\n if (element.dataset.initialized) return;\n element.dataset.initialized = \"true\";\n const listeners = new AbortController();\n // Astro strips transition attributes from unhydrated framework roots. Apply\n // the public persistence hook here and to the incoming matching search root.\n const persistenceKey = element.dataset.searchKey;\n if (persistenceKey)\n element.setAttribute(\"data-astro-transition-persist\", persistenceKey);\n const open = element.querySelector<HTMLButtonElement>(\"[data-open-modal]\")!;\n const close = element.querySelector<HTMLButtonElement>(\"[data-close-modal]\")!;\n const dialog = element.querySelector(\"dialog\")!;\n const frame = element.querySelector(\"[data-element=Frame]\")!;\n const status = element.querySelector<HTMLElement>(\"[data-search-status]\");\n const input = element.querySelector<HTMLInputElement>(\"[data-search-input]\");\n const clear = element.querySelector<HTMLButtonElement>(\"[data-clear-search]\");\n const shortcut = open.querySelector(\"kbd\")!;\n if (/(Mac|iPhone|iPod|iPad)/i.test(navigator.platform)) {\n shortcut.querySelector(\"kbd\")!.textContent = \"⌘\";\n open.setAttribute(\"aria-keyshortcuts\", \"Meta+K\");\n }\n delete shortcut.dataset.pending;\n let initialized: Promise<void> | undefined;\n let engineInput: HTMLInputElement | null = null;\n let returnFocus: HTMLElement | null = null;\n let closing = false;\n let generation = 0;\n const updateSearch = () => {\n if (clear) clear.hidden = !input?.value;\n if (engineInput) {\n engineInput.value = input?.value ?? \"\";\n engineInput.dispatchEvent(new Event(\"input\", { bubbles: true }));\n }\n };\n input?.addEventListener(\"input\", updateSearch);\n clear?.addEventListener(\"click\", () => {\n if (!input) return;\n input.value = \"\";\n updateSearch();\n input.focus();\n });\n const initialize = () => {\n if (development) return Promise.resolve();\n return (initialized ??= (async () => {\n // @ts-expect-error Pagefind publishes no declarations for its default UI.\n const { PagefindUI } = await import(\"@pagefind/default-ui\");\n const translations = JSON.parse(element.dataset.translations ?? \"{}\");\n const format = (url: string) =>\n element.hasAttribute(\"data-strip-trailing-slash\")\n ? url.replace(/(.)\\/(#.*)?$/, \"$1$2\")\n : url;\n new PagefindUI({\n ...options,\n element: element.querySelector(\"[data-search-results]\"),\n baseUrl: base,\n bundlePath: `${base.replace(/\\/$/, \"\")}/pagefind/`,\n showImages: false,\n showSubResults: true,\n translations,\n processResult(result: SearchResult) {\n result = options.processResult?.(result) ?? result;\n result.url = format(result.url);\n result.sub_results?.forEach((child) => {\n child.url = format(child.url);\n });\n return result;\n },\n });\n // Pagefind generates and controls these nodes; its UI API exposes only classes.\n engineInput = element.querySelector(\".pagefind-ui__search-input\");\n element.querySelector(\".pagefind-ui__form\")?.removeAttribute(\"role\");\n // Cookbook owns the field so focus stays within the opening tap on mobile.\n // Pagefind still owns query processing and its lazily rendered results.\n element\n .querySelectorAll<HTMLElement>(\n \".pagefind-ui__search-input, .pagefind-ui__search-clear\",\n )\n .forEach((control) => {\n control.hidden = true;\n control.tabIndex = -1;\n });\n updateSearch();\n })().catch((error: unknown) => {\n initialized = undefined;\n if (status) {\n status.hidden = false;\n // Reuse the localized Pagefind error, with a plain fallback.\n const translations = JSON.parse(element.dataset.translations ?? \"{}\");\n status.textContent =\n translations.error ?? \"Search could not load. Close and try again.\";\n }\n throw error;\n }));\n };\n const show = (trigger?: HTMLElement) => {\n if (dialog.open && !closing) return;\n generation += 1;\n closing = false;\n if (!dialog.open) {\n returnFocus =\n trigger ??\n (document.activeElement instanceof HTMLElement &&\n document.activeElement !== document.body\n ? document.activeElement\n : open);\n dialog.removeAttribute(\"data-open\");\n dialog.showModal();\n }\n // Do this synchronously, before the lazy import releases user activation.\n input?.focus({ preventScroll: true });\n // Establish the initial state after entering the top layer. The global\n // style renderer does not preserve @starting-style in server output.\n dialog.getBoundingClientRect();\n dialog.setAttribute(\"data-open\", \"\");\n document.body.setAttribute(\"data-search-modal-open\", \"\");\n if (!development && status) status.hidden = true;\n void initialize().catch(() => {\n /* Keep the close control usable when the search bundle fails. */\n });\n };\n const hide = async () => {\n if (!dialog.open || closing) return;\n closing = true;\n const current = ++generation;\n dialog.removeAttribute(\"data-open\");\n // Keep the modal in the top layer until its exit transition has finished.\n // This also works in browsers without discrete display/overlay transitions.\n await Promise.allSettled(\n dialog\n .getAnimations()\n .filter((animation) =>\n Number.isFinite(animation.effect?.getComputedTiming().endTime),\n )\n .map((animation) => animation.finished),\n );\n if (current === generation && dialog.open) dialog.close();\n };\n open.addEventListener(\"click\", () => {\n show(open);\n });\n open.disabled = false;\n close.addEventListener(\"click\", () => void hide());\n dialog.addEventListener(\"cancel\", (event) => {\n event.preventDefault();\n void hide();\n });\n dialog.addEventListener(\"click\", (event) => {\n if (!(event.target instanceof Element)) return;\n if (event.target.closest(\"a[href]\") || !frame.contains(event.target))\n void hide();\n });\n dialog.addEventListener(\"close\", () => {\n dialog.removeAttribute(\"data-open\");\n closing = false;\n document.body.removeAttribute(\"data-search-modal-open\");\n returnFocus?.focus();\n });\n document.addEventListener(\n \"astro:before-swap\",\n (event) => {\n // Keep the query and lazy engine for matching localized search shells,\n // while dismissing the modal before the destination content is displayed.\n generation += 1;\n returnFocus = null;\n if (dialog.open) dialog.close();\n dialog.removeAttribute(\"data-open\");\n document.body.removeAttribute(\"data-search-modal-open\");\n const next = (event as TransitionBeforeSwapEvent).newDocument;\n const nextRoot = persistenceKey\n ? [...next.querySelectorAll<HTMLElement>(\"site-search\")].find(\n (root) => root.dataset.searchKey === persistenceKey,\n )\n : undefined;\n if (nextRoot)\n nextRoot.setAttribute(\"data-astro-transition-persist\", persistenceKey!);\n else listeners.abort();\n },\n { signal: listeners.signal },\n );\n window.addEventListener(\n \"keydown\",\n (event) => {\n if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === \"k\") {\n event.preventDefault();\n if (dialog.open && !closing) void hide();\n else void show();\n }\n },\n { signal: listeners.signal },\n );\n}\n"],"mappings":"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"}
|
|
@@ -183,6 +183,19 @@ export default function DocumentStyles() {
|
|
|
183
183
|
whiteSpace: { "": null, "@own(sr-only)": "nowrap" },
|
|
184
184
|
border: { "": null, "@own(sr-only)": "0" },
|
|
185
185
|
},
|
|
186
|
+
RouteAnnouncer: {
|
|
187
|
+
// Astro's public router creates this class; its generated markup has
|
|
188
|
+
// no owned data-element hook. Keep the bridge scoped to its announcer.
|
|
189
|
+
$: ".astro-route-announcer",
|
|
190
|
+
position: "absolute",
|
|
191
|
+
inset: "0 top, 0 left",
|
|
192
|
+
"$visually-hidden-size": "1px",
|
|
193
|
+
inlineSize: "$visually-hidden-size",
|
|
194
|
+
blockSize: "$visually-hidden-size",
|
|
195
|
+
overflow: "hidden",
|
|
196
|
+
clip: "rect(0, 0, 0, 0)",
|
|
197
|
+
whiteSpace: "nowrap",
|
|
198
|
+
},
|
|
186
199
|
Strong: { $: ":where(strong), :where(b)", preset: "strong" },
|
|
187
200
|
Link: { $: "a", color: "#accent-text" },
|
|
188
201
|
NarrowBlock: {
|
|
@@ -59,7 +59,16 @@ const id = `select-${crypto.randomUUID()}`;
|
|
|
59
59
|
<script>
|
|
60
60
|
import { initializePopoverMotion } from "../client/popover-motion.js";
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
const initialized = new WeakSet<HTMLElement>();
|
|
63
|
+
function initialize(): void {
|
|
64
|
+
document
|
|
65
|
+
.querySelectorAll<HTMLElement>("[data-select-popover-panel]")
|
|
66
|
+
.forEach((panel) => {
|
|
67
|
+
if (initialized.has(panel)) return;
|
|
68
|
+
initialized.add(panel);
|
|
69
|
+
initializePopoverMotion(panel);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
initialize();
|
|
73
|
+
document.addEventListener("astro:page-load", initialize);
|
|
65
74
|
</script>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Kept dependency-free for the page shell's synchronous, pre-paint script.
|
|
2
|
+
(() => {
|
|
3
|
+
const root = globalThis.document.documentElement;
|
|
4
|
+
try {
|
|
5
|
+
const scheme = globalThis.localStorage.getItem("cookbook-theme");
|
|
6
|
+
if (scheme === "light" || scheme === "dark") root.dataset.theme = scheme;
|
|
7
|
+
else delete root.dataset.theme;
|
|
8
|
+
} catch {
|
|
9
|
+
// Without storage, the document's system appearance rules remain active.
|
|
10
|
+
}
|
|
11
|
+
try {
|
|
12
|
+
const appearance = JSON.parse(
|
|
13
|
+
globalThis.localStorage.getItem("cookbook-appearance") ?? "{}",
|
|
14
|
+
);
|
|
15
|
+
if (appearance?.contrast === "normal" || appearance?.contrast === "more")
|
|
16
|
+
root.dataset.contrast = appearance.contrast;
|
|
17
|
+
else delete root.dataset.contrast;
|
|
18
|
+
} catch {
|
|
19
|
+
// Malformed or unavailable storage must not prevent the first paint.
|
|
20
|
+
}
|
|
21
|
+
})();
|
package/dist/index.js
CHANGED
|
@@ -1273,9 +1273,18 @@ function configuredCookbook(options) {
|
|
|
1273
1273
|
srcDir: context.config.srcDir
|
|
1274
1274
|
};
|
|
1275
1275
|
let markdownRenderer;
|
|
1276
|
+
const prefetch = context.config.prefetch ?? {
|
|
1277
|
+
prefetchAll: true,
|
|
1278
|
+
defaultStrategy: "hover"
|
|
1279
|
+
};
|
|
1280
|
+
if (prefetch !== false) {
|
|
1281
|
+
const focusScript = fileURLToPath(new URL("./client/prefetch-focus.js", import.meta.url));
|
|
1282
|
+
context.injectScript("page", `import { initializePrefetchFocus } from ${JSON.stringify(focusScript)}; initializePrefetchFocus(${JSON.stringify(typeof prefetch === "object" ? prefetch : {})});`);
|
|
1283
|
+
}
|
|
1276
1284
|
context.updateConfig({
|
|
1277
1285
|
...configuredSite && !context.config.site ? { site: configuredSite } : {},
|
|
1278
1286
|
base,
|
|
1287
|
+
prefetch,
|
|
1279
1288
|
markdown: {
|
|
1280
1289
|
syntaxHighlight: "shiki",
|
|
1281
1290
|
shikiConfig: cookbookShikiConfig(context.config.markdown.shikiConfig)
|