diff --git a/src/compiler/parse/read/css-tree-cq/css_tree_parse.ts b/src/compiler/parse/read/css-tree-cq/css_tree_parse.ts index f25a6d0fc1..d56e6d72ed 100644 --- a/src/compiler/parse/read/css-tree-cq/css_tree_parse.ts +++ b/src/compiler/parse/read/css-tree-cq/css_tree_parse.ts @@ -8,6 +8,7 @@ import * as ContainerFeature from './node/container_feature'; import * as ContainerFeatureRange from './node/container_feature_range'; import * as ContainerFeatureStyle from './node/container_feature_style'; import * as ContainerQuery from './node/container_query'; +import * as QueryCSSFunction from './node/query_css_function'; /** * Extends `css-tree` for container query support by forking and adding new nodes and at-rule support for `@container`. @@ -34,7 +35,8 @@ const cqSyntax = fork({ ContainerFeature, ContainerFeatureRange, ContainerFeatureStyle, - ContainerQuery + ContainerQuery, + QueryCSSFunction } }); diff --git a/src/compiler/parse/read/css-tree-cq/node/container_feature.ts b/src/compiler/parse/read/css-tree-cq/node/container_feature.ts index 1063475462..67d826b076 100644 --- a/src/compiler/parse/read/css-tree-cq/node/container_feature.ts +++ b/src/compiler/parse/read/css-tree-cq/node/container_feature.ts @@ -3,7 +3,8 @@ import { Ident, Number, Dimension, - LeftParenthesis, + Function, + LeftParenthesis, RightParenthesis, Colon, Delim @@ -12,7 +13,7 @@ import { export const name = 'ContainerFeature'; export const structure = { name: String, - value: ['Identifier', 'Number', 'Dimension', 'Ratio', null] + value: ['Identifier', 'Number', 'Dimension', 'QueryCSSFunction', 'Ratio', null] }; export function parse() { @@ -36,19 +37,22 @@ export function parse() { } else { value = this.Number(); } - break; case Dimension: value = this.Dimension(); break; - case Ident: + case Function: + value = this.QueryCSSFunction(); + break; + + case Ident: value = this.Identifier(); break; default: - this.error('Number, dimension, ratio or identifier is expected'); + this.error('Number, dimension, ratio, function, or identifier is expected'); break; } diff --git a/src/compiler/parse/read/css-tree-cq/node/container_feature_range.ts b/src/compiler/parse/read/css-tree-cq/node/container_feature_range.ts index 68b2fc0aa3..62aa5b51d7 100644 --- a/src/compiler/parse/read/css-tree-cq/node/container_feature_range.ts +++ b/src/compiler/parse/read/css-tree-cq/node/container_feature_range.ts @@ -4,6 +4,7 @@ import { Number, Delim, Dimension, + Function, LeftParenthesis, RightParenthesis, WhiteSpace @@ -12,7 +13,7 @@ import { export const name = 'ContainerFeatureRange'; export const structure = { name: String, - value: ['Identifier', 'Number', 'Comparison', 'Dimension', 'Ratio', null] + value: ['Identifier', 'Number', 'Comparison', 'Dimension', 'QueryCSSFunction', 'Ratio', null] }; function lookupNonWSTypeAndValue(offset, type, referenceStr) { @@ -53,12 +54,16 @@ export function parse() { child = this.Dimension(); break; + case Function: + child = this.QueryCSSFunction(); + break; + case Ident: child = this.Identifier(); break; default: - this.error('Number, dimension, comparison, ratio or identifier is expected'); + this.error('Number, dimension, comparison, ratio, function, or identifier is expected'); break; } diff --git a/src/compiler/parse/read/css-tree-cq/node/container_feature_style.ts b/src/compiler/parse/read/css-tree-cq/node/container_feature_style.ts index 7d9b27bf52..50dc1049de 100644 --- a/src/compiler/parse/read/css-tree-cq/node/container_feature_style.ts +++ b/src/compiler/parse/read/css-tree-cq/node/container_feature_style.ts @@ -12,7 +12,7 @@ import { export const name = 'ContainerFeatureStyle'; export const structure = { name: String, - value: ['Function', 'Identifier', 'Number', 'Dimension', 'Ratio', null] + value: ['Function', 'Identifier', 'Number', 'Dimension', 'QueryCSSFunction', 'Ratio', null] }; export function parse() { @@ -40,19 +40,22 @@ export function parse() { } else { value = this.Number(); } - break; case Dimension: value = this.Dimension(); break; - case Ident: + case Function: + value = this.QueryCSSFunction(); + break; + + case Ident: value = this.Identifier(); break; default: - this.error('Number, dimension, ratio or identifier is expected'); + this.error('Number, dimension, ratio, function or identifier is expected'); break; } diff --git a/src/compiler/parse/read/css-tree-cq/node/query_css_function.ts b/src/compiler/parse/read/css-tree-cq/node/query_css_function.ts new file mode 100644 index 0000000000..792aeabd35 --- /dev/null +++ b/src/compiler/parse/read/css-tree-cq/node/query_css_function.ts @@ -0,0 +1,41 @@ +// @ts-nocheck +import { + RightParenthesis +} from 'css-tree/tokenizer'; + +const QUERY_CSS_FUNCTIONS = new Set(['calc', 'clamp', 'min', 'max']); + +export const name = 'QueryCSSFunction'; +export const structure = { + name: String, + expression: String +}; + +export function parse() { + const start = this.tokenStart; + + const name = this.consumeFunctionName(); + + if (!QUERY_CSS_FUNCTIONS.has(name)) { + this.error('Unknown query single value function; expected: "calc", "clamp", "max", min"'); + } + + const body = this.Raw(this.tokenIndex, null, false); + + this.eat(RightParenthesis); + + return { + type: 'QueryCSSFunction', + loc: this.getLocation(start, this.tokenStart), + name, + expression: body.value + }; +} + +export function generate(node) { + this.token(Function, `${node.name}(`); + + this.node(node.expression); + + this.token(RightParenthesis, ')'); +} diff --git a/test/css/samples/container-query/expected.css b/test/css/samples/container-query/expected.css index c5dca3a034..5002ed9c83 100644 --- a/test/css/samples/container-query/expected.css +++ b/test/css/samples/container-query/expected.css @@ -1 +1 @@ -div.svelte-xyz{container:test-container / inline-size}@container (min-width: 400px){div.svelte-xyz{color:red}}@container test-container (min-width: 410px){div.svelte-xyz{color:green}}@container test-container (width < 400px){div.svelte-xyz{color:blue}}@container test-container (0 <= width < 300px){div.svelte-xyz{color:purple}}@container not (width < 400px){div.svelte-xyz{color:pink}}@container (width > 400px) and (height > 400px){div.svelte-xyz{color:lightgreen}}@container (width > 400px) or (height > 400px){div.svelte-xyz{color:lightblue}}@container (width > 400px) and (width > 800px) or (orientation: portrait){div.svelte-xyz{color:salmon}}@container style(color: blue){div.svelte-xyz{color:salmon}} \ No newline at end of file +div.svelte-xyz{container:test-container / inline-size}@container (min-width: 400px){div.svelte-xyz{color:red}}@container test-container (min-width: 410px){div.svelte-xyz{color:green}}@container test-container (width < 400px){div.svelte-xyz{color:blue}}@container test-container (0 <= width < 300px){div.svelte-xyz{color:purple}}@container not (width < 400px){div.svelte-xyz{color:pink}}@container (width > 400px) and (height > 400px){div.svelte-xyz{color:lightgreen}}@container (width > 400px) or (height > 400px){div.svelte-xyz{color:lightblue}}@container (width > 400px) and (width > 800px) or (orientation: portrait){div.svelte-xyz{color:salmon}}@container style(color: blue){div.svelte-xyz{color:tan}}@container test-container (min-width: calc(400px + 1px)){div.svelte-xyz{color:green}}@container test-container (width < clamp(200px, 40%, 400px)){div.svelte-xyz{color:blue}}@container test-container (calc(400px + 1px) <= width < calc(500px + 1px)){div.svelte-xyz{color:purple}}@container style(--var: calc(400px + 1px)){div.svelte-xyz{color:sandybrown}} \ No newline at end of file diff --git a/test/css/samples/container-query/input.svelte b/test/css/samples/container-query/input.svelte index 15dc00d5b1..bb6de73618 100644 --- a/test/css/samples/container-query/input.svelte +++ b/test/css/samples/container-query/input.svelte @@ -57,7 +57,31 @@ @container style(color: blue) { div { - color: salmon; + color: tan; + } + } + + @container test-container (min-width: calc(400px + 1px)) { + div { + color: green; + } + } + + @container test-container (width < clamp(200px, 40%, 400px)) { + div { + color: blue; + } + } + + @container test-container (calc(400px + 1px) <= width < calc(500px + 1px)) { + div { + color: purple; + } + } + + @container style(--var: calc(400px + 1px)) { + div { + color: sandybrown; } }