diff --git a/src/browser/__tests__/__snapshots__/index.test.ts.snap b/src/browser/__tests__/__snapshots__/index.test.ts.snap index 853f30a..f74e9f5 100644 --- a/src/browser/__tests__/__snapshots__/index.test.ts.snap +++ b/src/browser/__tests__/__snapshots__/index.test.ts.snap @@ -18,7 +18,7 @@ exports[`with baseThemeId attaches one style node containing overrides with the --containerShadowBase-css:2px 3px orange, -1px 0 8px olive; --modalShadowContainer-css:2px 3px orange, -1px 0 8px olive; } -.compact.compact.secondary-theme:not(#\\\\9){ +.compact.compact.secondary-theme:not(#\\\\9), html.secondary-theme.secondary-theme .compact:not(#\\\\9){ --fontFamilyBase-css:\\"Helvetica Neue\\", Arial, sans-serif; --fontFamilyBody-css:\\"Helvetica Neue\\", Arial, sans-serif; --black-css:purple; @@ -30,7 +30,7 @@ exports[`with baseThemeId attaches one style node containing overrides with the --containerShadowBase-css:2px 3px orange, -1px 0 8px olive; --modalShadowContainer-css:2px 3px orange, -1px 0 8px olive; } -@media not print {.dark.dark.secondary-theme:not(#\\\\9){ +@media not print {.dark.dark.secondary-theme:not(#\\\\9), html.secondary-theme.secondary-theme .dark:not(#\\\\9){ --fontFamilyBase-css:\\"Helvetica Neue\\", Arial, sans-serif; --fontFamilyBody-css:\\"Helvetica Neue\\", Arial, sans-serif; --black-css:purple; @@ -45,7 +45,7 @@ exports[`with baseThemeId attaches one style node containing overrides with the --containerShadowBase-css:2px 3px orange, -1px 0 8px olive; --modalShadowContainer-css:2px 3px orange, -1px 0 8px olive; }} -.disabled-motion.disabled-motion.secondary-theme:not(#\\\\9){ +.disabled-motion.disabled-motion.secondary-theme:not(#\\\\9), html.secondary-theme.secondary-theme .disabled-motion:not(#\\\\9){ --fontFamilyBase-css:\\"Helvetica Neue\\", Arial, sans-serif; --fontFamilyBody-css:\\"Helvetica Neue\\", Arial, sans-serif; --black-css:purple; @@ -74,7 +74,7 @@ exports[`with baseThemeId attaches one style node containing overrides with the --containerShadowBase-css:2px 3px orange, -1px 0 8px olive; --modalShadowContainer-css:2px 3px orange, -1px 0 8px olive; } -.navigation.navigation.secondary-theme:not(#\\\\9){ +.navigation.navigation.secondary-theme:not(#\\\\9), html.secondary-theme.secondary-theme .navigation:not(#\\\\9){ --fontFamilyBase-css:\\"Helvetica Neue\\", Arial, sans-serif; --fontFamilyBody-css:\\"Helvetica Neue\\", Arial, sans-serif; --black-css:purple; @@ -91,7 +91,7 @@ exports[`with baseThemeId attaches one style node containing overrides with the --containerShadowBase-css:2px 3px orange, -1px 0 8px olive; --modalShadowContainer-css:2px 3px orange, -1px 0 8px olive; } -.compact.compact.secondary-theme .navigation:not(#\\\\9){ +.compact.compact.secondary-theme .navigation:not(#\\\\9), html.secondary-theme.secondary-theme .compact .navigation:not(#\\\\9){ --fontFamilyBase-css:\\"Helvetica Neue\\", Arial, sans-serif; --fontFamilyBody-css:\\"Helvetica Neue\\", Arial, sans-serif; --black-css:purple; @@ -103,7 +103,7 @@ exports[`with baseThemeId attaches one style node containing overrides with the --containerShadowBase-css:2px 3px orange, -1px 0 8px olive; --modalShadowContainer-css:2px 3px orange, -1px 0 8px olive; } -.compact.compact.navigation.secondary-theme:not(#\\\\9){ +.compact.compact.navigation.secondary-theme:not(#\\\\9), html.secondary-theme.secondary-theme .compact.navigation:not(#\\\\9){ --fontFamilyBase-css:\\"Helvetica Neue\\", Arial, sans-serif; --fontFamilyBody-css:\\"Helvetica Neue\\", Arial, sans-serif; --black-css:purple; @@ -115,7 +115,7 @@ exports[`with baseThemeId attaches one style node containing overrides with the --containerShadowBase-css:2px 3px orange, -1px 0 8px olive; --modalShadowContainer-css:2px 3px orange, -1px 0 8px olive; } -@media not print {.dark.dark.secondary-theme .navigation:not(#\\\\9){ +@media not print {.dark.dark.secondary-theme .navigation:not(#\\\\9), html.secondary-theme.secondary-theme .dark .navigation:not(#\\\\9){ --fontFamilyBase-css:\\"Helvetica Neue\\", Arial, sans-serif; --fontFamilyBody-css:\\"Helvetica Neue\\", Arial, sans-serif; --black-css:purple; @@ -130,7 +130,7 @@ exports[`with baseThemeId attaches one style node containing overrides with the --containerShadowBase-css:2px 3px orange, -1px 0 8px olive; --modalShadowContainer-css:2px 3px orange, -1px 0 8px olive; }} -@media not print {.dark.dark.navigation.secondary-theme:not(#\\\\9){ +@media not print {.dark.dark.navigation.secondary-theme:not(#\\\\9), html.secondary-theme.secondary-theme .dark.navigation:not(#\\\\9){ --fontFamilyBase-css:\\"Helvetica Neue\\", Arial, sans-serif; --fontFamilyBody-css:\\"Helvetica Neue\\", Arial, sans-serif; --black-css:purple; @@ -145,7 +145,7 @@ exports[`with baseThemeId attaches one style node containing overrides with the --containerShadowBase-css:2px 3px orange, -1px 0 8px olive; --modalShadowContainer-css:2px 3px orange, -1px 0 8px olive; }} -.disabled-motion.disabled-motion.secondary-theme .navigation:not(#\\\\9){ +.disabled-motion.disabled-motion.secondary-theme .navigation:not(#\\\\9), html.secondary-theme.secondary-theme .disabled-motion .navigation:not(#\\\\9){ --fontFamilyBase-css:\\"Helvetica Neue\\", Arial, sans-serif; --fontFamilyBody-css:\\"Helvetica Neue\\", Arial, sans-serif; --black-css:purple; @@ -157,7 +157,7 @@ exports[`with baseThemeId attaches one style node containing overrides with the --containerShadowBase-css:2px 3px orange, -1px 0 8px olive; --modalShadowContainer-css:2px 3px orange, -1px 0 8px olive; } -.disabled-motion.disabled-motion.navigation.secondary-theme:not(#\\\\9){ +.disabled-motion.disabled-motion.navigation.secondary-theme:not(#\\\\9), html.secondary-theme.secondary-theme .disabled-motion.navigation:not(#\\\\9){ --fontFamilyBase-css:\\"Helvetica Neue\\", Arial, sans-serif; --fontFamilyBody-css:\\"Helvetica Neue\\", Arial, sans-serif; --black-css:purple; diff --git a/src/build/__tests__/__snapshots__/public-secondary.test.ts.snap b/src/build/__tests__/__snapshots__/public-secondary.test.ts.snap index 1026d52..01f06fa 100644 --- a/src/build/__tests__/__snapshots__/public-secondary.test.ts.snap +++ b/src/build/__tests__/__snapshots__/public-secondary.test.ts.snap @@ -22,7 +22,7 @@ exports[`Build-time theming of main theme with matching baseThemeId generates th --color-background-button-primary-active-h8she0:#dd6baa; } -.dark-mode.secondary:not(#\\\\9) { +.dark-mode.secondary:not(#\\\\9), html.secondary .dark-mode:not(#\\\\9) { --color-background-button-primary-default-cqohzr:#dd6baa; --color-background-button-primary-active-h8she0:#ec72aa; }" @@ -49,7 +49,7 @@ exports[`Build-time theming of secondary theme generates the correct css files 1 --color-background-button-primary-active-h8she0:#dd6baa; } -.dark-mode.secondary:not(#\\\\9) { +.dark-mode.secondary:not(#\\\\9), html.secondary .dark-mode:not(#\\\\9) { --color-background-button-primary-default-l567s3:#bbbbbb; --color-background-button-primary-active-h8she0:#ec72aa; }" diff --git a/src/build/tasks/postcss/modules.ts b/src/build/tasks/postcss/modules.ts index cb5bc31..79824c8 100644 --- a/src/build/tasks/postcss/modules.ts +++ b/src/build/tasks/postcss/modules.ts @@ -1,5 +1,8 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 export function markGlobal(selector: string): string { - return `:global(${selector})`; + const split = selector.split(',').map((singleSelector) => { + return `:global(${singleSelector})`; + }); + return split.join(','); } diff --git a/src/shared/declaration/__tests__/__snapshots__/index.test.ts.snap b/src/shared/declaration/__tests__/__snapshots__/index.test.ts.snap index e7a8a2f..f059d65 100644 --- a/src/shared/declaration/__tests__/__snapshots__/index.test.ts.snap +++ b/src/shared/declaration/__tests__/__snapshots__/index.test.ts.snap @@ -56,7 +56,7 @@ exports[`renderDeclarations includes secondary theme 1`] = ` --black-css:purple; --brown-css:black; } -@media not print {.dark.secondary-theme{ +@media not print {.dark.secondary-theme, html.secondary-theme .dark{ --shadow-css:purple; --buttonShadow-css:purple; --boxShadow-css:black; @@ -67,18 +67,18 @@ exports[`renderDeclarations includes secondary theme 1`] = ` --buttonShadow-css:purple; --lineShadow-css:purple; } -.navigation.secondary-theme{ +.navigation.secondary-theme, html.secondary-theme .navigation{ --shadow-css:purple; --buttonShadow-css:purple; --lineShadow-css:purple; } -@media not print {.dark.secondary-theme .navigation{ +@media not print {.dark.secondary-theme .navigation, html.secondary-theme .dark .navigation{ --shadow-css:grey; --buttonShadow-css:grey; --boxShadow-css:black; --lineShadow-css:black; }} -@media not print {.dark.navigation.secondary-theme{ +@media not print {.dark.navigation.secondary-theme, html.secondary-theme .dark.navigation{ --shadow-css:grey; --buttonShadow-css:grey; --lineShadow-css:black; @@ -151,16 +151,16 @@ exports[`renderDeclarations renders declarations for theme with non :root select --containerShadowBase-css:2px 3px orange, -1px 0 8px olive; --modalShadowContainer-css:2px 3px orange, -1px 0 8px olive; } -.compact.secondary-theme{ +.compact.secondary-theme, html.secondary-theme .compact{ --scaledSize-css:1px; } -@media not print {.dark.secondary-theme{ +@media not print {.dark.secondary-theme, html.secondary-theme .dark{ --shadow-css:purple; --buttonShadow-css:purple; --boxShadow-css:black; --lineShadow-css:black; }} -.disabled-motion.secondary-theme{ +.disabled-motion.secondary-theme, html.secondary-theme .disabled-motion{ --appear-css:0; } .secondary-theme .navigation{ @@ -169,19 +169,19 @@ exports[`renderDeclarations renders declarations for theme with non :root select --boxShadow-css:purple; --lineShadow-css:purple; } -.navigation.secondary-theme{ +.navigation.secondary-theme, html.secondary-theme .navigation{ --shadow-css:purple; --buttonShadow-css:purple; --boxShadow-css:purple; --lineShadow-css:purple; } -@media not print {.dark.secondary-theme .navigation{ +@media not print {.dark.secondary-theme .navigation, html.secondary-theme .dark .navigation{ --shadow-css:grey; --buttonShadow-css:grey; --boxShadow-css:black; --lineShadow-css:black; }} -@media not print {.dark.navigation.secondary-theme{ +@media not print {.dark.navigation.secondary-theme, html.secondary-theme .dark.navigation{ --shadow-css:grey; --buttonShadow-css:grey; --boxShadow-css:black; diff --git a/src/shared/declaration/__tests__/selector.test.ts b/src/shared/declaration/__tests__/selector.test.ts index 73bf75b..6d6eac0 100644 --- a/src/shared/declaration/__tests__/selector.test.ts +++ b/src/shared/declaration/__tests__/selector.test.ts @@ -9,28 +9,34 @@ describe('Selector', () => { }); test('creates selector for theme', () => { - expect(selector.for({ global: ['.theme'] })).toEqual('.theme'); + expect(selector.for({ theme: ['.theme'] })).toEqual('.theme'); }); test('creates selector for mode', () => { - expect(selector.for({ global: ['.theme', '.mode'] })).toEqual('.mode.theme'); + expect(selector.for({ theme: ['.theme'], modeAndContext: ['.mode'] })).toEqual('.mode.theme, html.theme .mode'); }); test('creates selector for context', () => { - expect(selector.for({ global: ['.theme'], local: ['.context'] })).toEqual('.theme .context'); - expect(selector.for({ global: [':root'], local: ['.context'] })).toEqual('.context'); + expect(selector.for({ theme: ['.theme'], local: ['.context'] })).toEqual('.theme .context'); + expect(selector.for({ theme: [':root'], local: ['.context'] })).toEqual('.context'); }); test('creates selector for context within mode', () => { - expect(selector.for({ global: ['.theme', '.mode'], local: ['.context'] })).toEqual('.mode.theme .context'); + expect(selector.for({ theme: ['.theme'], modeAndContext: ['.mode'], local: ['.context'] })).toEqual( + '.mode.theme .context, html.theme .mode .context' + ); }); test('creates selector for mode with root selector', () => { - expect(selector.for({ global: [':root', '.mode'], local: ['.context'] })).toEqual('.mode .context'); + expect(selector.for({ theme: [':root'], modeAndContext: ['.mode'], local: ['.context'] })).toEqual( + '.mode .context' + ); }); test('customizes each selector when multiple', () => { const selector = new Selector((sel) => `${sel}:not(.theme)`); - expect(selector.for({ global: [':root', '.mode'], local: ['.context'] })).toEqual('.mode .context:not(.theme)'); + expect(selector.for({ theme: [':root'], modeAndContext: ['.mode'], local: ['.context'] })).toEqual( + '.mode .context:not(.theme)' + ); }); }); diff --git a/src/shared/declaration/multi.ts b/src/shared/declaration/multi.ts index 562bcf3..defa6c0 100644 --- a/src/shared/declaration/multi.ts +++ b/src/shared/declaration/multi.ts @@ -60,20 +60,21 @@ export class MultiThemeCreator extends AbstractCreator implements StylesheetCrea appendRulesForSecondary(stylesheet: Stylesheet, primary: Theme, secondary: Theme) { const secondaryResolution = resolveTheme(secondary); const defaults = reduce(secondaryResolution, secondary, defaultsReducer()); - const rootRule = this.ruleCreator.create({ global: [secondary.selector] }, defaults); - const parentRule = this.findRule(stylesheet, { global: [primary.selector] }); + const rootRule = this.ruleCreator.create({ theme: [secondary.selector] }, defaults); + const parentRule = this.findRule(stylesheet, { theme: [primary.selector] }); MultiThemeCreator.appendRuleToStylesheet(stylesheet, rootRule, compact([parentRule])); MultiThemeCreator.forEachOptionalModeState(secondary, (mode, state) => { const optionalState = mode.states[state] as OptionalState; const modeResolution = reduce(secondaryResolution, secondary, modeReducer(mode, state)); const modeRule = this.ruleCreator.create( - { global: [secondary.selector, optionalState.selector], media: optionalState.media }, + { theme: [secondary.selector], modeAndContext: [optionalState.selector], media: optionalState.media }, modeResolution ); const parentModeRule = stylesheet.findRule( this.ruleCreator.selectorFor({ - global: [primary.selector, optionalState.selector], + modeAndContext: [optionalState.selector], + theme: [primary.selector], }) ); MultiThemeCreator.appendRuleToStylesheet(stylesheet, modeRule, compact([rootRule, parentModeRule, parentRule])); @@ -82,12 +83,12 @@ export class MultiThemeCreator extends AbstractCreator implements StylesheetCrea MultiThemeCreator.forEachContext(secondary, (context) => { const contextResolution = reduce(resolveContext(secondary, context), secondary, defaultsReducer()); const contextRule = this.ruleCreator.create( - { global: [secondary.selector], local: [context.selector] }, + { theme: [secondary.selector], local: [context.selector] }, contextResolution ); const parentContextRule = stylesheet.findRule( this.ruleCreator.selectorFor({ - global: [primary.selector], + theme: [primary.selector], local: [context.selector], }) ); @@ -98,7 +99,7 @@ export class MultiThemeCreator extends AbstractCreator implements StylesheetCrea ); const contextRuleGlobal = this.ruleCreator.create( - { global: [secondary.selector, context.selector] }, + { modeAndContext: [context.selector], theme: [secondary.selector] }, contextResolution ); MultiThemeCreator.appendRuleToStylesheet( @@ -111,30 +112,34 @@ export class MultiThemeCreator extends AbstractCreator implements StylesheetCrea MultiThemeCreator.forEachContextWithinOptionalModeState(secondary, (context, mode, state) => { const optionalState = mode.states[state] as OptionalState; const contextResolution = reduce(resolveContext(secondary, context), secondary, modeReducer(mode, state)); - const contextRule = this.findRule(stylesheet, { global: [secondary.selector], local: [context.selector] }); + const contextRule = this.findRule(stylesheet, { theme: [secondary.selector], local: [context.selector] }); const modeRule = this.findRule(stylesheet, { - global: [secondary.selector, optionalState.selector], + theme: [secondary.selector], + modeAndContext: [optionalState.selector], }); const contextAndModeRule = this.ruleCreator.create( { - global: [secondary.selector, optionalState.selector], + modeAndContext: [optionalState.selector], + theme: [secondary.selector], local: [context.selector], media: optionalState.media, }, contextResolution ); const parentContextRule = stylesheet.findRule( - this.ruleCreator.selectorFor({ global: [primary.selector], local: [context.selector] }) + this.ruleCreator.selectorFor({ theme: [primary.selector], local: [context.selector] }) ); const parentModeRule = stylesheet.findRule( this.ruleCreator.selectorFor({ - global: [primary.selector, optionalState.selector], + modeAndContext: [optionalState.selector], + theme: [primary.selector], }) ); const parentContextAndModeRule = stylesheet.findRule( this.ruleCreator.selectorFor({ - global: [primary.selector, optionalState.selector], + modeAndContext: [optionalState.selector], + theme: [primary.selector], local: [context.selector], }) ); @@ -154,12 +159,13 @@ export class MultiThemeCreator extends AbstractCreator implements StylesheetCrea ); const parentContextAndModeRuleGlobal = stylesheet.findRule( - this.ruleCreator.selectorFor({ global: [secondary.selector, context.selector] }) + this.ruleCreator.selectorFor({ theme: [secondary.selector], modeAndContext: [context.selector] }) ); const contextAndModeRuleGlobal = this.ruleCreator.create( { - global: [secondary.selector, optionalState.selector, context.selector], + modeAndContext: [optionalState.selector, context.selector], + theme: [secondary.selector], media: optionalState.media, }, contextResolution diff --git a/src/shared/declaration/rule.ts b/src/shared/declaration/rule.ts index feaa1be..667574e 100644 --- a/src/shared/declaration/rule.ts +++ b/src/shared/declaration/rule.ts @@ -7,7 +7,8 @@ import { entries } from '../utils'; import { SpecificResolution } from '../theme'; export interface SelectorConfig { - global: string[]; + theme: string[]; + modeAndContext?: string[]; local?: string[]; media?: string; } diff --git a/src/shared/declaration/selector.ts b/src/shared/declaration/selector.ts index bf4ca3a..740ad02 100644 --- a/src/shared/declaration/selector.ts +++ b/src/shared/declaration/selector.ts @@ -3,7 +3,8 @@ import type { SelectorCustomizer } from './interfaces'; interface SelectorParams { - global: string[]; + theme: string[]; + modeAndContext?: string[]; local?: string[]; } @@ -14,16 +15,27 @@ export class Selector { this.customizer = customizer; } - for({ global, local }: SelectorParams): string { - if (global.length === 1 && !local?.length && global[0] === ':root') { + // Function to generate .theme -> .mode/context -> .local seletor, it returns: + // ".themeORmode/context .local" OR ".theme.mode/context .local, html.theme .mode/context .local" + for({ theme, modeAndContext = [], local }: SelectorParams): string { + if ([...theme, ...modeAndContext].length === 1 && !local?.length && theme[0] === ':root') { // :root is only applied alone return this.customizer(':root'); } - const globalWithoutRoot = global.filter((f) => f !== ':root'); + const themeWithoutRoot = theme.filter((f) => f !== ':root'); - let selector = this.toSelector(globalWithoutRoot); - if (local?.length) { - selector += ` ${this.toSelector(local)}`; + let selector = this.toSelector([...themeWithoutRoot, ...modeAndContext]); + const localSelector = local?.length ? ` ${this.toSelector(local)}` : ''; + selector += localSelector; + + // Only when .theme and mode/context both exist, we need additional "html.theme .modeORcontext .local" selector + // Because .theme can be in or while .mode/context can be only in + if (themeWithoutRoot.length && modeAndContext.length) { + selector = [ + selector, + `html${this.toSelector(themeWithoutRoot)} ${this.toSelector(modeAndContext)}` + localSelector, + ].join(', '); + return this.customizer(selector.trim()); } return this.customizer(selector.trim()); diff --git a/src/shared/declaration/single.ts b/src/shared/declaration/single.ts index c33ec9e..45e8fbc 100644 --- a/src/shared/declaration/single.ts +++ b/src/shared/declaration/single.ts @@ -32,14 +32,14 @@ export class SingleThemeCreator extends AbstractCreator implements StylesheetCre const stylesheet = new Stylesheet(); const defaults = reduce(this.resolution, this.theme, defaultsReducer()); - const rootRule = this.ruleCreator.create({ global: [this.theme.selector] }, defaults); + const rootRule = this.ruleCreator.create({ theme: [this.theme.selector] }, defaults); SingleThemeCreator.appendRuleToStylesheet(stylesheet, rootRule, []); SingleThemeCreator.forEachOptionalModeState(this.theme, (mode, state) => { const modeResolution = reduce(this.resolution, this.theme, modeReducer(mode, state)); const stateDetails = mode.states[state] as OptionalState; const modeRule = this.ruleCreator.create( - { global: [this.theme.selector, stateDetails.selector], media: stateDetails.media }, + { modeAndContext: [stateDetails.selector], theme: [this.theme.selector], media: stateDetails.media }, modeResolution ); SingleThemeCreator.appendRuleToStylesheet(stylesheet, modeRule, [rootRule]); @@ -48,13 +48,13 @@ export class SingleThemeCreator extends AbstractCreator implements StylesheetCre SingleThemeCreator.forEachContext(this.theme, (context) => { const contextResolution = reduce(resolveContext(this.theme, context), this.theme, defaultsReducer()); const contextRule = this.ruleCreator.create( - { global: [this.theme.selector], local: [context.selector] }, + { theme: [this.theme.selector], local: [context.selector] }, contextResolution ); SingleThemeCreator.appendRuleToStylesheet(stylesheet, contextRule, [rootRule]); const contextRule2 = this.ruleCreator.create( - { global: [this.theme.selector, context.selector] }, + { modeAndContext: [context.selector], theme: [this.theme.selector] }, contextResolution ); SingleThemeCreator.appendRuleToStylesheet(stylesheet, contextRule2, [rootRule]); @@ -64,20 +64,26 @@ export class SingleThemeCreator extends AbstractCreator implements StylesheetCre const contextResolution = reduce(resolveContext(this.theme, context), this.theme, modeReducer(mode, state)); const stateDetails = mode.states[state] as OptionalState; const contextAndModeRule = this.ruleCreator.create( - { global: [this.theme.selector, stateDetails.selector], local: [context.selector], media: stateDetails.media }, + { + modeAndContext: [stateDetails.selector], + theme: [this.theme.selector], + local: [context.selector], + media: stateDetails.media, + }, contextResolution ); const contextRule = stylesheet.findRule( - this.ruleCreator.selectorFor({ global: [this.theme.selector], local: [context.selector] }) + this.ruleCreator.selectorFor({ theme: [this.theme.selector], local: [context.selector] }) ); const modeRule = stylesheet.findRule( this.ruleCreator.selectorFor({ - global: [this.theme.selector, (mode.states[state] as OptionalState).selector], + modeAndContext: [(mode.states[state] as OptionalState).selector], + theme: [this.theme.selector], }) ); const contextRuleGlobal = stylesheet.findRule( - this.ruleCreator.selectorFor({ global: [this.theme.selector, context.selector] }) + this.ruleCreator.selectorFor({ modeAndContext: [context.selector], theme: [this.theme.selector] }) ); SingleThemeCreator.appendRuleToStylesheet( stylesheet, @@ -86,7 +92,11 @@ export class SingleThemeCreator extends AbstractCreator implements StylesheetCre ); const contextRuleAndModeRuleGlobal = this.ruleCreator.create( - { global: [this.theme.selector, stateDetails.selector, context.selector], media: stateDetails.media }, + { + modeAndContext: [stateDetails.selector, context.selector], + theme: [this.theme.selector], + media: stateDetails.media, + }, contextResolution ); SingleThemeCreator.appendRuleToStylesheet( diff --git a/src/shared/styles/selector.ts b/src/shared/styles/selector.ts index 60462a5..cb9e8c8 100644 --- a/src/shared/styles/selector.ts +++ b/src/shared/styles/selector.ts @@ -7,9 +7,12 @@ import { includes } from '../utils'; const specificitySuffix = ':not(#\\9)'; export function increaseSpecificity(selector: string): string { - const [main, ...pseudo] = selector.split(':'); - const pseudoSuffix = pseudo.length ? ':' + pseudo.join(':') : ''; - return `${main}${specificitySuffix}${pseudoSuffix}`; + const split = selector.split(',').map((singleSelector) => { + const [main, ...pseudo] = singleSelector.split(':'); + const pseudoSuffix = pseudo.length ? ':' + pseudo.join(':') : ''; + return `${main}${specificitySuffix}${pseudoSuffix}`; + }); + return split.join(','); } export const isIncreased: (selector: string) => boolean = (selector: string) => includes(selector, specificitySuffix);