b8e2a6e910
Front components run in a Web Worker with a fake DOM. Until now the worker had a hand-rolled `style` object for remote elements and the host had its own separate CSS-string parser: two implementations of the same parsing that kept drifting apart (several review rounds fixed edge cases in one copy but not the other). What changed: - One shared `createStyleProxy` now backs `element.style` in the worker, and one shared `parseCssDeclarations` feeds both the worker proxy and the host's `parseCssString`. Most of the diff is existing logic split out of `installStylePropertyOnRemoteElements` into small single-purpose utils (`splitCssDeclarations`, `stripImportantPriorityFromCssValue`, `normalizeCssPropertyName`, `formatCssValue`, ...), not new behavior. - `!important` is stripped from values instead of tracked. Nothing ever read priorities back, and the host applies styles through React inline styles, which cannot express `!important`. Rendering note: `color: red !important` used to reach React as an invalid value (property silently not applied); it now applies, without the priority. - Style writes flush to the host synchronously, exactly as on main. - The parser handles quotes, escapes and parentheses; CSS comments inside hand-written `cssText` are not supported. This shared proxy is also the base for the worker `getComputedStyle` stub in the geometry PR. Second of three PRs splitting the geometry mirror work.
56 lines
1.2 KiB
TypeScript
56 lines
1.2 KiB
TypeScript
export const splitCssDeclarations = (cssText: string): string[] => {
|
|
const declarations: string[] = [];
|
|
|
|
let currentDeclaration = '';
|
|
let quoteCharacter: string | null = null;
|
|
let isEscaped = false;
|
|
let parenthesisDepth = 0;
|
|
|
|
for (const character of cssText) {
|
|
if (quoteCharacter !== null) {
|
|
currentDeclaration += character;
|
|
|
|
if (isEscaped) {
|
|
isEscaped = false;
|
|
} else if (character === '\\') {
|
|
isEscaped = true;
|
|
} else if (character === quoteCharacter) {
|
|
quoteCharacter = null;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (character === '"' || character === "'") {
|
|
quoteCharacter = character;
|
|
currentDeclaration += character;
|
|
continue;
|
|
}
|
|
|
|
if (character === '(') {
|
|
parenthesisDepth += 1;
|
|
currentDeclaration += character;
|
|
continue;
|
|
}
|
|
|
|
if (character === ')') {
|
|
if (parenthesisDepth > 0) {
|
|
parenthesisDepth -= 1;
|
|
}
|
|
currentDeclaration += character;
|
|
continue;
|
|
}
|
|
|
|
if (character === ';' && parenthesisDepth === 0) {
|
|
declarations.push(currentDeclaration);
|
|
currentDeclaration = '';
|
|
continue;
|
|
}
|
|
|
|
currentDeclaration += character;
|
|
}
|
|
|
|
declarations.push(currentDeclaration);
|
|
|
|
return declarations;
|
|
};
|