diff --git a/packages/core/ui/animation/keyframe-animation.ts b/packages/core/ui/animation/keyframe-animation.ts index d5617034cb..edb7266b76 100644 --- a/packages/core/ui/animation/keyframe-animation.ts +++ b/packages/core/ui/animation/keyframe-animation.ts @@ -15,7 +15,7 @@ export interface Keyframes { keyframes: Array; tag?: string | number; scopedTag?: string; - mediaQueryString?: string; + mediaQueryString?: string | string[]; } export class UnparsedKeyframe { diff --git a/packages/core/ui/styling/css-selector.ts b/packages/core/ui/styling/css-selector.ts index 169046c4b9..451a843c75 100644 --- a/packages/core/ui/styling/css-selector.ts +++ b/packages/core/ui/styling/css-selector.ts @@ -6,8 +6,6 @@ import { isNullOrUndefined } from '../../utils/types'; import * as ReworkCSS from '../../css'; import { checkIfMediaQueryMatches } from '../../media-query-list'; -export const MEDIA_QUERY_SEPARATOR = '&&'; - /** * An interface describing the shape of a type on which the selectors may apply. * Note, the ui/core/view.View implements Node. @@ -830,7 +828,7 @@ export namespace Selector { export class RuleSet { public selectors: SelectorCore[]; public declarations: Declaration[]; - public mediaQueryString: string; + public mediaQueryString: string | string[]; public tag?: string | number; public scopedTag?: string; @@ -997,26 +995,28 @@ function isDeclaration(node: ReworkCSS.Node): node is ReworkCSS.Declaration { return node.type === 'declaration'; } -// Media query strings come from parsed stylesheets, so the distinct set is small -// and stable. Cache the split results as splitting happens on every style query. -const splitMediaQueryCache = new Map(); - -function splitMediaQueryString(mediaQueryString: string): string[] { - let mediaQueryStrings = splitMediaQueryCache.get(mediaQueryString); - if (!mediaQueryStrings) { - mediaQueryStrings = mediaQueryString.split(MEDIA_QUERY_SEPARATOR); - splitMediaQueryCache.set(mediaQueryString, mediaQueryStrings); +export function matchMediaQueryString(mediaQueryString: string | string[], cachedQueries: string[]): boolean { + if (!mediaQueryString) { + return false; } - return mediaQueryStrings; -} + if (typeof mediaQueryString === 'string') { + // Query has already been validated + if (cachedQueries.includes(mediaQueryString)) { + return true; + } + + const result = checkIfMediaQueryMatches(mediaQueryString); + if (result) { + cachedQueries.push(mediaQueryString); + return result; + } -export function matchMediaQueryString(mediaQueryString: string, cachedQueries: string[]): boolean { - // It can be a single or multiple queries in case of nested media queries - const mediaQueryStrings = splitMediaQueryString(mediaQueryString); + return false; + } - for (let i = 0, length = mediaQueryStrings.length; i < length; i++) { - const mq = mediaQueryStrings[i]; + for (let i = 0, length = mediaQueryString.length; i < length; i++) { + const mq = mediaQueryString[i]; // Query has already been validated if (cachedQueries.includes(mq)) { @@ -1097,15 +1097,15 @@ export abstract class SelectorScope implements LookupSorter { } export class MediaQuerySelectorScope extends SelectorScope { - private _mediaQueryString: string; + private _mediaQueryString: string | string[]; - constructor(mediaQueryString: string) { + constructor(mediaQueryString: string | string[]) { super(); this._mediaQueryString = mediaQueryString; } - get mediaQueryString(): string { + get mediaQueryString(): string | string[] { return this._mediaQueryString; } } @@ -1119,7 +1119,7 @@ export class StyleSheetSelectorScope extends SelectorScope { this.lookupRulesets(rulesets); } - private createMediaQuerySelectorScope(mediaQueryString: string): MediaQuerySelectorScope { + private createMediaQuerySelectorScope(mediaQueryString: string | string[]): MediaQuerySelectorScope { const selectorScope = new MediaQuerySelectorScope(mediaQueryString); selectorScope.position = this.position; diff --git a/packages/core/ui/styling/style-scope.ts b/packages/core/ui/styling/style-scope.ts index 4cad7effe4..931e7d18f6 100644 --- a/packages/core/ui/styling/style-scope.ts +++ b/packages/core/ui/styling/style-scope.ts @@ -5,7 +5,7 @@ import { _evaluateCssVariableExpression, _evaluateCssCalcExpression, isCssVariab import { unsetValue } from '../core/properties/property-shared'; import * as ReworkCSS from '../../css'; -import { RuleSet, StyleSheetSelectorScope, SelectorCore, SelectorsMatch, ChangeMap, fromAstNode, Node, MEDIA_QUERY_SEPARATOR, matchMediaQueryString } from './css-selector'; +import { RuleSet, StyleSheetSelectorScope, SelectorCore, SelectorsMatch, ChangeMap, fromAstNode, Node, matchMediaQueryString } from './css-selector'; import { Trace } from './styling-shared'; import { File, knownFolders, path } from '../../file-system'; import { Application, CssChangedEventData, LoadAppCSSEventData } from '../../application'; @@ -317,7 +317,7 @@ function populateRulesFromImports(nodes: ReworkCSS.Node[], rulesets: RuleSet[], } } -export function _populateRules(nodes: ReworkCSS.Node[], rulesets: RuleSet[], keyframes: Keyframes[], mediaQueryString?: string): void { +export function _populateRules(nodes: ReworkCSS.Node[], rulesets: RuleSet[], keyframes: Keyframes[], mediaQueryString?: string | string[]): void { for (const node of nodes) { if (isKeyframe(node)) { const keyframeRule: Keyframes = { @@ -328,8 +328,19 @@ export function _populateRules(nodes: ReworkCSS.Node[], rulesets: RuleSet[], key keyframes.push(keyframeRule); } else if (isMedia(node)) { - // Media query is composite in the case of nested media queries - const compositeMediaQuery = mediaQueryString ? mediaQueryString + MEDIA_QUERY_SEPARATOR + node.media : node.media; + // Media query can be an array of strings in case of nested queries + let compositeMediaQuery: string | string[]; + + if (mediaQueryString) { + if (typeof mediaQueryString === 'string') { + compositeMediaQuery = [mediaQueryString, node.media]; + } else { + mediaQueryString.push(node.media); + compositeMediaQuery = mediaQueryString; + } + } else { + compositeMediaQuery = node.media; + } _populateRules(node.rules, rulesets, keyframes, compositeMediaQuery); } else if (isRule(node)) {