Files
twenty/packages/twenty-front-component-renderer/src/utils/splitCssDeclarations.ts
T
Raphaël Bosi b8e2a6e910 Unify remote element style declarations (#23263)
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.
2026-07-28 12:59:33 +00:00

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;
};