@obvi/blueprint 1.1.3 → 1.2.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/blueprint-contract.d.ts +15 -0
- package/dist/blueprint-contract.js +1 -0
- package/dist/blueprint-contract.json +13 -0
- package/dist/blueprint.css +496 -95
- package/dist/blueprint.js +164 -45
- package/dist/vendor/blueprint/blueprint.css +6141 -0
- package/dist/vendor/blueprint/blueprint.js +2932 -0
- package/package.json +7 -1
package/dist/blueprint.js
CHANGED
|
@@ -756,11 +756,31 @@ function injectSidebar(doc, win) {
|
|
|
756
756
|
searchHint.append(searchHintCmd, searchHintKey);
|
|
757
757
|
searchField.append(searchIcon, searchLabel, searchHint);
|
|
758
758
|
search.append(searchField);
|
|
759
|
-
panel.append(search);
|
|
760
759
|
const switcher = buildDocSwitcher(doc, win);
|
|
761
|
-
|
|
760
|
+
const tocSwitcher = doc.createElement("details");
|
|
761
|
+
tocSwitcher.className = "bp-toc-switcher";
|
|
762
|
+
tocSwitcher.open = true;
|
|
763
|
+
const tocSummary = doc.createElement("summary");
|
|
764
|
+
tocSummary.className = "bp-toc-switcher__current sidebar-field";
|
|
765
|
+
tocSummary.setAttribute("aria-label", "Jump to section");
|
|
766
|
+
const tocLabel = doc.createElement("span");
|
|
767
|
+
tocLabel.className = "bp-toc-switcher__label";
|
|
768
|
+
const tocTitle = doc.createElement("span");
|
|
769
|
+
tocTitle.className = "bp-toc-switcher__title";
|
|
770
|
+
tocTitle.textContent = "Contents";
|
|
771
|
+
tocLabel.append(tocTitle);
|
|
772
|
+
const tocChevron = doc.createElement("span");
|
|
773
|
+
tocChevron.className = "bp-toc-switcher__chevron bp-transition-transform bp-duration-normal bp-ease-in-out";
|
|
774
|
+
tocChevron.setAttribute("aria-hidden", "true");
|
|
775
|
+
tocChevron.append(createChromeSvg(doc, DOC_CHEVRON_ICON));
|
|
776
|
+
tocSummary.append(tocLabel, tocChevron);
|
|
762
777
|
const list = doc.createElement("ul");
|
|
763
|
-
|
|
778
|
+
tocSwitcher.append(tocSummary, list);
|
|
779
|
+
const mobileHead = doc.createElement("div");
|
|
780
|
+
mobileHead.className = "sidebar-mobile-head";
|
|
781
|
+
mobileHead.append(tocSwitcher, search);
|
|
782
|
+
panel.append(mobileHead);
|
|
783
|
+
if (switcher) panel.append(switcher);
|
|
764
784
|
nav.append(panel, buildSidebarFooter(doc));
|
|
765
785
|
return nav;
|
|
766
786
|
}
|
|
@@ -834,6 +854,7 @@ function setThemeAnimated(doc, win, theme) {
|
|
|
834
854
|
transition = doc.startViewTransition(runUpdate);
|
|
835
855
|
}
|
|
836
856
|
if (!applied) runUpdate();
|
|
857
|
+
transition?.ready?.catch(clearSwitching);
|
|
837
858
|
if (transition?.finished) {
|
|
838
859
|
transition.finished.finally(clearSwitching).catch(clearSwitching);
|
|
839
860
|
} else {
|
|
@@ -931,14 +952,14 @@ function wireSearchPalette(doc, win) {
|
|
|
931
952
|
let panel = null;
|
|
932
953
|
let input = null;
|
|
933
954
|
let results = null;
|
|
934
|
-
let
|
|
955
|
+
let actionDefs = [];
|
|
935
956
|
let entries = [];
|
|
936
957
|
let visible = [];
|
|
937
958
|
let selected = 0;
|
|
938
959
|
let returnFocus = null;
|
|
939
960
|
let prevOverflow = "";
|
|
940
961
|
const collectEntries = () => {
|
|
941
|
-
const list = doc.querySelector(".bp-sidebar .bp-sidebar__panel > ul") ?? doc.querySelector(".bp-toc > ul");
|
|
962
|
+
const list = doc.querySelector(".bp-sidebar .bp-sidebar__panel .bp-toc-switcher > ul") ?? doc.querySelector(".bp-sidebar .bp-sidebar__panel > ul") ?? doc.querySelector(".bp-toc > ul");
|
|
942
963
|
if (!list) return [];
|
|
943
964
|
const out = [];
|
|
944
965
|
let group = "";
|
|
@@ -961,16 +982,57 @@ function wireSearchPalette(doc, win) {
|
|
|
961
982
|
}
|
|
962
983
|
return out;
|
|
963
984
|
};
|
|
964
|
-
const
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
985
|
+
const modGlyph = isMacLike ? "⌘" : "⌃";
|
|
986
|
+
const matchesShortcut = (event, key) => {
|
|
987
|
+
const mod = isMacLike ? event.metaKey : event.ctrlKey;
|
|
988
|
+
if (!mod || !event.shiftKey) return false;
|
|
989
|
+
return event.key.toLowerCase() === key.toLowerCase();
|
|
990
|
+
};
|
|
991
|
+
const buildActionDefs = () => {
|
|
992
|
+
const defs = [];
|
|
993
|
+
if (doc.querySelector(".theme-toggle")) {
|
|
994
|
+
defs.push({
|
|
995
|
+
label: "Toggle theme",
|
|
996
|
+
icon: THEME_MOON_ICON,
|
|
997
|
+
chip: `${modGlyph}⇧L`,
|
|
998
|
+
shortcut: "l",
|
|
999
|
+
run: () => doc.querySelector(".theme-toggle")?.click()
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
1002
|
+
if (doc.querySelector(".sidebar-toggle")) {
|
|
1003
|
+
defs.push({
|
|
1004
|
+
label: "Toggle sidebar",
|
|
1005
|
+
icon: SIDEBAR_COLLAPSE_ICON,
|
|
1006
|
+
chip: `${modGlyph}⇧B`,
|
|
1007
|
+
shortcut: "b",
|
|
1008
|
+
run: () => doc.querySelector(".sidebar-toggle")?.click()
|
|
1009
|
+
});
|
|
1010
|
+
}
|
|
1011
|
+
return defs;
|
|
1012
|
+
};
|
|
1013
|
+
const buildAction = (def) => {
|
|
1014
|
+
const button = doc.createElement("button");
|
|
1015
|
+
button.type = "button";
|
|
1016
|
+
button.className = "docs-search__action bp-transition-colors bp-ease";
|
|
1017
|
+
const icon = createChromeSvg(doc, def.icon, 16);
|
|
1018
|
+
icon.classList.add("docs-search__action-icon");
|
|
1019
|
+
const label2 = doc.createElement("span");
|
|
1020
|
+
label2.className = "docs-search__action-label";
|
|
1021
|
+
label2.textContent = def.label;
|
|
1022
|
+
button.append(icon, label2);
|
|
1023
|
+
if (def.chip) {
|
|
1024
|
+
const chip = doc.createElement("kbd");
|
|
1025
|
+
chip.className = "docs-search__chip";
|
|
1026
|
+
for (const glyph of Array.from(def.chip)) {
|
|
1027
|
+
const key = doc.createElement("span");
|
|
1028
|
+
key.textContent = glyph;
|
|
1029
|
+
chip.append(key);
|
|
1030
|
+
}
|
|
1031
|
+
button.append(chip);
|
|
1032
|
+
}
|
|
1033
|
+
button.addEventListener("click", () => def.run(button));
|
|
1034
|
+
def.button = button;
|
|
1035
|
+
return button;
|
|
974
1036
|
};
|
|
975
1037
|
const highlight = (text, q) => {
|
|
976
1038
|
if (!q) return [doc.createTextNode(text)];
|
|
@@ -1000,6 +1062,11 @@ function wireSearchPalette(doc, win) {
|
|
|
1000
1062
|
});
|
|
1001
1063
|
const mainCol = doc.createElement("span");
|
|
1002
1064
|
mainCol.className = "docs-search__row-main";
|
|
1065
|
+
const iconBox = doc.createElement("span");
|
|
1066
|
+
iconBox.className = "docs-search__icon-box";
|
|
1067
|
+
iconBox.setAttribute("aria-hidden", "true");
|
|
1068
|
+
iconBox.textContent = "#";
|
|
1069
|
+
mainCol.append(iconBox);
|
|
1003
1070
|
if (entry.crumb) {
|
|
1004
1071
|
const crumb = doc.createElement("span");
|
|
1005
1072
|
crumb.className = "docs-search__crumb";
|
|
@@ -1008,11 +1075,7 @@ function wireSearchPalette(doc, win) {
|
|
|
1008
1075
|
}
|
|
1009
1076
|
const title = doc.createElement("span");
|
|
1010
1077
|
title.className = "docs-search__title";
|
|
1011
|
-
|
|
1012
|
-
hash.className = "docs-search__hash";
|
|
1013
|
-
hash.setAttribute("aria-hidden", "true");
|
|
1014
|
-
hash.textContent = "#";
|
|
1015
|
-
title.append(hash, ...highlight(entry.title, q));
|
|
1078
|
+
title.append(...highlight(entry.title, q));
|
|
1016
1079
|
mainCol.append(title);
|
|
1017
1080
|
const enter = doc.createElement("kbd");
|
|
1018
1081
|
enter.className = "docs-search__enter";
|
|
@@ -1020,19 +1083,22 @@ function wireSearchPalette(doc, win) {
|
|
|
1020
1083
|
row.append(mainCol, enter);
|
|
1021
1084
|
return row;
|
|
1022
1085
|
};
|
|
1023
|
-
const buildEmpty = (
|
|
1086
|
+
const buildEmpty = () => {
|
|
1024
1087
|
const wrap = doc.createElement("div");
|
|
1025
1088
|
wrap.className = "docs-search__empty";
|
|
1026
|
-
const
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1089
|
+
const center = doc.createElement("div");
|
|
1090
|
+
center.className = "docs-search__empty-center";
|
|
1091
|
+
const copy = doc.createElement("div");
|
|
1092
|
+
copy.className = "docs-search__empty-copy";
|
|
1093
|
+
const title = doc.createElement("p");
|
|
1030
1094
|
title.className = "docs-search__empty-title";
|
|
1031
|
-
title.textContent =
|
|
1032
|
-
const note = doc.createElement("
|
|
1095
|
+
title.textContent = "No results found";
|
|
1096
|
+
const note = doc.createElement("p");
|
|
1033
1097
|
note.className = "docs-search__empty-note";
|
|
1034
|
-
note.textContent = "Try
|
|
1035
|
-
|
|
1098
|
+
note.textContent = "Try searching with different keywords";
|
|
1099
|
+
copy.append(title, note);
|
|
1100
|
+
center.append(copy);
|
|
1101
|
+
wrap.append(center);
|
|
1036
1102
|
return wrap;
|
|
1037
1103
|
};
|
|
1038
1104
|
const applySelection = () => {
|
|
@@ -1060,8 +1126,7 @@ function wireSearchPalette(doc, win) {
|
|
|
1060
1126
|
selected = 0;
|
|
1061
1127
|
results.replaceChildren();
|
|
1062
1128
|
if (visible.length === 0) {
|
|
1063
|
-
results.append(buildEmpty(
|
|
1064
|
-
footStatus.textContent = "0 results";
|
|
1129
|
+
results.append(buildEmpty());
|
|
1065
1130
|
input.removeAttribute("aria-activedescendant");
|
|
1066
1131
|
return;
|
|
1067
1132
|
}
|
|
@@ -1075,9 +1140,14 @@ function wireSearchPalette(doc, win) {
|
|
|
1075
1140
|
results.append(group);
|
|
1076
1141
|
visible.forEach((entry, index) => results.append(buildRow(entry, index, q)));
|
|
1077
1142
|
applySelection();
|
|
1078
|
-
footStatus.textContent = q ? `${visible.length} result${visible.length === 1 ? "" : "s"}` : "Jump to a section";
|
|
1079
1143
|
};
|
|
1080
1144
|
const onKeydown = (event) => {
|
|
1145
|
+
const action = actionDefs.find((def) => matchesShortcut(event, def.shortcut));
|
|
1146
|
+
if (action) {
|
|
1147
|
+
event.preventDefault();
|
|
1148
|
+
action.run(action.button);
|
|
1149
|
+
return;
|
|
1150
|
+
}
|
|
1081
1151
|
if (event.key === "Escape") {
|
|
1082
1152
|
event.preventDefault();
|
|
1083
1153
|
close();
|
|
@@ -1088,6 +1158,7 @@ function wireSearchPalette(doc, win) {
|
|
|
1088
1158
|
event.preventDefault();
|
|
1089
1159
|
move(-1);
|
|
1090
1160
|
} else if (event.key === "Enter") {
|
|
1161
|
+
if (event.target?.closest?.(".docs-search__action")) return;
|
|
1091
1162
|
const row = results.querySelector(
|
|
1092
1163
|
`.docs-search__row[data-index="${selected}"]`
|
|
1093
1164
|
);
|
|
@@ -1125,12 +1196,12 @@ function wireSearchPalette(doc, win) {
|
|
|
1125
1196
|
input = doc.createElement("input");
|
|
1126
1197
|
input.className = "docs-search__input";
|
|
1127
1198
|
input.type = "search";
|
|
1128
|
-
input.placeholder = "Search the
|
|
1199
|
+
input.placeholder = "Search the blueprint…";
|
|
1129
1200
|
input.setAttribute("role", "combobox");
|
|
1130
1201
|
input.setAttribute("aria-autocomplete", "list");
|
|
1131
1202
|
input.setAttribute("aria-controls", "docs-search-listbox");
|
|
1132
1203
|
input.setAttribute("aria-expanded", "false");
|
|
1133
|
-
input.setAttribute("aria-label", "Search the
|
|
1204
|
+
input.setAttribute("aria-label", "Search the blueprint");
|
|
1134
1205
|
input.autocomplete = "off";
|
|
1135
1206
|
input.spellcheck = false;
|
|
1136
1207
|
const esc = doc.createElement("span");
|
|
@@ -1144,15 +1215,11 @@ function wireSearchPalette(doc, win) {
|
|
|
1144
1215
|
results.setAttribute("aria-label", "Search results");
|
|
1145
1216
|
const foot = doc.createElement("div");
|
|
1146
1217
|
foot.className = "docs-search__foot";
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
keyHint(["↵"], "open"),
|
|
1153
|
-
keyHint(["esc"], "close")
|
|
1154
|
-
);
|
|
1155
|
-
foot.append(footStatus, keys);
|
|
1218
|
+
const actions = doc.createElement("div");
|
|
1219
|
+
actions.className = "docs-search__actions";
|
|
1220
|
+
actionDefs = buildActionDefs();
|
|
1221
|
+
for (const def of actionDefs) actions.append(buildAction(def));
|
|
1222
|
+
foot.append(actions);
|
|
1156
1223
|
panel.append(field, results, foot);
|
|
1157
1224
|
overlay.append(panel);
|
|
1158
1225
|
(doc.body || doc.documentElement).append(overlay);
|
|
@@ -1393,7 +1460,7 @@ function initializeBlueprintRuntime(doc = document, win = window) {
|
|
|
1393
1460
|
if (!list || !listItem) return true;
|
|
1394
1461
|
const container = link.closest(".bp-sidebar, .bp-toc, .sidebar");
|
|
1395
1462
|
if (!container) return true;
|
|
1396
|
-
const topList = container.querySelector(":scope > .bp-sidebar__panel > ul") ?? container.querySelector(":scope > ul");
|
|
1463
|
+
const topList = container.querySelector(":scope > .bp-sidebar__panel .bp-toc-switcher > ul") ?? container.querySelector(":scope > .bp-sidebar__panel > ul") ?? container.querySelector(":scope > ul");
|
|
1397
1464
|
return list === topList;
|
|
1398
1465
|
};
|
|
1399
1466
|
const entries = [...doc.querySelectorAll('.bp-sidebar a[href^="#"], .bp-toc a[href^="#"], .sidebar a[href^="#"]')].filter(isPrimaryNavLink).map((link) => ({
|
|
@@ -1405,6 +1472,14 @@ function initializeBlueprintRuntime(doc = document, win = window) {
|
|
|
1405
1472
|
);
|
|
1406
1473
|
let scheduled = false;
|
|
1407
1474
|
let scrollingTo = null;
|
|
1475
|
+
const tocSwitchers = [...doc.querySelectorAll(".bp-toc-switcher")];
|
|
1476
|
+
const tocSwitcherTitles = [...doc.querySelectorAll(".bp-toc-switcher__title")];
|
|
1477
|
+
const railColumnQuery = win.matchMedia("(min-width: 861px)");
|
|
1478
|
+
const syncTocSwitcherOpen = () => {
|
|
1479
|
+
for (const sw of tocSwitchers) sw.open = railColumnQuery.matches;
|
|
1480
|
+
};
|
|
1481
|
+
syncTocSwitcherOpen();
|
|
1482
|
+
railColumnQuery.addEventListener("change", syncTocSwitcherOpen);
|
|
1408
1483
|
const placeMarker = (link) => {
|
|
1409
1484
|
const container = link.closest(".bp-sidebar, .bp-toc, .sidebar");
|
|
1410
1485
|
const list = container?.querySelector(":scope > ul") ?? container?.querySelector("ul");
|
|
@@ -1412,18 +1487,59 @@ function initializeBlueprintRuntime(doc = document, win = window) {
|
|
|
1412
1487
|
list.style.setProperty("--bp-toc-y", `${link.offsetTop}px`);
|
|
1413
1488
|
list.style.setProperty("--bp-toc-h", `${link.offsetHeight}px`);
|
|
1414
1489
|
};
|
|
1490
|
+
const revealInRail = (link) => {
|
|
1491
|
+
const panel = link.closest(".bp-sidebar__panel");
|
|
1492
|
+
if (!panel || panel.scrollHeight <= panel.clientHeight) return;
|
|
1493
|
+
const style = win.getComputedStyle(panel);
|
|
1494
|
+
const padTop = Number.parseFloat(style.scrollPaddingTop) || 0;
|
|
1495
|
+
const padBottom = Number.parseFloat(style.scrollPaddingBottom) || 0;
|
|
1496
|
+
const panelRect = panel.getBoundingClientRect();
|
|
1497
|
+
const linkRect = link.getBoundingClientRect();
|
|
1498
|
+
const safeTop = panelRect.top + padTop;
|
|
1499
|
+
const safeBottom = panelRect.bottom - padBottom;
|
|
1500
|
+
let delta = 0;
|
|
1501
|
+
if (linkRect.top < safeTop) delta = linkRect.top - safeTop;
|
|
1502
|
+
else if (linkRect.bottom > safeBottom) delta = linkRect.bottom - safeBottom;
|
|
1503
|
+
if (delta === 0) return;
|
|
1504
|
+
panel.scrollBy({
|
|
1505
|
+
top: delta,
|
|
1506
|
+
behavior: prefersReducedMotion() ? "auto" : "smooth"
|
|
1507
|
+
});
|
|
1508
|
+
};
|
|
1509
|
+
let lastCurrent = null;
|
|
1415
1510
|
const setCurrent = (section) => {
|
|
1511
|
+
const changed = section !== lastCurrent;
|
|
1512
|
+
let activeLabel = "";
|
|
1416
1513
|
for (const item of entries) {
|
|
1417
1514
|
if (section && item.section === section) {
|
|
1418
1515
|
item.link.setAttribute("aria-current", "location");
|
|
1419
1516
|
placeMarker(item.link);
|
|
1517
|
+
if (changed) revealInRail(item.link);
|
|
1518
|
+
if (!activeLabel) activeLabel = item.link.textContent.trim();
|
|
1420
1519
|
} else {
|
|
1421
1520
|
item.link.removeAttribute("aria-current");
|
|
1422
1521
|
}
|
|
1423
1522
|
}
|
|
1523
|
+
lastCurrent = section;
|
|
1524
|
+
if (changed) {
|
|
1525
|
+
const summaryLabel = activeLabel || "Contents";
|
|
1526
|
+
for (const title of tocSwitcherTitles) title.textContent = summaryLabel;
|
|
1527
|
+
}
|
|
1528
|
+
};
|
|
1529
|
+
const mobileHead = doc.querySelector(".sidebar-mobile-head");
|
|
1530
|
+
const contentsRail = doc.querySelector("#bp-contents-rail");
|
|
1531
|
+
const syncHeadDivider = () => {
|
|
1532
|
+
if (!mobileHead || !contentsRail) return;
|
|
1533
|
+
if (win.getComputedStyle(mobileHead).position !== "fixed") {
|
|
1534
|
+
mobileHead.removeAttribute("data-bp-head-stuck");
|
|
1535
|
+
return;
|
|
1536
|
+
}
|
|
1537
|
+
const stuck = contentsRail.getBoundingClientRect().bottom <= mobileHead.getBoundingClientRect().bottom + 0.5;
|
|
1538
|
+
mobileHead.toggleAttribute("data-bp-head-stuck", stuck);
|
|
1424
1539
|
};
|
|
1425
1540
|
const update = () => {
|
|
1426
1541
|
scheduled = false;
|
|
1542
|
+
syncHeadDivider();
|
|
1427
1543
|
if (progress) {
|
|
1428
1544
|
const max = scrollHeight() - clientHeight();
|
|
1429
1545
|
progress.style.transform = `scaleX(${max > 0 ? scrollTop() / max : 0})`;
|
|
@@ -1505,6 +1621,9 @@ function initializeBlueprintRuntime(doc = document, win = window) {
|
|
|
1505
1621
|
event.preventDefault();
|
|
1506
1622
|
if (win.location.hash !== link.hash) win.history.pushState(null, "", link.hash);
|
|
1507
1623
|
if (entries.some(({ section: target }) => target === section)) setCurrent(section);
|
|
1624
|
+
if (!railColumnQuery.matches) {
|
|
1625
|
+
for (const sw of tocSwitchers) sw.open = false;
|
|
1626
|
+
}
|
|
1508
1627
|
scrollToSection(section);
|
|
1509
1628
|
});
|
|
1510
1629
|
let scrollSource = shellScroller ?? win;
|
|
@@ -1765,7 +1884,7 @@ function renderContentsTree(doc, tree) {
|
|
|
1765
1884
|
function findSidebarNavLists(doc) {
|
|
1766
1885
|
const lists = [];
|
|
1767
1886
|
for (const nav of doc.querySelectorAll(".bp-sidebar:not([data-bp-nav-manual])")) {
|
|
1768
|
-
const list = nav.querySelector(":scope > .bp-sidebar__panel > ul") ?? nav.querySelector(":scope > ul");
|
|
1887
|
+
const list = nav.querySelector(":scope > .bp-sidebar__panel .bp-toc-switcher > ul") ?? nav.querySelector(":scope > .bp-sidebar__panel > ul") ?? nav.querySelector(":scope > ul");
|
|
1769
1888
|
if (list) lists.push(list);
|
|
1770
1889
|
}
|
|
1771
1890
|
for (const nav of doc.querySelectorAll(".bp-toc:not([data-bp-nav-manual])")) {
|