@commentray/render 0.1.0 → 0.1.2
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/block-stretch-layout.d.ts.map +1 -1
- package/dist/block-stretch-layout.js +2 -1
- package/dist/block-stretch-layout.js.map +1 -1
- package/dist/browse-page-slug.d.ts +6 -1
- package/dist/browse-page-slug.d.ts.map +1 -1
- package/dist/browse-page-slug.js +6 -1
- package/dist/browse-page-slug.js.map +1 -1
- package/dist/browse-pair-html-test-fixtures.d.ts +10 -0
- package/dist/browse-pair-html-test-fixtures.d.ts.map +1 -0
- package/dist/browse-pair-html-test-fixtures.js +19 -0
- package/dist/browse-pair-html-test-fixtures.js.map +1 -0
- package/dist/build-commentray-nav-search.d.ts +4 -4
- package/dist/build-commentray-nav-search.js +1 -1
- package/dist/code-browser-block-rays.d.ts +29 -0
- package/dist/code-browser-block-rays.d.ts.map +1 -1
- package/dist/code-browser-block-rays.js +120 -0
- package/dist/code-browser-block-rays.js.map +1 -1
- package/dist/code-browser-client.bundle.js +11 -11
- package/dist/code-browser-client.js +80 -27
- package/dist/code-browser-client.js.map +1 -1
- package/dist/code-browser-pair-nav.d.ts +3 -3
- package/dist/code-browser-pair-nav.d.ts.map +1 -1
- package/dist/code-browser-pair-nav.js +25 -13
- package/dist/code-browser-pair-nav.js.map +1 -1
- package/dist/code-browser.d.ts +18 -4
- package/dist/code-browser.d.ts.map +1 -1
- package/dist/code-browser.js +66 -269
- package/dist/code-browser.js.map +1 -1
- package/dist/commentray-anchor-viewport-probe.d.ts +9 -0
- package/dist/commentray-anchor-viewport-probe.d.ts.map +1 -0
- package/dist/commentray-anchor-viewport-probe.js +13 -0
- package/dist/commentray-anchor-viewport-probe.js.map +1 -0
- package/dist/commentray-preview-html.d.ts +13 -0
- package/dist/commentray-preview-html.d.ts.map +1 -0
- package/dist/commentray-preview-html.js +12 -0
- package/dist/commentray-preview-html.js.map +1 -0
- package/dist/companion-markdown-preview-entry.d.ts +7 -0
- package/dist/companion-markdown-preview-entry.d.ts.map +1 -0
- package/dist/companion-markdown-preview-entry.js +6 -0
- package/dist/companion-markdown-preview-entry.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/inject-md-line-anchors.d.ts +18 -0
- package/dist/inject-md-line-anchors.d.ts.map +1 -0
- package/dist/inject-md-line-anchors.js +250 -0
- package/dist/inject-md-line-anchors.js.map +1 -0
- package/dist/inline-favicon.js +15 -15
- package/dist/markdown-pipeline.d.ts +5 -0
- package/dist/markdown-pipeline.d.ts.map +1 -1
- package/dist/markdown-pipeline.js +40 -0
- package/dist/markdown-pipeline.js.map +1 -1
- package/package.json +6 -2
- package/dist/side-by-side-layout.css +0 -58
- package/dist/side-by-side-layout.embedded.d.ts +0 -3
- package/dist/side-by-side-layout.embedded.d.ts.map +0 -1
- package/dist/side-by-side-layout.embedded.js +0 -3
- package/dist/side-by-side-layout.embedded.js.map +0 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { FuzzySearcher, PrefixSearcher, Query, SearcherFactory, SubstringSearcher, } from "@m31coding/fuzzy-search";
|
|
2
|
-
import { activeBlockIdForViewport, clampViewportYToGutterLocal, codeLineDomIndex0, gutterRayBezierPaths, sortBlockLinksBySource, } from "./code-browser-block-rays.js";
|
|
2
|
+
import { activeBlockIdForCommentrayLine0, activeBlockIdForViewport, clampViewportYToGutterLocal, codeLineDomIndex0, dedupeBlockScrollLinksById, gutterRayBezierPaths, maxRenderableCommentaryContentBottomViewport, nextBlockLinkInCommentrayOrder, sortBlockLinksBySource, } from "./code-browser-block-rays.js";
|
|
3
3
|
import { mirroredScrollTop, pickCommentrayLineForSourceScroll, pickSourceLine0ForCommentrayScroll, } from "./code-browser-scroll-sync.js";
|
|
4
|
+
import { maxCommentrayAnchorLine0AtOrAboveViewportY } from "./commentray-anchor-viewport-probe.js";
|
|
4
5
|
import { decodeBase64Utf8 } from "./code-browser-encoding.js";
|
|
5
6
|
import { readEmbeddedRawB64Strings } from "./code-browser-embedded-payload.js";
|
|
6
7
|
import { escapeHtmlHighlightingSearchTokens, filterPairsByDocumentedTreeQuery, findOrderedTokenSpans, lineAtIndex, offsetToLineIndex, pathRowsFromDocumentedPairs, tokenizeQuery, uniqueSourceFilePreviewRows, } from "./code-browser-search.js";
|
|
@@ -700,11 +701,22 @@ function parseScrollBlockLinksFromShell(b64) {
|
|
|
700
701
|
typeof o.commentrayLine === "number" &&
|
|
701
702
|
typeof o.sourceStart === "number" &&
|
|
702
703
|
typeof o.sourceEnd === "number") {
|
|
704
|
+
const mvRaw = o.markerViewportHalfOpen1Based;
|
|
705
|
+
const mv = typeof mvRaw === "object" &&
|
|
706
|
+
mvRaw !== null &&
|
|
707
|
+
typeof mvRaw.lo === "number" &&
|
|
708
|
+
typeof mvRaw.hiExclusive === "number"
|
|
709
|
+
? {
|
|
710
|
+
lo: mvRaw.lo,
|
|
711
|
+
hiExclusive: mvRaw.hiExclusive,
|
|
712
|
+
}
|
|
713
|
+
: { lo: o.sourceStart, hiExclusive: o.sourceEnd + 1 };
|
|
703
714
|
out.push({
|
|
704
715
|
id: o.id,
|
|
705
716
|
commentrayLine: o.commentrayLine,
|
|
706
717
|
sourceStart: o.sourceStart,
|
|
707
718
|
sourceEnd: o.sourceEnd,
|
|
719
|
+
markerViewportHalfOpen1Based: mv,
|
|
708
720
|
});
|
|
709
721
|
}
|
|
710
722
|
}
|
|
@@ -730,19 +742,15 @@ function readCommentrayLine0FromAnchor(el) {
|
|
|
730
742
|
return null;
|
|
731
743
|
return Number(lineAttr);
|
|
732
744
|
}
|
|
733
|
-
/** Greatest marker line whose anchor sits at or above viewport Y `y`. */
|
|
734
745
|
function bestCommentrayAnchorLine0AtOrAboveY(anchors, y) {
|
|
735
|
-
|
|
746
|
+
const readings = [];
|
|
736
747
|
for (const a of anchors) {
|
|
737
748
|
const line0 = readCommentrayLine0FromAnchor(a);
|
|
738
749
|
if (line0 === null)
|
|
739
750
|
continue;
|
|
740
|
-
|
|
741
|
-
best = line0;
|
|
742
|
-
else
|
|
743
|
-
break;
|
|
751
|
+
readings.push({ line0, top: a.getBoundingClientRect().top });
|
|
744
752
|
}
|
|
745
|
-
return
|
|
753
|
+
return maxCommentrayAnchorLine0AtOrAboveViewportY(readings, y);
|
|
746
754
|
}
|
|
747
755
|
function lastCommentrayAnchorLine0(anchors) {
|
|
748
756
|
const last = anchors[anchors.length - 1];
|
|
@@ -815,7 +823,8 @@ function probeCommentrayLine0FromDoc(docPane) {
|
|
|
815
823
|
if (paneScrollNearEnd(docPane))
|
|
816
824
|
return lastCommentrayAnchorLine0(anchors);
|
|
817
825
|
const dr = docPane.getBoundingClientRect();
|
|
818
|
-
|
|
826
|
+
/** Same band as the root-scroll branch: a few px below the pane top so block anchors sit inside `top <= y` while their prose is what the reader sees first. */
|
|
827
|
+
const y = dr.top + docPane.clientTop + Math.max(2, Math.min(40, docPane.clientHeight * 0.15));
|
|
819
828
|
return bestCommentrayAnchorLine0AtOrAboveY(anchors, y);
|
|
820
829
|
}
|
|
821
830
|
function pageBreakPullEnabled() {
|
|
@@ -1015,16 +1024,28 @@ function centerYInViewport(el) {
|
|
|
1015
1024
|
function codeLineHighlightCenterYViewport(lineEl) {
|
|
1016
1025
|
return centerYInViewport(lineEl);
|
|
1017
1026
|
}
|
|
1018
|
-
function commentaryBandEndYViewport(docScrollEl, next, docTop) {
|
|
1027
|
+
function commentaryBandEndYViewport(docScrollEl, next, docTop, clipThroughPageBreakGaps) {
|
|
1019
1028
|
if (next) {
|
|
1020
1029
|
const nextEl = document.getElementById(`commentray-block-${next.id}`);
|
|
1021
|
-
|
|
1030
|
+
if (!nextEl)
|
|
1031
|
+
return centerYInViewport(docTop);
|
|
1032
|
+
const nextTop = nextEl.getBoundingClientRect().top - 3;
|
|
1033
|
+
if (!clipThroughPageBreakGaps)
|
|
1034
|
+
return nextTop;
|
|
1035
|
+
const docBandTop = docTop.getBoundingClientRect().top + 4;
|
|
1036
|
+
const contentBottom = maxRenderableCommentaryContentBottomViewport(docScrollEl, docTop, nextEl);
|
|
1037
|
+
return Math.min(nextTop, Math.max(docBandTop, contentBottom));
|
|
1022
1038
|
}
|
|
1023
1039
|
const dr = docScrollEl.getBoundingClientRect();
|
|
1024
1040
|
let bottom = dr.bottom - 4;
|
|
1025
1041
|
const lastKid = docScrollEl.children[docScrollEl.children.length - 1];
|
|
1026
1042
|
if (lastKid)
|
|
1027
1043
|
bottom = Math.min(bottom, lastKid.getBoundingClientRect().bottom - 4);
|
|
1044
|
+
if (clipThroughPageBreakGaps) {
|
|
1045
|
+
const docBandTop = docTop.getBoundingClientRect().top + 4;
|
|
1046
|
+
const contentBottom = maxRenderableCommentaryContentBottomViewport(docScrollEl, docTop, null);
|
|
1047
|
+
bottom = Math.min(bottom, Math.max(docBandTop, contentBottom));
|
|
1048
|
+
}
|
|
1028
1049
|
return bottom;
|
|
1029
1050
|
}
|
|
1030
1051
|
function sourceAnchorIndexFromId(id, prefix) {
|
|
@@ -1087,7 +1108,7 @@ function subscribeBlockRayRedraw(gutter, codePane, docScrollEl, scheduleDraw) {
|
|
|
1087
1108
|
ro.observe(shell);
|
|
1088
1109
|
}
|
|
1089
1110
|
function drawBlockRaysIntoSvg(svg, gutter, docScrollEl, getLinks, probeTopSourceLine1Based, lineIdPrefix) {
|
|
1090
|
-
const links = getLinks();
|
|
1111
|
+
const links = dedupeBlockScrollLinksById(getLinks());
|
|
1091
1112
|
const sorted = sortBlockLinksBySource(links);
|
|
1092
1113
|
const gutterRect = gutter.getBoundingClientRect();
|
|
1093
1114
|
const w = gutterRect.width;
|
|
@@ -1096,7 +1117,11 @@ function drawBlockRaysIntoSvg(svg, gutter, docScrollEl, getLinks, probeTopSource
|
|
|
1096
1117
|
svg.replaceChildren();
|
|
1097
1118
|
return;
|
|
1098
1119
|
}
|
|
1099
|
-
|
|
1120
|
+
/** Doc-aligned active block matches visible commentary; code-only probe can lag in page gaps. */
|
|
1121
|
+
const activeId = docScrollEl.querySelector(".commentray-block-anchor") !== null
|
|
1122
|
+
? activeBlockIdForCommentrayLine0(links, probeCommentrayLine0FromDoc(docScrollEl))
|
|
1123
|
+
: activeBlockIdForViewport(links, probeTopSourceLine1Based());
|
|
1124
|
+
const clipGutterRaysThroughPageBreakGaps = pageBreakPullEnabled();
|
|
1100
1125
|
svg.setAttribute("viewBox", `0 0 ${String(w)} ${String(h)}`);
|
|
1101
1126
|
svg.setAttribute("preserveAspectRatio", "none");
|
|
1102
1127
|
const parts = [];
|
|
@@ -1108,7 +1133,7 @@ function drawBlockRaysIntoSvg(svg, gutter, docScrollEl, getLinks, probeTopSource
|
|
|
1108
1133
|
const link = sorted[i];
|
|
1109
1134
|
if (!link)
|
|
1110
1135
|
continue;
|
|
1111
|
-
const next =
|
|
1136
|
+
const next = nextBlockLinkInCommentrayOrder(links, link);
|
|
1112
1137
|
const i0 = codeLineDomIndex0(link.sourceStart);
|
|
1113
1138
|
const i1 = codeLineDomIndex0(link.sourceEnd);
|
|
1114
1139
|
const codeTop = document.getElementById(`${lineIdPrefix}${String(i0)}`) ??
|
|
@@ -1118,7 +1143,7 @@ function drawBlockRaysIntoSvg(svg, gutter, docScrollEl, getLinks, probeTopSource
|
|
|
1118
1143
|
const docTop = document.getElementById(`commentray-block-${link.id}`);
|
|
1119
1144
|
if (!codeTop || !codeBot || !docTop)
|
|
1120
1145
|
continue;
|
|
1121
|
-
const docEndYViewport = commentaryBandEndYViewport(docScrollEl, next, docTop);
|
|
1146
|
+
const docEndYViewport = commentaryBandEndYViewport(docScrollEl, next, docTop, clipGutterRaysThroughPageBreakGaps);
|
|
1122
1147
|
const yCodeTop = codeLineHighlightCenterYViewport(codeTop);
|
|
1123
1148
|
const yCodeBot = codeLineHighlightCenterYViewport(codeBot);
|
|
1124
1149
|
const yDocTop = docTop.getBoundingClientRect().top + 2;
|
|
@@ -1152,8 +1177,8 @@ function drawBlockRaysIntoSvg(svg, gutter, docScrollEl, getLinks, probeTopSource
|
|
|
1152
1177
|
}
|
|
1153
1178
|
/**
|
|
1154
1179
|
* Splines in the gutter between each block’s source range and its commentary band (dual pane,
|
|
1155
|
-
* index-backed blocks). Emphasizes the block aligned with the
|
|
1156
|
-
* off-screen endpoints so readers see which way to scroll.
|
|
1180
|
+
* index-backed blocks). Emphasizes the block aligned with the **doc** viewport when block anchors
|
|
1181
|
+
* exist; otherwise the source viewport. Clamps off-screen endpoints so readers see which way to scroll.
|
|
1157
1182
|
*
|
|
1158
1183
|
* @returns Request a redraw after DOM changes that do not resize the panes (e.g. multi-angle body swap).
|
|
1159
1184
|
*/
|
|
@@ -1493,12 +1518,13 @@ function wireDocumentedFilesTree() {
|
|
|
1493
1518
|
if (!(hub instanceof HTMLDetailsElement) || !(treeHost instanceof HTMLElement)) {
|
|
1494
1519
|
return;
|
|
1495
1520
|
}
|
|
1521
|
+
const detailsHub = hub;
|
|
1496
1522
|
const treeMount = treeHost;
|
|
1497
|
-
const jsonUrl =
|
|
1523
|
+
const jsonUrl = detailsHub.getAttribute("data-nav-json-url")?.trim() ?? "";
|
|
1498
1524
|
const embeddedB64 = shell?.getAttribute("data-documented-pairs-b64")?.trim() ?? "";
|
|
1499
1525
|
if (jsonUrl.length === 0 && embeddedB64.length === 0)
|
|
1500
1526
|
return;
|
|
1501
|
-
const placeDocHubFlyout = wireDocumentedFilesTreeMobileFlyout(
|
|
1527
|
+
const placeDocHubFlyout = wireDocumentedFilesTreeMobileFlyout(detailsHub);
|
|
1502
1528
|
const ensureLoaded = loadDocumentedPairs(jsonUrl, embeddedB64);
|
|
1503
1529
|
let cachedPairs = null;
|
|
1504
1530
|
function applyFilterAndRender() {
|
|
@@ -1521,21 +1547,31 @@ function wireDocumentedFilesTree() {
|
|
|
1521
1547
|
'<p class="nav-rail__doc-hub-hint" role="alert">Could not load the file list.</p>';
|
|
1522
1548
|
}
|
|
1523
1549
|
}
|
|
1524
|
-
|
|
1550
|
+
detailsHub.addEventListener("toggle", () => {
|
|
1525
1551
|
placeDocHubFlyout();
|
|
1526
|
-
if (
|
|
1552
|
+
if (detailsHub.open) {
|
|
1527
1553
|
globalThis.requestAnimationFrame(() => {
|
|
1528
1554
|
placeDocHubFlyout();
|
|
1529
1555
|
focusDocumentedFilesFilterInput();
|
|
1530
1556
|
});
|
|
1531
1557
|
}
|
|
1532
|
-
if (!
|
|
1558
|
+
if (!detailsHub.open)
|
|
1533
1559
|
return;
|
|
1534
1560
|
void hydrateTree();
|
|
1535
1561
|
});
|
|
1562
|
+
function onDocumentedFilesHubEscape(ev) {
|
|
1563
|
+
if (!detailsHub.open || ev.key !== "Escape")
|
|
1564
|
+
return;
|
|
1565
|
+
ev.preventDefault();
|
|
1566
|
+
detailsHub.open = false;
|
|
1567
|
+
const sum = detailsHub.querySelector("summary");
|
|
1568
|
+
if (sum instanceof HTMLElement)
|
|
1569
|
+
sum.focus({ preventScroll: true });
|
|
1570
|
+
}
|
|
1571
|
+
document.addEventListener("keydown", onDocumentedFilesHubEscape, true);
|
|
1536
1572
|
if (filterInput instanceof HTMLInputElement) {
|
|
1537
1573
|
filterInput.addEventListener("input", () => {
|
|
1538
|
-
if (!
|
|
1574
|
+
if (!detailsHub.open || cachedPairs === null)
|
|
1539
1575
|
return;
|
|
1540
1576
|
applyFilterAndRender();
|
|
1541
1577
|
});
|
|
@@ -2333,7 +2369,7 @@ function humaneBrowseAliasPathForSource(sourcePath) {
|
|
|
2333
2369
|
return sourcePath
|
|
2334
2370
|
.split("/")
|
|
2335
2371
|
.filter((seg) => seg.length > 0)
|
|
2336
|
-
.map((seg) => encodeURIComponent(seg))
|
|
2372
|
+
.map((seg) => seg.startsWith(".") ? `%2E${encodeURIComponent(seg.slice(1))}` : encodeURIComponent(seg))
|
|
2337
2373
|
.join("/");
|
|
2338
2374
|
}
|
|
2339
2375
|
function companionStemFromCommentrayPath(commentrayPath) {
|
|
@@ -2418,12 +2454,29 @@ function maybeBackfillAddressBarWithHumanePairLink() {
|
|
|
2418
2454
|
normalizeDocumentationHomeHrefForCurrentPath();
|
|
2419
2455
|
if (!shellEligibleForHumaneBackfill(shell, pathname))
|
|
2420
2456
|
return;
|
|
2421
|
-
const nextPath = nextHumaneBrowsePathForShell(shell, pathname);
|
|
2422
|
-
if (nextPath === null)
|
|
2423
|
-
return;
|
|
2424
2457
|
const beforeHref = globalThis.location.href;
|
|
2425
2458
|
absolutizeNavJsonUrls(shell, beforeHref);
|
|
2426
2459
|
normalizePairBrowseHrefForCurrentPath(shell, pathname);
|
|
2460
|
+
/** Prefer the same `staticBrowseUrl` the static build put on `#shell` (slug or `…/index.html` shims). */
|
|
2461
|
+
const canonicalBrowsePathname = (() => {
|
|
2462
|
+
const raw = shell.getAttribute("data-commentray-pair-browse-href")?.trim() ?? "";
|
|
2463
|
+
if (raw.length === 0)
|
|
2464
|
+
return null;
|
|
2465
|
+
try {
|
|
2466
|
+
const u = new URL(raw, globalThis.location.href);
|
|
2467
|
+
if (u.origin !== globalThis.location.origin)
|
|
2468
|
+
return null;
|
|
2469
|
+
if (!u.pathname.includes("/browse/"))
|
|
2470
|
+
return null;
|
|
2471
|
+
return u.pathname;
|
|
2472
|
+
}
|
|
2473
|
+
catch {
|
|
2474
|
+
return null;
|
|
2475
|
+
}
|
|
2476
|
+
})();
|
|
2477
|
+
const nextPath = canonicalBrowsePathname ?? nextHumaneBrowsePathForShell(shell, pathname);
|
|
2478
|
+
if (nextPath === null)
|
|
2479
|
+
return;
|
|
2427
2480
|
globalThis.history.replaceState(null, "", `${nextPath}${globalThis.location.search}${globalThis.location.hash}`);
|
|
2428
2481
|
}
|
|
2429
2482
|
function permalinkHashSuffixFromUi() {
|