UNPKG

next

Version:

The React Framework

124 lines (123 loc) 4.39 kB
/* @ts-check */ /** * Style injection mechanism for Next.js devtools with shadow DOM support * Handles caching of style elements when the nextjs-portal shadow root is not available */ // Global cache for style elements when shadow root is not available "use strict"; if (typeof window !== 'undefined') { window._nextjsDevtoolsStyleCache = window._nextjsDevtoolsStyleCache || { pendingElements: [], isObserving: false, lastInsertedElement: null, cachedShadowRoot: null }; } /** * @returns {ShadowRoot | null} */ function getShadowRoot() { const cache = window._nextjsDevtoolsStyleCache; // Return cached shadow root if available if (cache.cachedShadowRoot) { return cache.cachedShadowRoot; } // Query the DOM and cache the result if found const portal = document.querySelector('nextjs-portal'); const shadowRoot = (portal == null ? void 0 : portal.shadowRoot) || null; if (shadowRoot) { cache.cachedShadowRoot = shadowRoot; } return shadowRoot; } /** * @param {HTMLElement} element * @param {ShadowRoot} shadowRoot */ function insertElementIntoShadowRoot(element, shadowRoot) { const cache = window._nextjsDevtoolsStyleCache; if (!cache.lastInsertedElement) { shadowRoot.insertBefore(element, shadowRoot.firstChild); } else if (cache.lastInsertedElement.nextSibling) { shadowRoot.insertBefore(element, cache.lastInsertedElement.nextSibling); } else { shadowRoot.appendChild(element); } cache.lastInsertedElement = element; } function flushCachedElements() { const cache = window._nextjsDevtoolsStyleCache; const shadowRoot = getShadowRoot(); if (!shadowRoot) { return; } cache.pendingElements.forEach((element)=>{ insertElementIntoShadowRoot(element, shadowRoot); }); cache.pendingElements = []; } function startObservingForPortal() { const cache = window._nextjsDevtoolsStyleCache; if (cache.isObserving) { return; } cache.isObserving = true; // First check if the portal already exists const shadowRoot = getShadowRoot() // This will cache it if found ; if (shadowRoot) { flushCachedElements(); return; } // Set up MutationObserver to watch for the portal element const observer = new MutationObserver((mutations)=>{ if (mutations.length === 0 || mutations[0].addedNodes.length === 0) { return; } // Check if mutation is script[data-nextjs-dev-overlay] tag, which is the // parent of the nextjs-portal element const mutationNode = mutations[0].addedNodes[0]; let portalNode = null; if (// app router: body > script[data-nextjs-dev-overlay] > nextjs-portal mutationNode.tagName === 'SCRIPT' && mutationNode.getAttribute('data-nextjs-dev-overlay')) { portalNode = mutationNode.firstChild; } else if (// pages router: body > nextjs-portal mutationNode.tagName === 'NEXTJS-PORTAL') { portalNode = mutationNode; } if (!portalNode) { return; } // Wait until shadow root is available const checkShadowRoot = ()=>{ if (getShadowRoot()) { flushCachedElements(); observer.disconnect(); cache.isObserving = false; } else { // Try again after a short delay setTimeout(checkShadowRoot, 20); } }; checkShadowRoot(); }); observer.observe(document.body, { childList: true, subtree: true }); } /** * @param {HTMLElement} element */ function insertAtTop(element) { // Add special recognizable data prop to element element.setAttribute('data-nextjs-dev-tool-style', 'true'); const shadowRoot = getShadowRoot(); if (shadowRoot) { // Shadow root is available, insert directly insertElementIntoShadowRoot(element, shadowRoot); } else { // Shadow root not available, cache the element const cache = window._nextjsDevtoolsStyleCache; cache.pendingElements.push(element); // Start observing for the portal if not already observing startObservingForPortal(); } } module.exports = insertAtTop; //# sourceMappingURL=devtool-style-inject.js.map