Skip to content

Commit 1c89ca9

Browse files
committed
Fix: CSS - Work comma selector with parens
1 parent cdbc5a3 commit 1c89ca9

File tree

2 files changed

+72
-1
lines changed

2 files changed

+72
-1
lines changed

.changeset/twenty-laws-create.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@mincho-js/transform-to-vanilla": patch
3+
---
4+
5+
**Nested Selector with commas and parens**
6+
- Fixes an error that occurs when parentheses are present.

packages/transform-to-vanilla/src/transform-keys/complex-selectors.ts

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export function isSimpleSelectorKey(key: string) {
1616
}
1717

1818
export function nestedSelectorKey(key: string, context: TransformContext) {
19-
const parentSelectors = context.parentSelector.split(",");
19+
const parentSelectors = splitSelector(context.parentSelector);
2020
const result = [];
2121

2222
const parentSelectorsLength = parentSelectors.length;
@@ -29,6 +29,58 @@ export function nestedSelectorKey(key: string, context: TransformContext) {
2929
return result.join(", ");
3030
}
3131

32+
function splitSelector(selector: string): string[] {
33+
if (!selector.includes(",")) {
34+
return [selector];
35+
}
36+
37+
const result = [];
38+
let currentSelector = "";
39+
let parenLevel = 0;
40+
let bracketLevel = 0;
41+
42+
const selectorLength = selector.length;
43+
for (let i = 0; i < selectorLength; i++) {
44+
const char = selector[i];
45+
46+
switch (char) {
47+
case "(":
48+
parenLevel++;
49+
currentSelector += char;
50+
break;
51+
case ")":
52+
parenLevel--;
53+
currentSelector += char;
54+
break;
55+
case "[":
56+
bracketLevel++;
57+
currentSelector += char;
58+
break;
59+
case "]":
60+
bracketLevel--;
61+
currentSelector += char;
62+
break;
63+
case ",":
64+
if (parenLevel === 0 && bracketLevel === 0) {
65+
result.push(currentSelector);
66+
currentSelector = "";
67+
} else {
68+
currentSelector += char;
69+
}
70+
break;
71+
default:
72+
currentSelector += char;
73+
break;
74+
}
75+
}
76+
77+
if (currentSelector.trim() !== "") {
78+
result.push(currentSelector);
79+
}
80+
81+
return result;
82+
}
83+
3284
// == Tests ====================================================================
3385
// Ignore errors when compiling to CommonJS.
3486
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
@@ -88,5 +140,18 @@ if (import.meta.vitest) {
88140
":root[dir=rtl] nav li > &, :root[dir=rtl] .myClass > &[data-attr-value]"
89141
);
90142
});
143+
144+
it("Complex Nested Selectors", () => {
145+
const context: TransformContext = {
146+
...structuredClone(initTransformContext),
147+
parentSelector: `nav li > &:hover:not(:active, :disabled, [data-list="a, b, c"]), .myClass > &[data-attr-value]:where(:has(> :hover, + :focus), :active)`
148+
};
149+
expect(nestedSelectorKey("&::before", context)).toBe(
150+
`nav li > &:hover:not(:active, :disabled, [data-list="a, b, c"])::before, .myClass > &[data-attr-value]:where(:has(> :hover, + :focus), :active)::before`
151+
);
152+
expect(nestedSelectorKey(":root[dir=rtl] &", context)).toBe(
153+
`:root[dir=rtl] nav li > &:hover:not(:active, :disabled, [data-list="a, b, c"]), :root[dir=rtl] .myClass > &[data-attr-value]:where(:has(> :hover, + :focus), :active)`
154+
);
155+
});
91156
});
92157
}

0 commit comments

Comments
 (0)