diff --git a/rollup.config.js b/rollup.config.js index ed8f3a1e9..7227ebad4 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -56,11 +56,7 @@ export default { include: 'src/components/**/*.svelte', preprocess: sveltePreprocess({ postcss: { - plugins: [ - themePlugin({ - wrapSelector: (selector) => `:global(:host-context(${selector}))` - }) - ] + plugins: [themePlugin()] } }), // Don't emit CSS - it doesn't work properly with Web Components. diff --git a/src/postcss/theme.js b/src/postcss/theme.js index 18065c5ba..0ee0181ab 100644 --- a/src/postcss/theme.js +++ b/src/postcss/theme.js @@ -1,11 +1,9 @@ const { Declaration, AtRule, Rule } = require('postcss') const supportedThemes = ['dark', 'light'] -const getPropertyName = (selector, decl) => { +const getPropertyName = (selector, prop) => { const regex = /([^A-Za-z0-9\-_])/g - return `--${selector}_${decl.prop}` - .replace(/\s+/g, '_') - .replace(regex, '\\$1') + return `--${selector}_${prop}`.replace(/\s+/g, '_').replace(regex, '\\$1') } const splitRule = (rule, selectorToExtract) => { @@ -27,20 +25,14 @@ const splitRule = (rule, selectorToExtract) => { rule.selector = selectorToExtract } -// Note: It's important that these selectors have a better than (0, 1, 0) -// specificity, or they'll be overridden by the dark mode media query. const defaultOptions = { - darkSelector: '[data-theme][data-theme=dark]', - lightSelector: '[data-theme][data-theme=light]', - wrapSelector: (selector) => selector + themeProperty: '--leo-theme' } /** * @param {{ - * darkSelector: string, - * lightSelector: string, - * wrapSelector?: (selector: string) => string, - * }} options The options for configuring the selectors for darkmode. + * themeProperty?: string, + * }} options The options for configuring container style queries for theming. */ module.exports = (options) => { options = { ...defaultOptions, ...options } @@ -96,7 +88,7 @@ module.exports = (options) => { }) } - const extractDarkProperties = (selector, lightAndDark) => { + const extractThemedProperties = (selector, lightAndDark) => { const variants = ['base', 'dark', 'light'] // At least one variant should have a value. Take it, and get the root node. @@ -112,7 +104,6 @@ module.exports = (options) => { properties[property] = { base: {}, dark: {}, light: {} } return properties[property] } - const getDeclProp = (decl) => decl.light.prop || decl.dark.prop if (!lightAndDark.base) { lightAndDark.base = new Rule({ selector: selector }) @@ -123,8 +114,7 @@ module.exports = (options) => { lightAndDark.dark.each((decl) => { if (!decl.prop) return - const propertyName = getPropertyName(selector, decl) - getPropertyVariants([propertyName]).dark = decl + getPropertyVariants([decl.prop]).dark = decl }) } @@ -132,50 +122,108 @@ module.exports = (options) => { lightAndDark.light.each((decl) => { if (!decl.prop) return - const propertyName = getPropertyName(selector, decl) - getPropertyVariants([propertyName]).light = decl + getPropertyVariants([decl.prop]).light = decl }) } lightAndDark.base.each((decl) => { - const propertyName = getPropertyName(selector, decl) - if (!properties[propertyName]) return - properties[propertyName].base = decl + if (!properties[decl.prop]) return + properties[decl.prop].base = decl }) + // Create CSS variable declarations for light and dark modes + // Always create scoped variables (even for CSS custom properties) + const lightVariables = Object.entries(properties).map( + ([prop, decl]) => + new Declaration({ + prop: getPropertyName(selector, prop), + value: decl.light.value || decl.base.value || 'unset' + }) + ) const darkVariables = Object.entries(properties).map( - ([key, decl]) => + ([prop, decl]) => new Declaration({ - prop: key, + prop: getPropertyName(selector, prop), value: decl.dark.value || decl.base.value || 'unset' }) ) - const lightVariables = Object.entries(properties).map( - ([key, decl]) => - new Declaration({ - prop: key, - value: decl.light.value || decl.base.value || 'unset' + // 1. :root with default (light) values + const rootLightRule = new Rule({ + selector: `:global(:root)`, + nodes: lightVariables.map((decl) => decl.clone()) + }) + + // 2. @media (prefers-color-scheme: dark) for dark mode default + const darkMediaQuery = new AtRule({ + name: 'media', + params: '(prefers-color-scheme: dark)', + nodes: [ + new Rule({ + selector: `:global(${selector})`, + nodes: darkVariables.map((decl) => decl.clone()) }) - ) + ] + }) + + // 3. [data-theme] fallback rules for explicit theme selection (Firefox) + // Use descendant selectors to match when data-theme is on a parent + const fallbackLightRule = new Rule({ + selector: `:global([data-theme="light"])`, + nodes: lightVariables.map((decl) => decl.clone()) + }) + const fallbackDarkRule = new Rule({ + selector: `:global([data-theme="dark"])`, + nodes: darkVariables.map((decl) => decl.clone()) + }) + + // 4. @container style queries (highest specificity, modern browsers) + const lightContainer = new AtRule({ + name: 'container', + params: `style(--leo-theme: light)`, + nodes: [ + new Rule({ + selector: `:global(${selector})`, + nodes: lightVariables.map((decl) => decl.clone()) + }) + ] + }) - for (const [property, decls] of Object.entries(properties)) { - lightAndDark.base.push( - new Declaration({ prop: getDeclProp(decls), value: `var(${property})` }) + const darkContainer = new AtRule({ + name: 'container', + params: `style(--leo-theme: dark)`, + nodes: [ + new Rule({ + selector: `:global(${selector})`, + nodes: darkVariables.map((decl) => decl.clone()) + }) + ] + }) + + // Update base rule to use CSS variable references + for (const [prop, decl] of Object.entries(properties)) { + const varName = getPropertyName(selector, prop) + const originalProp = + decl.light?.prop || decl.dark?.prop || decl.base?.prop || prop + lightAndDark.base.append( + new Declaration({ prop: originalProp, value: `var(${varName})` }) ) } // Remove all of the overridden light rules. for (const decl of Object.values(properties)) { if ('remove' in decl.base) nodesToDelete.add(decl.base) - } - - return { - dark: darkVariables, - light: lightVariables - } + } // Add all rules: :root, media query, fallback rules, then container queries last (highest specificity) + + return [ + rootLightRule, + darkMediaQuery, + fallbackLightRule, + fallbackDarkRule, + lightContainer, + darkContainer + ] } - return { postcssPlugin: 'theme', AtRule: { @@ -198,48 +246,13 @@ module.exports = (options) => { } }, OnceExit: (root) => { - const darkProperties = [] - const lightProperties = [] - findMatchingBaseRules(root) + const rulesToAdd = [] for (const [selector, rule] of Object.entries(rules)) { - const { dark, light } = extractDarkProperties(selector, rule) - darkProperties.push(...dark) - lightProperties.push(...light) + rulesToAdd.push(...extractThemedProperties(selector, rule)) } - let lightSelectors = [ - ':root', - `:root${options.lightSelector}`, - options.lightSelector - ] - let darkSelectors = [`:root${options.darkSelector}`, options.darkSelector] - - lightSelectors = lightSelectors.map((s) => options.wrapSelector(s)) - darkSelectors = darkSelectors.map((s) => options.wrapSelector(s)) - - const lightRule = new Rule({ - selectors: lightSelectors, - nodes: lightProperties - }) - const darkRule = new Rule({ - selectors: darkSelectors, - nodes: darkProperties - }) - const darkMediaQuery = new AtRule({ - name: 'media', - params: '(prefers-color-scheme: dark)', - nodes: darkProperties.length - ? [ - new Rule({ - selector: options.wrapSelector(':root'), - nodes: darkProperties - }) - ] - : [] - }) - - root.prepend(lightRule, darkRule, darkMediaQuery) + root.prepend(...rulesToAdd) for (const node of nodesToDelete) { node.remove() diff --git a/src/tokens/transformation/web/formatCss.js b/src/tokens/transformation/web/formatCss.js index 7ff2c5f99..97fb9fcdc 100644 --- a/src/tokens/transformation/web/formatCss.js +++ b/src/tokens/transformation/web/formatCss.js @@ -30,17 +30,21 @@ export default ({ dictionary, options, file }) => { outputReferences }) - const lightVars = formattedVariables({ - format: 'css', - dictionary: groupedTokens.light, - outputReferences - }).replace(/-light-/gm, '-') + const lightVars = + ` --leo-theme: light;\n` + + formattedVariables({ + format: 'css', + dictionary: groupedTokens.light, + outputReferences + }).replace(/-light-/gm, '-') - const darkVars = formattedVariables({ - format: 'css', - dictionary: groupedTokens.dark, - outputReferences - }).replace(/-dark-/gm, '-') + const darkVars = + ` --leo-theme: dark;\n` + + formattedVariables({ + format: 'css', + dictionary: groupedTokens.dark, + outputReferences + }).replace(/-dark-/gm, '-') // prettier-ignore return ( @@ -53,8 +57,8 @@ export default ({ dictionary, options, file }) => { darkVars && varDefFormat`@media (prefers-color-scheme: dark) { :root {${darkVars} } }`, - lightVars && varDefFormat`[data-theme="light"] {${lightVars}}`, - lightVars && varDefFormat`[data-theme="dark"] {${darkVars}}`, + lightVars && varDefFormat`[data-theme="light"] { ${lightVars}}`, + lightVars && varDefFormat`[data-theme="dark"] { ${darkVars}}`, ] .filter((v) => !!v) .join('\n\n') + diff --git a/svelte.config.js b/svelte.config.js index 9f720e2aa..cd185b394 100644 --- a/svelte.config.js +++ b/svelte.config.js @@ -17,11 +17,7 @@ export default { extensions: ['.svelte'], preprocess: sveltePreprocess({ postcss: { - plugins: [ - themePlugin({ - wrapSelector: (selector) => `:global(${selector})` - }) - ] + plugins: [themePlugin()] } }), onwarn diff --git a/tests/theme.dark.test.js b/tests/theme.dark.test.js index 16a2ef908..952ac9108 100644 --- a/tests/theme.dark.test.js +++ b/tests/theme.dark.test.js @@ -17,22 +17,44 @@ it('Converts the base case', async () => { flex-direction: column; } }`, - `:root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { - --\\.component_background: pink; - --\\.component_flex-direction: row; - } - - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { - --\\.component_background: red; - --\\.component_flex-direction: column; - } + `:global(:root) { + --\\.component_background: pink; + --\\.component_flex-direction: row; +} @media (prefers-color-scheme: dark) { - :root { - --\\.component_background: red; - --\\.component_flex-direction: column; - } - } + + :global(.component) { + --\\.component_background: red; + --\\.component_flex-direction: column; + } +} + + :global([data-theme="light"]) { + --\\.component_background: pink; + --\\.component_flex-direction: row; +} + + :global([data-theme="dark"]) { + --\\.component_background: red; + --\\.component_flex-direction: column; +} + + @container style(--leo-theme: light) { + + :global(.component) { + --\\.component_background: pink; + --\\.component_flex-direction: row; + } +} + + @container style(--leo-theme: dark) { + + :global(.component) { + --\\.component_background: red; + --\\.component_flex-direction: column; + } +} .component { padding: 12px; @@ -59,22 +81,44 @@ it('Selectors can be overridden', async () => { flex-direction: column; } }`, - `:root, :root.light, .light { - --\\.component_background: pink; - --\\.component_flex-direction: row; - } - - :root.dark, .dark { - --\\.component_background: red; - --\\.component_flex-direction: column; - } + `:global(:root) { + --\\.component_background: pink; + --\\.component_flex-direction: row; +} @media (prefers-color-scheme: dark) { - :root { - --\\.component_background: red; - --\\.component_flex-direction: column; - } - } + + :global(.component) { + --\\.component_background: red; + --\\.component_flex-direction: column; + } +} + + :global([data-theme="light"]) { + --\\.component_background: pink; + --\\.component_flex-direction: row; +} + + :global([data-theme="dark"]) { + --\\.component_background: red; + --\\.component_flex-direction: column; +} + + @container style(--leo-theme: light) { + + :global(.component) { + --\\.component_background: pink; + --\\.component_flex-direction: row; + } +} + + @container style(--leo-theme: dark) { + + :global(.component) { + --\\.component_background: red; + --\\.component_flex-direction: column; + } +} .component { padding: 12px; @@ -82,7 +126,7 @@ it('Selectors can be overridden', async () => { background: var(--\\.component_background); flex-direction: var(--\\.component_flex-direction); }`, - { lightSelector: '.light', darkSelector: '.dark' } + {} ) }) @@ -93,10 +137,9 @@ it('Handles no dark mode', async () => { background: red; color: white; }`, - ` - .component { - background: red; - color: white; + `.component { + background: red; + color: white; }`, {} ) @@ -111,27 +154,49 @@ it('Handles no light mode', async () => { color: white; } }`, - `:root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_background: unset; - --\\.component_color: unset; - } + --\\.component_color: unset +} + +@media (prefers-color-scheme: dark) { - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { + :global(.component) { + --\\.component_background: red; + --\\.component_color: white + } +} + +:global([data-theme="light"]) { + --\\.component_background: unset; + --\\.component_color: unset +} + +:global([data-theme="dark"]) { --\\.component_background: red; - --\\.component_color: white; - } + --\\.component_color: white +} - @media (prefers-color-scheme: dark) { - :root { +@container style(--leo-theme: light) { + + :global(.component) { + --\\.component_background: unset; + --\\.component_color: unset + } +} + +@container style(--leo-theme: dark) { + + :global(.component) { --\\.component_background: red; - --\\.component_color: white; - } - } + --\\.component_color: white + } +} - .component { - background: var(--\\.component_background); - color: var(--\\.component_color); - }`, +.component { + background: var(--\\.component_background); + color: var(--\\.component_color) +}`, {} ) }) @@ -148,26 +213,48 @@ it('Converts darkmode only properties', async () => { color: white; } }`, - `:root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { - --\\.component_background: pink; - --\\.component_color: unset; - } - - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { - --\\.component_background: red; - --\\.component_color: white; - } + `:global(:root) { + --\\.component_background: pink; + --\\.component_color: unset; +} @media (prefers-color-scheme: dark) { - :root { + + :global(.component) { + --\\.component_background: red; + --\\.component_color: white; + } +} + + :global([data-theme="light"]) { + --\\.component_background: pink; + --\\.component_color: unset; +} + + :global([data-theme="dark"]) { --\\.component_background: red; --\\.component_color: white; - } - } +} + + @container style(--leo-theme: light) { + + :global(.component) { + --\\.component_background: pink; + --\\.component_color: unset; + } +} + + @container style(--leo-theme: dark) { + + :global(.component) { + --\\.component_background: red; + --\\.component_color: white; + } +} .component { - background: var(--\\.component_background); - color: var(--\\.component_color); + background: var(--\\.component_background); + color: var(--\\.component_color); }`, {} ) @@ -185,20 +272,38 @@ it('Converts nested selectors', async () => { background: red; } }`, - ` - :root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_\\.foo_background: pink; - } - - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { - --\\.component_\\.foo_background: red; - } - +} + @media (prefers-color-scheme: dark) { - :root { - --\\.component_\\.foo_background: red; + + :global(.component .foo) { + --\\.component_\\.foo_background: red; } - } +} + + :global([data-theme="light"]) { + --\\.component_\\.foo_background: pink; +} + + :global([data-theme="dark"]) { + --\\.component_\\.foo_background: red; +} + + @container style(--leo-theme: light) { + + :global(.component .foo) { + --\\.component_\\.foo_background: pink; + } +} + + @container style(--leo-theme: dark) { + + :global(.component .foo) { + --\\.component_\\.foo_background: red; + } +} .component .foo { background: var(--\\.component_\\.foo_background); @@ -218,20 +323,38 @@ it('Converts sibling selectors', async () => { background: red; } }`, - ` - :root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_\\+_\\.foo_background: pink; - } - - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { - --\\.component_\\+_\\.foo_background: red; - } - +} + @media (prefers-color-scheme: dark) { - :root { - --\\.component_\\+_\\.foo_background: red; + + :global(.component + .foo) { + --\\.component_\\+_\\.foo_background: red; } - } +} + + :global([data-theme="light"]) { + --\\.component_\\+_\\.foo_background: pink; +} + + :global([data-theme="dark"]) { + --\\.component_\\+_\\.foo_background: red; +} + + @container style(--leo-theme: light) { + + :global(.component + .foo) { + --\\.component_\\+_\\.foo_background: pink; + } +} + + @container style(--leo-theme: dark) { + + :global(.component + .foo) { + --\\.component_\\+_\\.foo_background: red; + } +} .component + .foo { background: var(--\\.component_\\+_\\.foo_background); @@ -251,20 +374,38 @@ it('Converts child selectors', async () => { background: red; } }`, - ` - :root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_\\>_\\.foo_background: pink; - } - - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { - --\\.component_\\>_\\.foo_background: red; - } - +} + @media (prefers-color-scheme: dark) { - :root { - --\\.component_\\>_\\.foo_background: red; + + :global(.component > .foo) { + --\\.component_\\>_\\.foo_background: red; } - } +} + + :global([data-theme="light"]) { + --\\.component_\\>_\\.foo_background: pink; +} + + :global([data-theme="dark"]) { + --\\.component_\\>_\\.foo_background: red; +} + + @container style(--leo-theme: light) { + + :global(.component > .foo) { + --\\.component_\\>_\\.foo_background: pink; + } +} + + @container style(--leo-theme: dark) { + + :global(.component > .foo) { + --\\.component_\\>_\\.foo_background: red; + } +} .component > .foo { background: var(--\\.component_\\>_\\.foo_background); @@ -284,20 +425,38 @@ it('Converts general sibling selectors', async () => { background: red; } }`, - ` - :root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_\\~_\\.foo_background: pink; - } - - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { - --\\.component_\\~_\\.foo_background: red; - } - +} + @media (prefers-color-scheme: dark) { - :root { - --\\.component_\\~_\\.foo_background: red; + + :global(.component ~ .foo) { + --\\.component_\\~_\\.foo_background: red; } - } +} + + :global([data-theme="light"]) { + --\\.component_\\~_\\.foo_background: pink; +} + + :global([data-theme="dark"]) { + --\\.component_\\~_\\.foo_background: red; +} + + @container style(--leo-theme: light) { + + :global(.component ~ .foo) { + --\\.component_\\~_\\.foo_background: pink; + } +} + + @container style(--leo-theme: dark) { + + :global(.component ~ .foo) { + --\\.component_\\~_\\.foo_background: red; + } +} .component ~ .foo { background: var(--\\.component_\\~_\\.foo_background); @@ -317,29 +476,58 @@ it('Converts multi selectors (light and dark same)', async () => { background: red; } }`, - ` - :root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_background: pink; - --\\.foo_background: pink; - } - - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { +} +@media (prefers-color-scheme: dark) { + :global(.component) { + --\\.component_background: red; + } +} +:global([data-theme="light"]) { + --\\.component_background: pink; +} +:global([data-theme="dark"]) { --\\.component_background: red; +} +@container style(--leo-theme: light) { + :global(.component) { + --\\.component_background: pink; + } +} +@container style(--leo-theme: dark) { + :global(.component) { + --\\.component_background: red; + } +} +:global(:root) { + --\\.foo_background: pink; +} +@media (prefers-color-scheme: dark) { + :global(.foo) { + --\\.foo_background: red; + } +} +:global([data-theme="light"]) { + --\\.foo_background: pink; +} +:global([data-theme="dark"]) { --\\.foo_background: red; - } - - @media (prefers-color-scheme: dark) { - :root { - --\\.component_background: red; - --\\.foo_background: red; +} +@container style(--leo-theme: light) { + :global(.foo) { + --\\.foo_background: pink; } - } - - .component { +} +@container style(--leo-theme: dark) { + :global(.foo) { + --\\.foo_background: red; + } +} +.component { background: var(--\\.component_background); } - - .foo { +.foo { background: var(--\\.foo_background); }` ) @@ -358,30 +546,59 @@ it('Converts multi selectors (light and dark same, with remainder)', async () => background: red; } }`, - ` - :root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_background: pink; - --\\.foo_background: pink; - } - - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { +} +@media (prefers-color-scheme: dark) { + :global(.component) { + --\\.component_background: red; + } +} +:global([data-theme="light"]) { + --\\.component_background: pink; +} +:global([data-theme="dark"]) { --\\.component_background: red; +} +@container style(--leo-theme: light) { + :global(.component) { + --\\.component_background: pink; + } +} +@container style(--leo-theme: dark) { + :global(.component) { + --\\.component_background: red; + } +} +:global(:root) { + --\\.foo_background: pink; +} +@media (prefers-color-scheme: dark) { + :global(.foo) { + --\\.foo_background: red; + } +} +:global([data-theme="light"]) { + --\\.foo_background: pink; +} +:global([data-theme="dark"]) { --\\.foo_background: red; - } - - @media (prefers-color-scheme: dark) { - :root { - --\\.component_background: red; - --\\.foo_background: red; +} +@container style(--leo-theme: light) { + :global(.foo) { + --\\.foo_background: pink; } - } - - .component { +} +@container style(--leo-theme: dark) { + :global(.foo) { + --\\.foo_background: red; + } +} +.component { padding: 12px; background: var(--\\.component_background); } - - .foo { +.foo { padding: 12px; background: var(--\\.foo_background); }` @@ -400,27 +617,75 @@ it('Converts multi selectors (light subset of dark)', async () => { background: red; } }`, - ` - :root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_background: pink; - --\\.foo_background: unset; - } - - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { +} + + @media (prefers-color-scheme: dark) { + + :global(.component) { + --\\.component_background: red; + } +} + + :global([data-theme="light"]) { + --\\.component_background: pink; +} + + :global([data-theme="dark"]) { --\\.component_background: red; - --\\.foo_background: red; - } - +} + + @container style(--leo-theme: light) { + + :global(.component) { + --\\.component_background: pink; + } +} + + @container style(--leo-theme: dark) { + + :global(.component) { + --\\.component_background: red; + } +} + + :global(:root) { + --\\.foo_background: unset; +} + @media (prefers-color-scheme: dark) { - :root { - --\\.component_background: red; - --\\.foo_background: red; + + :global(.foo) { + --\\.foo_background: red; } - } - +} + + :global([data-theme="light"]) { + --\\.foo_background: unset; +} + + :global([data-theme="dark"]) { + --\\.foo_background: red; +} + + @container style(--leo-theme: light) { + + :global(.foo) { + --\\.foo_background: unset; + } +} + + @container style(--leo-theme: dark) { + + :global(.foo) { + --\\.foo_background: red; + } +} + .foo { background: var(--\\.foo_background); - } +} .component { background: var(--\\.component_background); @@ -441,27 +706,75 @@ it('Converts multi selectors (light subset of dark, with remainder)', async () = background: red; } }`, - ` - :root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_background: pink; - --\\.foo_background: unset; - } - - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { +} + + @media (prefers-color-scheme: dark) { + + :global(.component) { + --\\.component_background: red; + } +} + + :global([data-theme="light"]) { + --\\.component_background: pink; +} + + :global([data-theme="dark"]) { --\\.component_background: red; - --\\.foo_background: red; - } - +} + + @container style(--leo-theme: light) { + + :global(.component) { + --\\.component_background: pink; + } +} + + @container style(--leo-theme: dark) { + + :global(.component) { + --\\.component_background: red; + } +} + + :global(:root) { + --\\.foo_background: unset; +} + @media (prefers-color-scheme: dark) { - :root { - --\\.component_background: red; - --\\.foo_background: red; + + :global(.foo) { + --\\.foo_background: red; } - } - +} + + :global([data-theme="light"]) { + --\\.foo_background: unset; +} + + :global([data-theme="dark"]) { + --\\.foo_background: red; +} + + @container style(--leo-theme: light) { + + :global(.foo) { + --\\.foo_background: unset; + } +} + + @container style(--leo-theme: dark) { + + :global(.foo) { + --\\.foo_background: red; + } +} + .foo { background: var(--\\.foo_background); - } +} .component { padding: 12px; @@ -482,26 +795,34 @@ it('Converts multi selectors (dark subset of light)', async () => { background: red; } }`, - ` - :root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_background: pink; - } - - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { +} +@media (prefers-color-scheme: dark) { + :global(.component) { + --\\.component_background: red; + } +} +:global([data-theme="light"]) { + --\\.component_background: pink; +} +:global([data-theme="dark"]) { --\\.component_background: red; - } - - @media (prefers-color-scheme: dark) { - :root { - --\\.component_background: red; +} +@container style(--leo-theme: light) { + :global(.component) { + --\\.component_background: pink; } - } - - .component { +} +@container style(--leo-theme: dark) { + :global(.component) { + --\\.component_background: red; + } +} +.component { background: var(--\\.component_background); } - - .foo { +.foo { background: pink; }` ) @@ -520,27 +841,35 @@ it('Converts multi selectors (dark subset of light, with remainder)', async () = background: red; } }`, - ` - :root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_background: pink; - } - - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { +} +@media (prefers-color-scheme: dark) { + :global(.component) { + --\\.component_background: red; + } +} +:global([data-theme="light"]) { + --\\.component_background: pink; +} +:global([data-theme="dark"]) { --\\.component_background: red; - } - - @media (prefers-color-scheme: dark) { - :root { - --\\.component_background: red; +} +@container style(--leo-theme: light) { + :global(.component) { + --\\.component_background: pink; } - } - - .component { +} +@container style(--leo-theme: dark) { + :global(.component) { + --\\.component_background: red; + } +} +.component { padding: 12px; background: var(--\\.component_background); } - - .foo { +.foo { padding: 12px; background: pink; }` @@ -553,37 +882,48 @@ it('Converts multi selectors (dark subset of light, with unset)', async () => { .component, .foo { background: pink; } - + @theme (dark) { .component { padding: 12px; background: red; } }`, - ` - :root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_padding: unset; --\\.component_background: pink; - } - - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { - --\\.component_padding: 12px; - --\\.component_background: red; - } - - @media (prefers-color-scheme: dark) { - :root { +} +@media (prefers-color-scheme: dark) { + :global(.component) { + --\\.component_padding: 12px; + --\\.component_background: red; + } +} +:global([data-theme="light"]) { + --\\.component_padding: unset; + --\\.component_background: pink; +} +:global([data-theme="dark"]) { --\\.component_padding: 12px; --\\.component_background: red; +} +@container style(--leo-theme: light) { + :global(.component) { + --\\.component_padding: unset; + --\\.component_background: pink; } - } - - .component { +} +@container style(--leo-theme: dark) { + :global(.component) { + --\\.component_padding: 12px; + --\\.component_background: red; + } +} +.component { padding: var(--\\.component_padding); background: var(--\\.component_background); } - - .foo { +.foo { background: pink; }` ) @@ -596,49 +936,83 @@ it('Converts multi selectors (weird intersection)', async () => { margin: 8px; background: pink; } - + @theme (dark) { .component, .frob { padding: 12px; background: red; } }`, - ` - :root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_padding: unset; --\\.component_background: pink; - --\\.frob_padding: unset; - --\\.frob_background: unset; - } - - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { - --\\.component_padding: 12px; - --\\.component_background: red; - --\\.frob_padding: 12px; - --\\.frob_background: red; - } - - @media (prefers-color-scheme: dark) { - :root { +} +@media (prefers-color-scheme: dark) { + :global(.component) { + --\\.component_padding: 12px; + --\\.component_background: red; + } +} +:global([data-theme="light"]) { + --\\.component_padding: unset; + --\\.component_background: pink; +} +:global([data-theme="dark"]) { --\\.component_padding: 12px; --\\.component_background: red; +} +@container style(--leo-theme: light) { + :global(.component) { + --\\.component_padding: unset; + --\\.component_background: pink; + } +} +@container style(--leo-theme: dark) { + :global(.component) { + --\\.component_padding: 12px; + --\\.component_background: red; + } +} +:global(:root) { + --\\.frob_padding: unset; + --\\.frob_background: unset; +} +@media (prefers-color-scheme: dark) { + :global(.frob) { + --\\.frob_padding: 12px; + --\\.frob_background: red; + } +} +:global([data-theme="light"]) { + --\\.frob_padding: unset; + --\\.frob_background: unset; +} +:global([data-theme="dark"]) { --\\.frob_padding: 12px; --\\.frob_background: red; +} +@container style(--leo-theme: light) { + :global(.frob) { + --\\.frob_padding: unset; + --\\.frob_background: unset; } - } - - .frob { +} +@container style(--leo-theme: dark) { + :global(.frob) { + --\\.frob_padding: 12px; + --\\.frob_background: red; + } +} +.frob { padding: var(--\\.frob_padding); background: var(--\\.frob_background); - } - - .component { +} +.component { margin: 8px; padding: var(--\\.component_padding); background: var(--\\.component_background); } - - .foo { +.foo { margin: 8px; background: pink; }` diff --git a/tests/theme.light.test.js b/tests/theme.light.test.js index d452af75e..cb95c5896 100644 --- a/tests/theme.light.test.js +++ b/tests/theme.light.test.js @@ -17,22 +17,44 @@ it('Converts the base case', async () => { flex-direction: column; } }`, - `:root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_background: red; --\\.component_flex-direction: column; - } +} + + @media (prefers-color-scheme: dark) { + + :global(.component) { + --\\.component_background: pink; + --\\.component_flex-direction: row; + } +} + + :global([data-theme="light"]) { + --\\.component_background: red; + --\\.component_flex-direction: column; +} - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { + :global([data-theme="dark"]) { --\\.component_background: pink; --\\.component_flex-direction: row; - } +} - @media (prefers-color-scheme: dark) { - :root { - --\\.component_background: pink; - --\\.component_flex-direction: row; + @container style(--leo-theme: light) { + + :global(.component) { + --\\.component_background: red; + --\\.component_flex-direction: column; } - } +} + + @container style(--leo-theme: dark) { + + :global(.component) { + --\\.component_background: pink; + --\\.component_flex-direction: row; + } +} .component { padding: 12px; @@ -59,22 +81,44 @@ it('Selectors can be overridden', async () => { flex-direction: column; } }`, - `:root, :root.light, .light { + `:global(:root) { --\\.component_background: red; --\\.component_flex-direction: column; - } +} + + @media (prefers-color-scheme: dark) { + + :global(.component) { + --\\.component_background: pink; + --\\.component_flex-direction: row; + } +} + + :global([data-theme="light"]) { + --\\.component_background: red; + --\\.component_flex-direction: column; +} - :root.dark, .dark { + :global([data-theme="dark"]) { --\\.component_background: pink; --\\.component_flex-direction: row; - } +} - @media (prefers-color-scheme: dark) { - :root { - --\\.component_background: pink; - --\\.component_flex-direction: row; + @container style(--leo-theme: light) { + + :global(.component) { + --\\.component_background: red; + --\\.component_flex-direction: column; } - } +} + + @container style(--leo-theme: dark) { + + :global(.component) { + --\\.component_background: pink; + --\\.component_flex-direction: row; + } +} .component { padding: 12px; @@ -82,7 +126,7 @@ it('Selectors can be overridden', async () => { background: var(--\\.component_background); flex-direction: var(--\\.component_flex-direction); }`, - { lightSelector: '.light', darkSelector: '.dark' } + {} ) }) @@ -95,27 +139,40 @@ it('Handles no dark mode', async () => { color: white; } }`, - `:root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_background: red; - --\\.component_color: white; - } - - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { + --\\.component_color: white +} +@media (prefers-color-scheme: dark) { + :global(.component) { + --\\.component_background: unset; + --\\.component_color: unset + } +} +:global([data-theme="light"]) { + --\\.component_background: red; + --\\.component_color: white +} +:global([data-theme="dark"]) { --\\.component_background: unset; - --\\.component_color: unset; - } - - @media (prefers-color-scheme: dark) { - :root { + --\\.component_color: unset +} +@container style(--leo-theme: light) { + :global(.component) { + --\\.component_background: red; + --\\.component_color: white + } +} +@container style(--leo-theme: dark) { + :global(.component) { --\\.component_background: unset; - --\\.component_color: unset; - } - } - - .component { - background: var(--\\.component_background); - color: var(--\\.component_color); - }`, + --\\.component_color: unset + } +} +.component { + background: var(--\\.component_background); + color: var(--\\.component_color) +}`, {} ) }) @@ -132,26 +189,48 @@ it('Converts lightmode only properties', async () => { color: white; } }`, - `:root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_background: red; --\\.component_color: white; - } +} + + @media (prefers-color-scheme: dark) { - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { + :global(.component) { + --\\.component_background: pink; + --\\.component_color: unset; + } +} + + :global([data-theme="light"]) { + --\\.component_background: red; + --\\.component_color: white; +} + + :global([data-theme="dark"]) { --\\.component_background: pink; --\\.component_color: unset; - } +} - @media (prefers-color-scheme: dark) { - :root { + @container style(--leo-theme: light) { + + :global(.component) { + --\\.component_background: red; + --\\.component_color: white; + } +} + + @container style(--leo-theme: dark) { + + :global(.component) { --\\.component_background: pink; --\\.component_color: unset; - } - } + } +} .component { - background: var(--\\.component_background); - color: var(--\\.component_color); + background: var(--\\.component_background); + color: var(--\\.component_color); }`, {} ) @@ -169,20 +248,38 @@ it('Converts nested selectors', async () => { background: red; } }`, - ` - :root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_\\.foo_background: red; - } - - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { - --\\.component_\\.foo_background: pink; - } - +} + @media (prefers-color-scheme: dark) { - :root { - --\\.component_\\.foo_background: pink; + + :global(.component .foo) { + --\\.component_\\.foo_background: pink; } - } +} + + :global([data-theme="light"]) { + --\\.component_\\.foo_background: red; +} + + :global([data-theme="dark"]) { + --\\.component_\\.foo_background: pink; +} + + @container style(--leo-theme: light) { + + :global(.component .foo) { + --\\.component_\\.foo_background: red; + } +} + + @container style(--leo-theme: dark) { + + :global(.component .foo) { + --\\.component_\\.foo_background: pink; + } +} .component .foo { background: var(--\\.component_\\.foo_background); @@ -202,20 +299,38 @@ it('Converts sibling selectors', async () => { background: pink; } }`, - ` - :root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_\\+_\\.foo_background: pink; - } - - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { - --\\.component_\\+_\\.foo_background: red; - } - +} + @media (prefers-color-scheme: dark) { - :root { - --\\.component_\\+_\\.foo_background: red; + + :global(.component + .foo) { + --\\.component_\\+_\\.foo_background: red; } - } +} + + :global([data-theme="light"]) { + --\\.component_\\+_\\.foo_background: pink; +} + + :global([data-theme="dark"]) { + --\\.component_\\+_\\.foo_background: red; +} + + @container style(--leo-theme: light) { + + :global(.component + .foo) { + --\\.component_\\+_\\.foo_background: pink; + } +} + + @container style(--leo-theme: dark) { + + :global(.component + .foo) { + --\\.component_\\+_\\.foo_background: red; + } +} .component + .foo { background: var(--\\.component_\\+_\\.foo_background); @@ -235,20 +350,38 @@ it('Converts child selectors', async () => { background: pink; } }`, - ` - :root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_\\>_\\.foo_background: pink; - } - - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { - --\\.component_\\>_\\.foo_background: red; - } - +} + @media (prefers-color-scheme: dark) { - :root { - --\\.component_\\>_\\.foo_background: red; + + :global(.component > .foo) { + --\\.component_\\>_\\.foo_background: red; } - } +} + + :global([data-theme="light"]) { + --\\.component_\\>_\\.foo_background: pink; +} + + :global([data-theme="dark"]) { + --\\.component_\\>_\\.foo_background: red; +} + + @container style(--leo-theme: light) { + + :global(.component > .foo) { + --\\.component_\\>_\\.foo_background: pink; + } +} + + @container style(--leo-theme: dark) { + + :global(.component > .foo) { + --\\.component_\\>_\\.foo_background: red; + } +} .component > .foo { background: var(--\\.component_\\>_\\.foo_background); @@ -268,20 +401,38 @@ it('Converts general sibling selectors', async () => { background: pink; } }`, - ` - :root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_\\~_\\.foo_background: pink; - } - - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { - --\\.component_\\~_\\.foo_background: red; - } - +} + @media (prefers-color-scheme: dark) { - :root { - --\\.component_\\~_\\.foo_background: red; + + :global(.component ~ .foo) { + --\\.component_\\~_\\.foo_background: red; } - } +} + + :global([data-theme="light"]) { + --\\.component_\\~_\\.foo_background: pink; +} + + :global([data-theme="dark"]) { + --\\.component_\\~_\\.foo_background: red; +} + + @container style(--leo-theme: light) { + + :global(.component ~ .foo) { + --\\.component_\\~_\\.foo_background: pink; + } +} + + @container style(--leo-theme: dark) { + + :global(.component ~ .foo) { + --\\.component_\\~_\\.foo_background: red; + } +} .component ~ .foo { background: var(--\\.component_\\~_\\.foo_background); @@ -301,29 +452,58 @@ it('Converts multi selectors (dark and light same)', async () => { background: pink; } }`, - ` - :root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_background: pink; - --\\.foo_background: pink; - } - - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { +} +@media (prefers-color-scheme: dark) { + :global(.component) { + --\\.component_background: red; + } +} +:global([data-theme="light"]) { + --\\.component_background: pink; +} +:global([data-theme="dark"]) { --\\.component_background: red; +} +@container style(--leo-theme: light) { + :global(.component) { + --\\.component_background: pink; + } +} +@container style(--leo-theme: dark) { + :global(.component) { + --\\.component_background: red; + } +} +:global(:root) { + --\\.foo_background: pink; +} +@media (prefers-color-scheme: dark) { + :global(.foo) { + --\\.foo_background: red; + } +} +:global([data-theme="light"]) { + --\\.foo_background: pink; +} +:global([data-theme="dark"]) { --\\.foo_background: red; - } - - @media (prefers-color-scheme: dark) { - :root { - --\\.component_background: red; - --\\.foo_background: red; +} +@container style(--leo-theme: light) { + :global(.foo) { + --\\.foo_background: pink; } - } - - .component { +} +@container style(--leo-theme: dark) { + :global(.foo) { + --\\.foo_background: red; + } +} +.component { background: var(--\\.component_background); } - - .foo { +.foo { background: var(--\\.foo_background); }` ) @@ -342,30 +522,59 @@ it('Converts multi selectors (dark and light same, with remainder)', async () => background: pink; } }`, - ` - :root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_background: pink; - --\\.foo_background: pink; - } - - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { +} +@media (prefers-color-scheme: dark) { + :global(.component) { + --\\.component_background: red; + } +} +:global([data-theme="light"]) { + --\\.component_background: pink; +} +:global([data-theme="dark"]) { --\\.component_background: red; +} +@container style(--leo-theme: light) { + :global(.component) { + --\\.component_background: pink; + } +} +@container style(--leo-theme: dark) { + :global(.component) { + --\\.component_background: red; + } +} +:global(:root) { + --\\.foo_background: pink; +} +@media (prefers-color-scheme: dark) { + :global(.foo) { + --\\.foo_background: red; + } +} +:global([data-theme="light"]) { + --\\.foo_background: pink; +} +:global([data-theme="dark"]) { --\\.foo_background: red; - } - - @media (prefers-color-scheme: dark) { - :root { - --\\.component_background: red; - --\\.foo_background: red; +} +@container style(--leo-theme: light) { + :global(.foo) { + --\\.foo_background: pink; } - } - - .component { +} +@container style(--leo-theme: dark) { + :global(.foo) { + --\\.foo_background: red; + } +} +.component { padding: 12px; background: var(--\\.component_background); } - - .foo { +.foo { padding: 12px; background: var(--\\.foo_background); }` @@ -384,29 +593,58 @@ it('Converts multi selectors (light subset of dark)', async () => { background: pink; } }`, - ` - :root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_background: pink; - --\\.foo_background: pink; - } - - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { +} +@media (prefers-color-scheme: dark) { + :global(.component) { + --\\.component_background: red; + } +} +:global([data-theme="light"]) { + --\\.component_background: pink; +} +:global([data-theme="dark"]) { --\\.component_background: red; +} +@container style(--leo-theme: light) { + :global(.component) { + --\\.component_background: pink; + } +} +@container style(--leo-theme: dark) { + :global(.component) { + --\\.component_background: red; + } +} +:global(:root) { + --\\.foo_background: pink; +} +@media (prefers-color-scheme: dark) { + :global(.foo) { + --\\.foo_background: unset; + } +} +:global([data-theme="light"]) { + --\\.foo_background: pink; +} +:global([data-theme="dark"]) { --\\.foo_background: unset; - } - - @media (prefers-color-scheme: dark) { - :root { - --\\.component_background: red; - --\\.foo_background: unset; +} +@container style(--leo-theme: light) { + :global(.foo) { + --\\.foo_background: pink; } - } - - .foo { +} +@container style(--leo-theme: dark) { + :global(.foo) { + --\\.foo_background: unset; + } +} +.foo { background: var(--\\.foo_background); - } - - .component { +} +.component { background: var(--\\.component_background); }` ) @@ -425,29 +663,58 @@ it('Converts multi selectors (light subset of dark, with remainder)', async () = background: pink; } }`, - ` - :root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_background: pink; - --\\.foo_background: pink; - } - - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { +} +@media (prefers-color-scheme: dark) { + :global(.component) { + --\\.component_background: red; + } +} +:global([data-theme="light"]) { + --\\.component_background: pink; +} +:global([data-theme="dark"]) { --\\.component_background: red; +} +@container style(--leo-theme: light) { + :global(.component) { + --\\.component_background: pink; + } +} +@container style(--leo-theme: dark) { + :global(.component) { + --\\.component_background: red; + } +} +:global(:root) { + --\\.foo_background: pink; +} +@media (prefers-color-scheme: dark) { + :global(.foo) { + --\\.foo_background: unset; + } +} +:global([data-theme="light"]) { + --\\.foo_background: pink; +} +:global([data-theme="dark"]) { --\\.foo_background: unset; - } - - @media (prefers-color-scheme: dark) { - :root { - --\\.component_background: red; - --\\.foo_background: unset; +} +@container style(--leo-theme: light) { + :global(.foo) { + --\\.foo_background: pink; } - } - - .foo { +} +@container style(--leo-theme: dark) { + :global(.foo) { + --\\.foo_background: unset; + } +} +.foo { background: var(--\\.foo_background); - } - - .component { +} +.component { padding: 12px; background: var(--\\.component_background); }` @@ -466,26 +733,34 @@ it('Converts multi selectors (light subset of dark)', async () => { background: white; } }`, - ` - :root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_background: white; - } - - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { +} +@media (prefers-color-scheme: dark) { + :global(.component) { + --\\.component_background: red; + } +} +:global([data-theme="light"]) { + --\\.component_background: white; +} +:global([data-theme="dark"]) { --\\.component_background: red; - } - - @media (prefers-color-scheme: dark) { - :root { - --\\.component_background: red; +} +@container style(--leo-theme: light) { + :global(.component) { + --\\.component_background: white; } - } - - .component { +} +@container style(--leo-theme: dark) { + :global(.component) { + --\\.component_background: red; + } +} +.component { background: var(--\\.component_background); } - - .foo { +.foo { background: red; }` ) @@ -504,27 +779,35 @@ it('Converts multi selectors (light subset of base, with remainder)', async () = background: red; } }`, - ` - :root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_background: red; - } - - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { +} +@media (prefers-color-scheme: dark) { + :global(.component) { + --\\.component_background: pink; + } +} +:global([data-theme="light"]) { + --\\.component_background: red; +} +:global([data-theme="dark"]) { --\\.component_background: pink; - } - - @media (prefers-color-scheme: dark) { - :root { - --\\.component_background: pink; +} +@container style(--leo-theme: light) { + :global(.component) { + --\\.component_background: red; } - } - - .component { +} +@container style(--leo-theme: dark) { + :global(.component) { + --\\.component_background: pink; + } +} +.component { padding: 12px; background: var(--\\.component_background); } - - .foo { +.foo { padding: 12px; background: pink; }` @@ -537,37 +820,48 @@ it('Converts multi selectors (light subset of dark, with unset)', async () => { .component, .foo { background: pink; } - + @theme (light) { .component { padding: 12px; background: red; } }`, - ` - :root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_padding: 12px; --\\.component_background: red; - } - - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { - --\\.component_padding: unset; - --\\.component_background: pink; - } - - @media (prefers-color-scheme: dark) { - :root { +} +@media (prefers-color-scheme: dark) { + :global(.component) { + --\\.component_padding: unset; + --\\.component_background: pink; + } +} +:global([data-theme="light"]) { + --\\.component_padding: 12px; + --\\.component_background: red; +} +:global([data-theme="dark"]) { --\\.component_padding: unset; --\\.component_background: pink; +} +@container style(--leo-theme: light) { + :global(.component) { + --\\.component_padding: 12px; + --\\.component_background: red; } - } - - .component { +} +@container style(--leo-theme: dark) { + :global(.component) { + --\\.component_padding: unset; + --\\.component_background: pink; + } +} +.component { padding: var(--\\.component_padding); background: var(--\\.component_background); } - - .foo { +.foo { background: pink; }` ) @@ -580,49 +874,83 @@ it('Converts multi selectors (weird intersection)', async () => { margin: 8px; background: pink; } - + @theme (light) { .component, .frob { padding: 12px; background: red; } }`, - ` - :root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_padding: 12px; --\\.component_background: red; - --\\.frob_padding: 12px; - --\\.frob_background: red; - } - - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { - --\\.component_padding: unset; - --\\.component_background: pink; - --\\.frob_padding: unset; - --\\.frob_background: unset; - } - - @media (prefers-color-scheme: dark) { - :root { +} +@media (prefers-color-scheme: dark) { + :global(.component) { + --\\.component_padding: unset; + --\\.component_background: pink; + } +} +:global([data-theme="light"]) { + --\\.component_padding: 12px; + --\\.component_background: red; +} +:global([data-theme="dark"]) { --\\.component_padding: unset; --\\.component_background: pink; +} +@container style(--leo-theme: light) { + :global(.component) { + --\\.component_padding: 12px; + --\\.component_background: red; + } +} +@container style(--leo-theme: dark) { + :global(.component) { + --\\.component_padding: unset; + --\\.component_background: pink; + } +} +:global(:root) { + --\\.frob_padding: 12px; + --\\.frob_background: red; +} +@media (prefers-color-scheme: dark) { + :global(.frob) { + --\\.frob_padding: unset; + --\\.frob_background: unset; + } +} +:global([data-theme="light"]) { + --\\.frob_padding: 12px; + --\\.frob_background: red; +} +:global([data-theme="dark"]) { --\\.frob_padding: unset; --\\.frob_background: unset; +} +@container style(--leo-theme: light) { + :global(.frob) { + --\\.frob_padding: 12px; + --\\.frob_background: red; } - } - - .frob { +} +@container style(--leo-theme: dark) { + :global(.frob) { + --\\.frob_padding: unset; + --\\.frob_background: unset; + } +} +.frob { padding: var(--\\.frob_padding); background: var(--\\.frob_background); - } - - .component { +} +.component { margin: 8px; padding: var(--\\.component_padding); background: var(--\\.component_background); } - - .foo { +.foo { margin: 8px; background: pink; }` diff --git a/tests/theme.mixed.test.js b/tests/theme.mixed.test.js index 49654512a..a9b166963 100644 --- a/tests/theme.mixed.test.js +++ b/tests/theme.mixed.test.js @@ -13,33 +13,55 @@ it('Can mix theme overrides', () => color: black; } } - + @theme (dark) { .component { background: black; } }`, - `:root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { - --\\.component_background: white; - --\\.component_color: black; - } - - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { - --\\.component_background: black; - --\\.component_color: white; - } + `:global(:root) { + --\\.component_background: white; + --\\.component_color: black; +} @media (prefers-color-scheme: dark) { - :root { + + :global(.component) { + --\\.component_background: black; + --\\.component_color: white; + } +} + + :global([data-theme="light"]) { + --\\.component_background: white; + --\\.component_color: black; +} + + :global([data-theme="dark"]) { --\\.component_background: black; --\\.component_color: white; - } - } +} + + @container style(--leo-theme: light) { + + :global(.component) { + --\\.component_background: white; + --\\.component_color: black; + } +} + + @container style(--leo-theme: dark) { + + :global(.component) { + --\\.component_background: black; + --\\.component_color: white; + } +} .component { - padding: 12px; - background: var(--\\.component_background); - color: var(--\\.component_color); + padding: 12px; + background: var(--\\.component_background); + color: var(--\\.component_color); }`, {} )) @@ -68,31 +90,62 @@ it('Light & Dark mode can be specified for a property', () => new-dark: dark; } }`, - `:root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_override-both: light; --\\.component_override-dark: light; --\\.component_new-dark: unset; --\\.component_override-light: light; --\\.component_new-light: light; - } +} + + @media (prefers-color-scheme: dark) { - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { + :global(.component) { + --\\.component_override-both: dark; + --\\.component_override-dark: dark; + --\\.component_new-dark: dark; + --\\.component_override-light: dark; + --\\.component_new-light: unset; + } +} + + :global([data-theme="light"]) { + --\\.component_override-both: light; + --\\.component_override-dark: light; + --\\.component_new-dark: unset; + --\\.component_override-light: light; + --\\.component_new-light: light; +} + + :global([data-theme="dark"]) { --\\.component_override-both: dark; --\\.component_override-dark: dark; --\\.component_new-dark: dark; --\\.component_override-light: dark; --\\.component_new-light: unset; - } +} - @media (prefers-color-scheme: dark) { - :root { - --\\.component_override-both: dark; - --\\.component_override-dark: dark; - --\\.component_new-dark: dark; - --\\.component_override-light: dark; - --\\.component_new-light: unset; + @container style(--leo-theme: light) { + + :global(.component) { + --\\.component_override-both: light; + --\\.component_override-dark: light; + --\\.component_new-dark: unset; + --\\.component_override-light: light; + --\\.component_new-light: light; } - } +} + + @container style(--leo-theme: dark) { + + :global(.component) { + --\\.component_override-both: dark; + --\\.component_override-dark: dark; + --\\.component_new-dark: dark; + --\\.component_override-light: dark; + --\\.component_new-light: unset; + } +} .component { no-override: none; @@ -125,118 +178,161 @@ it('Light & Dark mode work with weird class overlaps', () => dark: dark; } }`, - `:root, :root[data-theme][data-theme=light], [data-theme][data-theme=light] { + `:global(:root) { --\\.component_color: black; --\\.component_dark: unset; --\\.component_light: light; - --\\.other_color: black; - --\\.other_dark: unset; - --\\.other_light: light; - --\\.light_color: black; - --\\.light_light: light; - --\\.dark_color: unset; - --\\.dark_dark: unset; - } - - :root[data-theme][data-theme=dark], [data-theme][data-theme=dark] { +} +@media (prefers-color-scheme: dark) { + :global(.component) { + --\\.component_color: white; + --\\.component_dark: dark; + --\\.component_light: unset; + } +} +:global([data-theme="light"]) { + --\\.component_color: black; + --\\.component_dark: unset; + --\\.component_light: light; +} +:global([data-theme="dark"]) { --\\.component_color: white; --\\.component_dark: dark; --\\.component_light: unset; +} +@container style(--leo-theme: light) { + :global(.component) { + --\\.component_color: black; + --\\.component_dark: unset; + --\\.component_light: light; + } +} +@container style(--leo-theme: dark) { + :global(.component) { + --\\.component_color: white; + --\\.component_dark: dark; + --\\.component_light: unset; + } +} +:global(:root) { + --\\.other_color: black; + --\\.other_dark: unset; + --\\.other_light: light; +} +@media (prefers-color-scheme: dark) { + :global(.other) { + --\\.other_color: white; + --\\.other_dark: dark; + --\\.other_light: unset; + } +} +:global([data-theme="light"]) { + --\\.other_color: black; + --\\.other_dark: unset; + --\\.other_light: light; +} +:global([data-theme="dark"]) { --\\.other_color: white; --\\.other_dark: dark; --\\.other_light: unset; +} +@container style(--leo-theme: light) { + :global(.other) { + --\\.other_color: black; + --\\.other_dark: unset; + --\\.other_light: light; + } +} +@container style(--leo-theme: dark) { + :global(.other) { + --\\.other_color: white; + --\\.other_dark: dark; + --\\.other_light: unset; + } +} +:global(:root) { + --\\.light_color: black; + --\\.light_light: light; +} +@media (prefers-color-scheme: dark) { + :global(.light) { + --\\.light_color: unset; + --\\.light_light: unset; + } +} +:global([data-theme="light"]) { + --\\.light_color: black; + --\\.light_light: light; +} +:global([data-theme="dark"]) { --\\.light_color: unset; --\\.light_light: unset; +} +@container style(--leo-theme: light) { + :global(.light) { + --\\.light_color: black; + --\\.light_light: light; + } +} +@container style(--leo-theme: dark) { + :global(.light) { + --\\.light_color: unset; + --\\.light_light: unset; + } +} +:global(:root) { + --\\.dark_color: unset; + --\\.dark_dark: unset; +} +@media (prefers-color-scheme: dark) { + :global(.dark) { + --\\.dark_color: white; + --\\.dark_dark: dark; + } +} +:global([data-theme="light"]) { + --\\.dark_color: unset; + --\\.dark_dark: unset; +} +:global([data-theme="dark"]) { --\\.dark_color: white; --\\.dark_dark: dark; - } - - @media (prefers-color-scheme: dark) { - :root { - --\\.component_color: white; - --\\.component_dark: dark; - --\\.component_light: unset; - --\\.other_color: white; - --\\.other_dark: dark; - --\\.other_light: unset; - --\\.light_color: unset; - --\\.light_light: unset; - --\\.dark_color: white; - --\\.dark_dark: dark; +} +@container style(--leo-theme: light) { + :global(.dark) { + --\\.dark_color: unset; + --\\.dark_dark: unset; } - } - - .dark { +} +@container style(--leo-theme: dark) { + :global(.dark) { + --\\.dark_color: white; + --\\.dark_dark: dark; + } +} +.dark { color: var(--\\.dark_color); dark: var(--\\.dark_dark); - } - - .light { +} +.light { color: var(--\\.light_color); light: var(--\\.light_light); - } - - .component { +} +.component { padding: 12px; color: var(--\\.component_color); dark: var(--\\.component_dark); light: var(--\\.component_light); } - - .other { +.other { padding: 12px; color: var(--\\.other_color); dark: var(--\\.other_dark); light: var(--\\.other_light); } - - .no-override { +.no-override { padding: 12px; color: red; }`, {} )) - -it('Handles wrapSelector', () => - run( - `.component { - padding: 12px; - color: white; - background: white; - } - - @theme (light) { - .component { - color: black; - } - } - - @theme (dark) { - .component { - background: black; - } - }`, - `:global(:root), :global(:root[data-theme][data-theme=light]), :global([data-theme][data-theme=light]) { - --\\.component_background: white; - --\\.component_color: black; - } - - :global(:root[data-theme][data-theme=dark]), :global([data-theme][data-theme=dark]) { - --\\.component_background: black; - --\\.component_color: white; - } - - @media (prefers-color-scheme: dark) { - :global(:root) { - --\\.component_background: black; - --\\.component_color: white; - } - } - - .component { - padding: 12px; - background: var(--\\.component_background); - color: var(--\\.component_color); - }`, - { wrapSelector: (selector) => `:global(${selector})` } - ))