From 13d86e901913ba0b953b547be3f06b2c796e57d6 Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Thu, 25 Jul 2024 19:04:07 +0200 Subject: [PATCH] feat: allow `:global` in more places (alternative) (#12560) * `div { :global { &.x { ... } } }` is equivalent to `div:global.x { ... }`, so the latter should be allowed, too * finalize * replace obsolete breaking change (which turned out to be a wrong change and was since reverted), add new breaking change note * changeset * regenerate types * Update sites/svelte-5-preview/src/routes/docs/content/03-appendix/02-breaking-changes.md Co-authored-by: Rich Harris * always remove descendant selector before global * error on lone `:global` with nested `&`, revert "remove spaces" rule * regenerate types * documentation * oops * switch to removing descendant combinator * fix * revert combinator validation relaxation * error on first global being modified * tweak docs * tweak error messages * Update documentation/docs/02-template-syntax/05-styles-and-classes.md Co-authored-by: Rich Harris * clarify * tweak messages * update tests * tweak docs * tweak `:global(...)` docs * tweak docs --------- Co-authored-by: Rich Harris --- .changeset/tricky-balloons-care.md | 5 + .../05-styles-and-classes.md | 47 +++++--- .../svelte/messages/compile-errors/style.md | 20 ++-- packages/svelte/src/compiler/errors.js | 38 +++--- .../phases/2-analyze/css/css-analyze.js | 109 ++++++++++++------ .../phases/2-analyze/css/css-prune.js | 11 +- .../compiler/phases/3-transform/css/index.js | 42 +++++-- packages/svelte/src/compiler/types/css.d.ts | 31 ++++- .../css-global-block-combinator-2/_config.js | 9 ++ .../css-global-block-combinator-2/main.svelte | 11 ++ .../css-global-block-combinator/_config.js | 4 +- .../css-global-block-combinator/main.svelte | 8 +- .../css-global-block-declaration/_config.js | 4 +- .../css-global-block-declaration/main.svelte | 10 ++ .../_config.js | 10 -- .../main.svelte | 8 -- .../css-global-block-modifier/main.svelte | 3 - .../css-global-block-multiple/_config.js | 2 +- .../css-global-modifier-start-1/_config.js | 9 ++ .../css-global-modifier-start-1/main.svelte | 11 ++ .../css-global-modifier-start-2/_config.js | 9 ++ .../css-global-modifier-start-2/main.svelte | 22 ++++ .../_config.js | 4 +- .../samples/css-global-modifier/main.svelte | 11 ++ .../tests/css/samples/global-block/_config.js | 8 +- .../css/samples/global-block/expected.css | 54 +++++++++ .../css/samples/global-block/input.svelte | 53 +++++++++ .../errors.json | 2 +- .../errors.json | 2 +- .../errors.json | 2 +- .../errors.json | 2 +- .../errors.json | 2 +- .../css-invalid-global-placement/errors.json | 2 +- .../css-invalid-global-selector-2/errors.json | 2 +- .../css-invalid-global-selector-3/errors.json | 2 +- .../css-invalid-global-selector-4/errors.json | 2 +- .../css-invalid-global-selector-5/errors.json | 2 +- .../css-invalid-global-selector-6/errors.json | 2 +- .../errors.json | 2 +- .../css-invalid-global-selector/errors.json | 2 +- .../errors.json | 2 +- packages/svelte/types/index.d.ts | 31 ++++- .../03-appendix/02-breaking-changes.md | 13 ++- 43 files changed, 483 insertions(+), 142 deletions(-) create mode 100644 .changeset/tricky-balloons-care.md create mode 100644 packages/svelte/tests/compiler-errors/samples/css-global-block-combinator-2/_config.js create mode 100644 packages/svelte/tests/compiler-errors/samples/css-global-block-combinator-2/main.svelte delete mode 100644 packages/svelte/tests/compiler-errors/samples/css-global-block-invalid-selector/_config.js delete mode 100644 packages/svelte/tests/compiler-errors/samples/css-global-block-invalid-selector/main.svelte delete mode 100644 packages/svelte/tests/compiler-errors/samples/css-global-block-modifier/main.svelte create mode 100644 packages/svelte/tests/compiler-errors/samples/css-global-modifier-start-1/_config.js create mode 100644 packages/svelte/tests/compiler-errors/samples/css-global-modifier-start-1/main.svelte create mode 100644 packages/svelte/tests/compiler-errors/samples/css-global-modifier-start-2/_config.js create mode 100644 packages/svelte/tests/compiler-errors/samples/css-global-modifier-start-2/main.svelte rename packages/svelte/tests/compiler-errors/samples/{css-global-block-modifier => css-global-modifier}/_config.js (56%) create mode 100644 packages/svelte/tests/compiler-errors/samples/css-global-modifier/main.svelte diff --git a/.changeset/tricky-balloons-care.md b/.changeset/tricky-balloons-care.md new file mode 100644 index 0000000000..936f3ecddf --- /dev/null +++ b/.changeset/tricky-balloons-care.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +feat: allow `:global` in more places diff --git a/documentation/docs/02-template-syntax/05-styles-and-classes.md b/documentation/docs/02-template-syntax/05-styles-and-classes.md index 48cdeabce5..4a1497f2e6 100644 --- a/documentation/docs/02-template-syntax/05-styles-and-classes.md +++ b/documentation/docs/02-template-syntax/05-styles-and-classes.md @@ -25,31 +25,28 @@ This works by adding a class to affected elements, which is based on a hash of t ``` -## :global +## :global(...) -To apply styles to a selector globally, use the `:global(...)` modifier. +To apply styles to a single selector globally, use the `:global(...)` modifier: ```svelte ``` @@ -66,6 +63,30 @@ The `-global-` part will be removed when compiled, and the keyframe will then be ``` +## :global + +To apply styles to a group of selectors globally, create a `:global {...}` block: + +```svelte + +``` + +> The second example above could also be written as an equivalent `.a :global .b .c .d` selector, where everything after the `:global` is unscoped, though the nested form is preferred. + ## Nested style tags There should only be 1 top-level ` diff --git a/packages/svelte/tests/compiler-errors/samples/css-global-block-combinator/_config.js b/packages/svelte/tests/compiler-errors/samples/css-global-block-combinator/_config.js index 1014cd34c2..3d701e10b7 100644 --- a/packages/svelte/tests/compiler-errors/samples/css-global-block-combinator/_config.js +++ b/packages/svelte/tests/compiler-errors/samples/css-global-block-combinator/_config.js @@ -3,7 +3,7 @@ import { test } from '../../test'; export default test({ error: { code: 'css_global_block_invalid_combinator', - message: 'A :global {...} block cannot follow a > combinator', - position: [12, 21] + message: 'A `:global` selector cannot follow a `>` combinator', + position: [54, 63] } }); diff --git a/packages/svelte/tests/compiler-errors/samples/css-global-block-combinator/main.svelte b/packages/svelte/tests/compiler-errors/samples/css-global-block-combinator/main.svelte index b3b6ebe6ac..b3af8b4e21 100644 --- a/packages/svelte/tests/compiler-errors/samples/css-global-block-combinator/main.svelte +++ b/packages/svelte/tests/compiler-errors/samples/css-global-block-combinator/main.svelte @@ -1,3 +1,9 @@ diff --git a/packages/svelte/tests/compiler-errors/samples/css-global-block-declaration/_config.js b/packages/svelte/tests/compiler-errors/samples/css-global-block-declaration/_config.js index 3f7a82b54c..776cb9c7d0 100644 --- a/packages/svelte/tests/compiler-errors/samples/css-global-block-declaration/_config.js +++ b/packages/svelte/tests/compiler-errors/samples/css-global-block-declaration/_config.js @@ -3,7 +3,7 @@ import { test } from '../../test'; export default test({ error: { code: 'css_global_block_invalid_declaration', - message: 'A :global {...} block can only contain rules, not declarations', - position: [24, 34] + message: 'A top-level `:global {...}` block can only contain rules, not declarations', + position: [109, 119] } }); diff --git a/packages/svelte/tests/compiler-errors/samples/css-global-block-declaration/main.svelte b/packages/svelte/tests/compiler-errors/samples/css-global-block-declaration/main.svelte index 6a1891ca29..d3374f2aa0 100644 --- a/packages/svelte/tests/compiler-errors/samples/css-global-block-declaration/main.svelte +++ b/packages/svelte/tests/compiler-errors/samples/css-global-block-declaration/main.svelte @@ -1,5 +1,15 @@ diff --git a/packages/svelte/tests/compiler-errors/samples/css-global-block-invalid-selector/_config.js b/packages/svelte/tests/compiler-errors/samples/css-global-block-invalid-selector/_config.js deleted file mode 100644 index 0eb061e41e..0000000000 --- a/packages/svelte/tests/compiler-errors/samples/css-global-block-invalid-selector/_config.js +++ /dev/null @@ -1,10 +0,0 @@ -import { test } from '../../test'; - -export default test({ - error: { - code: 'css_global_block_invalid_placement', - message: - 'A :global {...} block can only appear at the end of a selector sequence (did you mean to use :global(...) instead?)', - position: [50, 57] - } -}); diff --git a/packages/svelte/tests/compiler-errors/samples/css-global-block-invalid-selector/main.svelte b/packages/svelte/tests/compiler-errors/samples/css-global-block-invalid-selector/main.svelte deleted file mode 100644 index 15d721f54f..0000000000 --- a/packages/svelte/tests/compiler-errors/samples/css-global-block-invalid-selector/main.svelte +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/packages/svelte/tests/compiler-errors/samples/css-global-block-modifier/main.svelte b/packages/svelte/tests/compiler-errors/samples/css-global-block-modifier/main.svelte deleted file mode 100644 index 7d274e3894..0000000000 --- a/packages/svelte/tests/compiler-errors/samples/css-global-block-modifier/main.svelte +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/packages/svelte/tests/compiler-errors/samples/css-global-block-multiple/_config.js b/packages/svelte/tests/compiler-errors/samples/css-global-block-multiple/_config.js index 9f06599f7a..9ae4e758c4 100644 --- a/packages/svelte/tests/compiler-errors/samples/css-global-block-multiple/_config.js +++ b/packages/svelte/tests/compiler-errors/samples/css-global-block-multiple/_config.js @@ -3,7 +3,7 @@ import { test } from '../../test'; export default test({ error: { code: 'css_global_block_invalid_list', - message: 'A :global {...} block cannot be part of a selector list with more than one item', + message: 'A `:global` selector cannot be part of a selector list with more than one item', position: [9, 31] } }); diff --git a/packages/svelte/tests/compiler-errors/samples/css-global-modifier-start-1/_config.js b/packages/svelte/tests/compiler-errors/samples/css-global-modifier-start-1/_config.js new file mode 100644 index 0000000000..9f58616ca7 --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/css-global-modifier-start-1/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + error: { + code: 'css_global_block_invalid_modifier_start', + message: 'A `:global` selector can only be modified if it is a descendant of other selectors', + position: [75, 77] + } +}); diff --git a/packages/svelte/tests/compiler-errors/samples/css-global-modifier-start-1/main.svelte b/packages/svelte/tests/compiler-errors/samples/css-global-modifier-start-1/main.svelte new file mode 100644 index 0000000000..027874c7a7 --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/css-global-modifier-start-1/main.svelte @@ -0,0 +1,11 @@ + diff --git a/packages/svelte/tests/compiler-errors/samples/css-global-modifier-start-2/_config.js b/packages/svelte/tests/compiler-errors/samples/css-global-modifier-start-2/_config.js new file mode 100644 index 0000000000..6d4b02adab --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/css-global-modifier-start-2/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + error: { + code: 'css_global_block_invalid_modifier_start', + message: 'A `:global` selector can only be modified if it is a descendant of other selectors', + position: [147, 148] + } +}); diff --git a/packages/svelte/tests/compiler-errors/samples/css-global-modifier-start-2/main.svelte b/packages/svelte/tests/compiler-errors/samples/css-global-modifier-start-2/main.svelte new file mode 100644 index 0000000000..5e5123a1c9 --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/css-global-modifier-start-2/main.svelte @@ -0,0 +1,22 @@ + diff --git a/packages/svelte/tests/compiler-errors/samples/css-global-block-modifier/_config.js b/packages/svelte/tests/compiler-errors/samples/css-global-modifier/_config.js similarity index 56% rename from packages/svelte/tests/compiler-errors/samples/css-global-block-modifier/_config.js rename to packages/svelte/tests/compiler-errors/samples/css-global-modifier/_config.js index 00843fa217..3659ac1d44 100644 --- a/packages/svelte/tests/compiler-errors/samples/css-global-block-modifier/_config.js +++ b/packages/svelte/tests/compiler-errors/samples/css-global-modifier/_config.js @@ -3,7 +3,7 @@ import { test } from '../../test'; export default test({ error: { code: 'css_global_block_invalid_modifier', - message: 'A :global {...} block cannot modify an existing selector', - position: [14, 21] + message: 'A `:global` selector cannot modify an existing selector', + position: [70, 77] } }); diff --git a/packages/svelte/tests/compiler-errors/samples/css-global-modifier/main.svelte b/packages/svelte/tests/compiler-errors/samples/css-global-modifier/main.svelte new file mode 100644 index 0000000000..0cb7273572 --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/css-global-modifier/main.svelte @@ -0,0 +1,11 @@ + diff --git a/packages/svelte/tests/css/samples/global-block/_config.js b/packages/svelte/tests/css/samples/global-block/_config.js index 430b45fe37..bee0d7204d 100644 --- a/packages/svelte/tests/css/samples/global-block/_config.js +++ b/packages/svelte/tests/css/samples/global-block/_config.js @@ -7,14 +7,14 @@ export default test({ code: 'css_unused_selector', message: 'Unused CSS selector ".unused :global"', start: { - line: 16, + line: 69, column: 1, - character: 128 + character: 917 }, end: { - line: 16, + line: 69, column: 16, - character: 143 + character: 932 } } ] diff --git a/packages/svelte/tests/css/samples/global-block/expected.css b/packages/svelte/tests/css/samples/global-block/expected.css index 8bf0f0e596..3acc1b0212 100644 --- a/packages/svelte/tests/css/samples/global-block/expected.css +++ b/packages/svelte/tests/css/samples/global-block/expected.css @@ -1,3 +1,4 @@ + /* :global {*/ .x { color: green; @@ -10,6 +11,59 @@ } } + /* some css preprocessors de-nest :global blocks with a single child + (e.g turn `:global { div { ... } }` into `:global div { ... }`), + so we need to support it, too */ + div { + .y { + color: green; + } + } + + div.svelte-xyz p { + .y { + color: green; + } + } + + /* `div { :global { &.x { ...} } }` is allowed ... */ + div.svelte-xyz { + /* :global {*/ + &.x { + color: green; + } + /*}*/ + } + + /* ...wich is equivalent to `div :global { &.x { ...} }` ... */ + div.svelte-xyz { + &.x { + color: green; + } + } + + /* ...so `div :global.x` must be, too ... */ + div.svelte-xyz.x { + color: green; + } + + /* ...and therefore `div { :global.x { ... }` aswell */ + div.svelte-xyz { + &.x { + color: green; + } + } + + div.svelte-xyz { + &.x { + color: green; + } + } + + div.svelte-xyz:is(html.dark-mode *) { + color: green; + } + /* (unused) .unused :global { .z { color: red; diff --git a/packages/svelte/tests/css/samples/global-block/input.svelte b/packages/svelte/tests/css/samples/global-block/input.svelte index d05a6b7edc..2f2cdfcbd5 100644 --- a/packages/svelte/tests/css/samples/global-block/input.svelte +++ b/packages/svelte/tests/css/samples/global-block/input.svelte @@ -13,6 +13,59 @@ } } + /* some css preprocessors de-nest :global blocks with a single child + (e.g turn `:global { div { ... } }` into `:global div { ... }`), + so we need to support it, too */ + :global div { + .y { + color: green; + } + } + + div :global p { + .y { + color: green; + } + } + + /* `div { :global { &.x { ...} } }` is allowed ... */ + div { + :global { + &.x { + color: green; + } + } + } + + /* ...wich is equivalent to `div :global { &.x { ...} }` ... */ + div :global { + &.x { + color: green; + } + } + + /* ...so `div :global.x` must be, too ... */ + div :global.x { + color: green; + } + + /* ...and therefore `div { :global.x { ... }` aswell */ + div { + :global.x { + color: green; + } + } + + div { + & :global.x { + color: green; + } + } + + div :global:is(html.dark-mode *) { + color: green; + } + .unused :global { .z { color: red; diff --git a/packages/svelte/tests/validator/samples/css-invalid-global-placement-2/errors.json b/packages/svelte/tests/validator/samples/css-invalid-global-placement-2/errors.json index cf556bf4c4..bab7b8a9e9 100644 --- a/packages/svelte/tests/validator/samples/css-invalid-global-placement-2/errors.json +++ b/packages/svelte/tests/validator/samples/css-invalid-global-placement-2/errors.json @@ -1,7 +1,7 @@ [ { "code": "css_global_invalid_placement", - "message": ":global(...) can be at the start or end of a selector sequence, but not in the middle", + "message": "`:global(...)` can be at the start or end of a selector sequence, but not in the middle", "start": { "line": 8, "column": 6 diff --git a/packages/svelte/tests/validator/samples/css-invalid-global-placement-3/errors.json b/packages/svelte/tests/validator/samples/css-invalid-global-placement-3/errors.json index 164daa5796..8ca06aa625 100644 --- a/packages/svelte/tests/validator/samples/css-invalid-global-placement-3/errors.json +++ b/packages/svelte/tests/validator/samples/css-invalid-global-placement-3/errors.json @@ -1,7 +1,7 @@ [ { "code": "css_global_invalid_placement", - "message": ":global(...) can be at the start or end of a selector sequence, but not in the middle", + "message": "`:global(...)` can be at the start or end of a selector sequence, but not in the middle", "start": { "line": 5, "column": 6 diff --git a/packages/svelte/tests/validator/samples/css-invalid-global-placement-4/errors.json b/packages/svelte/tests/validator/samples/css-invalid-global-placement-4/errors.json index 7b63fe4d7a..bf3dce8b7f 100644 --- a/packages/svelte/tests/validator/samples/css-invalid-global-placement-4/errors.json +++ b/packages/svelte/tests/validator/samples/css-invalid-global-placement-4/errors.json @@ -1,7 +1,7 @@ [ { "code": "css_global_invalid_selector_list", - "message": ":global(...) must not contain type or universal selectors when used in a compound selector", + "message": "`:global(...)` must not contain type or universal selectors when used in a compound selector", "start": { "line": 2, "column": 5 diff --git a/packages/svelte/tests/validator/samples/css-invalid-global-placement-5/errors.json b/packages/svelte/tests/validator/samples/css-invalid-global-placement-5/errors.json index fcc75beb5c..6260b09743 100644 --- a/packages/svelte/tests/validator/samples/css-invalid-global-placement-5/errors.json +++ b/packages/svelte/tests/validator/samples/css-invalid-global-placement-5/errors.json @@ -1,7 +1,7 @@ [ { "code": "css_global_invalid_selector_list", - "message": ":global(...) must not contain type or universal selectors when used in a compound selector", + "message": "`:global(...)` must not contain type or universal selectors when used in a compound selector", "start": { "line": 2, "column": 5 diff --git a/packages/svelte/tests/validator/samples/css-invalid-global-placement-6/errors.json b/packages/svelte/tests/validator/samples/css-invalid-global-placement-6/errors.json index e1bc38e0f1..1af01bce50 100644 --- a/packages/svelte/tests/validator/samples/css-invalid-global-placement-6/errors.json +++ b/packages/svelte/tests/validator/samples/css-invalid-global-placement-6/errors.json @@ -1,7 +1,7 @@ [ { "code": "css_global_invalid_selector_list", - "message": ":global(...) must not contain type or universal selectors when used in a compound selector", + "message": "`:global(...)` must not contain type or universal selectors when used in a compound selector", "start": { "line": 5, "column": 5 diff --git a/packages/svelte/tests/validator/samples/css-invalid-global-placement/errors.json b/packages/svelte/tests/validator/samples/css-invalid-global-placement/errors.json index 0b641f2115..484319ef06 100644 --- a/packages/svelte/tests/validator/samples/css-invalid-global-placement/errors.json +++ b/packages/svelte/tests/validator/samples/css-invalid-global-placement/errors.json @@ -1,7 +1,7 @@ [ { "code": "css_global_invalid_placement", - "message": ":global(...) can be at the start or end of a selector sequence, but not in the middle", + "message": "`:global(...)` can be at the start or end of a selector sequence, but not in the middle", "start": { "line": 2, "column": 6 diff --git a/packages/svelte/tests/validator/samples/css-invalid-global-selector-2/errors.json b/packages/svelte/tests/validator/samples/css-invalid-global-selector-2/errors.json index d0be529197..d61411ee96 100644 --- a/packages/svelte/tests/validator/samples/css-invalid-global-selector-2/errors.json +++ b/packages/svelte/tests/validator/samples/css-invalid-global-selector-2/errors.json @@ -1,7 +1,7 @@ [ { "code": "css_global_invalid_selector", - "message": ":global(...) must contain exactly one selector", + "message": "`:global(...)` must contain exactly one selector", "start": { "line": 11, "column": 5 diff --git a/packages/svelte/tests/validator/samples/css-invalid-global-selector-3/errors.json b/packages/svelte/tests/validator/samples/css-invalid-global-selector-3/errors.json index d37ff8d5d1..722e8be23f 100644 --- a/packages/svelte/tests/validator/samples/css-invalid-global-selector-3/errors.json +++ b/packages/svelte/tests/validator/samples/css-invalid-global-selector-3/errors.json @@ -1,7 +1,7 @@ [ { "code": "css_global_invalid_selector", - "message": ":global(...) must contain exactly one selector", + "message": "`:global(...)` must contain exactly one selector", "start": { "line": 5, "column": 5 diff --git a/packages/svelte/tests/validator/samples/css-invalid-global-selector-4/errors.json b/packages/svelte/tests/validator/samples/css-invalid-global-selector-4/errors.json index c05bb647ad..9a20737c5d 100644 --- a/packages/svelte/tests/validator/samples/css-invalid-global-selector-4/errors.json +++ b/packages/svelte/tests/validator/samples/css-invalid-global-selector-4/errors.json @@ -1,7 +1,7 @@ [ { "code": "css_global_invalid_selector", - "message": ":global(...) must contain exactly one selector", + "message": "`:global(...)` must contain exactly one selector", "start": { "line": 2, "column": 5 diff --git a/packages/svelte/tests/validator/samples/css-invalid-global-selector-5/errors.json b/packages/svelte/tests/validator/samples/css-invalid-global-selector-5/errors.json index b1d79c25b8..5317179d5b 100644 --- a/packages/svelte/tests/validator/samples/css-invalid-global-selector-5/errors.json +++ b/packages/svelte/tests/validator/samples/css-invalid-global-selector-5/errors.json @@ -1,7 +1,7 @@ [ { "code": "css_global_invalid_selector", - "message": ":global(...) must contain exactly one selector", + "message": "`:global(...)` must contain exactly one selector", "start": { "line": 5, "column": 1 diff --git a/packages/svelte/tests/validator/samples/css-invalid-global-selector-6/errors.json b/packages/svelte/tests/validator/samples/css-invalid-global-selector-6/errors.json index b1d79c25b8..5317179d5b 100644 --- a/packages/svelte/tests/validator/samples/css-invalid-global-selector-6/errors.json +++ b/packages/svelte/tests/validator/samples/css-invalid-global-selector-6/errors.json @@ -1,7 +1,7 @@ [ { "code": "css_global_invalid_selector", - "message": ":global(...) must contain exactly one selector", + "message": "`:global(...)` must contain exactly one selector", "start": { "line": 5, "column": 1 diff --git a/packages/svelte/tests/validator/samples/css-invalid-global-selector-list/errors.json b/packages/svelte/tests/validator/samples/css-invalid-global-selector-list/errors.json index e9261e5e1c..406fd6129c 100644 --- a/packages/svelte/tests/validator/samples/css-invalid-global-selector-list/errors.json +++ b/packages/svelte/tests/validator/samples/css-invalid-global-selector-list/errors.json @@ -1,7 +1,7 @@ [ { "code": "css_global_invalid_selector_list", - "message": ":global(...) must not contain type or universal selectors when used in a compound selector", + "message": "`:global(...)` must not contain type or universal selectors when used in a compound selector", "start": { "line": 20, "column": 6 diff --git a/packages/svelte/tests/validator/samples/css-invalid-global-selector/errors.json b/packages/svelte/tests/validator/samples/css-invalid-global-selector/errors.json index 3d96fbc1ff..3d8ae68ec0 100644 --- a/packages/svelte/tests/validator/samples/css-invalid-global-selector/errors.json +++ b/packages/svelte/tests/validator/samples/css-invalid-global-selector/errors.json @@ -1,7 +1,7 @@ [ { "code": "css_global_invalid_selector", - "message": ":global(...) must contain exactly one selector", + "message": "`:global(...)` must contain exactly one selector", "start": { "line": 11, "column": 5 diff --git a/packages/svelte/tests/validator/samples/css-invalid-type-selector-placement/errors.json b/packages/svelte/tests/validator/samples/css-invalid-type-selector-placement/errors.json index e7c461b699..5c75d86774 100644 --- a/packages/svelte/tests/validator/samples/css-invalid-type-selector-placement/errors.json +++ b/packages/svelte/tests/validator/samples/css-invalid-type-selector-placement/errors.json @@ -1,7 +1,7 @@ [ { "code": "css_type_selector_invalid_placement", - "message": ":global(...) must not be followed with a type selector", + "message": "`:global(...)` must not be followed by a type selector", "start": { "line": 17, "column": 14 diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index b393174e0f..9de214c847 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -1322,17 +1322,32 @@ declare module 'svelte/compiler' { metadata: { parent_rule: null | Rule; has_local_selectors: boolean; + /** + * `true` if the rule contains a `:global` selector, and therefore everything inside should be unscoped + */ is_global_block: boolean; }; } + /** + * A list of selectors, e.g. `a, b, c {}` + */ export interface SelectorList extends BaseNode { type: 'SelectorList'; + /** + * The `a`, `b` and `c` in `a, b, c {}` + */ children: ComplexSelector[]; } + /** + * A complex selector, e.g. `a b c {}` + */ export interface ComplexSelector extends BaseNode { type: 'ComplexSelector'; + /** + * The `a`, `b` and `c` in `a b c {}` + */ children: RelativeSelector[]; metadata: { rule: null | Rule; @@ -1340,14 +1355,26 @@ declare module 'svelte/compiler' { }; } + /** + * A relative selector, e.g the `a` and `> b` in `a > b {}` + */ export interface RelativeSelector extends BaseNode { type: 'RelativeSelector'; + /** + * In `a > b`, `> b` forms one relative selector, and `>` is the combinator. `null` for the first selector. + */ combinator: null | Combinator; + /** + * The `b:is(...)` in `> b:is(...)` + */ selectors: SimpleSelector[]; metadata: { - /** :global(..) */ + /** + * `true` if the whole selector is unscoped, e.g. `:global(...)` or `:global` or `:global.x`. + * Selectors like `:global(...).x` are not considered global, because they still need scoping. + */ is_global: boolean; - /** :root, :host, ::view-transition */ + /** `:root`, `:host`, `::view-transition`, or selectors after a `:global` */ is_global_like: boolean; scoped: boolean; }; diff --git a/sites/svelte-5-preview/src/routes/docs/content/03-appendix/02-breaking-changes.md b/sites/svelte-5-preview/src/routes/docs/content/03-appendix/02-breaking-changes.md index e85ee2d529..5c475b7ec8 100644 --- a/sites/svelte-5-preview/src/routes/docs/content/03-appendix/02-breaking-changes.md +++ b/sites/svelte-5-preview/src/routes/docs/content/03-appendix/02-breaking-changes.md @@ -202,9 +202,18 @@ This is because the Svelte compiler treated the assignment to `foo.value` as an Assignments to destructured parts of a `@const` declaration are no longer allowed. It was an oversight that this was ever allowed. -### Stricter CSS `:global` selector validation +### :is(...) and :where(...) are scoped -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. +Previously, Svelte did not analyse selectors inside `:is(...)` and `:where(...)`, effectively treating them as global. Svelte 5 analyses them in the context of the current component. As such, some selectors may now be treated as unused if they were relying on this treatment. To fix this, use `:global(...)` inside the `:is(...)/:where(...)` selectors. + +When using Tailwind's `@apply` directive, add a `:global` selector to preserve rules that use Tailwind-generated `:is(...)` selectors: + +```diff +- main { ++ main :global { + @apply bg-blue-100 dark:bg-blue-900 +} +``` ### CSS hash position no longer deterministic