Styles: Migrate away from storing DOM nodes, prepare for popout support

This commit is contained in:
Sqaaakoi 2025-01-20 03:29:06 +13:00
parent a60af65b6d
commit dc957fc8e6
No known key found for this signature in database
4 changed files with 35 additions and 24 deletions

View file

@ -276,7 +276,7 @@ export const stylePlugin = {
name: "style-plugin", name: "style-plugin",
setup: ({ onResolve, onLoad }) => { setup: ({ onResolve, onLoad }) => {
onResolve({ filter: /\.css\?managed$/, namespace: "file" }, ({ path, resolveDir }) => ({ 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", namespace: "managed-style",
})); }));
onLoad({ filter: /\.css$/, namespace: "managed-style" }, async ({ path }) => { onLoad({ filter: /\.css$/, namespace: "managed-style" }, async ({ path }) => {
@ -287,7 +287,7 @@ export const stylePlugin = {
loader: "js", loader: "js",
contents: styleModule contents: styleModule
.replaceAll("STYLE_SOURCE", JSON.stringify(css)) .replaceAll("STYLE_SOURCE", JSON.stringify(css))
.replaceAll("STYLE_NAME", JSON.stringify(name)) .replaceAll("STYLE_NAME", JSON.stringify("managed-style:" + name))
}; };
}); });
} }

View file

@ -19,8 +19,7 @@
(window.VencordStyles ??= new Map()).set(STYLE_NAME, { (window.VencordStyles ??= new Map()).set(STYLE_NAME, {
name: STYLE_NAME, name: STYLE_NAME,
source: STYLE_SOURCE, source: STYLE_SOURCE,
classNames: {}, enabled: false
dom: null,
}); });
export default STYLE_NAME; export default STYLE_NAME;

View file

@ -28,6 +28,11 @@ export function requireStyle(name: string) {
return style; 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 * 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 * @param name The name of the style
@ -41,16 +46,11 @@ export function requireStyle(name: string) {
export function enableStyle(name: string) { export function enableStyle(name: string) {
const style = requireStyle(name); const style = requireStyle(name);
if (style.dom?.isConnected) if (style.enabled)
return false; return false;
if (!style.dom) { style.enabled = true;
style.dom = document.createElement("style");
style.dom.dataset.vencordName = style.name;
}
compileStyle(style); compileStyle(style);
document.head.appendChild(style.dom);
return true; return true;
} }
@ -61,11 +61,14 @@ export function enableStyle(name: string) {
*/ */
export function disableStyle(name: string) { export function disableStyle(name: string) {
const style = requireStyle(name); const style = requireStyle(name);
if (!style.dom?.isConnected) if (!style.enabled)
return false; return false;
style.dom.remove(); findDocuments().forEach(doc => {
style.dom = null; [...doc.head.querySelectorAll<HTMLStyleElement>("style[data-vencord-name]")].find(e => e.dataset.vencordName === style.name)?.remove();
});
style.enabled = false;
return true; return true;
} }
@ -81,7 +84,7 @@ export const toggleStyle = (name: string) => isStyleEnabled(name) ? disableStyle
* @returns Whether the style is enabled * @returns Whether the style is enabled
* @see {@link enableStyle} for info on getting the name of an imported style * @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 * 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<string, string>, recompile = true) => { export const setStyleClassNames = (name: string, classNames: Record<string, string>, recompile = true) => {
const style = requireStyle(name); 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)) if (recompile && isStyleEnabled(style.name))
compileStyle(style); compileStyle(style);
}; };
@ -123,13 +132,16 @@ export const setStyleClassNames = (name: string, classNames: Record<string, stri
* @see {@link setStyleClassNames} for more info on style classnames * @see {@link setStyleClassNames} for more info on style classnames
*/ */
export const compileStyle = (style: Style) => { export const compileStyle = (style: Style) => {
if (!style.dom) throw new Error("Style has no DOM element"); findDocuments().forEach(doc => {
let styleElement = [...doc.head.querySelectorAll<HTMLStyleElement>("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;
});
}; };
/** /**

4
src/globals.d.ts vendored
View file

@ -48,8 +48,8 @@ declare global {
export var VencordStyles: Map<string, { export var VencordStyles: Map<string, {
name: string; name: string;
source: string; source: string;
classNames: Record<string, string>; enabled: boolean;
dom: HTMLStyleElement | null; edit?(source: string): string;
}>; }>;
export var appSettings: { export var appSettings: {
set(setting: string, v: any): void; set(setting: string, v: any): void;