Skip to content

Commit 220b390

Browse files
committed
Implement scroll-state container queries
Closes parcel-bundler#887, closes parcel-bundler#1031
1 parent 400f705 commit 220b390

File tree

5 files changed

+407
-19
lines changed

5 files changed

+407
-19
lines changed

node/ast.d.ts

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@ export type MediaCondition =
134134
*/
135135
operator: Operator;
136136
type: "operation";
137+
}
138+
| {
139+
type: "unknown";
140+
value: TokenOrValue[];
137141
};
138142
/**
139143
* A generic media feature or container feature.
@@ -6420,7 +6424,7 @@ export type ZIndex =
64206424
/**
64216425
* A value for the [container-type](https://drafts.csswg.org/css-contain-3/#container-type) property. Establishes the element as a query container for the purpose of container queries.
64226426
*/
6423-
export type ContainerType = "normal" | "inline-size" | "size";
6427+
export type ContainerType = "normal" | "inline-size" | "size" | "scroll-state";
64246428
/**
64256429
* A value for the [container-name](https://drafts.csswg.org/css-contain-3/#container-name) property.
64266430
*/
@@ -6944,6 +6948,25 @@ export type PseudoElement =
69446948
*/
69456949
part: ViewTransitionPartSelector;
69466950
}
6951+
| {
6952+
/**
6953+
* A form control identifier.
6954+
*/
6955+
identifier: String;
6956+
kind: "picker-function";
6957+
}
6958+
| {
6959+
kind: "picker-icon";
6960+
}
6961+
| {
6962+
kind: "checkmark";
6963+
}
6964+
| {
6965+
kind: "grammar-error";
6966+
}
6967+
| {
6968+
kind: "spelling-error";
6969+
}
69476970
| {
69486971
kind: "custom";
69496972
/**
@@ -7390,6 +7413,14 @@ export type ContainerCondition<D = Declaration> = | {
73907413
| {
73917414
type: "style";
73927415
value: StyleQuery<D>;
7416+
}
7417+
| {
7418+
type: "scroll-state";
7419+
value: ScrollStateQuery;
7420+
}
7421+
| {
7422+
type: "unknown";
7423+
value: TokenOrValue[];
73937424
};
73947425
/**
73957426
* A generic media feature or container feature.
@@ -7485,6 +7516,97 @@ export type StyleQuery<D = Declaration> = | {
74857516
operator: Operator;
74867517
type: "operation";
74877518
};
7519+
/**
7520+
* Represents a scroll state query within a container condition.
7521+
*/
7522+
export type ScrollStateQuery =
7523+
| {
7524+
type: "feature";
7525+
value: QueryFeatureFor_ScrollStateFeatureId;
7526+
}
7527+
| {
7528+
type: "not";
7529+
value: ScrollStateQuery;
7530+
}
7531+
| {
7532+
/**
7533+
* The conditions for the operator.
7534+
*/
7535+
conditions: ScrollStateQuery[];
7536+
/**
7537+
* The operator for the conditions.
7538+
*/
7539+
operator: Operator;
7540+
type: "operation";
7541+
};
7542+
/**
7543+
* A generic media feature or container feature.
7544+
*/
7545+
export type QueryFeatureFor_ScrollStateFeatureId =
7546+
| {
7547+
/**
7548+
* The name of the feature.
7549+
*/
7550+
name: MediaFeatureNameFor_ScrollStateFeatureId;
7551+
type: "plain";
7552+
/**
7553+
* The feature value.
7554+
*/
7555+
value: MediaFeatureValue;
7556+
}
7557+
| {
7558+
/**
7559+
* The name of the feature.
7560+
*/
7561+
name: MediaFeatureNameFor_ScrollStateFeatureId;
7562+
type: "boolean";
7563+
}
7564+
| {
7565+
/**
7566+
* The name of the feature.
7567+
*/
7568+
name: MediaFeatureNameFor_ScrollStateFeatureId;
7569+
/**
7570+
* A comparator.
7571+
*/
7572+
operator: MediaFeatureComparison;
7573+
type: "range";
7574+
/**
7575+
* The feature value.
7576+
*/
7577+
value: MediaFeatureValue;
7578+
}
7579+
| {
7580+
/**
7581+
* The end value.
7582+
*/
7583+
end: MediaFeatureValue;
7584+
/**
7585+
* A comparator for the end value.
7586+
*/
7587+
endOperator: MediaFeatureComparison;
7588+
/**
7589+
* The name of the feature.
7590+
*/
7591+
name: MediaFeatureNameFor_ScrollStateFeatureId;
7592+
/**
7593+
* A start value.
7594+
*/
7595+
start: MediaFeatureValue;
7596+
/**
7597+
* A comparator for the start value.
7598+
*/
7599+
startOperator: MediaFeatureComparison;
7600+
type: "interval";
7601+
};
7602+
/**
7603+
* A media feature name.
7604+
*/
7605+
export type MediaFeatureNameFor_ScrollStateFeatureId = ScrollStateFeatureId | String | String;
7606+
/**
7607+
* A container query scroll state feature identifier.
7608+
*/
7609+
export type ScrollStateFeatureId = "stuck" | "snapped" | "scrollable" | "scrolled";
74887610
/**
74897611
* A property within a `@view-transition` rule.
74907612
*

src/lib.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9108,6 +9108,12 @@ mod tests {
91089108
"@media (prefers-color-scheme = dark) { .foo { color: chartreuse }}",
91099109
ParserError::InvalidMediaQuery,
91109110
);
9111+
error_test(
9112+
"@media unknown(foo) {}",
9113+
ParserError::UnexpectedToken(crate::properties::custom::Token::Function("unknown".into())),
9114+
);
9115+
9116+
error_recovery_test("@media unknown(foo) {}");
91119117
}
91129118

91139119
#[test]
@@ -29335,6 +29341,56 @@ mod tests {
2933529341
"#,
2933629342
"@container style(width){.foo{color:red}}",
2933729343
);
29344+
minify_test(
29345+
r#"
29346+
@container scroll-state(scrollable: top) {
29347+
.foo {
29348+
color: red;
29349+
}
29350+
}
29351+
"#,
29352+
"@container scroll-state(scrollable:top){.foo{color:red}}",
29353+
);
29354+
minify_test(
29355+
r#"
29356+
@container scroll-state((stuck: top) and (stuck: left)) {
29357+
.foo {
29358+
color: red;
29359+
}
29360+
}
29361+
"#,
29362+
"@container scroll-state((stuck:top) and (stuck:left)){.foo{color:red}}",
29363+
);
29364+
minify_test(
29365+
r#"
29366+
@container scroll-state(not ((scrollable: bottom) and (scrollable: right))) {
29367+
.foo {
29368+
color: red;
29369+
}
29370+
}
29371+
"#,
29372+
"@container scroll-state(not ((scrollable:bottom) and (scrollable:right))){.foo{color:red}}",
29373+
);
29374+
minify_test(
29375+
r#"
29376+
@container (scroll-state(scrollable: inline-end)) {
29377+
.foo {
29378+
color: red;
29379+
}
29380+
}
29381+
"#,
29382+
"@container scroll-state(scrollable:inline-end){.foo{color:red}}",
29383+
);
29384+
minify_test(
29385+
r#"
29386+
@container not scroll-state(scrollable: top) {
29387+
.foo {
29388+
color: red;
29389+
}
29390+
}
29391+
"#,
29392+
"@container not scroll-state(scrollable:top){.foo{color:red}}",
29393+
);
2933829394

2933929395
// Disallow 'none', 'not', 'and', 'or' as a `<container-name>`
2934029396
// https://github.com/w3c/csswg-drafts/issues/7203#issuecomment-1144257312
@@ -29379,6 +29435,16 @@ mod tests {
2937929435
"@container style(style(--foo: bar)) {}",
2938029436
ParserError::UnexpectedToken(crate::properties::custom::Token::Function("style".into())),
2938129437
);
29438+
error_test(
29439+
"@container scroll-state(scroll-state(scrollable: top)) {}",
29440+
ParserError::InvalidMediaQuery,
29441+
);
29442+
error_test(
29443+
"@container unknown(foo) {}",
29444+
ParserError::UnexpectedToken(crate::properties::custom::Token::Function("unknown".into())),
29445+
);
29446+
29447+
error_recovery_test("@container unknown(foo) {}");
2938229448
}
2938329449

2938429450
#[test]

0 commit comments

Comments
 (0)