Skip to content
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
5 changes: 5 additions & 0 deletions .changeset/serious-kids-deliver.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"svelte": patch
---

fix: allow `:global(..)` in compound selectors
15 changes: 1 addition & 14 deletions packages/svelte/src/compiler/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ const css = {
`:global(...) can be at the start or end of a selector sequence, but not in the middle`,
'invalid-css-global-selector': () => `:global(...) must contain exactly one selector`,
'invalid-css-global-selector-list': () =>
`:global(...) cannot be used to modify a selector, or be modified by another selector`,
`:global(...) must not contain type or universal selectors when used in a compound selector`,
'invalid-css-selector': () => `Invalid selector`,
'invalid-css-identifier': () => 'Expected a valid CSS identifier'
};
Expand Down Expand Up @@ -447,19 +447,6 @@ const errors = {
// code: 'illegal-variable-declaration',
// message: 'Cannot declare same variable name which is imported inside <script context="module">'
// },
// css_invalid_global_selector: {
// code: 'css-invalid-global-selector',
// message: ':global(...) must contain a single selector'
// },
// css_invalid_global_selector_position: {
// code: 'css-invalid-global-selector-position',
// message:
// ':global(...) not at the start of a selector sequence should not contain type or universal selectors'
// },
// css_invalid_selector: /** @param {string} selector */ (selector) => ({
// code: 'css-invalid-selector',
// message: `Invalid selector "${selector}"`
// }),
// invalid_directive_value: {
// code: 'invalid-directive-value',
// message:
Expand Down
17 changes: 7 additions & 10 deletions packages/svelte/src/compiler/phases/2-analyze/css/Selector.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,18 +177,15 @@ export default class Selector {

validate_global_compound_selector() {
for (const block of this.blocks) {
if (block.selectors.length === 1) continue;

for (let i = 0; i < block.selectors.length; i++) {
const selector = block.selectors[i];
if (
selector.type === 'PseudoClassSelector' &&
selector.name === 'global' &&
block.selectors.length !== 1 &&
(i === block.selectors.length - 1 ||
block.selectors
.slice(i + 1)
.some((s) => s.type !== 'PseudoElementSelector' && s.type !== 'PseudoClassSelector'))
) {
error(selector, 'invalid-css-global-selector-list');
if (selector.type === 'PseudoClassSelector' && selector.name === 'global') {
const child = selector.args?.children[0].children[0];
if (child?.type === 'TypeSelector' && !/[.:#]/.test(child.name[0])) {
error(selector, 'invalid-css-global-selector-list');
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { test } from '../../test';

export default test({
warnings: []
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
div.svelte-xyz.blue {
color: blue;
}
span.blue.x.svelte-xyz {
color: blue;
}
span.x.svelte-xyz.bg {
background: red;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<div class="svelte-xyz">someone could programmatically add a class to this, so having global be part of a modifier is necessary</div>
<span class="x svelte-xyz">-</span>
14 changes: 14 additions & 0 deletions packages/svelte/tests/css/samples/global-with-class/input.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<div>someone could programmatically add a class to this, so having global be part of a modifier is necessary</div>
<span class="x">-</span>

<style>
div:global(.blue) {
color: blue;
}
span:global(.blue).x {
color: blue;
}
span.x:global(.bg) {
background: red;
}
</style>
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[
{
"code": "invalid-css-global-selector-list",
"message": ":global(...) cannot be used to modify a selector, or be modified by another selector",
"message": ":global(...) must not contain type or universal selectors when used in a compound selector",
"start": {
"line": 2,
"column": 5
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[
{
"code": "invalid-css-global-selector-list",
"message": ":global(...) cannot be used to modify a selector, or be modified by another selector",
"message": ":global(...) must not contain type or universal selectors when used in a compound selector",
"start": {
"line": 2,
"column": 5
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ Assignments to destructured parts of a `@const` declaration are no longer allowe

### Stricter CSS `:global` selector validation

Previously, a selector like `.foo :global(bar).baz` was valid. In Svelte 5, this is a validation error instead. The reason is that in this selector the resulting CSS would be equivalent to one without `:global` - in other words, `:global` is ignored in this case.
Previously, a compound selector starting with a global modifier which has universal or type selectors (like `:global(span).foo`) was valid. In Svelte 5, this is a validation error instead. The reason is that in this selector the resulting CSS would be equivalent to one without `:global` - in other words, `:global` is ignored in this case.

### CSS hash position no longer deterministic

Expand Down