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

fix(issue:3766) add support for container queries #3811

Merged
merged 4 commits into from
Aug 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14,089 changes: 7,123 additions & 6,966 deletions dist/less.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions dist/less.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/less.min.js.map

Large diffs are not rendered by default.

14,089 changes: 7,123 additions & 6,966 deletions packages/less/dist/less.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions packages/less/dist/less.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/less/dist/less.min.js.map

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions packages/less/src/less/parser/parser-input.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,13 @@ export default () => {
return tok;
};

parserInput.$peekChar = tok => {
if (input.charAt(parserInput.i) !== tok) {
return null;
}
return tok;
};

parserInput.$str = tok => {
const tokLength = tok.length;

Expand Down
95 changes: 62 additions & 33 deletions packages/less/src/less/parser/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import visitors from '../visitors';
import getParserInput from './parser-input';
import * as utils from '../utils';
import functionRegistry from '../functions/function-registry';
import { ContainerSyntaxOptions, MediaSyntaxOptions } from '../tree/atrule-syntax';

//
// less.js - parser
Expand Down Expand Up @@ -1698,7 +1699,7 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
const options = (dir ? this.importOptions() : null) || {};

if ((path = this.entities.quoted() || this.entities.url())) {
features = this.mediaFeatures();
features = this.mediaFeatures({});

if (!parserInput.$char(';')) {
parserInput.i = index;
Expand Down Expand Up @@ -1752,22 +1753,39 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
}
},

mediaFeature: function () {
mediaFeature: function (syntaxOptions) {
const entities = this.entities;
const nodes = [];
let e;
let p;
let rangeP;
parserInput.save();
do {
e = entities.keyword() || entities.variable() || entities.mixinLookup();
if (e) {
nodes.push(e);
} else if (parserInput.$char('(')) {
p = this.property();
e = this.value();
parserInput.save();
if (!p && syntaxOptions.queryInParens && parserInput.$re(/^[0-9a-z-]*\s*([<>]=|<=|>=|[<>]|=)/)) {
parserInput.restore();
p = this.condition();

parserInput.save();
rangeP = this.atomicCondition(null, p.rvalue);
if (!rangeP) {
parserInput.restore();
}
} else {
parserInput.restore();
e = this.value();
}
if (parserInput.$char(')')) {
if (p && e) {
nodes.push(new(tree.Paren)(new(tree.Declaration)(p, e, null, null, parserInput.i + currentIndex, fileInfo, true)));
if (p && !e) {
nodes.push(new (tree.Paren)(new (tree.QueryInParens)(p.op, p.lvalue, p.rvalue, rangeP ? rangeP.op : null, rangeP ? rangeP.rvalue : null, p._index)));
e = p;
} else if (p && e) {
nodes.push(new (tree.Paren)(new (tree.Declaration)(p, e, null, null, parserInput.i + currentIndex, fileInfo, true)));
} else if (e) {
nodes.push(new(tree.Paren)(e));
} else {
Expand All @@ -1785,12 +1803,12 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
}
},

mediaFeatures: function () {
mediaFeatures: function (syntaxOptions) {
const entities = this.entities;
const features = [];
let e;
do {
e = this.mediaFeature();
e = this.mediaFeature(syntaxOptions);
if (e) {
features.push(e);
if (!parserInput.$char(',')) { break; }
Expand All @@ -1806,38 +1824,44 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
return features.length > 0 ? features : null;
},

media: function () {
let features;
let rules;
let media;
prepareAndGetNestableAtRule: function (treeType, index, debugInfo, syntaxOptions) {
const features = this.mediaFeatures(syntaxOptions);

const rules = this.block();

if (!rules) {
error('media definitions require block statements after any features');
}

parserInput.forget();

const atRule = new (treeType)(rules, features, index + currentIndex, fileInfo);
if (context.dumpLineNumbers) {
atRule.debugInfo = debugInfo;
}

return atRule;
},

nestableAtRule: function () {
let debugInfo;
const index = parserInput.i;

if (context.dumpLineNumbers) {
debugInfo = getDebugInfo(index);
}

parserInput.save();

if (parserInput.$str('@media')) {
features = this.mediaFeatures();

rules = this.block();

if (!rules) {
error('media definitions require block statements after any features');
if (parserInput.$peekChar('@')) {
if (parserInput.$str('@media')) {
return this.prepareAndGetNestableAtRule(tree.Media, index, debugInfo, MediaSyntaxOptions);
}

parserInput.forget();

media = new(tree.Media)(rules, features, index + currentIndex, fileInfo);
if (context.dumpLineNumbers) {
media.debugInfo = debugInfo;

if (parserInput.$str('@container')) {
return this.prepareAndGetNestableAtRule(tree.Container, index, debugInfo, ContainerSyntaxOptions);
}

return media;
}

parserInput.restore();
},

Expand Down Expand Up @@ -1919,7 +1943,7 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {

if (parserInput.currentChar() !== '@') { return; }

value = this['import']() || this.plugin() || this.media();
value = this['import']() || this.plugin() || this.nestableAtRule();
if (value) {
return value;
}
Expand Down Expand Up @@ -2231,7 +2255,7 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
parserInput.forget();
return body;
},
atomicCondition: function () {
atomicCondition: function (needsParens, preparsedCond) {
const entities = this.entities;
const index = parserInput.i;
let a;
Expand All @@ -2243,7 +2267,12 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
return this.addition() || entities.keyword() || entities.quoted() || entities.mixinLookup();
}).bind(this)

a = cond();
if (preparsedCond) {
a = preparsedCond;
} else {
a = cond();
}

if (a) {
if (parserInput.$char('>')) {
if (parserInput.$char('=')) {
Expand Down Expand Up @@ -2275,7 +2304,7 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
} else {
error('expected expression');
}
} else {
} else if (!preparsedCond) {
c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index + currentIndex, false);
}
return c;
Expand Down Expand Up @@ -2422,4 +2451,4 @@ Parser.serializeVars = vars => {
return s;
};

export default Parser;
export default Parser;
7 changes: 7 additions & 0 deletions packages/less/src/less/tree/atrule-syntax.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const MediaSyntaxOptions = {
queryInParens: true
};

export const ContainerSyntaxOptions = {
queryInParens: true
};
63 changes: 63 additions & 0 deletions packages/less/src/less/tree/container.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import Ruleset from './ruleset';
import Value from './value';
import Selector from './selector';
import AtRule from './atrule';
import NestableAtRulePrototype from './nested-at-rule';

const Container = function(value, features, index, currentFileInfo, visibilityInfo) {
this._index = index;
this._fileInfo = currentFileInfo;

const selectors = (new Selector([], null, null, this._index, this._fileInfo)).createEmptySelectors();

this.features = new Value(features);
this.rules = [new Ruleset(selectors, value)];
this.rules[0].allowImports = true;
this.copyVisibilityInfo(visibilityInfo);
this.allowRoot = true;
this.setParent(selectors, this);
this.setParent(this.features, this);
this.setParent(this.rules, this);
};

Container.prototype = Object.assign(new AtRule(), {
type: 'Container',

...NestableAtRulePrototype,

genCSS(context, output) {
output.add('@container ', this._fileInfo, this._index);
this.features.genCSS(context, output);
this.outputRuleset(context, output, this.rules);
},

eval(context) {
if (!context.mediaBlocks) {
context.mediaBlocks = [];
context.mediaPath = [];
}

const media = new Container(null, [], this._index, this._fileInfo, this.visibilityInfo());
if (this.debugInfo) {
this.rules[0].debugInfo = this.debugInfo;
media.debugInfo = this.debugInfo;
}

media.features = this.features.eval(context);

context.mediaPath.push(media);
context.mediaBlocks.push(media);

this.rules[0].functionRegistry = context.frames[0].functionRegistry.inherit();
context.frames.unshift(this.rules[0]);
media.rules = [this.rules[0].eval(context)];
context.frames.shift();

context.mediaPath.pop();

return context.mediaPath.length === 0 ? media.evalTop(context) :
media.evalNested(context);
}
});

export default Container;
7 changes: 5 additions & 2 deletions packages/less/src/less/tree/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ import Value from './value';
import JavaScript from './javascript';
import Assignment from './assignment';
import Condition from './condition';
import QueryInParens from './query-in-parens';
import Paren from './paren';
import Media from './media';
import Container from './container';
import UnicodeDescriptor from './unicode-descriptor';
import Negative from './negative';
import Extend from './extend';
Expand All @@ -43,8 +45,9 @@ export default {
Ruleset, Element, Attribute, Combinator, Selector,
Quoted, Expression, Declaration, Call, URL, Import,
Comment, Anonymous, Value, JavaScript, Assignment,
Condition, Paren, Media, UnicodeDescriptor, Negative,
Extend, VariableCall, NamespaceValue,
Condition, Paren, Media, Container, QueryInParens,
UnicodeDescriptor, Negative, Extend, VariableCall,
NamespaceValue,
mixin: {
Call: MixinCall,
Definition: MixinDefinition
Expand Down
Loading