Skip to content

Conversation

@layershifter
Copy link
Member

@layershifter layershifter commented Sep 6, 2022

Fixes #204.
Fixes #206.


Changes in selectors handling

In resolveStyleRules() & compileCSS() I renamed pseudo to selectors and changed their type to be string[]:

  • To reflect what it contains as selectors can contain not only pseudo selectors.

  • To handle selectors properly as it was a problem without a solution:

    makeStyles({
      ":hover,:focus-within": {
        "::before": {
          color: "orange"
        }
      }
    });

    Before we were concatenating inputs with selectors and getting ":hover,:focus-within::before" that will be compiled by Stylis to:

    .class:hover,.class:focus-within::before {}

    And without proper wrapping with curly braces we cannot handle it. With selectors as an array with can send as input :hover,:focus-within { ::before { } } that will be handled properly.

Changes in :global() handling

Because before we didn't know scopes of selectors we were doing .trim() and were losing " " in rules (#206):

// should be normalized to handle ":global(SELECTOR) &"
const normalizedPseudo = normalizeNestedProperty(restPseudo.trim());

Currently I kept existing hack with :global() in place to avoid more changes in this PR, but in a follow up - I will replace it with a Stylis plugin.

@layershifter layershifter force-pushed the fix/comma-nested branch 2 times, most recently from 6799698 to 058744f Compare September 6, 2022 15:40
@github-actions
Copy link

github-actions bot commented Sep 6, 2022

📊 Bundle size report

Package & Exports Baseline (minified/GZIP) PR Change
core
makeStyles + mergeClasses (runtime)
20.339 kB
7.598 kB
20.454 kB
7.616 kB
115 B
18 B
react
makeStyles + mergeClasses (runtime)
22.099 kB
8.317 kB
22.214 kB
8.324 kB
115 B
7 B
Unchanged fixtures
Package & Exports Size (minified/GZIP)
core
makeStyles + mergeClasses (build time)
1.8 kB
861 B
react
__css + mergeClasses (build time)
1.837 kB
857 B
react
__styles + mergeClasses (build time)
3.535 kB
1.595 kB
react
makeStaticStyles (runtime)
8.982 kB
3.908 kB
🤖 This report was generated against 0e358cbda0f663246ed7c1cc1ad7db0bdc86c22c

expect(
compileCSS({
...defaultOptions,
pseudo: ':global(body) &',
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original selector is invalid, replaced it with a proper test case.

Comment on lines +70 to +89
// Issues are reported:
// https://github.com/thysultan/stylis.js/issues/253
// https://github.com/thysultan/stylis.js/issues/252
if (selector.indexOf(':global(') === 0) {
// 👇 :global(GROUP_1)GROUP_2
const GLOBAL_PSEUDO_REGEX = /global\((.+)\)(.+)?/;
const result = GLOBAL_PSEUDO_REGEX.exec(selector)!;

let rtlClassNameSelector: string | null = null;
let rtlCSSDeclaration: string | null = null;
globalSelector = result[1] + ' ';
const restPseudo = result[2] || '';

if (rtlProperty && rtlClassName) {
rtlClassNameSelector = `.${rtlClassName}`;
rtlCSSDeclaration = Array.isArray(rtlValue)
? `{ ${rtlValue.map(v => `${hyphenateProperty(rtlProperty)}: ${v}`).join(';')}; }`
: `{ ${hyphenateProperty(rtlProperty)}: ${rtlValue}; }`;
}
// should be normalized to handle ":global(SELECTOR) &"
const normalizedPseudoSelector = normalizePseudoSelector(restPseudo);

let cssRule = '';
if (normalizedPseudoSelector === '') {
return acc;
}

// Should be handled by namespace plugin of Stylis, is buggy now
// Issues are reported:
// https://github.com/thysultan/stylis.js/issues/253
// https://github.com/thysultan/stylis.js/issues/252
if (pseudo.indexOf(':global(') === 0) {
// 👇 :global(GROUP_1)GROUP_2
const GLOBAL_PSEUDO_REGEX = /global\((.+)\)(.+)?/;
const [, globalSelector, restPseudo = ''] = GLOBAL_PSEUDO_REGEX.exec(pseudo)!;
return `${normalizedPseudoSelector} { ${acc} }`;
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved the hack with small changes, will replace it with a Stylis plugin in a follow up PR.

Comment on lines +5 to +6
expect(getStyleBucketName([], '', '', '')).toBe('d');
expect(getStyleBucketName(['.foo'], '', '', '')).toBe('d');
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New test cases.

Comment on lines +60 to +61
if (selectors.length > 0) {
const normalizedPseudo = selectors[0].trim();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We take into account only the first pseudo selector, so it's find to use the first element.

Comment on lines +416 to +429
expect(
resolveStyleRules({
':hover,:focus-within': {
'::before': {
color: 'orange',
},
},
}),
).toMatchInlineSnapshot(`
.fij4gri:hover::before,
.fij4gri:focus-within::before {
color: orange;
}
`);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test case from #204.

Comment on lines -576 to -586
it('handles :global selector', () => {
expect(
resolveStyleRules({
':global(body) &': { color: 'green' },
}),
).toMatchInlineSnapshot(`
body .fm1e7ra {
color: green;
}
`);
});
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again a test that does not have any sense.

`);
expect(
resolveStyleRules({
':global(body):focus': { color: 'pink' },
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now spaces are handled (#206).

Comment on lines +636 to +646
it('supports :global as a nested selector', () => {
expect(
resolveStyleRules({
':focus': { ':global(body)': { color: 'green' } },
}),
).toMatchInlineSnapshot(`
body .fz7er5p:focus {
color: green;
}
`);
});
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As now we have scopes this test surprisingly works 🐱

@layershifter layershifter marked this pull request as ready for review September 6, 2022 16:18
@layershifter layershifter requested a review from a team as a code owner September 6, 2022 16:18
// https://github.com/thysultan/stylis.js/issues/252
if (selector.indexOf(':global(') === 0) {
// 👇 :global(GROUP_1)GROUP_2
const GLOBAL_PSEUDO_REGEX = /global\((.+)\)(.+)?/;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe hoist the regex so it doesn't get created on every iteration ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, but in a followup I will get it of this part anyway (I will replace this part with a stylis plugin).

className: string;

pseudo: string;
selectors: string[];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would the length of selectors ever exceed 2 ? It seems that the only case we are handling here is pseudo selector + element. It shouldn't be possible to go further since it would be invalid css ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please provide an example?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

core: :global() selector does not handle spaces core: comma-separated nested selectors are not handled properly

3 participants