mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(compiler): namespace @property declarations
The `@property` atrule allows users to define custom CSS variables. These changes update the compiler to account for when namespacing variables.
(cherry picked from commit 9b80d4ce9e)
This commit is contained in:
@@ -1036,32 +1036,33 @@ const _cssColonInPlaceholderReGlobal = new RegExp(COLON_IN_PLACEHOLDER, 'g');
|
||||
|
||||
// Matches any CSS variable name, defined by a double-hyphen followed by any valid ident.
|
||||
// https://www.w3.org/TR/css-syntax-3/#ident-token-diagram
|
||||
const _cssVariableRe = /(var\(\s*)?(--(?:[a-zA-Z0-9_-]|[^\x00-\x7F])+)(\s*:)?/g;
|
||||
const _cssVariableRe = /(var\(\s*|@property\s+)?(--(?:[a-zA-Z0-9_-]|[^\x00-\x7F])+)(\s*:)?/g;
|
||||
|
||||
/**
|
||||
* Transforms CSS variables within a stylesheet to include a namespace placeholder.
|
||||
*
|
||||
* E.g. `--foo: bar;` becomes `--%NS%foo: bar;`
|
||||
* E.g. `color: var(--foo);` becomes `color: var(--%NS%foo);`
|
||||
* E.g. `@property --foo` becomes `@property --%NS%foo`
|
||||
*
|
||||
* If a variable is prefixed with `--global--`, it is NOT namespaced and the prefix is removed.
|
||||
* E.g. `--global--mycolor: red;` becomes `--mycolor: red;`
|
||||
*/
|
||||
export function namespaceCssVariables(cssText: string): string {
|
||||
return cssText.replace(_cssVariableRe, (match, leadingVar, varName, trailingColon) => {
|
||||
// Check for a leading `var(` or trailing `:` to approximate whether we're operating on a
|
||||
// real CSS variable, not another piece of syntax that resembles it. For example, this
|
||||
// guards against:
|
||||
return cssText.replace(_cssVariableRe, (match, prefix, varName, trailingColon) => {
|
||||
// Check for a leading `var(`, `@property`, or trailing `:` to approximate whether we're
|
||||
// operating on a real CSS variable, not another piece of syntax that resembles it.
|
||||
// For example, this guards against:
|
||||
// - `.foo--bar {}`
|
||||
// - `/* --foo */`
|
||||
// - `p { content: "--foo" }`
|
||||
// - `[data---bar] {}`
|
||||
// - `[data-status=foo--bar] {}`
|
||||
// etc.
|
||||
if (!leadingVar && !trailingColon) {
|
||||
if (!prefix && !trailingColon) {
|
||||
return match;
|
||||
}
|
||||
return (leadingVar ?? '') + namespaceCssVariable(varName) + (trailingColon ?? '');
|
||||
return (prefix ?? '') + namespaceCssVariable(varName) + (trailingColon ?? '');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -433,7 +433,7 @@ describe('ShadowCss', () => {
|
||||
const input = `
|
||||
.foo {
|
||||
border: var(--global--border-size) solid var(--border-color);
|
||||
box-shadow:
|
||||
box-shadow:
|
||||
var(--shadow-1),
|
||||
var(--global--shadow-2),
|
||||
var(--shadow-3);
|
||||
@@ -443,7 +443,7 @@ describe('ShadowCss', () => {
|
||||
const expected = `
|
||||
.foo {
|
||||
border: var(--border-size) solid var(--%NS%border-color);
|
||||
box-shadow:
|
||||
box-shadow:
|
||||
var(--%NS%shadow-1),
|
||||
var(--shadow-2),
|
||||
var(--%NS%shadow-3);
|
||||
@@ -597,5 +597,93 @@ p {
|
||||
'CSS variable "--global-" has a single hyphen after "--global". Use two hyphens ("--global--") to opt-out of namespacing.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should namespace @property declarations', () => {
|
||||
const input = `
|
||||
@property --myColor {
|
||||
syntax: "<color>";
|
||||
inherits: true;
|
||||
initial-value: rebeccapurple;
|
||||
}
|
||||
|
||||
@property --myWidth {
|
||||
syntax: "<length> | <percentage>";
|
||||
inherits: true;
|
||||
initial-value: 200px;
|
||||
}
|
||||
|
||||
p {
|
||||
background-color: var(--myColor);
|
||||
width: var(--myWidth);
|
||||
color: white;
|
||||
}
|
||||
`.trim();
|
||||
|
||||
const expected = `
|
||||
@property --%NS%myColor {
|
||||
syntax: "<color>";
|
||||
inherits: true;
|
||||
initial-value: rebeccapurple;
|
||||
}
|
||||
|
||||
@property --%NS%myWidth {
|
||||
syntax: "<length> | <percentage>";
|
||||
inherits: true;
|
||||
initial-value: 200px;
|
||||
}
|
||||
|
||||
p {
|
||||
background-color: var(--%NS%myColor);
|
||||
width: var(--%NS%myWidth);
|
||||
color: white;
|
||||
}
|
||||
`.trim();
|
||||
|
||||
expect(namespaceCssVariables(input)).toBe(expected);
|
||||
});
|
||||
|
||||
it('should not namespace @property if --global-- is present', () => {
|
||||
const input = `
|
||||
@property --global--my-color {
|
||||
syntax: "<color>";
|
||||
inherits: true;
|
||||
initial-value: rebeccapurple;
|
||||
}
|
||||
|
||||
@property --global--my-width {
|
||||
syntax: "<length> | <percentage>";
|
||||
inherits: true;
|
||||
initial-value: 200px;
|
||||
}
|
||||
|
||||
p {
|
||||
background-color: var(--global--my-color);
|
||||
width: var(--global--my-width);
|
||||
color: white;
|
||||
}
|
||||
`.trim();
|
||||
|
||||
const expected = `
|
||||
@property --my-color {
|
||||
syntax: "<color>";
|
||||
inherits: true;
|
||||
initial-value: rebeccapurple;
|
||||
}
|
||||
|
||||
@property --my-width {
|
||||
syntax: "<length> | <percentage>";
|
||||
inherits: true;
|
||||
initial-value: 200px;
|
||||
}
|
||||
|
||||
p {
|
||||
background-color: var(--my-color);
|
||||
width: var(--my-width);
|
||||
color: white;
|
||||
}
|
||||
`.trim();
|
||||
|
||||
expect(namespaceCssVariables(input)).toBe(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user