Skip to content

Commit 3856279

Browse files
authored
use the new selector specificity package (#353)
* use the new selector specificity package * npm install * fix
1 parent ae7bd5f commit 3856279

File tree

17 files changed

+74
-386
lines changed

17 files changed

+74
-386
lines changed

experimental/css-has-pseudo/CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Changes to CSS Has Pseudo
22

3+
### Unreleased
4+
5+
- Use `@csstools/selector-specificity` for specificity calculations.
6+
- Improve documentation
7+
38
### 0.5.0 (April 24, 2022)
49

510
- Rules within `@supports` selector check for `:has` won't be transformed. This respects stylesheet author of making the selector conditional:

experimental/css-has-pseudo/README-BROWSER.md

-10
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,6 @@
88
[EXPERIMENTAL CSS Has Pseudo] lets you style elements relative to other elements in CSS,
99
following the [Selectors Level 4] specification.
1010

11-
```css
12-
input {
13-
/* style an input */
14-
}
15-
16-
body[\:has\(\:focus\)] {
17-
/* style an input without a value */
18-
}
19-
```
20-
2111
## Usage
2212

2313
Add [EXPERIMENTAL CSS Has Pseudo] to your build tool:

experimental/css-has-pseudo/README-POSTCSS.md

+19-19
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ following the [Selectors Level 4] specification.
1010

1111
```css
1212
body:has(:focus) {
13-
background-color: yellow;
13+
background-color: yellow;
1414
}
1515

1616
/* becomes */
1717

18-
[body\:has\(\:focus\)] {
18+
[csstools-has-2q-33-2s-3d-1m-2w-2p-37-14-1m-2u-33-2r-39-37-15]:not(does-not-exist) {
1919
background-color: yellow;
2020
}
2121

@@ -43,7 +43,7 @@ const postcss = require('postcss');
4343
const cssHasPseudoExperimental = require('@csstools/css-has-pseudo-experimental');
4444

4545
postcss([
46-
cssHasPseudoExperimental(/* pluginOptions */)
46+
cssHasPseudoExperimental(/* pluginOptions */)
4747
]).process(YOUR_CSS /*, processOptions */);
4848
```
4949

@@ -66,13 +66,13 @@ cssHasPseudoExperimental({ preserve: false });
6666

6767
```css
6868
body:has(:focus) {
69-
background-color: yellow;
69+
background-color: yellow;
7070
}
7171

7272
/* becomes */
7373

74-
body[\:has\(\:focus\)] {
75-
background-color: yellow;
74+
[csstools-has-2q-33-2s-3d-1m-2w-2p-37-14-1m-2u-33-2r-39-37-15]:not(does-not-exist) {
75+
background-color: yellow;
7676
}
7777
```
7878

@@ -86,7 +86,7 @@ See how `:not` is used to modify [specificity](#specificity).
8686

8787
```js
8888
postcss([
89-
cssHasPseudoExperimental({ specificityMatchingName: 'something-random' })
89+
cssHasPseudoExperimental({ specificityMatchingName: 'something-random' })
9090
]).process(YOUR_CSS /*, processOptions */);
9191
```
9292

@@ -102,10 +102,10 @@ Before :
102102

103103
After :
104104

105-
[specificity 1, 2, 0](https://polypane.app/css-specificity-calculator/#selector=%5B%5C.x%5C%3Ahas%5C(%5C%253E%5C%2520%5C%2523a%5C%3Ahover%5C)%5D%3Anot(%23does-not-exist)%3Anot(.does-not-exist))
105+
[specificity 1, 2, 0](https://polypane.app/css-specificity-calculator/#selector=%5Bcsstools-has-1a-3c-1m-2w-2p-37-14-1q-w-z-2p-1m-2w-33-3a-2t-36-15%5D%3Anot(%23does-not-exist)%3Anot(.does-not-exist))
106106

107107
```css
108-
[\.x\:has\(\%3E\%20\%23a\:hover\)]:not(#does-not-exist):not(.does-not-exist) {
108+
[csstools-has-1a-3c-1m-2w-2p-37-14-1q-w-z-2p-1m-2w-33-3a-2t-36-15]:not(#does-not-exist):not(.does-not-exist) {
109109
order: 11;
110110
}
111111
```
@@ -127,10 +127,10 @@ figure:has(> img)
127127

128128
After :
129129

130-
[specificity 0, 1, 2](https://polypane.app/css-specificity-calculator/#selector=%5Bfigure%5C%3Ahas%5C(%5C%253E%5C%2520img%5C)%5D%3Anot(does-not-exist)%3Anot(does-not-exist))
130+
[specificity 0, 1, 2](https://polypane.app/css-specificity-calculator/#selector=%5Bcsstools-has-2u-2x-2v-39-36-2t-1m-2w-2p-37-14-1q-w-2x-31-2v-15%5D%3Anot(does-not-exist)%3Anot(does-not-exist))
131131

132132
```css
133-
[figure\:has\(\%3E\%20img\)]:not(does-not-exist):not(does-not-exist)
133+
[csstools-has-2u-2x-2v-39-36-2t-1m-2w-2p-37-14-1q-w-2x-31-2v-15]:not(does-not-exist):not(does-not-exist)
134134
```
135135

136136
### Plugin order
@@ -152,14 +152,14 @@ The experimental plugin must be added after any other plugin that modifies selec
152152

153153
```js
154154
plugins: [
155-
// other plugins
156-
postcssPresetEnv({
157-
features: {
158-
'css-has-pseudo': false
159-
}
160-
}),
161-
// other plugins
162-
cssHasPseudoExperimental(), // last
155+
// other plugins
156+
postcssPresetEnv({
157+
features: {
158+
'css-has-pseudo': false
159+
}
160+
}),
161+
// other plugins
162+
cssHasPseudoExperimental(), // last
163163
]
164164
```
165165

experimental/css-has-pseudo/README.md

+18-18
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,19 @@ following the [Selectors Level 4] specification.
1212

1313
```css
1414
a:has(> img) {
15-
/* style links that contain an image */
15+
/* style links that contain an image */
1616
}
1717

1818
h1:has(+ p) {
19-
/* style level 1 headings that are followed by a paragraph */
19+
/* style level 1 headings that are followed by a paragraph */
2020
}
2121

2222
section:not(:has(h1, h2, h3, h4, h5, h6)) {
23-
/* style sections that don’t contain any heading elements */
23+
/* style sections that don’t contain any heading elements */
2424
}
2525

2626
body:has(:focus) {
27-
/* style the body if it contains a focused element */
27+
/* style the body if it contains a focused element */
2828
}
2929
```
3030

@@ -55,24 +55,24 @@ replacing them with an alternative `[:has]` selector.
5555

5656
```css
5757
body:has(:focus) {
58-
background-color: yellow;
58+
background-color: yellow;
5959
}
6060

6161
section:not(:has(h1, h2, h3, h4, h5, h6)) {
62-
background-color: gray;
62+
background-color: gray;
6363
}
6464

6565
/* becomes */
6666

67-
[body\:has\(\:focus\)] {
67+
[csstools-has-2q-33-2s-3d-1m-2w-2p-37-14-1m-2u-33-2r-39-37-15]:not(does-not-exist) {
6868
background-color: yellow;
6969
}
7070

7171
body:has(:focus) {
7272
background-color: yellow;
7373
}
7474

75-
[section\:not\(\:has\(h1\,\%20h2\,\%20h3\,\%20h4\,\%20h5\,\%20h6\)\)] {
75+
[csstools-has-37-2t-2r-38-2x-33-32-1m-32-33-38-14-1m-2w-2p-37-14-2w-1d-18-w-2w-1e-18-w-2w-1f-18-w-2w-1g-18-w-2w-1h-18-w-2w-1i-15-15]:not(does-not-exist):not(does-not-exist) {
7676
background-color: gray;
7777
}
7878

@@ -85,8 +85,8 @@ Next, the [JavaScript library](README-BROWSER.md) adds a `[:has]` attribute to
8585
elements otherwise matching `:has` natively.
8686

8787
```html
88-
<body body:has(:focus)>
89-
<input value="This element is focused">
88+
<body csstools-has-2q-33-2s-3d-1m-2w-2p-37-14-1m-2u-33-2r-39-37-15>
89+
<input value="This element is focused">
9090
</body>
9191
```
9292

@@ -98,14 +98,14 @@ The experimental plugin must be added after any other plugin that modifies selec
9898

9999
```js
100100
plugins: [
101-
// other plugins
102-
postcssPresetEnv({
103-
features: {
104-
'css-has-pseudo': false
105-
}
106-
}),
107-
// other plugins
108-
cssHasPseudoExperimental(), // last
101+
// other plugins
102+
postcssPresetEnv({
103+
features: {
104+
'css-has-pseudo': false
105+
}
106+
}),
107+
// other plugins
108+
cssHasPseudoExperimental(), // last
109109
]
110110
```
111111

experimental/css-has-pseudo/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"dist"
3737
],
3838
"dependencies": {
39+
"@csstools/selector-specificity": "1.0.0",
3940
"postcss-selector-parser": "^6.0.10"
4041
},
4142
"peerDependencies": {
+1-111
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import parser from 'postcss-selector-parser';
2+
import selectorSpecificity from '@csstools/selector-specificity';
23
import encodeCSS from './encode/encode.mjs';
34
import type { PluginCreator } from 'postcss';
45

@@ -117,114 +118,3 @@ function isWithinSupportCheck(rule) {
117118

118119
return isSupportCheck;
119120
}
120-
121-
function selectorSpecificity(node) {
122-
let a = 0;
123-
let b = 0;
124-
let c = 0;
125-
126-
if (node.type == 'universal') {
127-
return {
128-
a: 0,
129-
b: 0,
130-
c: 0,
131-
};
132-
} else if (node.type === 'id') {
133-
a += 1;
134-
} else if (node.type === 'tag') {
135-
c += 1;
136-
} else if (node.type === 'class') {
137-
b += 1;
138-
} else if (node.type === 'attribute') {
139-
b += 1;
140-
} else if (node.type === 'pseudo' && node.value.indexOf('::') === 0) {
141-
c += 1;
142-
} else if (node.type === 'pseudo') {
143-
switch (node.value) {
144-
case ':after':
145-
case ':before':
146-
c += 1;
147-
break;
148-
149-
case ':is':
150-
case ':has':
151-
case ':not':
152-
{
153-
if (node.nodes && node.nodes.length > 0) {
154-
let mostSpecificListItem = {
155-
a: 0,
156-
b: 0,
157-
c: 0,
158-
};
159-
160-
node.nodes.forEach((child) => {
161-
const itemSpecificity = selectorSpecificity(child);
162-
if (itemSpecificity.a > mostSpecificListItem.a) {
163-
mostSpecificListItem = itemSpecificity;
164-
return;
165-
} else if (itemSpecificity.a < mostSpecificListItem.a) {
166-
return;
167-
}
168-
169-
if (itemSpecificity.b > mostSpecificListItem.b) {
170-
mostSpecificListItem = itemSpecificity;
171-
return;
172-
} else if (itemSpecificity.b < mostSpecificListItem.b) {
173-
return;
174-
}
175-
176-
if (itemSpecificity.c > mostSpecificListItem.c) {
177-
mostSpecificListItem = itemSpecificity;
178-
return;
179-
}
180-
});
181-
182-
a += mostSpecificListItem.a;
183-
b += mostSpecificListItem.b;
184-
c += mostSpecificListItem.c;
185-
}
186-
break;
187-
}
188-
189-
case 'where':
190-
break;
191-
192-
case ':nth-child':
193-
case ':nth-last-child':
194-
{
195-
const ofSeparatorIndex = node.nodes.findIndex((x) => {
196-
x.value === 'of';
197-
});
198-
199-
if (ofSeparatorIndex > -1) {
200-
const ofSpecificity = selectorSpecificity(parser.selector({ nodes: node.nodes.slice(ofSeparatorIndex + 1), value: '' }));
201-
a += ofSpecificity.a;
202-
b += ofSpecificity.b;
203-
c += ofSpecificity.c;
204-
} else {
205-
a += a;
206-
b += b;
207-
c += c;
208-
}
209-
}
210-
break;
211-
212-
default:
213-
b += 1;
214-
}
215-
} else if (node.nodes && node.nodes.length > 0) {
216-
node.nodes.forEach((child) => {
217-
const specificity = selectorSpecificity(child);
218-
a += specificity.a;
219-
b += specificity.b;
220-
c += specificity.c;
221-
});
222-
}
223-
224-
return {
225-
a,
226-
b,
227-
c,
228-
};
229-
}
230-

0 commit comments

Comments
 (0)