Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 28 additions & 1 deletion scripts/docs-site/docs-layout.css
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,7 @@
.doc .home-channel:hover { color: var(--ink); border-color: color-mix(in srgb,var(--ink) 24%,transparent); background: var(--paper); }}
@media (min-width:1281px) {
.docs-layout:not(.docs-home-layout) .main:has(> .toc) { padding-inline-end: var(--header-padding); }
.docs-layout .toc { padding-block-start: 43px; background: transparent; }}
.docs-layout .toc { --toc-rail-inset: 43px; background: transparent; }}
@media (max-width:1280px) {
.docs-layout { --docs-nav: 240px; --docs-inset: 38px; }
.docs-layout.docs-home-layout .article { padding-inline: 38px; }}
Expand Down Expand Up @@ -656,6 +656,33 @@
}
.docs-sidebar-levels .can-scroll-up { --nav-fade-top: 28px; }
.docs-sidebar-levels .can-scroll-down { --nav-fade-bottom: 36px; }

/* Match the left navigation's overflow cues without fading the native scrollbar. */
@property --docs-toc-thumb { syntax: "<color>"; inherits: true; initial-value: transparent; }
@media (min-width:1281px) {
.docs-layout .toc { --toc-fade-distance: 36px; --toc-fade-top: 0px; --toc-fade-bottom: 0px; --docs-toc-thumb: color-mix(in srgb,var(--muted) 42%,transparent); scrollbar-width: thin; scrollbar-gutter: stable; scrollbar-color: var(--docs-toc-thumb) transparent; overscroll-behavior-y: contain; mask-image: linear-gradient(to bottom,transparent,#000 var(--toc-fade-top),#000 calc(100% - var(--toc-fade-bottom)),transparent),linear-gradient(#000,#000),linear-gradient(#000,#000); mask-size: 100% 100%,12px 100%,12px 100%; mask-position: center,left,right; mask-repeat: no-repeat; }
.docs-layout .toc::-webkit-scrollbar { width: 8px; background: transparent; }
.docs-layout .toc::-webkit-scrollbar-track, .docs-layout .toc::-webkit-scrollbar-corner { background: transparent; border: 0; box-shadow: none; }
.docs-layout .toc::-webkit-scrollbar-button { display: none; }
.docs-layout .toc::-webkit-scrollbar-thumb { background: var(--docs-toc-thumb); border: 2px solid transparent; border-radius: var(--oc-radius-round); background-clip: padding-box; }
.docs-layout .toc.can-scroll-up { --toc-fade-top: 28px; }
.docs-layout .toc.can-scroll-down { --toc-fade-bottom: var(--toc-fade-distance); }
.docs-layout .toc:has(:focus-visible) { mask-image: none; }
}
/* Opt into the custom thumb where supported; standard scrollbar properties take precedence otherwise. */
@supports selector(::-webkit-scrollbar) {
@media (min-width:1281px) {
.docs-layout .toc { scrollbar-width: auto; scrollbar-color: auto; }
}
}
@media (min-width:1281px) and (hover:hover) and (pointer:fine) {
.docs-layout .toc { --docs-toc-thumb: transparent; transition: --docs-toc-thumb var(--oc-duration-ui) ease; }
.docs-layout .toc:hover { --docs-toc-thumb: color-mix(in srgb,var(--muted) 42%,transparent); transition-duration: var(--oc-duration-fast); }
.docs-layout .toc:has(:focus-visible) { --docs-toc-thumb: color-mix(in srgb,var(--muted) 42%,transparent); transition-duration: 0s; }
}
@media (min-width:1281px) and (forced-colors:active) {
.docs-layout .toc { scrollbar-color: auto; mask-image: none; }
}
.docs-sidebar-levels[data-level="section"] .docs-sidebar-directory,
.docs-sidebar-levels[data-level="directory"] .docs-sidebar-context { position: absolute; inset-block-start: 0; max-height: 100%; overflow: hidden; visibility: hidden; opacity: 0; pointer-events: none; transition: opacity 180ms var(--oc-ease-out), transform 180ms var(--oc-ease-out), visibility 0s 180ms; }
.docs-sidebar-levels[data-level="section"] .docs-sidebar-directory { transform: translateX(-12px); }
Expand Down
41 changes: 33 additions & 8 deletions scripts/docs-site/site-js.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,35 @@ function syncSidebar(nextDoc){const current=document.querySelector(".sidebar");c
const compactTocQuery=matchMedia("(max-width:1280px)");function isCompactToc(){return compactTocQuery.matches}function syncStickyHeaderOffset(){const headerHeight=document.querySelector(".site-header")?.getBoundingClientRect().height||0;root.style.setProperty("--header-row-h",headerHeight+"px");const tocHeight=isCompactToc()?document.querySelector(".toc summary")?.getBoundingClientRect().height||0:0;root.style.setProperty("--sticky-header-h",Math.ceil(headerHeight+tocHeight)+"px");syncHeaderSurface();syncTocCurrentFade()}
function syncTocSpace(){
const toc=document.querySelector(".toc");if(!toc)return;
if(isCompactToc()){toc.style.removeProperty("--toc-available-height");return}
const rect=toc.getBoundingClientRect();let bottom=innerHeight-24;
for(const floating of document.querySelectorAll(".docs-chat-launcher,.community-invite")){if(isUsableFocusTarget(floating)){const control=floating.getBoundingClientRect();if(rect.left<control.right&&rect.right>control.left)bottom=Math.min(bottom,control.top-12)}}
if(isCompactToc()){toc.style.removeProperty("--toc-available-height");toc.style.removeProperty("--toc-scroll-end-space");syncTocFade();return}
const rect=toc.getBoundingClientRect();let bottom=innerHeight,endSpace=parseFloat(getComputedStyle(toc).getPropertyValue("--toc-fade-distance"))||36;
const overlapsRail=control=>rect.left<control.right&&rect.right>control.left;
const card=document.querySelector(".community-invite");
if(isUsableFocusTarget(card)){const control=card.getBoundingClientRect();if(overlapsRail(control))bottom=Math.min(bottom,control.top-12)}
// Keep the rail full-height beside the small launcher, with room to scroll its last link clear.
const launcher=document.querySelector(".docs-chat-launcher");
if(isUsableFocusTarget(launcher)){const control=launcher.getBoundingClientRect();if(overlapsRail(control)&&control.top<bottom)endSpace=Math.max(endSpace,bottom-control.top+12)}
toc.style.setProperty("--toc-available-height",Math.max(0,bottom-rect.top)+"px");
toc.style.setProperty("--toc-scroll-end-space",Math.min(endSpace,Math.max(0,bottom-rect.top))+"px");
revealTocFocus();syncTocFade();
}
function syncTocFade(){
const toc=document.querySelector(".toc");if(!toc)return;
const overflow=!isCompactToc()&&toc.scrollHeight>toc.clientHeight+1;
toc.classList.toggle("can-scroll-up",overflow&&toc.scrollTop>1);
toc.classList.toggle("can-scroll-down",overflow&&toc.scrollHeight-toc.clientHeight-toc.scrollTop>1);
}
function revealTocFocus(){
const target=document.activeElement,toc=target?.closest?.(".toc");
if(!toc||isCompactToc()||!target.matches("a"))return;
const visible=tocScrollBounds(toc),link=target.getBoundingClientRect();
if(link.bottom>visible.bottom)toc.scrollTop+=link.bottom-visible.bottom;
else if(link.top<visible.top)toc.scrollTop+=link.top-visible.top;
}
// Programmatic reveals share the same fade and floating-control clearances as keyboard scrolling.
function tocScrollBounds(toc){
const box=toc.getBoundingClientRect(),style=getComputedStyle(toc);
return{top:box.top+(parseFloat(style.scrollPaddingTop)||0),bottom:box.bottom-(parseFloat(style.scrollPaddingBottom)||0)};
}
function syncTocDisclosure(){document.querySelectorAll(".toc").forEach(toc=>{if(isCompactToc()){if(!toc.dataset.compactTocReady){toc.open=false;toc.dataset.compactTocReady="true"}toc.classList.add("is-visible")}else{toc.open=true;toc.classList.remove("is-visible");delete toc.dataset.compactTocReady}});syncTocSpace()}
const mobileNavQuery=matchMedia("(max-width:820px)");
Expand All @@ -118,7 +143,7 @@ if(!isUsableFocusTarget(launcher))return;
const focusRect=target.getBoundingClientRect(),launcherRect=launcher.getBoundingClientRect();
if(focusRect.left<launcherRect.right&&focusRect.right>launcherRect.left&&focusRect.top<launcherRect.bottom&&focusRect.bottom>launcherRect.top)target.scrollIntoView({behavior:"instant",block:"center",inline:"nearest"});
}
document.addEventListener("focusin",e=>{if(!e.target?.closest?.("[data-language-picker]"))closeLanguage();navigationFocusOwned=Boolean(e.target?.closest?.(".sidebar,.community-invite,[data-nav-toggle]"));if(e.target?.closest?.(".sidebar"))requestAnimationFrame(revealSidebarFocus)});
document.addEventListener("focusin",e=>{if(!e.target?.closest?.("[data-language-picker]"))closeLanguage();navigationFocusOwned=Boolean(e.target?.closest?.(".sidebar,.community-invite,[data-nav-toggle]"));if(e.target?.closest?.(".sidebar"))requestAnimationFrame(revealSidebarFocus);if(e.target?.closest?.(".toc"))requestAnimationFrame(revealTocFocus)});
document.addEventListener("pointerdown",e=>{if(!e.target?.closest?.(".sidebar,.community-invite,[data-nav-toggle]"))navigationFocusOwned=false});
// Keep keyboard order aligned with the compact header's language, search, menu row.
function syncHeaderSearchPosition(){
Expand Down Expand Up @@ -240,7 +265,7 @@ function revealTarget(target){
for(const accordion of animated)accordion.removeAttribute("data-accordion-reveal");
}
function scrollTarget(hash){if(hash){const id=fragmentId(hash);const found=document.getElementById(id);const target=found?.classList.contains("anchor-alias")?found.closest("h1,h2,h3,h4,h5,h6"):found;revealTarget(target);target?.scrollIntoView();tocSpyHoldUntil=Date.now()+900;setActiveTocLink(target?.id)}else{scrollTo({top:0,behavior:"instant"})}}
let tocObserver=null;let tocScrollHandler=null;let tocSpyHoldUntil=0;let currentDocKey=location.pathname+location.search;
let tocObserver=null;let tocSizeObserver=null;let tocScrollHandler=null;let tocSpyHoldUntil=0;let currentDocKey=location.pathname+location.search;
function tocLinkId(link){return fragmentId(link.hash)}
function syncTocCurrentFade(){
const current=document.querySelector("[data-toc-current]");
Expand All @@ -252,9 +277,9 @@ const label=active?.textContent?.trim()||"";
if(current.textContent===label)return;
current.textContent=label;current.title=label;syncTocCurrentFade();
}
function setActiveTocLink(id){const toc=document.querySelector(".toc");if(!toc)return;let active=null;toc.querySelectorAll('a[href^="#"]').forEach(link=>{const on=Boolean(id&&tocLinkId(link)===id);link.classList.toggle("active",on);if(on)active=link});syncTocCurrent(toc,active);if(active){const list=active.closest(".toc");if(list&&list.scrollHeight>list.clientHeight){const lr=list.getBoundingClientRect();if(!isCompactToc()&&lr.top>parseFloat(getComputedStyle(list).top)+1)return;const ar=active.getBoundingClientRect();if(ar.top<lr.top)list.scrollTop+=ar.top-lr.top;else if(ar.bottom>lr.bottom)list.scrollTop+=ar.bottom-lr.bottom}}}
function setActiveTocLink(id){const toc=document.querySelector(".toc");if(!toc)return;let active=null;toc.querySelectorAll('a[href^="#"]').forEach(link=>{const on=Boolean(id&&tocLinkId(link)===id);link.classList.toggle("active",on);if(on)active=link});syncTocCurrent(toc,active);if(active){const list=active.closest(".toc");if(list&&list.scrollHeight>list.clientHeight){const lr=list.getBoundingClientRect();if(!isCompactToc()&&lr.top>parseFloat(getComputedStyle(list).top)+1)return;const visible=isCompactToc()?lr:tocScrollBounds(list),ar=active.getBoundingClientRect();if(ar.top<visible.top)list.scrollTop+=ar.top-visible.top;else if(ar.bottom>visible.bottom)list.scrollTop+=ar.bottom-visible.bottom}}}
function currentTocHeadingId(headings){const top=parseFloat(getComputedStyle(document.documentElement).scrollPaddingTop)||120;const scroller=document.scrollingElement||document.documentElement;if(scroller.scrollTop+innerHeight>=scroller.scrollHeight-2)return headings.at(-1)?.id||"";let current=headings[0];for(const heading of headings){if(heading.getBoundingClientRect().top<=top+1)current=heading;else break}return current?.id||""}
function initTocScrollspy(){tocObserver?.disconnect();tocObserver=null;if(tocScrollHandler){removeEventListener("scroll",tocScrollHandler);tocScrollHandler=null;}const toc=document.querySelector(".toc");if(!toc)return;const links=[...toc.querySelectorAll('a[href^="#"]')];const headings=[...document.querySelectorAll(".doc h2[id],.doc h3[id]")].filter(heading=>links.some(link=>tocLinkId(link)===heading.id));links.forEach(link=>link.classList.remove("active"));if(!headings.length)return;const sync=()=>{if(Date.now()<tocSpyHoldUntil)return;setActiveTocLink(currentTocHeadingId(headings))};let tocScrollRaf=0;tocScrollHandler=()=>{cancelAnimationFrame(tocScrollRaf);tocScrollRaf=requestAnimationFrame(sync)};addEventListener("scroll",tocScrollHandler,{passive:true});requestAnimationFrame(sync);if(!("IntersectionObserver" in window)){sync();return}tocObserver=new IntersectionObserver(sync,{rootMargin:"-120px 0px -70% 0px",threshold:[0,1]});headings.forEach(heading=>tocObserver.observe(heading))}
function initTocScrollspy(){tocObserver?.disconnect();tocObserver=null;tocSizeObserver?.disconnect();tocSizeObserver=null;if(tocScrollHandler){removeEventListener("scroll",tocScrollHandler);tocScrollHandler=null;}const toc=document.querySelector(".toc");if(!toc)return;if("ResizeObserver" in window){tocSizeObserver=new ResizeObserver(syncTocSpace);tocSizeObserver.observe(toc);const nav=toc.querySelector("nav");if(nav)tocSizeObserver.observe(nav)}const links=[...toc.querySelectorAll('a[href^="#"]')];const headings=[...document.querySelectorAll(".doc h2[id],.doc h3[id]")].filter(heading=>links.some(link=>tocLinkId(link)===heading.id));links.forEach(link=>link.classList.remove("active"));if(!headings.length)return;const sync=()=>{if(Date.now()<tocSpyHoldUntil)return;setActiveTocLink(currentTocHeadingId(headings))};let tocScrollRaf=0;tocScrollHandler=()=>{cancelAnimationFrame(tocScrollRaf);tocScrollRaf=requestAnimationFrame(sync)};addEventListener("scroll",tocScrollHandler,{passive:true});requestAnimationFrame(sync);if(!("IntersectionObserver" in window)){sync();return}tocObserver=new IntersectionObserver(sync,{rootMargin:"-120px 0px -70% 0px",threshold:[0,1]});headings.forEach(heading=>tocObserver.observe(heading))}
async function navigateTo(url,replace=false,animateHome=false){if(navigating)return false;navigating=true;if(!animateHome)homeGlimm.cancel();closeLanguage();closeMermaidOverlay();try{const res=await fetch(url.href,{credentials:"same-origin"});if(!res.ok||!res.headers.get("content-type")?.includes("text/html"))return false;const nextDoc=new DOMParser().parseFromString(await res.text(),"text/html");if(!nextDoc.querySelector(".main"))return false;const commit=()=>{disposeHomeHero();for(const name of ["docs-home","docs-home-layout"])document.body.classList.toggle(name,nextDoc.body.classList.contains(name));syncSidebar(nextDoc);swap(".header-left",nextDoc);swap(".main",nextDoc);initHomeHero();syncStickyHeaderOffset();syncTocDisclosure();initCodeGroups();initCodeFades();initAccordionMotion();initPageFeedback();initMermaid();document.title=nextDoc.title;history[replace?"replaceState":"pushState"]({docs:true},"",url.href);docsAnalytics.pageView();currentDocKey=location.pathname+location.search;setNavOpen(false);initTocScrollspy();scrollTarget(url.hash);syncCommunityInvite()};if(animateHome)await homeGlimm.run(commit);else commit();return true}catch{return false}finally{navigating=false}}
function unavailableSearch(){return {unavailable:true,search:async()=>({results:[]})}}
function loadPagefind(){if(pagefindReady)return pagefindReady;const src=withBase("/pagefind/pagefind.js")+(pagefindLoadAttempt?"?retry="+pagefindLoadAttempt:"");pagefindLoadAttempt+=1;pagefindReady=import(src).then(m=>m.init?.().then?.(()=>m)??m).catch(()=>{pagefindReady=null;return unavailableSearch()});return pagefindReady}
Expand Down Expand Up @@ -331,7 +356,7 @@ document.addEventListener("click",async e=>{const pageActions=e.target.closest("
addEventListener("keydown",e=>{handleMermaidOverlayKeydown(e)},{capture:true});modal?.addEventListener("click",e=>{if(e.target===modal)closeSearch("backdrop")});function isEditableTarget(target){return target instanceof Element&&!!target.closest("input,textarea,select,[contenteditable]")}function isSearchShortcutEvent(e){return (e.metaKey||e.ctrlKey)&&!e.altKey&&!e.shiftKey&&(e.code==="KeyK"||String(e.key).toLowerCase()==="k")}function searchFocusable(){return [...modal?.querySelectorAll("a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex=\\\"-1\\\"])")||[]].filter(el=>el.tabIndex>=0&&!el.hidden&&el.getAttribute("aria-hidden")!=="true"&&el.offsetParent!==null)}function trapSearchFocus(e){if(e.key!=="Tab"||!modal?.classList.contains("open"))return false;const items=searchFocusable();if(!items.length){e.preventDefault();input?.focus();return true}const first=items[0];const last=items[items.length-1];if(!modal.contains(document.activeElement)){e.preventDefault();first.focus();return true}if(e.shiftKey&&document.activeElement===first){e.preventDefault();last.focus();return true}if(!e.shiftKey&&document.activeElement===last){e.preventDefault();first.focus();return true}return false}addEventListener("keydown",e=>{if(trapSearchFocus(e)||trapNavFocus(e)||handleLanguageKeydown(e))return;if(isSearchShortcutEvent(e)){if(!isEditableTarget(e.target)){e.preventDefault();e.stopPropagation();openSearch()}return}if(e.key==="Escape"){closeSearch("escape");document.querySelectorAll(".page-actions-more[open]").forEach(menu=>menu.removeAttribute("open"));document.querySelectorAll(".toc[open]").forEach(menu=>{if(isCompactToc()){const restore=menu.contains(document.activeElement);menu.open=false;if(restore)menu.querySelector("summary")?.focus({preventScroll:true})}});closeLanguage();setNavOpen(false)}},{capture:true});
addEventListener("popstate",()=>{closeMermaidOverlay();const key=location.pathname+location.search;if(key===currentDocKey){docsAnalytics.pageView();scrollTarget(location.hash);return}docsAnalytics.suspend();navigateTo(new URL(location.href),true)});
document.addEventListener("toggle",e=>{const section=e.target;if(section?.matches?.(".nav-section,.nav-nested")){updateSidebarFade();return}if(!section?.matches?.(".docs-section")||section.closest(".docs-sidebar-levels"))return;updateSidebarFade();if(section.open)requestAnimationFrame(()=>{const summary=section.querySelector(":scope>summary");if(section.open&&isUsableFocusTarget(summary))summary.scrollIntoView({behavior:"instant",block:"nearest",inline:"nearest"})})},{capture:true});
document.addEventListener("scroll",e=>{if(e.target?.classList?.contains("sidebar")||e.target?.matches?.(".docs-sidebar-directory,.docs-sidebar-context > .docs-sections"))updateSidebarFade()},{capture:true,passive:true});
document.addEventListener("scroll",e=>{if(e.target?.classList?.contains("sidebar")||e.target?.matches?.(".docs-sidebar-directory,.docs-sidebar-context > .docs-sections"))updateSidebarFade();if(e.target?.matches?.(".toc"))syncTocFade()},{capture:true,passive:true});
let tocScrollRaf=0;function scheduleTocDisclosure(){if(tocScrollRaf)return;tocScrollRaf=requestAnimationFrame(()=>{tocScrollRaf=0;syncTocDisclosure();syncCommunityInvite()})}addEventListener("scroll",scheduleTocDisclosure,{passive:true});addEventListener("scrollend",scheduleTocDisclosure,{passive:true});
// Keep desktop navigation focus clear of fixed corner controls after responsive layout changes.
let layoutResizeRaf=0;addEventListener("resize",()=>{syncStickyHeaderOffset();syncTocDisclosure();cancelAnimationFrame(layoutResizeRaf);layoutResizeRaf=requestAnimationFrame(()=>{updateSidebarFade();syncCommunityInvite();const focused=document.activeElement;if(focused?.matches("[data-locale-option]")&&focused.closest(".language-picker.open"))focusLanguageOption(focused);if(focused?.closest(".sidebar")&&isUsableFocusTarget(focused))focused.scrollIntoView({behavior:"instant",block:mobileNavQuery.matches?"nearest":"center",inline:"nearest"})})});
Expand Down
Loading
Loading