wxt
Version:
⚡ Next-gen Web Extension Framework
88 lines (87 loc) • 2.64 kB
JavaScript
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 "";
}
}