Skip to content

Commit

Permalink
feat(style-compiler): enable :root & :host-context() for native-shado…
Browse files Browse the repository at this point in the history
…w-only CSS (#4833)

Co-authored-by: Nolan Lawson <[email protected]>
  • Loading branch information
cardoso and nolanlawson authored Nov 12, 2024
1 parent bf231db commit c6ca331
Show file tree
Hide file tree
Showing 18 changed files with 82 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:host-context(.foo) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"disableSyntheticShadowSupport": true,
"scoped": true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "CssSyntaxError",
"reason": "Invalid usage of unsupported selector \":host-context\". This selector is only supported in non-scoped CSS where the `disableSyntheticShadowSupport` flag is set to true.",
"column": 1,
"line": 1
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:host-context(.foo) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"disableSyntheticShadowSupport": true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
function stylesheet() {
var token;
var useActualHostSelector = true;
var useNativeDirPseudoclass = true;
var shadowSelector = token ? ("[" + token + "]") : "";
var hostSelector = token ? ("[" + token + "-host]") : "";
var suffixToken = token ? ("-" + token) : "";
return ":host-context(.foo)" + shadowSelector + " {}";
/*LWC compiler vX.X.X*/
}
stylesheet.$nativeOnly$ = true;
export default [stylesheet];
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:root {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"disableSyntheticShadowSupport": true,
"scoped": true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "CssSyntaxError",
"reason": "Invalid usage of unsupported selector \":root\". This selector is only supported in non-scoped CSS where the `disableSyntheticShadowSupport` flag is set to true.",
"column": 1,
"line": 1
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:root {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"disableSyntheticShadowSupport": true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
function stylesheet() {
var token;
var useActualHostSelector = true;
var useNativeDirPseudoclass = true;
var shadowSelector = token ? ("[" + token + "]") : "";
var hostSelector = token ? ("[" + token + "-host]") : "";
var suffixToken = token ? ("-" + token) : "";
return ":root" + shadowSelector + " {}";
/*LWC compiler vX.X.X*/
}
stylesheet.$nativeOnly$ = true;
export default [stylesheet];
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "CssSyntaxError",
"reason": "Invalid usage of unsupported selector \":host-context\".",
"reason": "Invalid usage of unsupported selector \":host-context\". This selector is only supported in non-scoped CSS where the `disableSyntheticShadowSupport` flag is set to true.",
"column": 1,
"line": 1
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "CssSyntaxError",
"reason": "Invalid usage of unsupported selector \":root\".",
"reason": "Invalid usage of unsupported selector \":root\". This selector is only supported in non-scoped CSS where the `disableSyntheticShadowSupport` flag is set to true.",
"column": 1,
"line": 1
}
5 changes: 5 additions & 0 deletions packages/@lwc/style-compiler/src/postcss-lwc-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,20 @@ function selectorProcessorFactory(transformConfig: SelectorScopingConfig) {
export default function postCssLwcPlugin(options: {
scoped: boolean;
apiVersion: APIVersion;
disableSyntheticShadowSupport: boolean;
}): TransformCallback {
// We need 2 types of selectors processors, since transforming the :host selector make the selector
// unusable when used in the context of the native shadow and vice-versa.
// This distinction also applies to light DOM in scoped (synthetic-like) vs unscoped (native-like) mode.
const nativeShadowSelectorProcessor = selectorProcessorFactory({
transformHost: false,
disableSyntheticShadowSupport: options.disableSyntheticShadowSupport,
scoped: options.scoped,
});
const syntheticShadowSelectorProcessor = selectorProcessorFactory({
transformHost: true,
disableSyntheticShadowSupport: options.disableSyntheticShadowSupport,
scoped: options.scoped,
});

return (root, result) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ type ChildNode = Exclude<Node, Selector>;
export interface SelectorScopingConfig {
/** When set to true, the :host selector gets replace with the the scoping token. */
transformHost: boolean;
/** When set to true, the synthetic shadow support is disabled. */
disableSyntheticShadowSupport: boolean;
/** When set to true, the selector is scoped. */
scoped: boolean;
}

function isHostPseudoClass(node: Node): node is Pseudo {
Expand Down Expand Up @@ -145,7 +149,10 @@ function transformHost(selector: Selector) {
}

export default function transformSelector(root: Root, transformConfig: SelectorScopingConfig) {
validateSelectors(root);
validateSelectors(
root,
transformConfig.disableSyntheticShadowSupport && !transformConfig.scoped
);

root.each(scopeSelector);

Expand Down
19 changes: 11 additions & 8 deletions packages/@lwc/style-compiler/src/selector-scoping/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const DEPRECATED_SELECTORS = new Set(['/deep/', '::shadow', '>>>']);
const UNSUPPORTED_SELECTORS = new Set([':root', ':host-context']);
const TEMPLATE_DIRECTIVES = [/^key$/, /^lwc:*/, /^if:*/, /^for:*/, /^iterator:*/];

function validateSelectors(root: Root) {
function validateSelectors(root: Root, native: boolean) {
root.walk((node) => {
const { value, sourceIndex } = node;

Expand All @@ -24,11 +24,14 @@ function validateSelectors(root: Root) {
}

// Ensure the selector doesn't use an unsupported selector.
if (UNSUPPORTED_SELECTORS.has(value)) {
throw root.error(`Invalid usage of unsupported selector "${value}".`, {
index: sourceIndex,
word: value,
});
if (!native && UNSUPPORTED_SELECTORS.has(value)) {
throw root.error(
`Invalid usage of unsupported selector "${value}". This selector is only supported in non-scoped CSS where the \`disableSyntheticShadowSupport\` flag is set to true.`,
{
index: sourceIndex,
word: value,
}
);
}
}
});
Expand All @@ -55,7 +58,7 @@ function validateAttribute(root: Root) {
});
}

export default function validate(root: Root) {
validateSelectors(root);
export default function validate(root: Root, native: boolean) {
validateSelectors(root, native);
validateAttribute(root);
}
3 changes: 2 additions & 1 deletion packages/@lwc/style-compiler/src/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ export function transform(src: string, id: string, config: Config = {}): { code:

const scoped = !!config.scoped;
const apiVersion = getAPIVersionFromNumber(config.apiVersion);
const disableSyntheticShadowSupport = !!config.disableSyntheticShadowSupport;

const plugins = [postcssLwc({ scoped, apiVersion })];
const plugins = [postcssLwc({ scoped, apiVersion, disableSyntheticShadowSupport })];

const result = postcss(plugins).process(src, { from: id }).sync();

Expand Down

0 comments on commit c6ca331

Please sign in to comment.