Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: @import CSS at-rule supports both layer and supports #9098

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/odd-poems-admire.md
@@ -0,0 +1,5 @@
---
'svelte': patch
---

@import CSS at-rule now supports layer() and supports() syntax
3 changes: 2 additions & 1 deletion packages/svelte/src/compiler/compile/css/Stylesheet.js
Expand Up @@ -207,7 +207,8 @@ class Atrule {
this.node.name === 'container' ||
this.node.name === 'media' ||
this.node.name === 'supports' ||
this.node.name === 'layer'
this.node.name === 'layer' ||
this.node.name === 'import'
) {
this.children.forEach((child) => {
child.apply(node);
Expand Down
@@ -1,5 +1,6 @@
// @ts-nocheck
import { fork } from 'css-tree';
import { String, Url, Function, Ident, Semicolon } from 'css-tree/tokenizer';

import * as node from './node/index.js';

Expand All @@ -20,6 +21,75 @@ const cqSyntax = fork({
return this.Block(isStyleBlock);
}
}
},
// TODO: Wait until css-tree supports layer() or supports() for import and remove this
import: {
parse: {
prelude() {
const children = this.createList();

this.skipSC();

switch (this.tokenType) {
case String:
children.push(this.String());
break;

case Url:
case Function:
children.push(this.Url());
break;
}

this.skipSC();

if (
this.tokenType === Function &&
this.cmpStr(this.tokenStart, this.tokenEnd, 'layer(')
) {
children.push(
this.Function(() => {
const children = this.createList();
this.skipSC();
children.push(this.LayerName());
this.skipSC();
return children;
}, this.scope.AtrulePrelude)
);
} else if (
this.tokenType === Ident &&
this.cmpStr(this.tokenStart, this.tokenEnd, 'layer')
) {
children.push(this.Identifier());
}

this.skipSC();

if (
this.tokenType === Function &&
this.cmpStr(this.tokenStart, this.tokenEnd, 'supports(')
) {
children.push(
this.Function(() => {
const children = this.createList();
this.skipSC();
children.push(this.SupportsCondition());
this.skipSC();
return children;
}, this.scope.AtrulePrelude)
);
}

this.skipSC();

if (this.tokenType !== Semicolon) {
children.push(this.MediaQueryList());
}

return children;
},
block: null
}
}
},
node
Expand Down
@@ -1,7 +1,9 @@
export * as Comparison from './comparison.js';
export * as ContainerFeatureStyle from './container_feature_style.js';
export * as ContainerQuery from './container_query.js';
export * as LayerName from './layer_name.js';
export * as MediaQuery from './media_query.js';
export * as QueryFeature from './query_feature.js';
export * as QueryFeatureRange from './query_feature_range.js';
export * as QueryCSSFunction from './query_css_function.js';
export * as SupportsCondition from './supports_condition.js';
@@ -0,0 +1,42 @@
// @ts-nocheck
import { Delim, Ident } from 'css-tree/tokenizer';

const FULLSTOP = 0x002e; // U+002E FULL STOP (.)

export const name = 'LayerName';
export const structure = {
name: 'Identifier',
sublayer: ['LayerName', null]
};

// TODO: Wait for css-tree to support a layer name AST and remove this file
export function parse() {
const start = this.tokenStart;
const name = this.Identifier();

const char_idx = this.tokenStart;
const char_code = this.charCodeAt(char_idx);

let sublayer;
if (char_code === FULLSTOP) {
this.next();
sublayer = parse.call(this);
} else {
sublayer = null;
}

return {
type: 'LayerName',
name,
sublayer,
loc: this.getLocation(start, this.tokenStart)
};
}

export function generate(node) {
this.token(Ident, node.name);
this.token(Delim, '.');
if (node.sublayer !== null) {
generate.call(this, node.sublayer);
}
}
@@ -0,0 +1,21 @@
// @ts-nocheck
export const name = 'SupportsCondition';
export const structure = {
children: [[]]
};

// TODO: Wait until css-tree has better @supports condition AST and remove this file
export function parse() {
const start = this.tokenStart;
const support_condition = this.atrule.supports.prelude.call(this);

return {
type: 'SupportsCondition',
children: support_condition,
loc: this.getLocation(start, this.tokenStart)
};
}

export function generate(node) {
this.children(node);
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

@@ -0,0 +1,52 @@
<style>
@import "theme.css";
@import url(themes.css);
@import url("http://themes.css");
@import "theme.css" layer;
@import url(theme.css) layer;
@import url("http://themes.css") layer;
@import "theme.css" layer(abcd);
@import url(theme.css) layer(abcd);
@import url("http://themes.css") layer(abcd);
@import "theme.css" layer(abcd.efgh.ijkl);
@import url(theme.css) layer(abcd.efgh.ijkl);
@import url("http://themes.css") layer(abcd.efgh.ijkl);
@import "theme.css" screen and (orientation: portrait);
@import url(theme.css) screen and (orientation: portrait);
@import url("http://themes.css") screen and (orientation: portrait);
@import "theme.css" layer (min-width: 500px);
@import url(theme.css) layer (min-width: 500px);
@import url("http://themes.css") layer (min-width: 500px);
@import "theme.css" layer(abcd) screen and (orientation: portrait);
@import url(theme.css) layer(abcd) screen and (orientation: portrait);
@import url("http://themes.css") layer(abcd) screen and (orientation: portrait);
@import "theme.css" layer(abcd.efgh.ijkl) (min-width: 500px);
@import url(theme.css) layer(abcd.efgh.ijkl) (min-width: 500px);
@import url("http://themes.css") layer(abcd.efgh.ijkl) (min-width: 500px);

/* As of August 11 2023, supports in @import is supported only by Firefox */
@import "theme.css" supports((display: flex));
@import url(themes.css) supports((selector(h2 > p)) and (font-tech(color-COLRv1)));
@import url("http://themes.css") supports(not (display: grid) and (display: flex));
@import "theme.css" layer supports((selector(h2 > p)) and (font-tech(color-COLRv1)));
@import url(theme.css) layer supports(not (display: grid) and (display: flex));
@import url("http://themes.css") layer supports((display: flex));
@import "theme.css" layer(abcd) supports(not (display: grid) and (display: flex));
@import url(theme.css) layer(abcd) supports((display: flex));
@import url("http://themes.css") layer(abcd) supports((selector(h2 > p)) and (font-tech(color-COLRv1)));
@import "theme.css" layer(abcd.efgh.ijkl) supports((display: flex));
@import url(theme.css) layer(abcd.efgh.ijkl) supports((selector(h2 > p)) and (font-tech(color-COLRv1)));
@import url("http://themes.css") layer(abcd.efgh.ijkl) supports(not (display: grid) and (display: flex));
@import "theme.css" supports((selector(h2 > p)) and (font-tech(color-COLRv1))) screen and (orientation: portrait);
@import url(theme.css) supports(not (display: grid) and (display: flex)) screen and (orientation: portrait);
@import url("http://themes.css") supports((display: flex)) screen and (orientation: portrait);
@import "theme.css" layer supports(not (display: grid) and (display: flex) (min-width: 500px));
@import url(theme.css) layer supports((display : flex)) (min-width: 500px);
@import url("http://themes.css") supports((selector(h2 > p)) and (font-tech(color-COLRv1))) layer (min-width: 500px);
@import "theme.css" layer(abcd) supports(not (display: grid) and (display: flex)) screen and (orientation: portrait);
@import url(theme.css) layer(abcd) supports((display : flex)) screen and (orientation: portrait);
@import url("http://themes.css") layer(abcd) supports((selector(h2 > p)) and (font-tech(color-COLRv1))) screen and (orientation: portrait);
@import "theme.css" layer(abcd.efgh.ijkl) supports(not (display: grid) and (display: flex)) (min-width: 500px);
@import url(theme.css) layer(abcd.efgh.ijkl) supports((display : flex)) (min-width: 500px);
@import url("http://themes.css") layer(abcd.efgh.ijkl) supports((selector(h2 > p)) and (font-tech(color-COLRv1))) (min-width: 500px);
</style>