import { createAccentVariables, type RgbTuple } from "./accent.js"; export type NodedcTheme = "dark" | "light"; export interface NodedcMaterial { /** Base fill used by glass panels, application windows and modals. */ panel?: RgbTuple; /** 0–1 alpha for the base glass panel. */ panelOpacity?: number; /** Base fill used by text, range and selection fields. */ field?: RgbTuple; /** 0–1 alpha for field fill. */ fieldOpacity?: number; } export interface ApplyThemeOptions { theme?: NodedcTheme; accent?: RgbTuple; material?: NodedcMaterial; } function formatRgb([red, green, blue]: RgbTuple): string { return `${red} ${green} ${blue}`; } function clampOpacity(value: number): number { return Math.max(0, Math.min(1, value)); } export function applyNodedcTheme( target: HTMLElement, { theme = "dark", accent, material }: ApplyThemeOptions = {}, ): void { target.dataset.nodedcTheme = theme; target.dataset.nodedcUi = "true"; if (accent) { const variables = createAccentVariables(accent); Object.entries(variables).forEach(([property, value]) => { target.style.setProperty(property, value); }); } if (!material) return; if (material.panel) target.style.setProperty("--nodedc-panel-material-rgb", formatRgb(material.panel)); if (typeof material.panelOpacity === "number" && Number.isFinite(material.panelOpacity)) { const opacity = clampOpacity(material.panelOpacity); target.style.setProperty("--nodedc-panel-material-opacity", String(opacity)); target.style.setProperty("--nodedc-panel-material-strong-opacity", String(clampOpacity(opacity + 0.12))); target.style.setProperty("--nodedc-panel-material-soft-opacity", String(clampOpacity(Math.max(0.12, opacity - 0.2)))); } if (material.field) target.style.setProperty("--nodedc-field-material-rgb", formatRgb(material.field)); if (typeof material.fieldOpacity === "number" && Number.isFinite(material.fieldOpacity)) { target.style.setProperty("--nodedc-field-material-opacity", String(clampOpacity(material.fieldOpacity))); } } export function clearNodedcAccent(target: HTMLElement): void { target.style.removeProperty("--nodedc-accent-rgb"); target.style.removeProperty("--nodedc-on-accent-rgb"); } export function clearNodedcMaterial(target: HTMLElement): void { [ "--nodedc-panel-material-rgb", "--nodedc-panel-material-opacity", "--nodedc-panel-material-strong-opacity", "--nodedc-panel-material-soft-opacity", "--nodedc-field-material-rgb", "--nodedc-field-material-opacity", ].forEach((property) => target.style.removeProperty(property)); }