UNPKG

wxt

Version:

⚡ Next-gen Web Extension Framework

78 lines (77 loc) 2.83 kB
import { logger } from "../internal/logger.mjs"; import { applyPosition, createMountFunctions, mountUi } from "./shared.mjs"; import { splitShadowRootCss } from "../split-shadow-root-css.mjs"; import { browser } from "wxt/browser"; import { createIsolatedElement } from "@webext-core/isolated-element"; //#region src/utils/content-script-ui/shadow-root.ts /** @module wxt/utils/content-script-ui/shadow-root */ /** * Create a content script UI inside a * [`ShadowRoot`](https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot). * * > This function is async because it has to load the CSS via a network call. * * @see https://wxt.dev/guide/essentials/content-scripts.html#shadow-root */ async function createShadowRootUi(ctx, options) { const instanceId = Math.random().toString(36).substring(2, 15); const css = []; if (!options.inheritStyles) css.push(`/* WXT Shadow Root Reset */ :host{all:initial !important;}`); if (options.css) css.push(options.css); if (ctx.options?.cssInjectionMode === "ui") { const entryCss = await loadCss(); css.push(entryCss.replaceAll(":root", ":host")); } const { shadowCss, documentCss } = splitShadowRootCss(css.join("\n").trim()); const { isolatedElement: uiContainer, parentElement: shadowHost, shadow } = await createIsolatedElement({ name: options.name, css: { textContent: shadowCss }, mode: options.mode ?? "open", isolateEvents: options.isolateEvents }); let mounted; const mount = () => { mountUi(shadowHost, options); applyPosition(shadowHost, uiContainer, options); if (documentCss && !document.querySelector(`style[wxt-shadow-root-document-styles="${instanceId}"]`)) { const style = document.createElement("style"); style.textContent = documentCss; style.setAttribute("wxt-shadow-root-document-styles", instanceId); (document.head ?? document.body).append(style); } mounted = options.onMount(uiContainer, shadow, shadowHost); }; const remove = () => { options.onRemove?.(mounted); shadowHost.remove(); document.querySelector(`style[wxt-shadow-root-document-styles="${instanceId}"]`)?.remove(); while (uiContainer.lastChild) uiContainer.removeChild(uiContainer.lastChild); mounted = void 0; }; const mountFunctions = createMountFunctions({ mount, remove }, options); ctx.onInvalidated(remove); return { shadow, shadowHost, uiContainer, ...mountFunctions, get mounted() { return mounted; } }; } /** Load the CSS for the current entrypoint. */ async function loadCss() { const url = browser.runtime.getURL(`/content-scripts/${import.meta.env.ENTRYPOINT}.css`); try { return await (await fetch(url)).text(); } catch (err) { logger.warn(`Failed to load styles @ ${url}. Did you forget to import the stylesheet in your entrypoint?`, err); return ""; } } //#endregion export { createShadowRootUi };