mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-12 05:48:57 +00:00
Skip redundant root mutations during initial load
This commit is contained in:
@@ -62,8 +62,23 @@ export const useIsAIChatMaxWidth = () =>
|
||||
|
||||
// Hoisted so the synchronous persist rehydrate (during create() above) can call them before this point.
|
||||
function setWidthOnViewport(width: number) {
|
||||
if (typeof document !== 'undefined') {
|
||||
document.documentElement.style.setProperty('--ai-chat-width', `${capToViewport(width)}px`);
|
||||
if (typeof document === 'undefined') {
|
||||
return;
|
||||
}
|
||||
// Any change to the <html> style attribute re-styles the whole document, so only write when
|
||||
// the value differs from what is already in effect (the stylesheet default is the min width).
|
||||
const style = document.documentElement.style;
|
||||
const current = style.getPropertyValue('--ai-chat-width');
|
||||
const capped = capToViewport(width);
|
||||
if (capped === AI_CHAT_MIN_WIDTH) {
|
||||
if (current) {
|
||||
style.removeProperty('--ai-chat-width');
|
||||
}
|
||||
return;
|
||||
}
|
||||
const value = `${capped}px`;
|
||||
if (current !== value) {
|
||||
style.setProperty('--ai-chat-width', value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,22 +24,33 @@ export function PreservePageLayout(props: { wideLayout: boolean; pageHasToc: boo
|
||||
return;
|
||||
}
|
||||
|
||||
if (wideLayout) {
|
||||
header.classList.add('layout-wide');
|
||||
header.classList.remove('layout-default');
|
||||
} else {
|
||||
header.classList.remove('layout-wide');
|
||||
header.classList.add('layout-default');
|
||||
}
|
||||
|
||||
if (pageHasToc) {
|
||||
header.classList.add('page-has-toc');
|
||||
header.classList.remove('page-no-toc');
|
||||
} else {
|
||||
header.classList.add('page-no-toc');
|
||||
header.classList.remove('page-has-toc');
|
||||
}
|
||||
// The header is a `body:has()` subject, so touching its classes re-styles the whole
|
||||
// document. Only correct it when a previous page left it disagreeing with this one, and
|
||||
// stamp this page's layout on it as the page leaves, which is when the next one needs it.
|
||||
syncLayoutClasses(header, { wideLayout, pageHasToc }, false);
|
||||
return () => {
|
||||
syncLayoutClasses(header, { wideLayout, pageHasToc }, true);
|
||||
};
|
||||
}, [wideLayout, pageHasToc]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function syncLayoutClasses(
|
||||
header: Element,
|
||||
layout: { wideLayout: boolean; pageHasToc: boolean },
|
||||
force: boolean
|
||||
) {
|
||||
const pairs: [wanted: string, other: string][] = [
|
||||
layout.wideLayout ? ['layout-wide', 'layout-default'] : ['layout-default', 'layout-wide'],
|
||||
layout.pageHasToc ? ['page-has-toc', 'page-no-toc'] : ['page-no-toc', 'page-has-toc'],
|
||||
];
|
||||
for (const [wanted, other] of pairs) {
|
||||
if (header.classList.contains(other)) {
|
||||
header.classList.remove(other);
|
||||
header.classList.add(wanted);
|
||||
} else if (force && !header.classList.contains(wanted)) {
|
||||
header.classList.add(wanted);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,12 @@ import { useEffect } from 'react';
|
||||
export function TableOfContentsScript() {
|
||||
useEffect(() => {
|
||||
const root = document.documentElement;
|
||||
// Writing the <html> style attribute re-styles the whole document, so skip unchanged values.
|
||||
const setVar = (name: string, value: string) => {
|
||||
if (root.style.getPropertyValue(name) !== value) {
|
||||
root.style.setProperty(name, value);
|
||||
}
|
||||
};
|
||||
|
||||
// Calculate and set TOC dimensions
|
||||
const updateTocLayout = () => {
|
||||
@@ -42,8 +48,8 @@ export function TableOfContentsScript() {
|
||||
}
|
||||
|
||||
// Update height
|
||||
root.style.setProperty('--toc-height', `${Math.max(height, 0)}px`);
|
||||
root.style.setProperty('--toc-top-offset', `${Math.max(offset, 0)}px`);
|
||||
setVar('--toc-height', `${Math.max(height, 0)}px`);
|
||||
setVar('--toc-top-offset', `${Math.max(offset, 0)}px`);
|
||||
|
||||
// Subtract visible pageCover (if any)
|
||||
if (
|
||||
@@ -64,8 +70,8 @@ export function TableOfContentsScript() {
|
||||
}
|
||||
}
|
||||
|
||||
root.style.setProperty('--outline-height', `${Math.max(height, 0)}px`);
|
||||
root.style.setProperty('--outline-top-offset', `${Math.max(offset, 0)}px`);
|
||||
setVar('--outline-height', `${Math.max(height, 0)}px`);
|
||||
setVar('--outline-top-offset', `${Math.max(offset, 0)}px`);
|
||||
};
|
||||
|
||||
// Initial update
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import { useEffect, useLayoutEffect } from 'react';
|
||||
import { useEffect, useLayoutEffect, useRef } from 'react';
|
||||
|
||||
import { useIsNavigating } from '../hooks';
|
||||
import { tcls } from '@/lib/tailwind';
|
||||
@@ -15,8 +15,14 @@ export const NavigationLoader = () => {
|
||||
}, []);
|
||||
|
||||
// On route changes, add a transient class for the first paint of the new page.
|
||||
// Skipped on the initial mount: toggling a class on <html> re-styles the whole document.
|
||||
const isInitialMount = useRef(true);
|
||||
useLayoutEffect(() => {
|
||||
void pathname;
|
||||
if (isInitialMount.current) {
|
||||
isInitialMount.current = false;
|
||||
return;
|
||||
}
|
||||
const root = document.documentElement;
|
||||
root.classList.add('route-change');
|
||||
let raf2 = 0;
|
||||
|
||||
Reference in New Issue
Block a user