From fc05c581b1b1ece6cd0b87852b0b5661738ea36c Mon Sep 17 00:00:00 2001 From: Chris Zuber Date: Fri, 10 Apr 2026 14:46:01 -0700 Subject: [PATCH] Refactor theming (light/dark modes) ### Changed - Components now inherit `color-scheme` from the document or nearest `[data-theme]` ancestor, replacing the deprecated `:host-context()` CSS pseudo-class. ### Deprecated - `componentDarkTheme`, `componentLightTheme`, `darkTheme`, `lightTheme`. These exports remain as disabled `CSSStyleSheet` stubs for backwards compatibility and will be removed in a future major release. --- CHANGELOG.md | 10 ++++ createSheets.js | 6 +-- package-lock.json | 4 +- package.json | 2 +- test/index.js | 4 +- theme.js | 123 +++++++++++++++------------------------------- 6 files changed, 58 insertions(+), 91 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c12ce9..3c2deba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [v0.3.2] - 2026-04-10 + +### Changed +- Components now inherit `color-scheme` from the document or nearest `[data-theme]` ancestor, + replacing the deprecated `:host-context()` CSS pseudo-class. + +### Deprecated +- `componentDarkTheme`, `componentLightTheme`, `darkTheme`, `lightTheme`. These exports remain + as disabled `CSSStyleSheet` stubs for backwards compatibility and will be removed in a future major release. + ## [v0.3.1] - 2026-04-10 ### Added diff --git a/createSheets.js b/createSheets.js index d2d7061..c0b6259 100644 --- a/createSheets.js +++ b/createSheets.js @@ -34,9 +34,9 @@ class CSSStyleSheet { if (this.disabled) { return ''; } else if (typeof this.#media === 'string') { - return `@media (${this.#media}) {${this.#text}}`; + return `@media ${this.#media} {${this.#text.trim()}}`; } else { - return this.#text; + return this.#text.trim(); } } @@ -80,7 +80,7 @@ globalThis.MediaQueryList = class MediaQueryList extends EventTarget { async function saveSheet(path) { const module = await import(path); - const sheets = Object.values(module).filter(exp => exp instanceof CSSStyleSheet); + const sheets = Object.values(module).filter(exp => exp instanceof CSSStyleSheet && ! exp.disabled); if (sheets.length !== 0) { await writeFile(path.replace('./', './css/').replace('.js', '.css'), sheets.join('\n\n')); diff --git a/package-lock.json b/package-lock.json index 50a8141..7484ff1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@aegisjsproject/styles", - "version": "0.3.1", + "version": "0.3.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@aegisjsproject/styles", - "version": "0.3.1", + "version": "0.3.2", "funding": [ { "type": "librepay", diff --git a/package.json b/package.json index 47006ba..713e513 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@aegisjsproject/styles", - "version": "0.3.1", + "version": "0.3.2", "description": "Pre-made and reusable styles for `@aegisjsproject/core`", "keywords": [ "aegis", diff --git a/test/index.js b/test/index.js index 9b67771..628facd 100644 --- a/test/index.js +++ b/test/index.js @@ -1,5 +1,5 @@ import { css } from '@aegisjsproject/parsers/css.js'; -import { componentBase, componentDarkTheme, componentLightTheme, componentBorder } from '../theme.js'; +import { componentBase, componentBorder } from '../theme.js'; import { presentation } from '../presentation.js'; import props from '../css/properties.css' with { type: 'css' }; import theme from '../css/theme.css' with { type: 'css' }; @@ -59,7 +59,7 @@ customElements.define('test-el', class TestElement extends HTMLElement { slot.name = 'content'; slot.textContent = 'Hello, World!'; this.#shadow.adoptedStyleSheets = [ - componentBase, componentBorder, componentDarkTheme, componentLightTheme, btn, reset, + componentBase, componentBorder, btn, reset, css`:host { padding: 0.7em 0.3em; width: max-content; diff --git a/theme.js b/theme.js index 97c4895..abd483e 100644 --- a/theme.js +++ b/theme.js @@ -1,49 +1,32 @@ import { light, dark, gray } from './palette/bootstrap.js'; -import { css, createCSSParser } from '@aegisjsproject/parsers/css.js'; - -const darkCSS = createCSSParser({ media: '(prefers-color-scheme: dark)' }); -const lightCSS = createCSSParser({ media: '(prefers-color-scheme: light)' }); +import { css } from '@aegisjsproject/parsers/css.js'; export const baseTheme = css`@layer base.aegisjsproject.theme { :root { color-scheme: light dark; - color: var(--aegis-color-light, ${dark}); - background-color: var(--aegis-bg-light, ${light}); font-family: var(--aegis-font, system-ui); } - :root[data-theme="light"] { - color-scheme: light; - color: var(--aegis-color-light, ${dark}); - background-color: var(--aegis-bg-light, ${light}); + [data-theme="light"] { + color-scheme: only light; } - :root[data-theme="dark"] { - color-scheme: dark; - color: var(--aegis-color-dark, ${light}); - background-color: var(--aegis-bg-dark, ${dark}); + [data-theme="dark"] { + color-scheme: only dark; } -}`; -export const darkTheme = darkCSS`@layer base.aegisjsproject.theme { - :root:not([data-theme="light"]) { - color: var(--aegis-color-dark, ${light}); - background-color: var(--aegis-bg-dark, ${dark}); - } -}`; - -export const lightTheme = lightCSS`@layer base.aegisjsproject.theme { - :root:not([data-theme="dark"]) { - color: var(--aegis-color-light, ${dark}); - background-color: var(--aegis-bg-light, ${light}); + :root, [data-theme] { + color: light-dark(var(--aegis-color-light, ${dark}), var(--aegis-color-dark, ${light})); + background-color: light-dark(var(--aegis-bg-light, ${light}), var(--aegis-bg-dark, ${dark})); } }`; export const componentBase = css`@layer components.aegisjsproject.theme { :host { - color-scheme: light dark; color: var(--aegis-color-light, ${light}); + color: light-dark(var(--aegis-color-light, ${dark}), var(--aegis-color-dark, ${light})); background-color: var(--aegis-bg-light, ${dark}); + background-color: light-dark(var(--aegis-bg-light, ${light}), var(--aegis-bg-dark, ${dark})); font-family: system-ui; } @@ -51,28 +34,12 @@ export const componentBase = css`@layer components.aegisjsproject.theme { display: block; } - :host-context([data-theme="light"]):host(:not([theme="dark"])) { - color-scheme: light; - color: var(--aegis-color-light, ${dark}); - background-color: var(--aegis-bg-light, ${light}); - } - - :host-context([data-theme="dark"]):host(:not([theme="light"])) { - color-scheme: dark; - color: var(--aegis-color-dark, ${light}); - background-color: var(--aegis-bg-dark, ${dark}); - } - :host([theme="light"]) { - color-scheme: light; - color: var(--aegis-color-light, ${dark}); - background-color: var(--aegis-bg-light, ${light}); + color-scheme: only light; } :host([theme="dark"]) { - color-scheme: dark; - color: var(--aegis-color-dark, ${light}); - background-color: var(--aegis-bg-dark, ${dark}); + color-scheme: only dark; } }`; @@ -80,45 +47,35 @@ export const componentBorder = css`@layer components.aegisjsproject.theme { :host { border-width: 1px; border-style: solid; - border-color: var(--aegis-border-color-light, ${gray[2]}); + border-color: light-dark(var(--aegis-border-color-light, ${gray[2]}), var(--aegis-border-color-dark, ${gray[6]})); border-radius: var(--aegis-border-radius, 8px); } - - :host([theme="light"]) { - border-color: var(--aegis-border-color-light, ${gray[2]}); - } - - :host([theme="dark"]) { - border-color: var(--aegis-border-color-dark, ${gray[6]}); - } - - :host-context([data-theme="light"]):host(:not([theme="dark"])) { - border-color: var(--aegis-border-color-light, ${gray[2]}); - } - - :host-context([data-theme="dark"]):host(:not([theme="light"])) { - border-color: var(--aegis-border-color-dark, ${gray[6]}); - } - - @media (prefers-color-scheme: dark) { - :host(:not([theme="light"])) { - border-color: var(--aegis-border-color-dark, ${gray[6]}); - } - } -}`; - -export const componentDarkTheme = darkCSS`@layer base.aegisjsproject.theme { - :host(:not([theme="light"])) { - color-scheme: dark; - color: var(--aegis-color-dark, ${light}); - background-color: var(--aegis-bg-dark, ${dark}); - } }`; -export const componentLightTheme = lightCSS`@layer base.aegisjsproject.theme { - :host(:not([theme="dark"])) { - color-scheme: light; - color: var(--aegis-color-light, ${dark}); - background-color: var(--aegis-bg-light, ${light}); - } -}`; +/** + * @deprecated + * + * Preserving sheets just to avoid breaking on import. Now using `color-scheme` & `light-dark()` only. + */ +export const componentDarkTheme = new CSSStyleSheet({ disabled: true }); + +/** + * @deprecated + * + * Preserving sheets just to avoid breaking on import. Now using `color-scheme` & `light-dark()` only. + */ +export const componentLightTheme = new CSSStyleSheet({ disabled: true }); + +/** + * @deprecated + * + * Preserving sheets just to avoid breaking on import. Now using `color-scheme` & `light-dark()` only. + */ +export const darkTheme = new CSSStyleSheet({ disabled: true }); + +/** + * @deprecated + * + * Preserving sheets just to avoid breaking on import. Now using `color-scheme` & `light-dark()` only. + */ +export const lightTheme = new CSSStyleSheet({ disabled: true });