From 2e6e2275f14c2598292068e3e703fc1c13ec5db6 Mon Sep 17 00:00:00 2001 From: Adam Skoufis Date: Thu, 19 Dec 2024 14:26:46 +1100 Subject: [PATCH 1/4] Allow optional `@layer` property in `createTheme` and `createGlobalTheme` --- packages/css/src/theme.ts | 67 ++++++++++++++++++++++++++++++--------- packages/css/src/types.ts | 4 +++ 2 files changed, 56 insertions(+), 15 deletions(-) diff --git a/packages/css/src/theme.ts b/packages/css/src/theme.ts index fd5ed30b..4667191a 100644 --- a/packages/css/src/theme.ts +++ b/packages/css/src/theme.ts @@ -1,55 +1,77 @@ import type { Contract, MapLeafNodes } from '@vanilla-extract/private'; -import type { ThemeVars, Tokens } from './types'; +import type { GlobalStyleRule, Resolve, ThemeVars, Tokens } from './types'; import { appendCss, registerClassName } from './adapter'; import { getFileScope } from './fileScope'; import { generateIdentifier } from './identifier'; import { createThemeContract, assignVars } from './vars'; +type WithOptionalLayer = T & { + '@layer'?: string; +}; + +type WithoutLayer = Omit; + export function createGlobalTheme( selector: string, - tokens: ThemeTokens, -): ThemeVars; + tokens: WithOptionalLayer, +): Resolve>>; export function createGlobalTheme( selector: string, themeContract: ThemeContract, - tokens: MapLeafNodes, + tokens: WithOptionalLayer>, ): void; export function createGlobalTheme( selector: string, arg2: any, arg3?: any, ): any { - const shouldCreateVars = Boolean(!arg3); + const themeContractProvided = Boolean(arg3); + + const tokenArg = ( + themeContractProvided ? arg3 : arg2 + ) as WithOptionalLayer; - const themeVars = shouldCreateVars - ? createThemeContract(arg2) - : (arg2 as ThemeVars); + const { layerName, tokens } = extractLayerFromTokens(tokenArg); - const tokens = shouldCreateVars ? arg2 : arg3; + const themeContract = themeContractProvided + ? (arg2 as ThemeVars) + : createThemeContract(tokens); + + let rule: GlobalStyleRule = { + vars: assignVars(themeContract, tokens), + }; + + if (layerName) { + rule = { + '@layer': { + [layerName]: rule, + }, + }; + } appendCss( { type: 'global', selector: selector, - rule: { vars: assignVars(themeVars, tokens) }, + rule, }, getFileScope(), ); - if (shouldCreateVars) { - return themeVars; + if (!themeContractProvided) { + return themeContract; } } export function createTheme( themeContract: ThemeContract, - tokens: MapLeafNodes, + tokens: WithOptionalLayer>, debugId?: string, ): string; export function createTheme( - tokens: ThemeTokens, + tokens: WithOptionalLayer, debugId?: string, -): [className: string, vars: ThemeVars]; +): [className: string, vars: Resolve>>]; export function createTheme(arg1: any, arg2?: any, arg3?: string): any { const themeClassName = generateIdentifier( typeof arg2 === 'object' ? arg3 : arg2, @@ -64,3 +86,18 @@ export function createTheme(arg1: any, arg2?: any, arg3?: string): any { return vars ? [themeClassName, vars] : themeClassName; } + +function extractLayerFromTokens( + tokens: WithOptionalLayer>, +): { + layerName?: string; + tokens: MapLeafNodes; +} { + if ('@layer' in tokens) { + const { '@layer': layerName, ...rest } = tokens; + + return { layerName, tokens: rest }; + } + + return { tokens }; +} diff --git a/packages/css/src/types.ts b/packages/css/src/types.ts index 078f0b92..419e8723 100644 --- a/packages/css/src/types.ts +++ b/packages/css/src/types.ts @@ -3,6 +3,10 @@ import type { AtRule, Properties } from 'csstype'; import type { SimplePseudos } from './simplePseudos'; +export type Resolve = { + [Key in keyof T]: T[Key]; +} & {}; + // csstype is yet to ship container property types as they are not in // the output MDN spec files yet. Remove this once that's done. // https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries From d3eec49fa3dec76272bb1515532e57968393a481 Mon Sep 17 00:00:00 2001 From: Adam Skoufis Date: Thu, 19 Dec 2024 14:46:42 +1100 Subject: [PATCH 2/4] Test generated CSS of themes created within layers --- fixtures/themed/src/themes.css.ts | 31 ++++++ .../__snapshots__/rollup-plugin.test.ts.snap | 96 +++++++++++++++---- .../themed-esbuild--development.css | 24 ++++- .../themed-esbuild--production.css | 24 ++++- .../themed-esbuild-next--development.css | 24 ++++- .../themed-esbuild-next--production.css | 24 ++++- .../themed-mini-css-extract--development.css | 24 ++++- .../themed-mini-css-extract--production.css | 24 ++++- .../themed-parcel--development.css | 48 +++++++++- .../themed-parcel--production.css | 48 +++++++++- .../themed-vite--production.css | 24 ++++- 11 files changed, 351 insertions(+), 40 deletions(-) diff --git a/fixtures/themed/src/themes.css.ts b/fixtures/themed/src/themes.css.ts index 9a8aed24..44e125dd 100644 --- a/fixtures/themed/src/themes.css.ts +++ b/fixtures/themed/src/themes.css.ts @@ -3,6 +3,7 @@ import { createTheme, assignVars, style, + layer, } from '@vanilla-extract/css'; export const theme = style({}); @@ -31,6 +32,36 @@ export const altTheme = createTheme(vars, { }, }); +const themeLayer = layer(); + +// Not tested visually, exported for CSS output testing +export const [altTheme2Class, altTheme2Contract] = createTheme({ + '@layer': themeLayer, + colors: { + backgroundColor: 'green', + text: 'white', + }, + space: { + 1: '8px', + 2: '12px', + 3: '16px', + }, +}); + +// Not tested visually, exported for CSS output testing +export const altTheme3 = createGlobalTheme(':root', altTheme2Contract, { + '@layer': 'globalThemeLayer', + colors: { + backgroundColor: 'green', + text: 'white', + }, + space: { + 1: '8px', + 2: '12px', + 3: '16px', + }, +}); + export const responsiveTheme = style({ vars: assignVars(vars, { colors: { diff --git a/packages/rollup-plugin/test/__snapshots__/rollup-plugin.test.ts.snap b/packages/rollup-plugin/test/__snapshots__/rollup-plugin.test.ts.snap index 46e3cb57..ffe7cb1b 100644 --- a/packages/rollup-plugin/test/__snapshots__/rollup-plugin.test.ts.snap +++ b/packages/rollup-plugin/test/__snapshots__/rollup-plugin.test.ts.snap @@ -68,8 +68,10 @@ html .styles_opacity_1\\/4__jteyb17 { }", ], [ - "assets/src/themes.css.ts.vanilla-DMMXGwB8.css", - ":root, .themes_theme__cvta170 { + "assets/src/themes.css.ts.vanilla-s9rcEmBH.css", + "@layer themes_themeLayer__cvta177; +@layer globalThemeLayer; +:root, .themes_theme__cvta170 { --colors-backgroundColor__cvta171: blue; --colors-text__cvta172: white; --space-1__cvta173: 4px; @@ -83,15 +85,33 @@ html .styles_opacity_1\\/4__jteyb17 { --space-2__cvta174: 12px; --space-3__cvta175: 16px; } -.themes_responsiveTheme__cvta177 { +.themes_responsiveTheme__cvta17e { --colors-backgroundColor__cvta171: pink; --colors-text__cvta172: purple; --space-1__cvta173: 6px; --space-2__cvta174: 12px; --space-3__cvta175: 18px; } +@layer themes_themeLayer__cvta177 { + .themes_altTheme2Class__cvta178 { + --colors-backgroundColor__cvta179: green; + --colors-text__cvta17a: white; + --space-1__cvta17b: 8px; + --space-2__cvta17c: 12px; + --space-3__cvta17d: 16px; + } +} +@layer globalThemeLayer { + :root { + --colors-backgroundColor__cvta179: green; + --colors-text__cvta17a: white; + --space-1__cvta17b: 8px; + --space-2__cvta17c: 12px; + --space-3__cvta17d: 16px; + } +} @media screen and (min-width: 768px) { - .themes_responsiveTheme__cvta177 { + .themes_responsiveTheme__cvta17e { --colors-backgroundColor__cvta171: purple; --colors-text__cvta172: pink; } @@ -193,7 +213,7 @@ export { shadow }; [ "src/styles.css.js", "import './../assets/src/shared.css.ts.vanilla-G_Gyt4-e.css'; -import './../assets/src/themes.css.ts.vanilla-DMMXGwB8.css'; +import './../assets/src/themes.css.ts.vanilla-s9rcEmBH.css'; import './../assets/src/styles.css.ts.vanilla-C7NI1Ovc.css'; var button = "styles_button__jteyb13 shared_shadow__4dtfen0 styles_iDunno__jteyb12"; @@ -205,10 +225,10 @@ export { button, container, opacity }; ], [ "src/themes.css.js", - "import './../assets/src/themes.css.ts.vanilla-DMMXGwB8.css'; + "import './../assets/src/themes.css.ts.vanilla-s9rcEmBH.css'; var altTheme = "themes_altTheme__cvta176"; -var responsiveTheme = "themes_responsiveTheme__cvta177"; +var responsiveTheme = "themes_responsiveTheme__cvta17e"; var theme = "themes_theme__cvta170"; var vars = { colors: { backgroundColor: "var(--colors-backgroundColor__cvta171)", text: "var(--colors-text__cvta172)" }, space: { "1": "var(--space-1__cvta173)", "2": "var(--space-2__cvta174)", "3": "var(--space-3__cvta175)" } }; @@ -464,7 +484,7 @@ export { altButton, altContainer, testNodes as default, dynamicVarsButton, dynam "import './themes.css.ts.vanilla.css'; var altTheme = "themes_altTheme__cvta176"; -var responsiveTheme = "themes_responsiveTheme__cvta177"; +var responsiveTheme = "themes_responsiveTheme__cvta17e"; var theme = "themes_theme__cvta170"; var vars = { colors: { backgroundColor: "var(--colors-backgroundColor__cvta171)", text: "var(--colors-text__cvta172)" }, space: { "1": "var(--space-1__cvta173)", "2": "var(--space-2__cvta174)", "3": "var(--space-3__cvta175)" } }; @@ -473,7 +493,9 @@ export { altTheme, responsiveTheme, theme, vars }; ], [ "themes.css.ts.vanilla.css", - ":root, .themes_theme__cvta170 { + "@layer themes_themeLayer__cvta177; +@layer globalThemeLayer; +:root, .themes_theme__cvta170 { --colors-backgroundColor__cvta171: blue; --colors-text__cvta172: white; --space-1__cvta173: 4px; @@ -487,15 +509,33 @@ export { altTheme, responsiveTheme, theme, vars }; --space-2__cvta174: 12px; --space-3__cvta175: 16px; } -.themes_responsiveTheme__cvta177 { +.themes_responsiveTheme__cvta17e { --colors-backgroundColor__cvta171: pink; --colors-text__cvta172: purple; --space-1__cvta173: 6px; --space-2__cvta174: 12px; --space-3__cvta175: 18px; } +@layer themes_themeLayer__cvta177 { + .themes_altTheme2Class__cvta178 { + --colors-backgroundColor__cvta179: green; + --colors-text__cvta17a: white; + --space-1__cvta17b: 8px; + --space-2__cvta17c: 12px; + --space-3__cvta17d: 16px; + } +} +@layer globalThemeLayer { + :root { + --colors-backgroundColor__cvta179: green; + --colors-text__cvta17a: white; + --space-1__cvta17b: 8px; + --space-2__cvta17c: 12px; + --space-3__cvta17d: 16px; + } +} @media screen and (min-width: 768px) { - .themes_responsiveTheme__cvta177 { + .themes_responsiveTheme__cvta17e { --colors-backgroundColor__cvta171: purple; --colors-text__cvta172: pink; } @@ -515,7 +555,7 @@ exports[`rollup-plugin should build with sourcemaps 1`] = ` "", ], [ - "assets/src/themes.css.ts.vanilla-DMMXGwB8.css", + "assets/src/themes.css.ts.vanilla-s9rcEmBH.css", "", ], [ @@ -629,8 +669,10 @@ html .styles_opacity_1\\/4__jteyb17 { }", ], [ - "assets/src/themes.css.ts.vanilla-DMMXGwB8.css", - ":root, .themes_theme__cvta170 { + "assets/src/themes.css.ts.vanilla-s9rcEmBH.css", + "@layer themes_themeLayer__cvta177; +@layer globalThemeLayer; +:root, .themes_theme__cvta170 { --colors-backgroundColor__cvta171: blue; --colors-text__cvta172: white; --space-1__cvta173: 4px; @@ -644,15 +686,33 @@ html .styles_opacity_1\\/4__jteyb17 { --space-2__cvta174: 12px; --space-3__cvta175: 16px; } -.themes_responsiveTheme__cvta177 { +.themes_responsiveTheme__cvta17e { --colors-backgroundColor__cvta171: pink; --colors-text__cvta172: purple; --space-1__cvta173: 6px; --space-2__cvta174: 12px; --space-3__cvta175: 18px; } +@layer themes_themeLayer__cvta177 { + .themes_altTheme2Class__cvta178 { + --colors-backgroundColor__cvta179: green; + --colors-text__cvta17a: white; + --space-1__cvta17b: 8px; + --space-2__cvta17c: 12px; + --space-3__cvta17d: 16px; + } +} +@layer globalThemeLayer { + :root { + --colors-backgroundColor__cvta179: green; + --colors-text__cvta17a: white; + --space-1__cvta17b: 8px; + --space-2__cvta17c: 12px; + --space-3__cvta17d: 16px; + } +} @media screen and (min-width: 768px) { - .themes_responsiveTheme__cvta177 { + .themes_responsiveTheme__cvta17e { --colors-backgroundColor__cvta171: purple; --colors-text__cvta172: pink; } @@ -661,12 +721,12 @@ html .styles_opacity_1\\/4__jteyb17 { [ "index.js", "import { assignInlineVars, setElementVars } from '@vanilla-extract/dynamic'; -import './assets/src/themes.css.ts.vanilla-DMMXGwB8.css'; +import './assets/src/themes.css.ts.vanilla-s9rcEmBH.css'; import './assets/src/shared.css.ts.vanilla-G_Gyt4-e.css'; import './assets/src/styles.css.ts.vanilla-C7NI1Ovc.css'; var altTheme = "themes_altTheme__cvta176"; -var responsiveTheme = "themes_responsiveTheme__cvta177"; +var responsiveTheme = "themes_responsiveTheme__cvta17e"; var theme = "themes_theme__cvta170"; var vars = { colors: { backgroundColor: "var(--colors-backgroundColor__cvta171)", text: "var(--colors-text__cvta172)" }, space: { "1": "var(--space-1__cvta173)", "2": "var(--space-2__cvta174)", "3": "var(--space-3__cvta175)" } }; diff --git a/tests/e2e/themed.playwright.ts-snapshots/themed-esbuild--development.css b/tests/e2e/themed.playwright.ts-snapshots/themed-esbuild--development.css index b446bfc3..607d2913 100644 --- a/tests/e2e/themed.playwright.ts-snapshots/themed-esbuild--development.css +++ b/tests/e2e/themed.playwright.ts-snapshots/themed-esbuild--development.css @@ -1,3 +1,5 @@ +@layer themes_themeLayer__cvta177; +@layer globalThemeLayer; :root, .themes_theme__cvta170 { --colors-backgroundColor__cvta171: blue; @@ -13,15 +15,33 @@ --space-2__cvta174: 12px; --space-3__cvta175: 16px; } -.themes_responsiveTheme__cvta177 { +.themes_responsiveTheme__cvta17e { --colors-backgroundColor__cvta171: pink; --colors-text__cvta172: purple; --space-1__cvta173: 6px; --space-2__cvta174: 12px; --space-3__cvta175: 18px; } +@layer themes_themeLayer__cvta177 { + .themes_altTheme2Class__cvta178 { + --colors-backgroundColor__cvta179: green; + --colors-text__cvta17a: white; + --space-1__cvta17b: 8px; + --space-2__cvta17c: 12px; + --space-3__cvta17d: 16px; + } +} +@layer globalThemeLayer { + :root { + --colors-backgroundColor__cvta179: green; + --colors-text__cvta17a: white; + --space-1__cvta17b: 8px; + --space-2__cvta17c: 12px; + --space-3__cvta17d: 16px; + } +} @media screen and (min-width: 768px) { - .themes_responsiveTheme__cvta177 { + .themes_responsiveTheme__cvta17e { --colors-backgroundColor__cvta171: purple; --colors-text__cvta172: pink; } diff --git a/tests/e2e/themed.playwright.ts-snapshots/themed-esbuild--production.css b/tests/e2e/themed.playwright.ts-snapshots/themed-esbuild--production.css index 241f9bec..8f135508 100644 --- a/tests/e2e/themed.playwright.ts-snapshots/themed-esbuild--production.css +++ b/tests/e2e/themed.playwright.ts-snapshots/themed-esbuild--production.css @@ -1,3 +1,5 @@ +@layer cvta177; +@layer globalThemeLayer; :root, .cvta170 { --cvta171: blue; @@ -13,15 +15,33 @@ --cvta174: 12px; --cvta175: 16px; } -.cvta177 { +.cvta17e { --cvta171: pink; --cvta172: purple; --cvta173: 6px; --cvta174: 12px; --cvta175: 18px; } +@layer cvta177 { + .cvta178 { + --cvta179: green; + --cvta17a: white; + --cvta17b: 8px; + --cvta17c: 12px; + --cvta17d: 16px; + } +} +@layer globalThemeLayer { + :root { + --cvta179: green; + --cvta17a: white; + --cvta17b: 8px; + --cvta17c: 12px; + --cvta17d: 16px; + } +} @media screen and (min-width: 768px) { - .cvta177 { + .cvta17e { --cvta171: purple; --cvta172: pink; } diff --git a/tests/e2e/themed.playwright.ts-snapshots/themed-esbuild-next--development.css b/tests/e2e/themed.playwright.ts-snapshots/themed-esbuild-next--development.css index b446bfc3..607d2913 100644 --- a/tests/e2e/themed.playwright.ts-snapshots/themed-esbuild-next--development.css +++ b/tests/e2e/themed.playwright.ts-snapshots/themed-esbuild-next--development.css @@ -1,3 +1,5 @@ +@layer themes_themeLayer__cvta177; +@layer globalThemeLayer; :root, .themes_theme__cvta170 { --colors-backgroundColor__cvta171: blue; @@ -13,15 +15,33 @@ --space-2__cvta174: 12px; --space-3__cvta175: 16px; } -.themes_responsiveTheme__cvta177 { +.themes_responsiveTheme__cvta17e { --colors-backgroundColor__cvta171: pink; --colors-text__cvta172: purple; --space-1__cvta173: 6px; --space-2__cvta174: 12px; --space-3__cvta175: 18px; } +@layer themes_themeLayer__cvta177 { + .themes_altTheme2Class__cvta178 { + --colors-backgroundColor__cvta179: green; + --colors-text__cvta17a: white; + --space-1__cvta17b: 8px; + --space-2__cvta17c: 12px; + --space-3__cvta17d: 16px; + } +} +@layer globalThemeLayer { + :root { + --colors-backgroundColor__cvta179: green; + --colors-text__cvta17a: white; + --space-1__cvta17b: 8px; + --space-2__cvta17c: 12px; + --space-3__cvta17d: 16px; + } +} @media screen and (min-width: 768px) { - .themes_responsiveTheme__cvta177 { + .themes_responsiveTheme__cvta17e { --colors-backgroundColor__cvta171: purple; --colors-text__cvta172: pink; } diff --git a/tests/e2e/themed.playwright.ts-snapshots/themed-esbuild-next--production.css b/tests/e2e/themed.playwright.ts-snapshots/themed-esbuild-next--production.css index 241f9bec..8f135508 100644 --- a/tests/e2e/themed.playwright.ts-snapshots/themed-esbuild-next--production.css +++ b/tests/e2e/themed.playwright.ts-snapshots/themed-esbuild-next--production.css @@ -1,3 +1,5 @@ +@layer cvta177; +@layer globalThemeLayer; :root, .cvta170 { --cvta171: blue; @@ -13,15 +15,33 @@ --cvta174: 12px; --cvta175: 16px; } -.cvta177 { +.cvta17e { --cvta171: pink; --cvta172: purple; --cvta173: 6px; --cvta174: 12px; --cvta175: 18px; } +@layer cvta177 { + .cvta178 { + --cvta179: green; + --cvta17a: white; + --cvta17b: 8px; + --cvta17c: 12px; + --cvta17d: 16px; + } +} +@layer globalThemeLayer { + :root { + --cvta179: green; + --cvta17a: white; + --cvta17b: 8px; + --cvta17c: 12px; + --cvta17d: 16px; + } +} @media screen and (min-width: 768px) { - .cvta177 { + .cvta17e { --cvta171: purple; --cvta172: pink; } diff --git a/tests/e2e/themed.playwright.ts-snapshots/themed-mini-css-extract--development.css b/tests/e2e/themed.playwright.ts-snapshots/themed-mini-css-extract--development.css index 01fd9157..bc6b6aa0 100644 --- a/tests/e2e/themed.playwright.ts-snapshots/themed-mini-css-extract--development.css +++ b/tests/e2e/themed.playwright.ts-snapshots/themed-mini-css-extract--development.css @@ -1,3 +1,5 @@ +@layer themes_themeLayer__cdwe0v7; +@layer globalThemeLayer; :root, .themes_theme__cdwe0v0 { --colors-backgroundColor__cdwe0v1: blue; @@ -13,15 +15,33 @@ --space-2__cdwe0v4: 12px; --space-3__cdwe0v5: 16px; } -.themes_responsiveTheme__cdwe0v7 { +.themes_responsiveTheme__cdwe0ve { --colors-backgroundColor__cdwe0v1: pink; --colors-text__cdwe0v2: purple; --space-1__cdwe0v3: 6px; --space-2__cdwe0v4: 12px; --space-3__cdwe0v5: 18px; } +@layer themes_themeLayer__cdwe0v7 { + .themes_altTheme2Class__cdwe0v8 { + --colors-backgroundColor__cdwe0v9: green; + --colors-text__cdwe0va: white; + --space-1__cdwe0vb: 8px; + --space-2__cdwe0vc: 12px; + --space-3__cdwe0vd: 16px; + } +} +@layer globalThemeLayer { + :root { + --colors-backgroundColor__cdwe0v9: green; + --colors-text__cdwe0va: white; + --space-1__cdwe0vb: 8px; + --space-2__cdwe0vc: 12px; + --space-3__cdwe0vd: 16px; + } +} @media screen and (min-width: 768px) { - .themes_responsiveTheme__cdwe0v7 { + .themes_responsiveTheme__cdwe0ve { --colors-backgroundColor__cdwe0v1: purple; --colors-text__cdwe0v2: pink; } diff --git a/tests/e2e/themed.playwright.ts-snapshots/themed-mini-css-extract--production.css b/tests/e2e/themed.playwright.ts-snapshots/themed-mini-css-extract--production.css index 852cfaca..6da858d3 100644 --- a/tests/e2e/themed.playwright.ts-snapshots/themed-mini-css-extract--production.css +++ b/tests/e2e/themed.playwright.ts-snapshots/themed-mini-css-extract--production.css @@ -1,3 +1,5 @@ +@layer cdwe0v7; +@layer globalThemeLayer; :root, .cdwe0v0 { --cdwe0v1: blue; @@ -13,15 +15,33 @@ --cdwe0v4: 12px; --cdwe0v5: 16px; } -.cdwe0v7 { +.cdwe0ve { --cdwe0v1: pink; --cdwe0v2: purple; --cdwe0v3: 6px; --cdwe0v4: 12px; --cdwe0v5: 18px; } +@layer cdwe0v7 { + .cdwe0v8 { + --cdwe0v9: green; + --cdwe0va: white; + --cdwe0vb: 8px; + --cdwe0vc: 12px; + --cdwe0vd: 16px; + } +} +@layer globalThemeLayer { + :root { + --cdwe0v9: green; + --cdwe0va: white; + --cdwe0vb: 8px; + --cdwe0vc: 12px; + --cdwe0vd: 16px; + } +} @media screen and (min-width: 768px) { - .cdwe0v7 { + .cdwe0ve { --cdwe0v1: purple; --cdwe0v2: pink; } diff --git a/tests/e2e/themed.playwright.ts-snapshots/themed-parcel--development.css b/tests/e2e/themed.playwright.ts-snapshots/themed-parcel--development.css index 66d98aec..c874cc99 100644 --- a/tests/e2e/themed.playwright.ts-snapshots/themed-parcel--development.css +++ b/tests/e2e/themed.playwright.ts-snapshots/themed-parcel--development.css @@ -1,3 +1,5 @@ +@layer themes_themeLayer__cdwe0v7; +@layer globalThemeLayer; :root, .themes_theme__cdwe0v0 { --colors-backgroundColor__cdwe0v1: blue; @@ -13,15 +15,33 @@ --space-2__cdwe0v4: 12px; --space-3__cdwe0v5: 16px; } -.themes_responsiveTheme__cdwe0v7 { +.themes_responsiveTheme__cdwe0ve { --colors-backgroundColor__cdwe0v1: pink; --colors-text__cdwe0v2: purple; --space-1__cdwe0v3: 6px; --space-2__cdwe0v4: 12px; --space-3__cdwe0v5: 18px; } +@layer themes_themeLayer__cdwe0v7 { + .themes_altTheme2Class__cdwe0v8 { + --colors-backgroundColor__cdwe0v9: green; + --colors-text__cdwe0va: white; + --space-1__cdwe0vb: 8px; + --space-2__cdwe0vc: 12px; + --space-3__cdwe0vd: 16px; + } +} +@layer globalThemeLayer { + :root { + --colors-backgroundColor__cdwe0v9: green; + --colors-text__cdwe0va: white; + --space-1__cdwe0vb: 8px; + --space-2__cdwe0vc: 12px; + --space-3__cdwe0vd: 16px; + } +} @media screen and (min-width: 768px) { - .themes_responsiveTheme__cdwe0v7 { + .themes_responsiveTheme__cdwe0ve { --colors-backgroundColor__cdwe0v1: purple; --colors-text__cdwe0v2: pink; } @@ -36,6 +56,8 @@ body, button { line-height: 16px; } +@layer themes_themeLayer__cdwe0v7; +@layer globalThemeLayer; :root, .themes_theme__cdwe0v0 { --colors-backgroundColor__cdwe0v1: blue; @@ -51,15 +73,33 @@ button { --space-2__cdwe0v4: 12px; --space-3__cdwe0v5: 16px; } -.themes_responsiveTheme__cdwe0v7 { +.themes_responsiveTheme__cdwe0ve { --colors-backgroundColor__cdwe0v1: pink; --colors-text__cdwe0v2: purple; --space-1__cdwe0v3: 6px; --space-2__cdwe0v4: 12px; --space-3__cdwe0v5: 18px; } +@layer themes_themeLayer__cdwe0v7 { + .themes_altTheme2Class__cdwe0v8 { + --colors-backgroundColor__cdwe0v9: green; + --colors-text__cdwe0va: white; + --space-1__cdwe0vb: 8px; + --space-2__cdwe0vc: 12px; + --space-3__cdwe0vd: 16px; + } +} +@layer globalThemeLayer { + :root { + --colors-backgroundColor__cdwe0v9: green; + --colors-text__cdwe0va: white; + --space-1__cdwe0vb: 8px; + --space-2__cdwe0vc: 12px; + --space-3__cdwe0vd: 16px; + } +} @media screen and (min-width: 768px) { - .themes_responsiveTheme__cdwe0v7 { + .themes_responsiveTheme__cdwe0ve { --colors-backgroundColor__cdwe0v1: purple; --colors-text__cdwe0v2: pink; } diff --git a/tests/e2e/themed.playwright.ts-snapshots/themed-parcel--production.css b/tests/e2e/themed.playwright.ts-snapshots/themed-parcel--production.css index 1bea106f..43eaa401 100644 --- a/tests/e2e/themed.playwright.ts-snapshots/themed-parcel--production.css +++ b/tests/e2e/themed.playwright.ts-snapshots/themed-parcel--production.css @@ -1,3 +1,5 @@ +@layer cdwe0v7; +@layer globalThemeLayer; :root, .cdwe0v0 { --cdwe0v1: blue; @@ -13,15 +15,33 @@ --cdwe0v4: 12px; --cdwe0v5: 16px; } -.cdwe0v7 { +.cdwe0ve { --cdwe0v1: pink; --cdwe0v2: purple; --cdwe0v3: 6px; --cdwe0v4: 12px; --cdwe0v5: 18px; } +@layer cdwe0v7 { + .cdwe0v8 { + --cdwe0v9: green; + --cdwe0va: white; + --cdwe0vb: 8px; + --cdwe0vc: 12px; + --cdwe0vd: 16px; + } +} +@layer globalThemeLayer { + :root { + --cdwe0v9: green; + --cdwe0va: white; + --cdwe0vb: 8px; + --cdwe0vc: 12px; + --cdwe0vd: 16px; + } +} @media screen and (min-width: 768px) { - .cdwe0v7 { + .cdwe0ve { --cdwe0v1: purple; --cdwe0v2: pink; } @@ -36,6 +56,8 @@ body, button { line-height: 16px; } +@layer cdwe0v7; +@layer globalThemeLayer; :root, .cdwe0v0 { --cdwe0v1: blue; @@ -51,15 +73,33 @@ button { --cdwe0v4: 12px; --cdwe0v5: 16px; } -.cdwe0v7 { +.cdwe0ve { --cdwe0v1: pink; --cdwe0v2: purple; --cdwe0v3: 6px; --cdwe0v4: 12px; --cdwe0v5: 18px; } +@layer cdwe0v7 { + .cdwe0v8 { + --cdwe0v9: green; + --cdwe0va: white; + --cdwe0vb: 8px; + --cdwe0vc: 12px; + --cdwe0vd: 16px; + } +} +@layer globalThemeLayer { + :root { + --cdwe0v9: green; + --cdwe0va: white; + --cdwe0vb: 8px; + --cdwe0vc: 12px; + --cdwe0vd: 16px; + } +} @media screen and (min-width: 768px) { - .cdwe0v7 { + .cdwe0ve { --cdwe0v1: purple; --cdwe0v2: pink; } diff --git a/tests/e2e/themed.playwright.ts-snapshots/themed-vite--production.css b/tests/e2e/themed.playwright.ts-snapshots/themed-vite--production.css index 241f9bec..8f135508 100644 --- a/tests/e2e/themed.playwright.ts-snapshots/themed-vite--production.css +++ b/tests/e2e/themed.playwright.ts-snapshots/themed-vite--production.css @@ -1,3 +1,5 @@ +@layer cvta177; +@layer globalThemeLayer; :root, .cvta170 { --cvta171: blue; @@ -13,15 +15,33 @@ --cvta174: 12px; --cvta175: 16px; } -.cvta177 { +.cvta17e { --cvta171: pink; --cvta172: purple; --cvta173: 6px; --cvta174: 12px; --cvta175: 18px; } +@layer cvta177 { + .cvta178 { + --cvta179: green; + --cvta17a: white; + --cvta17b: 8px; + --cvta17c: 12px; + --cvta17d: 16px; + } +} +@layer globalThemeLayer { + :root { + --cvta179: green; + --cvta17a: white; + --cvta17b: 8px; + --cvta17c: 12px; + --cvta17d: 16px; + } +} @media screen and (min-width: 768px) { - .cvta177 { + .cvta17e { --cvta171: purple; --cvta172: pink; } From db05f2551da6024191a20d40a26c14f4c5817ed3 Mon Sep 17 00:00:00 2001 From: Adam Skoufis Date: Thu, 19 Dec 2024 15:01:06 +1100 Subject: [PATCH 3/4] Add `@layer` sections to `createTheme` and `createGlobalTheme` docs --- site/docs/api/create-theme.md | 27 +++++++++++++++++++ site/docs/global-api/create-global-theme.md | 30 +++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/site/docs/api/create-theme.md b/site/docs/api/create-theme.md index f664ae85..a6021e55 100644 --- a/site/docs/api/create-theme.md +++ b/site/docs/api/create-theme.md @@ -62,3 +62,30 @@ export const brandText = style({ fontFamily: vars.font.body }); ``` + +## @layer + +Themes can be assigned to a layer by name using the `@layer` key at the top-level of the theme definition. + +> 🚧  Ensure your target browsers [support layers]. +> Vanilla Extract supports the [layers syntax][layer] but does not polyfill the feature in unsupported browsers. + +```ts compiled +// themes.css.ts +import { createTheme, layer } from '@vanilla-extract/css'; + +export const themeLayer = layer(); + +export const [themeA, vars] = createTheme({ + '@layer': themeLayer, + color: { + brand: 'blue' + }, + font: { + body: 'arial' + } +}); +``` + +[support layers]: https://caniuse.com/css-cascade-layers +[layer]: https://developer.mozilla.org/en-US/docs/Web/CSS/@layer diff --git a/site/docs/global-api/create-global-theme.md b/site/docs/global-api/create-global-theme.md index abec1e60..4937643f 100644 --- a/site/docs/global-api/create-global-theme.md +++ b/site/docs/global-api/create-global-theme.md @@ -61,3 +61,33 @@ createGlobalTheme(':root', vars, { } }); ``` + +## @layer + +Global themes can be assigned to a layer by name using the `@layer` key at the top-level of the theme definition. + +> 🚧  Ensure your target browsers [support layers]. +> Vanilla Extract supports the [layers syntax][layer] but does not polyfill the feature in unsupported browsers. + +```ts compiled +// theme.css.ts +import { + createGlobalTheme, + layer +} from '@vanilla-extract/css'; + +export const themeLayer = layer(); + +export const vars = createGlobalTheme(':root', { + '@layer': themeLayer, + color: { + brand: 'blue' + }, + font: { + body: 'arial' + } +}); +``` + +[support layers]: https://caniuse.com/css-cascade-layers +[layer]: https://developer.mozilla.org/en-US/docs/Web/CSS/@layer From 0326d21c9e0e46a85dd9531d87c448f1c438c8d0 Mon Sep 17 00:00:00 2001 From: Adam Skoufis Date: Thu, 19 Dec 2024 15:12:03 +1100 Subject: [PATCH 4/4] Add changeset --- .changeset/nasty-wasps-tie.md | 51 +++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 .changeset/nasty-wasps-tie.md diff --git a/.changeset/nasty-wasps-tie.md b/.changeset/nasty-wasps-tie.md new file mode 100644 index 00000000..a7caf608 --- /dev/null +++ b/.changeset/nasty-wasps-tie.md @@ -0,0 +1,51 @@ +--- +'@vanilla-extract/css': minor +--- + +`createTheme`, `createGlobalTheme`: Add support for assigning themes to a layer + +Themes can now be assigned to a layer by name using the `@layer` key at the top-level of the theme definition. + +**EXAMPLE USAGE**: + +```ts +// themes.css.ts +import { createTheme, createGlobalTheme, layer } from '@vanilla-extract/css'; + +export const themeLayer = layer(); + +export const [themeA, vars] = createTheme({ + '@layer': themeLayer, + color: { + brand: 'blue' + }, + font: { + body: 'arial' + } +}); + +export const vars = createGlobalTheme(':root', { + '@layer': themeLayer, + space: { + small: '10px', + large: '20px', + } +}); +``` + +This will generate the following CSS: + +```css +@layer themes_themeLayer__1k6oxph0; +@layer themes_themeLayer__1k6oxph0 { + .themes_themeA__1k6oxph1 { + --color-brand__1k6oxph2: blue; + --font-body__1k6oxph3: arial; + } + + :root { + --space-small__z05zdf1: 10px; + --space-large__z05zdf2: 20px; + } +} +```