lildocs 0.1.20 → 0.1.22

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.
@@ -1,63 +0,0 @@
1
- const sectionHighlightStorageKey = "lildocs:section-highlight";
2
- let pendingSectionUrl: string | undefined;
3
-
4
- export function initSectionHighlights() {
5
- document.addEventListener("click", (event) => {
6
- if (!(event.target instanceof Element)) {
7
- return;
8
- }
9
-
10
- const link = event.target.closest<HTMLAnchorElement>('.toc a[href^="#"]');
11
- if (link) {
12
- queueSectionHighlight(link.href);
13
- }
14
- });
15
- document.addEventListener("lildocs:page-view", highlightPendingSection);
16
- window.addEventListener("hashchange", highlightPendingSection);
17
- highlightPendingSection();
18
- }
19
-
20
- export function queueSectionHighlight(href: string) {
21
- pendingSectionUrl = href;
22
- try {
23
- window.sessionStorage.setItem(sectionHighlightStorageKey, href);
24
- } catch {}
25
- window.requestAnimationFrame(highlightPendingSection);
26
- }
27
-
28
- function highlightPendingSection() {
29
- let href = pendingSectionUrl;
30
- if (!href) {
31
- try {
32
- href =
33
- window.sessionStorage.getItem(sectionHighlightStorageKey) ?? undefined;
34
- } catch {}
35
- }
36
- if (!href) {
37
- return;
38
- }
39
-
40
- const targetUrl = new URL(href, document.baseURI);
41
- if (
42
- targetUrl.origin !== window.location.origin ||
43
- targetUrl.pathname !== window.location.pathname ||
44
- targetUrl.search !== window.location.search ||
45
- targetUrl.hash !== window.location.hash
46
- ) {
47
- return;
48
- }
49
-
50
- const target = document.getElementById(
51
- decodeURIComponent(targetUrl.hash.slice(1)),
52
- );
53
- if (!target) {
54
- return;
55
- }
56
-
57
- pendingSectionUrl = undefined;
58
- try {
59
- window.sessionStorage.removeItem(sectionHighlightStorageKey);
60
- } catch {}
61
- target.classList.remove("sectionHighlight");
62
- window.requestAnimationFrame(() => target.classList.add("sectionHighlight"));
63
- }
@@ -1,93 +0,0 @@
1
- export function initSidebar() {
2
- const sidebar = document.querySelector("#lildocs-sidebar");
3
- const collapseButton = document.querySelector<HTMLButtonElement>(
4
- "#lildocs-sidebar-toggle",
5
- );
6
- const expandButton = document.querySelector<HTMLButtonElement>(
7
- "#lildocs-sidebar-expand",
8
- );
9
- const searchButton = document.querySelector<HTMLButtonElement>(
10
- "#lildocs-floating-search",
11
- );
12
-
13
- if (!sidebar || !collapseButton || !expandButton || !searchButton) {
14
- return;
15
- }
16
-
17
- const mobileQuery = window.matchMedia("(max-width: 860px)");
18
-
19
- const setMenuOpen = (open: boolean) => {
20
- document.documentElement.classList.toggle("sidebar-menu-open", open);
21
- collapseButton.setAttribute("aria-expanded", String(open));
22
- collapseButton.setAttribute(
23
- "aria-label",
24
- open ? "Close navigation menu" : "Open navigation menu",
25
- );
26
- };
27
-
28
- const setCollapsed = (collapsed: boolean) => {
29
- document.documentElement.classList.toggle("sidebar-collapsed", collapsed);
30
- collapseButton.setAttribute(
31
- "aria-label",
32
- collapsed ? "Expand sidebar" : "Collapse sidebar",
33
- );
34
- };
35
-
36
- const syncResponsiveState = () => {
37
- document.documentElement.classList.remove("sidebar-menu-open");
38
- collapseButton.setAttribute("aria-expanded", "false");
39
- collapseButton.setAttribute(
40
- "aria-label",
41
- mobileQuery.matches ? "Open navigation menu" : "Collapse sidebar",
42
- );
43
- };
44
-
45
- collapseButton.addEventListener("click", () => {
46
- if (mobileQuery.matches) {
47
- setMenuOpen(
48
- !document.documentElement.classList.contains("sidebar-menu-open"),
49
- );
50
- return;
51
- }
52
- setCollapsed(true);
53
- });
54
- expandButton.addEventListener("click", () => setCollapsed(false));
55
- document.addEventListener("keydown", (event) => {
56
- if (event.key === "Escape" && mobileQuery.matches) {
57
- setMenuOpen(false);
58
- return;
59
- }
60
- if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "b") {
61
- event.preventDefault();
62
- if (mobileQuery.matches) {
63
- setMenuOpen(
64
- !document.documentElement.classList.contains("sidebar-menu-open"),
65
- );
66
- return;
67
- }
68
- setCollapsed(
69
- !document.documentElement.classList.contains("sidebar-collapsed"),
70
- );
71
- }
72
- });
73
- sidebar.addEventListener("click", (event) => {
74
- if (
75
- mobileQuery.matches &&
76
- event.target instanceof Element &&
77
- event.target.closest("a[href]")
78
- ) {
79
- setMenuOpen(false);
80
- }
81
- });
82
- searchButton.addEventListener("click", () => {
83
- setCollapsed(false);
84
- document.dispatchEvent(new CustomEvent("lildocs:search-toggle"));
85
- });
86
- document.addEventListener("lildocs:sidebar-menu-open", () => {
87
- if (mobileQuery.matches) {
88
- setMenuOpen(true);
89
- }
90
- });
91
- mobileQuery.addEventListener("change", syncResponsiveState);
92
- syncResponsiveState();
93
- }
@@ -1,161 +0,0 @@
1
- let activeDialog: HTMLDialogElement | undefined;
2
-
3
- export function initTableViewer() {
4
- enhanceTables();
5
- enhanceMermaidDiagrams();
6
- document.addEventListener("lildocs:page-view", () => {
7
- activeDialog?.close();
8
- enhanceTables();
9
- enhanceMermaidDiagrams();
10
- });
11
- }
12
-
13
- function enhanceTables() {
14
- const tables = document.querySelectorAll<HTMLTableElement>(
15
- ".content article table",
16
- );
17
- for (const table of Array.from(tables)) {
18
- if (table.closest(".tableFrame")) {
19
- continue;
20
- }
21
-
22
- const frame = document.createElement("div");
23
- frame.className = "tableFrame";
24
- const toolbar = document.createElement("div");
25
- toolbar.className = "tableToolbar";
26
- const button = document.createElement("button");
27
- button.type = "button";
28
- button.className = "tableExpandButton";
29
- button.title = "Expand table";
30
- button.setAttribute("aria-label", "View table in full screen");
31
- button.innerHTML =
32
- '<span class="ti ti-arrows-maximize" aria-hidden="true"></span>';
33
- const viewport = document.createElement("div");
34
- viewport.className = "tableViewport";
35
-
36
- button.addEventListener("click", () =>
37
- openFullscreenDialog(table, button, {
38
- dialogClass: "tableFullscreenDialog",
39
- dialogLabel: "Full screen table",
40
- title: table.querySelector("caption")?.textContent?.trim() || "Table",
41
- closeLabel: "Minimize table",
42
- viewportClass: "tableFullscreenViewport content",
43
- openClass: "tableFullscreenOpen",
44
- }),
45
- );
46
- table.before(frame);
47
- toolbar.append(button);
48
- viewport.append(table);
49
- frame.append(viewport, toolbar);
50
- }
51
- }
52
-
53
- function enhanceMermaidDiagrams() {
54
- const diagrams = document.querySelectorAll<HTMLElement>(
55
- ".content article .mermaidDiagram",
56
- );
57
- for (const diagram of Array.from(diagrams)) {
58
- if (diagram.closest(".mermaidFrame")) {
59
- continue;
60
- }
61
-
62
- const frame = document.createElement("div");
63
- frame.className = "mermaidFrame";
64
- const toolbar = document.createElement("div");
65
- toolbar.className = "mermaidToolbar";
66
- const button = document.createElement("button");
67
- button.type = "button";
68
- button.className = "mermaidExpandButton";
69
- button.title = "Expand diagram";
70
- button.setAttribute("aria-label", "View diagram in full screen");
71
- button.innerHTML =
72
- '<span class="ti ti-arrows-maximize" aria-hidden="true"></span>';
73
- const viewport = document.createElement("div");
74
- viewport.className = "mermaidViewport";
75
-
76
- button.addEventListener("click", () =>
77
- openFullscreenDialog(diagram, button, {
78
- dialogClass: "mermaidFullscreenDialog",
79
- dialogLabel: "Full screen diagram",
80
- title: "Diagram",
81
- closeLabel: "Minimize diagram",
82
- viewportClass: "mermaidFullscreenViewport content",
83
- openClass: "mermaidFullscreenOpen",
84
- }),
85
- );
86
- diagram.before(frame);
87
- toolbar.append(button);
88
- viewport.append(diagram);
89
- frame.append(viewport, toolbar);
90
- }
91
- }
92
-
93
- type FullscreenDialogOptions = {
94
- dialogClass: string;
95
- dialogLabel: string;
96
- title: string;
97
- closeLabel: string;
98
- viewportClass: string;
99
- openClass: string;
100
- };
101
-
102
- function openFullscreenDialog(
103
- source: HTMLElement,
104
- opener: HTMLButtonElement,
105
- options: FullscreenDialogOptions,
106
- ) {
107
- activeDialog?.close();
108
-
109
- const dialog = document.createElement("dialog");
110
- dialog.className = options.dialogClass;
111
- dialog.setAttribute("aria-label", options.dialogLabel);
112
- const content = document.createElement("div");
113
- content.className = "tableFullscreenContent";
114
- const header = document.createElement("header");
115
- header.className = "tableFullscreenHeader";
116
- const title = document.createElement("strong");
117
- title.textContent = options.title;
118
- const closeButton = document.createElement("button");
119
- closeButton.type = "button";
120
- closeButton.className = "tableFullscreenClose";
121
- closeButton.title = options.closeLabel;
122
- closeButton.setAttribute("aria-label", options.closeLabel);
123
- closeButton.innerHTML =
124
- '<span class="ti ti-arrows-minimize" aria-hidden="true"></span>';
125
- const viewport = document.createElement("div");
126
- viewport.className = options.viewportClass;
127
- viewport.append(source.cloneNode(true));
128
-
129
- closeButton.addEventListener("click", () => dialog.close());
130
- dialog.addEventListener("cancel", (event) => {
131
- event.preventDefault();
132
- dialog.close();
133
- });
134
- dialog.addEventListener("click", (event) => {
135
- if (event.target === dialog) {
136
- dialog.close();
137
- }
138
- });
139
- dialog.addEventListener(
140
- "close",
141
- () => {
142
- document.documentElement.classList.remove(options.openClass);
143
- dialog.remove();
144
- if (activeDialog === dialog) {
145
- activeDialog = undefined;
146
- }
147
- if (opener.isConnected) {
148
- opener.focus();
149
- }
150
- },
151
- { once: true },
152
- );
153
-
154
- header.append(title, closeButton);
155
- content.append(header, viewport);
156
- dialog.append(content);
157
- document.body.append(dialog);
158
- document.documentElement.classList.add(options.openClass);
159
- activeDialog = dialog;
160
- dialog.showModal();
161
- }
@@ -1,78 +0,0 @@
1
- let animationFrame: number | undefined;
2
-
3
- export function initTocVisibility() {
4
- window.addEventListener("scroll", scheduleTocVisibilityUpdate, {
5
- passive: true,
6
- });
7
- window.addEventListener("resize", scheduleTocVisibilityUpdate);
8
- document.addEventListener("lildocs:page-view", scheduleTocVisibilityUpdate);
9
- void document.fonts?.ready.then(scheduleTocVisibilityUpdate);
10
- scheduleTocVisibilityUpdate();
11
- }
12
-
13
- function scheduleTocVisibilityUpdate() {
14
- if (animationFrame !== undefined) {
15
- return;
16
- }
17
-
18
- animationFrame = window.requestAnimationFrame(() => {
19
- animationFrame = undefined;
20
- updateTocVisibility();
21
- });
22
- }
23
-
24
- function updateTocVisibility() {
25
- const container = document.querySelector<HTMLElement>("[data-toc-links]");
26
- const indicator = container?.querySelector<HTMLElement>(
27
- "[data-toc-visibility]",
28
- );
29
- if (!container || !indicator) {
30
- return;
31
- }
32
-
33
- const items = Array.from(
34
- container.querySelectorAll<HTMLAnchorElement>('a[href^="#"]'),
35
- )
36
- .map((link) => {
37
- const heading = headingForLink(link);
38
- return heading ? { heading, link } : undefined;
39
- })
40
- .filter((item): item is { heading: HTMLElement; link: HTMLAnchorElement } =>
41
- Boolean(item),
42
- );
43
- const visibleItems = items.filter(({ heading }) => {
44
- const bounds = heading.getBoundingClientRect();
45
- return bounds.bottom > 0 && bounds.top < window.innerHeight;
46
- });
47
- if (visibleItems.length === 0 || visibleItems.length === items.length) {
48
- indicator.classList.remove("isVisible");
49
- return;
50
- }
51
-
52
- const containerBounds = container.getBoundingClientRect();
53
- const firstBounds = visibleItems[0].link.getBoundingClientRect();
54
- const lastBounds =
55
- visibleItems.at(-1)?.link.getBoundingClientRect() ?? firstBounds;
56
- indicator.style.setProperty(
57
- "--ld-toc-visibility-top",
58
- `${firstBounds.top - containerBounds.top}px`,
59
- );
60
- indicator.style.setProperty(
61
- "--ld-toc-visibility-height",
62
- `${lastBounds.bottom - firstBounds.top}px`,
63
- );
64
- indicator.classList.add("isVisible");
65
- }
66
-
67
- function headingForLink(link: HTMLAnchorElement): HTMLElement | null {
68
- const id = link.hash.slice(1);
69
- if (!id) {
70
- return null;
71
- }
72
-
73
- try {
74
- return document.getElementById(decodeURIComponent(id));
75
- } catch {
76
- return document.getElementById(id);
77
- }
78
- }
@@ -1,9 +0,0 @@
1
- export type AdjacentPageLink = {
2
- title: string;
3
- href: string;
4
- };
5
-
6
- export type PageNavigation = {
7
- previous?: AdjacentPageLink;
8
- next?: AdjacentPageLink;
9
- };