Files
twenty/packages/twenty-front-component-renderer/src/utils/__tests__/splitCssDeclarations.test.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

55 lines
1.7 KiB
TypeScript

import { splitCssDeclarations } from '../splitCssDeclarations';
describe('splitCssDeclarations', () => {
it('should split plain declarations on semicolons', () => {
expect(splitCssDeclarations('color: red; font-size: 14px')).toEqual([
'color: red',
' font-size: 14px',
]);
});
it('should keep semicolons inside quoted strings', () => {
expect(splitCssDeclarations('content: "a;b"; color: red')).toEqual([
'content: "a;b"',
' color: red',
]);
});
it('should keep semicolons inside single quoted strings', () => {
expect(splitCssDeclarations("content: 'a;b'")).toEqual(["content: 'a;b'"]);
});
it('should keep semicolons after an escaped quote inside a string', () => {
expect(splitCssDeclarations('content: "a\\";b"; color: red')).toEqual([
'content: "a\\";b"',
' color: red',
]);
});
it('should keep semicolons inside url parentheses', () => {
expect(
splitCssDeclarations(
'background: url(data:image/png;base64,abc); color: red',
),
).toEqual(['background: url(data:image/png;base64,abc)', ' color: red']);
});
it('should keep slash star sequences as plain characters', () => {
expect(
splitCssDeclarations(
'background: url(http://example.com/a/*/b.png); color: red',
),
).toEqual(['background: url(http://example.com/a/*/b.png)', ' color: red']);
});
it('should handle nested parentheses', () => {
expect(
splitCssDeclarations('width: calc(min(10px; 2px)); color: red'),
).toEqual(['width: calc(min(10px; 2px))', ' color: red']);
});
it('should return the whole text when there is no top level semicolon', () => {
expect(splitCssDeclarations('color: red')).toEqual(['color: red']);
});
});