postcss-pseudo-where-fallback 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -8
- package/dist/index.cjs +57 -85
- package/dist/index.mjs +53 -54
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -27,6 +27,8 @@ export default {
|
|
|
27
27
|
};
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
+
**Note:** This plugin currently does not accept any options. Simply use it without arguments: `postcssPluginPseudoWhereFallback()`.
|
|
31
|
+
|
|
30
32
|
### With PostCSS CLI
|
|
31
33
|
|
|
32
34
|
```js
|
|
@@ -91,6 +93,43 @@ The plugin keeps the original `:where()` selector for modern browsers (which wil
|
|
|
91
93
|
- **Older browsers with `@supports`**: Ignore the invalid `:where()` selector and use the fallback with normal specificity
|
|
92
94
|
- **Very old browsers** (no `@supports` support): Ignore both the `:where()` and `@supports` blocks, resulting in no styles (these are pre-2013 browsers)
|
|
93
95
|
|
|
96
|
+
## Important Note on Specificity
|
|
97
|
+
|
|
98
|
+
The key feature of `:where()` is that it has **zero specificity**, while the fallback selectors have **normal specificity**. This can result in different behavior in legacy browsers when combined with other selectors:
|
|
99
|
+
|
|
100
|
+
```css
|
|
101
|
+
/* Your CSS */
|
|
102
|
+
.sidebar :where(.button) {
|
|
103
|
+
background: blue;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.button {
|
|
107
|
+
background: red;
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**In modern browsers:**
|
|
112
|
+
```css
|
|
113
|
+
/* .sidebar :where(.button) = 0,1,0 specificity (only .sidebar counts) */
|
|
114
|
+
/* .button = 0,1,0 specificity */
|
|
115
|
+
/* Result: red background (last rule wins due to equal specificity) ✓ */
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**In legacy browsers with the fallback:**
|
|
119
|
+
```css
|
|
120
|
+
.sidebar :where(.button) { background: blue; }
|
|
121
|
+
@supports not selector(:where(*)) {
|
|
122
|
+
.sidebar .button { background: blue; } /* 0,2,0 specificity! */
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.button { background: red; } /* 0,1,0 specificity */
|
|
126
|
+
/* Result: blue background (fallback wins due to higher specificity) ✗ */
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
The fallback `.sidebar .button` has **higher specificity** (0,2,0) than the intended override `.button` (0,1,0), causing different behavior in legacy browsers.
|
|
130
|
+
|
|
131
|
+
**Recommendation:** If you're using `:where()` specifically for its zero-specificity behavior in complex cascade scenarios, test thoroughly in legacy browsers or consider using more specific overrides.
|
|
132
|
+
|
|
94
133
|
## More Examples
|
|
95
134
|
|
|
96
135
|
### Selector Lists with Mixed Types
|
|
@@ -158,14 +197,6 @@ Output:
|
|
|
158
197
|
}
|
|
159
198
|
```
|
|
160
199
|
|
|
161
|
-
## Options
|
|
162
|
-
|
|
163
|
-
This plugin currently does not accept any options. Simply use it without arguments:
|
|
164
|
-
|
|
165
|
-
```js
|
|
166
|
-
postcssPluginPseudoWhereFallback()
|
|
167
|
-
```
|
|
168
|
-
|
|
169
200
|
## Browser Support
|
|
170
201
|
|
|
171
202
|
This plugin helps support browsers that don't have native `:where()` support, including:
|
package/dist/index.cjs
CHANGED
|
@@ -1,92 +1,64 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var
|
|
4
|
-
|
|
5
|
-
var
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
for (var name in all)
|
|
9
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
-
};
|
|
11
|
-
var __copyProps = (to, from, except, desc) => {
|
|
12
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
-
for (let key of __getOwnPropNames(from))
|
|
14
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
-
}
|
|
17
|
-
return to;
|
|
18
|
-
};
|
|
19
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
-
mod
|
|
26
|
-
));
|
|
27
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
-
var index_exports = {};
|
|
29
|
-
__export(index_exports, {
|
|
30
|
-
default: () => index_default
|
|
31
|
-
});
|
|
32
|
-
module.exports = __toCommonJS(index_exports);
|
|
33
|
-
var import_postcss = __toESM(require("postcss"), 1);
|
|
34
|
-
var import_postcss_selector_parser = __toESM(require("postcss-selector-parser"), 1);
|
|
35
|
-
const plugin = () => {
|
|
36
|
-
return {
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var postcss = require("postcss");
|
|
4
|
+
|
|
5
|
+
var selectorParser = require("postcss-selector-parser");
|
|
6
|
+
|
|
7
|
+
const plugin = () => ({
|
|
37
8
|
postcssPlugin: "postcss-pseudo-where-fallback",
|
|
38
9
|
Once(root) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
10
|
+
const rulesToProcess = [];
|
|
11
|
+
root.walkRules(rule => {
|
|
12
|
+
if (rule.selector && rule.selector.includes(":where(")) {
|
|
13
|
+
rulesToProcess.push(rule);
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
rulesToProcess.forEach(rule => {
|
|
17
|
+
const fallbackSelectors = [];
|
|
18
|
+
selectorParser(selectors => {
|
|
19
|
+
selectors.each(selector => {
|
|
20
|
+
selector.walkPseudos(pseudo => {
|
|
21
|
+
if (pseudo.value === ":where" && pseudo.nodes) {
|
|
22
|
+
const parent = pseudo.parent;
|
|
23
|
+
const index = parent.index(pseudo);
|
|
24
|
+
const prefix = parent.nodes.slice(0, index);
|
|
25
|
+
const suffix = parent.nodes.slice(index + 1);
|
|
26
|
+
pseudo.nodes.forEach(whereSelector => {
|
|
27
|
+
let selectorString = "";
|
|
28
|
+
prefix.forEach(node => {
|
|
29
|
+
selectorString += node.toString();
|
|
30
|
+
});
|
|
31
|
+
whereSelector.nodes.forEach((node, i) => {
|
|
32
|
+
const nodeStr = node.toString();
|
|
33
|
+
if (i === 0) {
|
|
34
|
+
selectorString += nodeStr.trimStart();
|
|
35
|
+
} else {
|
|
36
|
+
selectorString += nodeStr;
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
suffix.forEach(node => {
|
|
40
|
+
selectorString += node.toString();
|
|
41
|
+
});
|
|
42
|
+
fallbackSelectors.push(selectorString);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
});
|
|
72
46
|
});
|
|
73
|
-
|
|
47
|
+
}).processSync(rule.selector);
|
|
48
|
+
const fallbackRule = rule.clone({
|
|
49
|
+
selector: fallbackSelectors.map(s => s.trim()).join(", ")
|
|
74
50
|
});
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
params: "not selector(:where(*))",
|
|
83
|
-
source: rule.source
|
|
51
|
+
const fallbackSupports = postcss.atRule({
|
|
52
|
+
name: "supports",
|
|
53
|
+
params: "not selector(:where(*))",
|
|
54
|
+
source: rule.source
|
|
55
|
+
});
|
|
56
|
+
fallbackSupports.append(fallbackRule);
|
|
57
|
+
rule.after(fallbackSupports);
|
|
84
58
|
});
|
|
85
|
-
fallbackSupports.append(fallbackRule);
|
|
86
|
-
rule.after(fallbackSupports);
|
|
87
|
-
});
|
|
88
59
|
}
|
|
89
|
-
|
|
90
|
-
|
|
60
|
+
});
|
|
61
|
+
|
|
91
62
|
plugin.postcss = true;
|
|
92
|
-
|
|
63
|
+
|
|
64
|
+
module.exports = plugin;
|
package/dist/index.mjs
CHANGED
|
@@ -1,63 +1,62 @@
|
|
|
1
1
|
import postcss from "postcss";
|
|
2
|
+
|
|
2
3
|
import selectorParser from "postcss-selector-parser";
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
const plugin = () => ({
|
|
5
6
|
postcssPlugin: "postcss-pseudo-where-fallback",
|
|
6
7
|
Once(root) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
8
|
+
const rulesToProcess = [];
|
|
9
|
+
root.walkRules(rule => {
|
|
10
|
+
if (rule.selector && rule.selector.includes(":where(")) {
|
|
11
|
+
rulesToProcess.push(rule);
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
rulesToProcess.forEach(rule => {
|
|
15
|
+
const fallbackSelectors = [];
|
|
16
|
+
selectorParser(selectors => {
|
|
17
|
+
selectors.each(selector => {
|
|
18
|
+
selector.walkPseudos(pseudo => {
|
|
19
|
+
if (pseudo.value === ":where" && pseudo.nodes) {
|
|
20
|
+
const parent = pseudo.parent;
|
|
21
|
+
const index = parent.index(pseudo);
|
|
22
|
+
const prefix = parent.nodes.slice(0, index);
|
|
23
|
+
const suffix = parent.nodes.slice(index + 1);
|
|
24
|
+
pseudo.nodes.forEach(whereSelector => {
|
|
25
|
+
let selectorString = "";
|
|
26
|
+
prefix.forEach(node => {
|
|
27
|
+
selectorString += node.toString();
|
|
28
|
+
});
|
|
29
|
+
whereSelector.nodes.forEach((node, i) => {
|
|
30
|
+
const nodeStr = node.toString();
|
|
31
|
+
if (i === 0) {
|
|
32
|
+
selectorString += nodeStr.trimStart();
|
|
33
|
+
} else {
|
|
34
|
+
selectorString += nodeStr;
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
suffix.forEach(node => {
|
|
38
|
+
selectorString += node.toString();
|
|
39
|
+
});
|
|
40
|
+
fallbackSelectors.push(selectorString);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
});
|
|
40
44
|
});
|
|
41
|
-
|
|
45
|
+
}).processSync(rule.selector);
|
|
46
|
+
const fallbackRule = rule.clone({
|
|
47
|
+
selector: fallbackSelectors.map(s => s.trim()).join(", ")
|
|
42
48
|
});
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
params: "not selector(:where(*))",
|
|
51
|
-
source: rule.source
|
|
49
|
+
const fallbackSupports = postcss.atRule({
|
|
50
|
+
name: "supports",
|
|
51
|
+
params: "not selector(:where(*))",
|
|
52
|
+
source: rule.source
|
|
53
|
+
});
|
|
54
|
+
fallbackSupports.append(fallbackRule);
|
|
55
|
+
rule.after(fallbackSupports);
|
|
52
56
|
});
|
|
53
|
-
fallbackSupports.append(fallbackRule);
|
|
54
|
-
rule.after(fallbackSupports);
|
|
55
|
-
});
|
|
56
57
|
}
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
});
|
|
59
|
+
|
|
59
60
|
plugin.postcss = true;
|
|
60
|
-
|
|
61
|
-
export {
|
|
62
|
-
index_default as default
|
|
63
|
-
};
|
|
61
|
+
|
|
62
|
+
export { plugin as default };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "postcss-pseudo-where-fallback",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "PostCSS plugin to provide fallbacks for :where() pseudo-class",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"LICENSE"
|
|
18
18
|
],
|
|
19
19
|
"scripts": {
|
|
20
|
-
"build": "
|
|
20
|
+
"build": "rollup -c",
|
|
21
21
|
"test": "node --test",
|
|
22
22
|
"prepublishOnly": "npm run build"
|
|
23
23
|
},
|
|
@@ -44,9 +44,10 @@
|
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@csstools/postcss-tape": "^7.0.0",
|
|
47
|
-
"
|
|
47
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
48
48
|
"postcss": "^8.4.0",
|
|
49
|
-
"postcss-selector-parser": "^7.1.1"
|
|
49
|
+
"postcss-selector-parser": "^7.1.1",
|
|
50
|
+
"rollup": "^4.57.1"
|
|
50
51
|
},
|
|
51
52
|
"engines": {
|
|
52
53
|
"node": ">=14.0.0"
|