Skip to content

Commit

Permalink
fix(transfrom): global() and nested styles (#45)
Browse files Browse the repository at this point in the history
* fix(transfrom): global() and nested styles

* chore: changeset

* update tests & remove weakref

* use a symbol

---------

Co-authored-by: Oleksandr Fediashov <olfedias@microsoft.com>
  • Loading branch information
Anber and layershifter authored Feb 5, 2024
1 parent d2d3f6a commit edf8c81
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 12 deletions.
5 changes: 5 additions & 0 deletions .changeset/brave-nails-draw.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@wyw-in-js/transform': patch
---

Fix support of :global() selector in nested rules (fixes #42)
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,18 @@ describe('stylisGlobalPlugin', () => {
).toMatchInlineSnapshot(`".global .component {color:red;}"`);
});

it('multi-level nested selector', () => {
expect(
compileRule(
'.component :global() { .global { .nested { color: red } } }'
)
).toMatchInlineSnapshot(`".global .nested {color:red;}"`);

expect(
compileRule(':global() { body { .someClassName { color: red; } } }')
).toMatchInlineSnapshot(`"body .someClassName {color:red;}"`);
});

it('multiple selectors', () => {
const cssRuleA = dedent(`
.component :global() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
tokenize,
RULESET,
} from 'stylis';
import type { Middleware } from 'stylis';
import type { Middleware, Element } from 'stylis';

import type { Options } from '../../types';

Expand All @@ -34,11 +34,36 @@ export function transformUrl(
return relative.split(platformPath.sep).join(POSIX_SEP);
}

interface IGlobalSelectorModifiers {
includeBaseSelector: boolean;
includeSpaceDelimiter: boolean;
}

const ORIGINAL_VALUE_KEY = Symbol('originalValue');

const getOriginalElementValue = (
element: (Element & { [ORIGINAL_VALUE_KEY]?: string }) | null
) => {
return element ? element[ORIGINAL_VALUE_KEY] ?? element.value : '';
};

/**
* Stylis plugin that mimics :global() selector behavior from Stylis v3.
*/
export const stylisGlobalPlugin: Middleware = (element) => {
function getGlobalSelectorModifiers(value: string) {
function getGlobalSelectorModifiers(el: Element): IGlobalSelectorModifiers {
const { parent } = el;

const value = getOriginalElementValue(el);
const parentValue = getOriginalElementValue(parent);

if (
(parent?.children.length === 0 && parentValue.includes(':global(')) ||
(parent && !value.includes(':global('))
) {
return getGlobalSelectorModifiers(parent);
}

const match = value.match(/(&\f( )?)?:global\(/);

if (match === null) {
Expand Down Expand Up @@ -73,26 +98,20 @@ export const stylisGlobalPlugin: Middleware = (element) => {

Object.assign(element, {
props: element.props.map((cssSelector) => {
// The value can be changed by other middlewares, but we need an original one with `&`
Object.assign(element, { [ORIGINAL_VALUE_KEY]: element.value });

// Avoids calling tokenize() on every string
if (!cssSelector.includes(':global(')) {
return cssSelector;
}

if (element.children.length === 0) {
Object.assign(element, {
global: getGlobalSelectorModifiers(element.value),
});
return cssSelector;
}

const { includeBaseSelector, includeSpaceDelimiter } =
(
element.parent as unknown as
| (Element & {
global: ReturnType<typeof getGlobalSelectorModifiers>;
})
| undefined
)?.global || getGlobalSelectorModifiers(element.value);
getGlobalSelectorModifiers(element);

const tokens = tokenize(cssSelector);
let selector = '';
Expand Down

0 comments on commit edf8c81

Please sign in to comment.