From dc957fc8e609962284e76c835fb78b212830f49d Mon Sep 17 00:00:00 2001 From: Sqaaakoi Date: Mon, 20 Jan 2025 03:29:06 +1300 Subject: [PATCH] Styles: Migrate away from storing DOM nodes, prepare for popout support --- scripts/build/common.mjs | 4 +-- scripts/build/module/style.js | 3 +-- src/api/Styles.ts | 48 ++++++++++++++++++++++------------- src/globals.d.ts | 4 +-- 4 files changed, 35 insertions(+), 24 deletions(-) diff --git a/scripts/build/common.mjs b/scripts/build/common.mjs index e88f1e2b9..76f293a0d 100644 --- a/scripts/build/common.mjs +++ b/scripts/build/common.mjs @@ -276,7 +276,7 @@ export const stylePlugin = { name: "style-plugin", setup: ({ onResolve, onLoad }) => { onResolve({ filter: /\.css\?managed$/, namespace: "file" }, ({ path, resolveDir }) => ({ - path: relative(process.cwd(), join(resolveDir, path.replace("?managed", ""))), + path: relative(process.cwd(), join(resolveDir, path.replace(/\?managed$/, ""))), namespace: "managed-style", })); onLoad({ filter: /\.css$/, namespace: "managed-style" }, async ({ path }) => { @@ -287,7 +287,7 @@ export const stylePlugin = { loader: "js", contents: styleModule .replaceAll("STYLE_SOURCE", JSON.stringify(css)) - .replaceAll("STYLE_NAME", JSON.stringify(name)) + .replaceAll("STYLE_NAME", JSON.stringify("managed-style:" + name)) }; }); } diff --git a/scripts/build/module/style.js b/scripts/build/module/style.js index 5981a3de2..4715d3b46 100644 --- a/scripts/build/module/style.js +++ b/scripts/build/module/style.js @@ -19,8 +19,7 @@ (window.VencordStyles ??= new Map()).set(STYLE_NAME, { name: STYLE_NAME, source: STYLE_SOURCE, - classNames: {}, - dom: null, + enabled: false }); export default STYLE_NAME; diff --git a/src/api/Styles.ts b/src/api/Styles.ts index 6b0ac2cdf..d9bdc9aa4 100644 --- a/src/api/Styles.ts +++ b/src/api/Styles.ts @@ -28,6 +28,11 @@ export function requireStyle(name: string) { return style; } +// TODO: Implement popouts +function findDocuments() { + return [document]; +} + /** * A style's name can be obtained from importing a stylesheet with `?managed` at the end of the import * @param name The name of the style @@ -41,16 +46,11 @@ export function requireStyle(name: string) { export function enableStyle(name: string) { const style = requireStyle(name); - if (style.dom?.isConnected) + if (style.enabled) return false; - if (!style.dom) { - style.dom = document.createElement("style"); - style.dom.dataset.vencordName = style.name; - } + style.enabled = true; compileStyle(style); - - document.head.appendChild(style.dom); return true; } @@ -61,11 +61,14 @@ export function enableStyle(name: string) { */ export function disableStyle(name: string) { const style = requireStyle(name); - if (!style.dom?.isConnected) + if (!style.enabled) return false; - style.dom.remove(); - style.dom = null; + findDocuments().forEach(doc => { + [...doc.head.querySelectorAll("style[data-vencord-name]")].find(e => e.dataset.vencordName === style.name)?.remove(); + }); + + style.enabled = false; return true; } @@ -81,7 +84,7 @@ export const toggleStyle = (name: string) => isStyleEnabled(name) ? disableStyle * @returns Whether the style is enabled * @see {@link enableStyle} for info on getting the name of an imported style */ -export const isStyleEnabled = (name: string) => requireStyle(name).dom?.isConnected ?? false; +export const isStyleEnabled = (name: string) => requireStyle(name).enabled ?? false; /** * Sets the variables of a style @@ -111,7 +114,13 @@ export const isStyleEnabled = (name: string) => requireStyle(name).dom?.isConnec */ export const setStyleClassNames = (name: string, classNames: Record, recompile = true) => { const style = requireStyle(name); - style.classNames = classNames; + style.edit = source => { + return source + .replace(/\[--(\w+)\]/g, (match, name) => { + const className = classNames[name]; + return className ? classNameToSelector(className) : match; + }); + }; if (recompile && isStyleEnabled(style.name)) compileStyle(style); }; @@ -123,13 +132,16 @@ export const setStyleClassNames = (name: string, classNames: Record { - if (!style.dom) throw new Error("Style has no DOM element"); + findDocuments().forEach(doc => { + let styleElement = [...doc.head.querySelectorAll("style[data-vencord-name]")].find(e => e.dataset.vencordName === style.name); + if (!styleElement) { + styleElement = doc.createElement("style"); + styleElement.dataset.vencordName = style.name; + document.head.appendChild(styleElement); + } + styleElement.textContent = style.edit ? style.edit(style.source) : style.source; + }); - style.dom.textContent = style.source - .replace(/\[--(\w+)\]/g, (match, name) => { - const className = style.classNames[name]; - return className ? classNameToSelector(className) : match; - }); }; /** diff --git a/src/globals.d.ts b/src/globals.d.ts index e20ca4b71..1d6541f05 100644 --- a/src/globals.d.ts +++ b/src/globals.d.ts @@ -48,8 +48,8 @@ declare global { export var VencordStyles: Map; - dom: HTMLStyleElement | null; + enabled: boolean; + edit?(source: string): string; }>; export var appSettings: { set(setting: string, v: any): void;