UNPKG

wxt

Version:

⚡ Next-gen Web Extension Framework

88 lines (87 loc) 2.64 kB
import { browser } from "wxt/browser"; import { createIsolatedElement } from "@webext-core/isolated-element"; import { applyPosition, createMountFunctions, mountUi } from "./shared.mjs"; import { logger } from "../internal/logger.mjs"; import { splitShadowRootCss } from "../split-shadow-root-css.mjs"; export 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, shadow.querySelector("html"), 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(); const documentStyle = document.querySelector( `style[wxt-shadow-root-document-styles="${instanceId}"]` ); documentStyle?.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; } }; } async function loadCss() { const url = browser.runtime.getURL(`/content-scripts/${import.meta.env.ENTRYPOINT}.css`); try { const res = await fetch(url); return await res.text(); } catch (err) { logger.warn( `Failed to load styles @ ${url}. Did you forget to import the stylesheet in your entrypoint?`, err ); return ""; } }