css-has-pseudo 3.0.2 → 4.0.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/CHANGELOG.md +39 -0
- package/README.md +262 -60
- package/dist/browser-global.js +1 -116
- package/dist/browser-global.js.map +1 -1
- package/dist/browser.cjs +1 -111
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.mjs +1 -111
- package/dist/browser.mjs.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.mjs +1 -1
- package/dist/is-guarded-by-at-supports.d.ts +2 -0
- package/package.json +105 -78
- package/browser.js +0 -117
- package/dist/cli.cjs +0 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,44 @@
|
|
|
1
1
|
# Changes to CSS Has Pseudo
|
|
2
2
|
|
|
3
|
+
### 4.0.0 (July 8, 2022)
|
|
4
|
+
|
|
5
|
+
[Read the full changelog](https://github.com/csstools/postcss-plugins/wiki/PostCSS-Preset-Env-8)
|
|
6
|
+
|
|
7
|
+
- Breaking: removed old CDN urls
|
|
8
|
+
- Added: 'hover' options for browser polyfill
|
|
9
|
+
- Added: 'observedAttributes' options for browser polyfill
|
|
10
|
+
- Added: 'forcePolyfill' options for browser polyfill
|
|
11
|
+
- Added: Rules within `@supports selector(:has(something))` won't be transformed.
|
|
12
|
+
- Fix: Use base36 encoding to support all possible selectors.
|
|
13
|
+
- Fix: case insensitive matching.
|
|
14
|
+
|
|
15
|
+
#### How to migrate :
|
|
16
|
+
|
|
17
|
+
##### Re-build your CSS with the new version of the library.
|
|
18
|
+
|
|
19
|
+
##### If you use a CDN url, please update it.
|
|
20
|
+
|
|
21
|
+
```diff
|
|
22
|
+
- <script src="https://unpkg.com/css-has-pseudo/browser"></script>
|
|
23
|
+
+ <script src="https://unpkg.com/css-has-pseudo/dist/browser-global.js"></script>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
```diff
|
|
27
|
+
- <script src="https://unpkg.com/css-has-pseudo/browser.min"></script>
|
|
28
|
+
+ <script src="https://unpkg.com/css-has-pseudo/dist/browser-global.js"></script>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 3.0.4 (February 5, 2022)
|
|
32
|
+
|
|
33
|
+
- Rebuild of browser polyfills
|
|
34
|
+
|
|
35
|
+
### 3.0.3 (January 12, 2022)
|
|
36
|
+
|
|
37
|
+
- Fix compatibility with PostCSS `v8.2.x` [#147](https://github.com/csstools/postcss-plugins/issues/147)
|
|
38
|
+
|
|
39
|
+
This version is not officially supported but some tool providers pinned PostCSS to `v8.2.x`,
|
|
40
|
+
making it impossible for end users to have a working setup.
|
|
41
|
+
|
|
3
42
|
### 3.0.2 (January 2, 2022)
|
|
4
43
|
|
|
5
44
|
- Removed Sourcemaps from package tarball.
|
package/README.md
CHANGED
|
@@ -1,106 +1,308 @@
|
|
|
1
|
-
#
|
|
1
|
+
# PostCSS Has Pseudo [<img src="https://postcss.github.io/postcss/logo.svg" alt="PostCSS Logo" width="90" height="90" align="right">][postcss]
|
|
2
2
|
|
|
3
|
-
[
|
|
4
|
-
[![Support Chat][git-img]][git-url]
|
|
3
|
+
[<img alt="npm version" src="https://img.shields.io/npm/v/css-has-pseudo.svg" height="20">][npm-url] [<img alt="CSS Standard Status" src="https://cssdb.org/images/badges/has-pseudo-class.svg" height="20">][css-url] [<img alt="Build Status" src="https://github.com/csstools/postcss-plugins/workflows/test/badge.svg" height="20">][cli-url] [<img alt="Discord" src="https://shields.io/badge/Discord-5865F2?logo=discord&logoColor=white">][discord]
|
|
5
4
|
|
|
6
|
-
[
|
|
7
|
-
following the [Selectors Level 4] specification.
|
|
5
|
+
[PostCSS Has Pseudo] lets you style elements relative to other elements in CSS, following the [Selectors Level 4] specification.
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
a:has(> img) {
|
|
13
|
-
/* style links that contain an image */
|
|
7
|
+
```pcss
|
|
8
|
+
.title:has(+ p) {
|
|
9
|
+
margin-bottom: 1.5rem;
|
|
14
10
|
}
|
|
15
11
|
|
|
16
|
-
|
|
17
|
-
/* style level 1 headings that are followed by a paragraph */
|
|
18
|
-
}
|
|
12
|
+
/* becomes */
|
|
19
13
|
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
[csstools-has-1a-38-2x-38-30-2t-1m-2w-2p-37-14-17-w-34-15]:not(does-not-exist) {
|
|
15
|
+
margin-bottom: 1.5rem;
|
|
22
16
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
/* style the body if it contains a focused element */
|
|
17
|
+
.title:has(+ p) {
|
|
18
|
+
margin-bottom: 1.5rem;
|
|
26
19
|
}
|
|
27
20
|
```
|
|
28
21
|
|
|
29
22
|
## Usage
|
|
30
23
|
|
|
31
|
-
|
|
24
|
+
Add [PostCSS Has Pseudo] to your project:
|
|
32
25
|
|
|
33
26
|
```bash
|
|
34
|
-
|
|
27
|
+
npm install postcss css-has-pseudo --save-dev
|
|
35
28
|
```
|
|
36
29
|
|
|
37
|
-
|
|
30
|
+
Use it as a [PostCSS] plugin:
|
|
38
31
|
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
32
|
+
```js
|
|
33
|
+
const postcss = require('postcss');
|
|
34
|
+
const postcssHasPseudo = require('css-has-pseudo');
|
|
35
|
+
|
|
36
|
+
postcss([
|
|
37
|
+
postcssHasPseudo(/* pluginOptions */)
|
|
38
|
+
]).process(YOUR_CSS /*, processOptions */);
|
|
43
39
|
```
|
|
44
40
|
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
[PostCSS Has Pseudo] runs in all Node environments, with special
|
|
42
|
+
instructions for:
|
|
47
43
|
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
| [Node](INSTALL.md#node) | [PostCSS CLI](INSTALL.md#postcss-cli) | [Webpack](INSTALL.md#webpack) | [Create React App](INSTALL.md#create-react-app) | [Gulp](INSTALL.md#gulp) | [Grunt](INSTALL.md#grunt) |
|
|
45
|
+
| --- | --- | --- | --- | --- | --- |
|
|
50
46
|
|
|
51
|
-
|
|
52
|
-
Internet Explorer 11. With a [Mutation Observer polyfill], the script will work
|
|
53
|
-
down to Internet Explorer 9.
|
|
47
|
+
## Options
|
|
54
48
|
|
|
55
|
-
|
|
49
|
+
### preserve
|
|
56
50
|
|
|
57
|
-
|
|
51
|
+
The `preserve` option determines whether the original notation
|
|
52
|
+
is preserved. By default the original rules are preserved.
|
|
58
53
|
|
|
59
|
-
|
|
60
|
-
|
|
54
|
+
```js
|
|
55
|
+
postcssHasPseudo({ preserve: false })
|
|
56
|
+
```
|
|
61
57
|
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
|
|
58
|
+
```pcss
|
|
59
|
+
.title:has(+ p) {
|
|
60
|
+
margin-bottom: 1.5rem;
|
|
65
61
|
}
|
|
66
62
|
|
|
67
|
-
|
|
68
|
-
|
|
63
|
+
/* becomes */
|
|
64
|
+
|
|
65
|
+
[csstools-has-1a-38-2x-38-30-2t-1m-2w-2p-37-14-17-w-34-15]:not(does-not-exist) {
|
|
66
|
+
margin-bottom: 1.5rem;
|
|
69
67
|
}
|
|
68
|
+
```
|
|
70
69
|
|
|
71
|
-
|
|
70
|
+
### specificityMatchingName
|
|
71
|
+
|
|
72
|
+
The `specificityMatchingName` option allows you to change to selector that is used to adjust specificity.
|
|
73
|
+
The default value is `does-not-exist`.
|
|
74
|
+
If this is an actual class, id or tag name in your code, you will need to set a different option here.
|
|
75
|
+
|
|
76
|
+
See how `:not` is used to modify [specificity](#specificity).
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
postcssHasPseudo({ specificityMatchingName: 'something-random' })
|
|
80
|
+
```
|
|
72
81
|
|
|
73
|
-
|
|
74
|
-
|
|
82
|
+
[specificity 1, 2, 0](https://polypane.app/css-specificity-calculator/#selector=.x%3Ahas(%3E%20%23a%3Ahover))
|
|
83
|
+
|
|
84
|
+
Before :
|
|
85
|
+
|
|
86
|
+
```css
|
|
87
|
+
.x:has(> #a:hover) {
|
|
88
|
+
order: 11;
|
|
75
89
|
}
|
|
90
|
+
```
|
|
76
91
|
|
|
77
|
-
|
|
78
|
-
|
|
92
|
+
After :
|
|
93
|
+
|
|
94
|
+
[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))
|
|
95
|
+
|
|
96
|
+
```css
|
|
97
|
+
[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) {
|
|
98
|
+
order: 11;
|
|
79
99
|
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## ⚠️ Known shortcomings
|
|
103
|
+
|
|
104
|
+
### Specificity
|
|
105
|
+
|
|
106
|
+
`:has` transforms will result in at least one attribute selector with specificity `0, 1, 0`.<br>
|
|
107
|
+
If your selector only has tags we won't be able to match the original specificity.
|
|
108
|
+
|
|
109
|
+
Before :
|
|
110
|
+
|
|
111
|
+
[specificity 0, 0, 2](https://polypane.app/css-specificity-calculator/#selector=figure%3Ahas(%3E%20img))
|
|
112
|
+
|
|
113
|
+
```css
|
|
114
|
+
figure:has(> img)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
After :
|
|
118
|
+
|
|
119
|
+
[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))
|
|
120
|
+
|
|
121
|
+
```css
|
|
122
|
+
[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)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Plugin order
|
|
126
|
+
|
|
127
|
+
As selectors are encoded, this plugin (or `postcss-preset-env`) must be run after any other plugin that transforms selectors.
|
|
128
|
+
|
|
129
|
+
If other plugins are used, you need to place these in your config before `postcss-preset-env` or `css-has-pseudo`.
|
|
130
|
+
|
|
131
|
+
Please let us know if you have issues with plugins that transform selectors.
|
|
132
|
+
Then we can investigate and maybe fix these.
|
|
133
|
+
|
|
134
|
+
## Browser
|
|
135
|
+
|
|
136
|
+
```js
|
|
137
|
+
// initialize prefersColorScheme (applies the current OS color scheme, if available)
|
|
138
|
+
import cssHasPseudo from 'css-has-pseudo/browser';
|
|
139
|
+
cssHasPseudo(document);
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
or
|
|
143
|
+
|
|
144
|
+
```html
|
|
145
|
+
<!-- When using a CDN url you will have to manually update the version number -->
|
|
146
|
+
<script src="https://unpkg.com/css-has-pseudo@3.0.4/dist/browser-global.js"></script>
|
|
147
|
+
<script>cssHasPseudo(document)</script>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
⚠️ Please use a versioned url, like this : `https://unpkg.com/css-has-pseudo@3.0.4/dist/browser-global.js`
|
|
151
|
+
Without the version, you might unexpectedly get a new major version of the library with breaking changes.
|
|
80
152
|
|
|
81
|
-
|
|
82
|
-
|
|
153
|
+
[PostCSS Has Pseudo] works in all major browsers, including
|
|
154
|
+
Internet Explorer 11. With a [Mutation Observer polyfill](https://github.com/webmodules/mutation-observer), the script will work
|
|
155
|
+
down to Internet Explorer 9.
|
|
156
|
+
|
|
157
|
+
### Browser Usage
|
|
158
|
+
|
|
159
|
+
#### hover
|
|
160
|
+
|
|
161
|
+
The `hover` option determines if `:hover` pseudo-class should be tracked.
|
|
162
|
+
This is disabled by default because it is an expensive operation.
|
|
163
|
+
|
|
164
|
+
```js
|
|
165
|
+
cssHasPseudo(document, { hover: true });
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
#### observedAttributes
|
|
169
|
+
|
|
170
|
+
The `observedAttributes` option determines which html attributes are observed.
|
|
171
|
+
If you do any client side modification of non-standard attributes and use these in combination with `:has()` you should add these here.
|
|
172
|
+
|
|
173
|
+
```js
|
|
174
|
+
cssHasPseudo(document, { observedAttributes: ['something-not-standard'] });
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
#### forcePolyfill
|
|
178
|
+
|
|
179
|
+
The `forcePolyfill` option determines if the polyfill is used even when the browser has native support.
|
|
180
|
+
This is needed when you set `preserve: false` in the PostCSS plugin config.
|
|
181
|
+
|
|
182
|
+
```js
|
|
183
|
+
cssHasPseudo(document, { forcePolyfill: true });
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
#### debug
|
|
187
|
+
|
|
188
|
+
The `debug` option determines if errors are emitted to the console in browser.
|
|
189
|
+
By default the polyfill will not emit errors or warnings.
|
|
190
|
+
|
|
191
|
+
```js
|
|
192
|
+
cssHasPseudo(document, { debug: true });
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
### Browser Dependencies
|
|
197
|
+
|
|
198
|
+
Web API's:
|
|
199
|
+
|
|
200
|
+
- [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver)
|
|
201
|
+
- [requestAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame)
|
|
202
|
+
- [querySelectorAll](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll) with support for post CSS 2.1 selectors and `:scope` selectors.
|
|
203
|
+
|
|
204
|
+
ECMA Script:
|
|
205
|
+
|
|
206
|
+
- `Array.prototype.filter`
|
|
207
|
+
- `Array.prototype.forEach`
|
|
208
|
+
- `Array.prototype.indexOf`
|
|
209
|
+
- `Array.prototype.join`
|
|
210
|
+
- `Array.prototype.map`
|
|
211
|
+
- `Array.prototype.splice`
|
|
212
|
+
- `RegExp.prototype.exec`
|
|
213
|
+
- `String.prototype.match`
|
|
214
|
+
- `String.prototype.replace`
|
|
215
|
+
- `String.prototype.split`
|
|
216
|
+
|
|
217
|
+
## CORS
|
|
218
|
+
|
|
219
|
+
⚠️ Applies to you if you load CSS from a different domain than the page.
|
|
220
|
+
|
|
221
|
+
In this case the CSS is treated as untrusted and will not be made available to the JavaScript polyfill.
|
|
222
|
+
The polyfill will not work without applying the correct configuration for CORS.
|
|
223
|
+
|
|
224
|
+
Example :
|
|
225
|
+
|
|
226
|
+
| page | css | CORS applies |
|
|
227
|
+
| --- | --- | --- |
|
|
228
|
+
| https://example.com/ | https://example.com/style.css | no |
|
|
229
|
+
| https://example.com/ | https://other.com/style.css | yes |
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
**You might see one of these error messages :**
|
|
233
|
+
|
|
234
|
+
Chrome :
|
|
235
|
+
|
|
236
|
+
> DOMException: Failed to read the 'cssRules' property from 'CSSStyleSheet': Cannot access rules
|
|
237
|
+
|
|
238
|
+
Safari :
|
|
239
|
+
|
|
240
|
+
> SecurityError: Not allowed to access cross-origin stylesheet
|
|
241
|
+
|
|
242
|
+
Firefox :
|
|
243
|
+
|
|
244
|
+
> DOMException: CSSStyleSheet.cssRules getter: Not allowed to access cross-origin stylesheet
|
|
245
|
+
|
|
246
|
+
To resolve CORS errors you need to take two steps :
|
|
247
|
+
|
|
248
|
+
- add an HTTP header `Access-Control-Allow-Origin: <your-value>` when serving your CSS file.
|
|
249
|
+
- add `crossorigin="anonymous"` to the `<link rel="stylesheet">` tag for your CSS file.
|
|
250
|
+
|
|
251
|
+
In a node server setting the HTTP header might look like this :
|
|
252
|
+
|
|
253
|
+
```js
|
|
254
|
+
// http://localhost:8080 is the domain of your page!
|
|
255
|
+
res.setHeader('Access-Control-Allow-Origin', 'https://example.com');
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
You can also configure a wildcard but please be aware that this might be a security risk.
|
|
259
|
+
It is better to only set the header for the domain you want to allow and only on the responses you want to allow.
|
|
260
|
+
|
|
261
|
+
HTML might look like this :
|
|
262
|
+
|
|
263
|
+
```html
|
|
264
|
+
<link rel="stylesheet" href="https://example.com/styles.css" crossorigin="anonymous">
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
## How it works
|
|
269
|
+
|
|
270
|
+
The [PostCSS Has Pseudo] clones rules containing `:has()`,
|
|
271
|
+
replacing them with an alternative `[csstools-has-]` selector.
|
|
272
|
+
|
|
273
|
+
```pcss
|
|
274
|
+
.title:has(+ p) {
|
|
275
|
+
margin-bottom: 1.5rem;
|
|
83
276
|
}
|
|
84
277
|
|
|
85
|
-
|
|
86
|
-
|
|
278
|
+
/* becomes */
|
|
279
|
+
|
|
280
|
+
[csstools-has-1a-38-2x-38-30-2t-1m-2w-2p-37-14-17-w-34-15]:not(does-not-exist) {
|
|
281
|
+
margin-bottom: 1.5rem;
|
|
282
|
+
}
|
|
283
|
+
.title:has(+ p) {
|
|
284
|
+
margin-bottom: 1.5rem;
|
|
87
285
|
}
|
|
88
286
|
```
|
|
89
287
|
|
|
90
|
-
Next, the [
|
|
288
|
+
Next, the [browser script](#browser) adds a `[:has]` attribute to
|
|
91
289
|
elements otherwise matching `:has` natively.
|
|
92
290
|
|
|
93
291
|
```html
|
|
94
|
-
<
|
|
95
|
-
|
|
96
|
-
</
|
|
292
|
+
<div class="title" [csstools-has-1a-38-2x-38-30-2t-1m-2w-2p-37-14-17-w-34-15]>
|
|
293
|
+
<h1>A title block</h1>
|
|
294
|
+
<p>With an extra paragraph</p>
|
|
295
|
+
</div>
|
|
97
296
|
```
|
|
98
297
|
|
|
99
|
-
[
|
|
100
|
-
[
|
|
101
|
-
[
|
|
298
|
+
[cli-url]: https://github.com/csstools/postcss-plugins/actions/workflows/test.yml?query=workflow/test
|
|
299
|
+
[css-url]: https://cssdb.org/#has-pseudo-class
|
|
300
|
+
[discord]: https://discord.gg/bUadyRwkJS
|
|
102
301
|
[npm-url]: https://www.npmjs.com/package/css-has-pseudo
|
|
103
302
|
|
|
104
|
-
[
|
|
105
|
-
[
|
|
106
|
-
[
|
|
303
|
+
[Gulp PostCSS]: https://github.com/postcss/gulp-postcss
|
|
304
|
+
[Grunt PostCSS]: https://github.com/nDmitry/grunt-postcss
|
|
305
|
+
[PostCSS]: https://github.com/postcss/postcss
|
|
306
|
+
[PostCSS Loader]: https://github.com/postcss/postcss-loader
|
|
307
|
+
[PostCSS Has Pseudo]: https://github.com/csstools/postcss-plugins/tree/main/plugins/css-has-pseudo
|
|
308
|
+
[Selectors Level 4]: https://www.w3.org/TR/selectors-4/#has-pseudo
|
package/dist/browser-global.js
CHANGED
|
@@ -1,117 +1,2 @@
|
|
|
1
|
-
(function () {
|
|
2
|
-
|
|
3
|
-
/* global MutationObserver,requestAnimationFrame */
|
|
4
|
-
function cssHasPseudo(document) {
|
|
5
|
-
var observedItems = []; // document.createAttribute() doesn't support `:` in the name. innerHTML does
|
|
6
|
-
|
|
7
|
-
var attributeElement = document.createElement('x'); // walk all stylesheets to collect observed css rules
|
|
8
|
-
|
|
9
|
-
[].forEach.call(document.styleSheets, walkStyleSheet);
|
|
10
|
-
transformObservedItems(); // observe DOM modifications that affect selectors
|
|
11
|
-
|
|
12
|
-
var mutationObserver = new MutationObserver(function (mutationsList) {
|
|
13
|
-
mutationsList.forEach(function (mutation) {
|
|
14
|
-
[].forEach.call(mutation.addedNodes || [], function (node) {
|
|
15
|
-
// walk stylesheets to collect observed css rules
|
|
16
|
-
if (node.nodeType === 1 && node.sheet) {
|
|
17
|
-
walkStyleSheet(node.sheet);
|
|
18
|
-
}
|
|
19
|
-
}); // transform observed css rules
|
|
20
|
-
|
|
21
|
-
cleanupObservedCssRules();
|
|
22
|
-
transformObservedItems();
|
|
23
|
-
});
|
|
24
|
-
});
|
|
25
|
-
mutationObserver.observe(document, {
|
|
26
|
-
childList: true,
|
|
27
|
-
subtree: true
|
|
28
|
-
}); // observe DOM events that affect pseudo-selectors
|
|
29
|
-
|
|
30
|
-
document.addEventListener('focus', transformObservedItems, true);
|
|
31
|
-
document.addEventListener('blur', transformObservedItems, true);
|
|
32
|
-
document.addEventListener('input', transformObservedItems); // transform observed css rules
|
|
33
|
-
|
|
34
|
-
function transformObservedItems() {
|
|
35
|
-
requestAnimationFrame(function () {
|
|
36
|
-
observedItems.forEach(function (item) {
|
|
37
|
-
var nodes = [];
|
|
38
|
-
[].forEach.call(document.querySelectorAll(item.scopeSelector), function (element) {
|
|
39
|
-
var nthChild = [].indexOf.call(element.parentNode.children, element) + 1;
|
|
40
|
-
var relativeSelectors = item.relativeSelectors.map(function (relativeSelector) {
|
|
41
|
-
return item.scopeSelector + ':nth-child(' + nthChild + ') ' + relativeSelector;
|
|
42
|
-
}).join(); // find any relative :has element from the :scope element
|
|
43
|
-
|
|
44
|
-
var relativeElement = element.parentNode.querySelector(relativeSelectors);
|
|
45
|
-
var shouldElementMatch = item.isNot ? !relativeElement : relativeElement;
|
|
46
|
-
|
|
47
|
-
if (shouldElementMatch) {
|
|
48
|
-
// memorize the node
|
|
49
|
-
nodes.push(element); // set an attribute with an irregular attribute name
|
|
50
|
-
// document.createAttribute() doesn't support special characters
|
|
51
|
-
|
|
52
|
-
attributeElement.innerHTML = '<x ' + item.attributeName + '>';
|
|
53
|
-
element.setAttributeNode(attributeElement.children[0].attributes[0].cloneNode()); // trigger a style refresh in IE and Edge
|
|
54
|
-
|
|
55
|
-
document.documentElement.style.zoom = 1;
|
|
56
|
-
document.documentElement.style.zoom = null;
|
|
57
|
-
}
|
|
58
|
-
}); // remove the encoded attribute from all nodes that no longer match them
|
|
59
|
-
|
|
60
|
-
item.nodes.forEach(function (node) {
|
|
61
|
-
if (nodes.indexOf(node) === -1) {
|
|
62
|
-
node.removeAttribute(item.attributeName); // trigger a style refresh in IE and Edge
|
|
63
|
-
|
|
64
|
-
document.documentElement.style.zoom = 1;
|
|
65
|
-
document.documentElement.style.zoom = null;
|
|
66
|
-
}
|
|
67
|
-
}); // update the
|
|
68
|
-
|
|
69
|
-
item.nodes = nodes;
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
} // remove any observed cssrules that no longer apply
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
function cleanupObservedCssRules() {
|
|
76
|
-
[].push.apply(observedItems, observedItems.splice(0).filter(function (item) {
|
|
77
|
-
return item.rule.parentStyleSheet && item.rule.parentStyleSheet.ownerNode && document.documentElement.contains(item.rule.parentStyleSheet.ownerNode);
|
|
78
|
-
}));
|
|
79
|
-
} // walk a stylesheet to collect observed css rules
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
function walkStyleSheet(styleSheet) {
|
|
83
|
-
try {
|
|
84
|
-
// walk a css rule to collect observed css rules
|
|
85
|
-
[].forEach.call(styleSheet.cssRules || [], function (rule) {
|
|
86
|
-
if (rule.selectorText) {
|
|
87
|
-
// decode the selector text in all browsers to:
|
|
88
|
-
// [1] = :scope, [2] = :not(:has), [3] = :has relative, [4] = :scope relative
|
|
89
|
-
var selectors = decodeURIComponent(rule.selectorText.replace(/\\(.)/g, '$1')).match(/^(.*?)\[:(not-)?has\((.+?)\)\](.*?)$/);
|
|
90
|
-
|
|
91
|
-
if (selectors) {
|
|
92
|
-
var attributeName = ':' + (selectors[2] ? 'not-' : '') + 'has(' + // encode a :has() pseudo selector as an attribute name
|
|
93
|
-
encodeURIComponent(selectors[3]).replace(/%3A/g, ':').replace(/%5B/g, '[').replace(/%5D/g, ']').replace(/%2C/g, ',') + ')';
|
|
94
|
-
observedItems.push({
|
|
95
|
-
rule: rule,
|
|
96
|
-
scopeSelector: selectors[1],
|
|
97
|
-
isNot: selectors[2],
|
|
98
|
-
relativeSelectors: selectors[3].split(/\s*,\s*/),
|
|
99
|
-
attributeName: attributeName,
|
|
100
|
-
nodes: []
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
} else {
|
|
104
|
-
walkStyleSheet(rule);
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
} catch (error) {
|
|
108
|
-
/* do nothing and continue */
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/* global self */
|
|
114
|
-
self.cssHasPseudo = cssHasPseudo;
|
|
115
|
-
|
|
116
|
-
})();
|
|
1
|
+
!function(){function e(e){if("csstools-has-"!==e.slice(0,13))return"";for(var t=(e=e.slice(13)).split("-"),r="",n=0;n<t.length;n++)r+=String.fromCharCode(parseInt(t[n],36));return r}function t(e){if(""===e)return"";for(var t,r="",n=0;n<e.length;n++)t=e.charCodeAt(n).toString(36),r+=0===n?t:"-"+t;return"csstools-has-"+r}!function(e){try{if(e.document.querySelector(":has(*, :does-not-exist, > *)"),e.document.querySelector(":has(:has(any))"),!e.document.querySelector(":has(:scope *)"))return}catch(e){}var t=d(e.Element.prototype.querySelector);e.Element.prototype.querySelector=function(e){return t.apply(this,arguments)};var r=d(e.Element.prototype.querySelectorAll);if(e.Element.prototype.querySelectorAll=function(e){return r.apply(this,arguments)},e.Element.prototype.matches){var n=d(e.Element.prototype.matches);e.Element.prototype.matches=function(e){return n.apply(this,arguments)}}if(e.Element.prototype.closest){var o=d(e.Element.prototype.closest);e.Element.prototype.closest=function(e){return o.apply(this,arguments)}}if("Document"in e&&"prototype"in e.Document){var i=d(e.Document.prototype.querySelector);e.Document.prototype.querySelector=function(e){return i.apply(this,arguments)};var s=d(e.Document.prototype.querySelectorAll);if(e.Document.prototype.querySelectorAll=function(e){return s.apply(this,arguments)},e.Document.prototype.matches){var c=d(e.Document.prototype.matches);e.Document.prototype.matches=function(e){return c.apply(this,arguments)}}if(e.Document.prototype.closest){var a=d(e.Document.prototype.closest);e.Document.prototype.closest=function(e){return a.apply(this,arguments)}}}function u(e){for(var t="",r=0,n=0,o=!1,i=!1,s=!1,c=!1,a=0;a<e.length;a++){var u=e[a];if(o)t+=u,o=!1;else switch(":has("!==t.toLowerCase()||c||(c=!0,r=a,t=""),u){case":":if(i){t+=u;continue}c||(t=""),t+=u;continue;case"(":c&&n++,t+=u;continue;case")":if(c){if(0===n)return{innerQuery:t,start:r,end:a-1};n--}t+=u;continue;case"\\":t+=u,o=!0;continue;case'"':case"'":if(i&&u===s){t+=u,i=!1;continue}t+=u,i=!0,s=u;continue;default:t+=u;continue}}return!1}function l(e,t){for(var r=[],n="",o=!1,i=!1,s=!1,c=0;c<e.length;c++){var a=e[c];if(o)n+=a,o=!1;else switch(":scope"!==n.toLowerCase()||/^[\w|\\]/.test(a||"")||(r.push(n.slice(0,n.length-6)),r.push("["+t+"]"),n=""),a){case":":if(i){n+=a;continue}r.push(n),n="",n+=a;continue;case"\\":n+=a,o=!0;continue;case'"':case"'":if(i&&a===s){n+=a,i=!1;continue}n+=a,i=!0,s=a;continue;default:n+=a;continue}}return 0===r.length?e:r.join("")+n}function f(e){for(var t,r,n=[],o="",i=!1,s=!1,c=!1,a=!1,u=0,l=0;l<e.length;l++){var f=e[l];if(i)o+=f,i=!1;else switch(f){case",":if(s){o+=f;continue}if(u>0){o+=f;continue}n.push(o),o="";continue;case"\\":o+=f,i=!0;continue;case'"':case"'":if(s&&f===c){o+=f,s=!1;continue}o+=f,s=!0,c=f;continue;case"(":case")":case"[":case"]":if(s){o+=f;continue}if(t=f,"("===(r=a)&&")"===t||"["===r&&"]"===t){o+=f,0===--u&&(a=!1);continue}if(f===a){o+=f,u++;continue}o+=f,u++,a=f;continue;default:o+=f;continue}}return n.push(o),n}function p(e,t,r){var n=u(e);if(!n)return e;if(t)return!1;var o=n.innerQuery,i="q-has"+(Math.floor(9e6*Math.random())+1e6),s="["+i+"]",c=e;if(n.innerQuery.toLowerCase().indexOf(":has(")>-1){for(var a=f(n.innerQuery),l=[],h=0;h<a.length;h++){var d=a[h];p(d,!0,(function(){}))?l.push(d):l.push(":not(*)")}var m=c.substring(0,n.start-5),y=c.substring(n.end+2);return m+l.join(", ")+y}m=c.substring(0,n.start-5),y=c.substring(n.end+2);if(c=m+s+y,r(o,i),c.toLowerCase().indexOf(":has(")>-1){var v=p(c,!1,r);if(v)return v}return c}function h(e,t){if("setAttribute"in e&&"querySelector"in e&&t(e),e.hasChildNodes())for(var r=e.childNodes,n=0;n<r.length;++n)h(r[n],t)}function d(t){return function(r){if(-1===r.toLowerCase().indexOf(":has(")||!u(r))return t.apply(this,arguments);var n;if("getRootNode"in this)n=this.getRootNode();else for(var o=this;o;)n=o,o=o.parentNode;var i=this;i===e.document&&(i=e.document.documentElement);var s="q-has-scope"+(Math.floor(9e6*Math.random())+1e6);i.setAttribute(s,"");try{r=l(r,s);var c=[s],a=p(r,!1,(function(e,t){c.push(t);for(var r=f(e),o=0;o<r.length;o++){var i=r[o].trim(),s=i;s=">"===i[0]||"+"===i[0]||"~"===i[0]?i.slice(1).trim():":scope "+i;try{h(n,(function(e){if(e.querySelector(s))switch(i[0]){case"~":case"+":for(var r=e.childNodes,n=0;n<r.length;n++){var o=r[n];if("setAttribute"in o){var c="q-has-id"+(Math.floor(9e6*Math.random())+1e6);o.setAttribute(c,""),e.querySelector(":scope ["+c+"] "+i)&&o.setAttribute(t,""),o.removeAttribute(c)}}break;case">":c="q-has-id"+(Math.floor(9e6*Math.random())+1e6);e.setAttribute(c,""),e.querySelector(":scope["+c+"] "+i)&&e.setAttribute(t,""),e.removeAttribute(c);break;default:e.setAttribute(t,"")}}))}catch(e){}}}));arguments[0]=a;var d=t.apply(this,arguments);if(i.removeAttribute(s),c.length>0){for(var m=[],y=0;y<c.length;y++)m.push("["+c[y]+"]");for(var v=e.document.querySelectorAll(m.join(",")),b=0;b<v.length;b++)for(var g=v[b],E=0;E<c.length;E++)g.removeAttribute(c[E])}return d}catch(t){if(i.removeAttribute(s),c.length>0){for(m=[],y=0;y<c.length;y++)m.push("["+c[y]+"]");for(v=e.document.querySelectorAll(m.join(",")),b=0;b<v.length;b++)for(g=v[b],E=0;E<c.length;E++)g.removeAttribute(c[E])}throw t}}}}(self),self.cssHasPseudo=function(r,n){n||(n={}),(n={hover:!!n.hover||!1,debug:!!n.debug||!1,observedAttributes:n.observedAttributes||[],forcePolyfill:!!n.forcePolyfill||!1}).mustPolyfill=n.forcePolyfill||!function(e){try{if(e.querySelector(":has(*, :does-not-exist, > *)"),e.querySelector(":has(:has(any))"),e.querySelector(":has(:scope *)"))return!1;if(!("CSS"in self)||!("supports"in self.CSS)||!self.CSS.supports(":has(any)"))return!1}catch(e){return!1}return!0}(r),Array.isArray(n.observedAttributes)||(n.observedAttributes=[]),n.observedAttributes=n.observedAttributes.filter((function(e){return"string"==typeof e})),n.observedAttributes=n.observedAttributes.concat(["accept","accept-charset","accesskey","action","align","allow","alt","async","autocapitalize","autocomplete","autofocus","autoplay","buffered","capture","challenge","charset","checked","cite","class","code","codebase","cols","colspan","content","contenteditable","contextmenu","controls","coords","crossorigin","csp","data","datetime","decoding","default","defer","dir","dirname","disabled","download","draggable","enctype","enterkeyhint","for","form","formaction","formenctype","formmethod","formnovalidate","formtarget","headers","hidden","high","href","hreflang","http-equiv","icon","id","importance","integrity","intrinsicsize","inputmode","ismap","itemprop","keytype","kind","label","lang","language","list","loop","low","manifest","max","maxlength","minlength","media","method","min","multiple","muted","name","novalidate","open","optimum","pattern","ping","placeholder","poster","preload","radiogroup","readonly","referrerpolicy","rel","required","reversed","rows","rowspan","sandbox","scope","scoped","selected","shape","size","sizes","slot","span","spellcheck","src","srcdoc","srclang","srcset","start","step","summary","tabindex","target","title","translate","type","usemap","value","width","wrap"]);var o=[],i=r.createElement("x");if([].forEach.call(r.styleSheets,u),n.mustPolyfill){if(a(),"MutationObserver"in self)new MutationObserver((function(e){e.forEach((function(e){[].forEach.call(e.addedNodes||[],(function(e){1===e.nodeType&&e.sheet&&u(e.sheet)})),[].push.apply(o,o.splice(0).filter((function(e){return e.rule.parentStyleSheet&&e.rule.parentStyleSheet.ownerNode&&r.documentElement.contains(e.rule.parentStyleSheet.ownerNode)}))),a()}))})).observe(r,{childList:!0,subtree:!0,attributes:!0,attributeFilter:n.observedAttributes});if(r.addEventListener("focus",a,!0),r.addEventListener("blur",a,!0),r.addEventListener("input",a),r.addEventListener("change",a,!0),n.hover&&("onpointerenter"in r?(r.addEventListener("pointerenter",a,!0),r.addEventListener("pointerleave",a,!0)):(r.addEventListener("mouseover",a,!0),r.addEventListener("mouseout",a,!0))),"defineProperty"in Object&&"getOwnPropertyDescriptor"in Object&&"hasOwnProperty"in Object)try{var s=function(e,t){if(e.hasOwnProperty(t)){var r=Object.getOwnPropertyDescriptor(e,t);r&&r.configurable&&"set"in r&&Object.defineProperty(e,t,{configurable:r.configurable,enumerable:r.enumerable,get:function(){return r.get.apply(this,arguments)},set:function(){r.set.apply(this,arguments);try{a()}catch(e){}}})}};"HTMLElement"in self&&HTMLElement.prototype&&s(HTMLElement.prototype,"disabled"),["checked","selected","readOnly","required"].forEach((function(e){["HTMLButtonElement","HTMLFieldSetElement","HTMLInputElement","HTMLMeterElement","HTMLOptGroupElement","HTMLOptionElement","HTMLOutputElement","HTMLProgressElement","HTMLSelectElement","HTMLTextAreaElement"].forEach((function(t){t in self&&self[t].prototype&&s(self[t].prototype,e)}))}))}catch(e){n.debug&&console.error(e)}var c=!1}function a(){c&&cancelAnimationFrame(c),c=requestAnimationFrame((function(){o.forEach((function(e){var t=[],o=[];try{o=r.querySelectorAll(e.selector)}catch(e){return void(n.debug&&console.error(e))}[].forEach.call(o,(function(n){t.push(n),i.innerHTML="<x "+e.attributeName+">",n.setAttributeNode(i.children[0].attributes[0].cloneNode()),r.documentElement.style.zoom=1,r.documentElement.style.zoom=null})),e.nodes.forEach((function(n){-1===t.indexOf(n)&&(n.removeAttribute(e.attributeName),r.documentElement.style.zoom=1,r.documentElement.style.zoom=null)})),e.nodes=t}))}))}function u(r){try{[].forEach.call(r.cssRules||[],(function(r){if(r.selectorText){r.selectorText=r.selectorText.replace(/\.js-has-pseudo\s/g,"");try{var i=function(t){for(var r,n,o=[],i=0,s=!1,c=!1,a=0;a<t.length;a++){var u=t[a];switch(u){case"[":if(s){r+=u;continue}0===i?r="":r+=u,i++;continue;case"]":if(s){r+=u;continue}if(0==--i){var l=e(r);c&&o.push(l)}else r+=u;continue;case"\\":r+=t[a],r+=t[a+1],a++;continue;case'"':case"'":if(s&&u===n){s=!1;continue}if(s){r+=u;continue}s=!0,n=u;continue;default:""===r&&1===i&&"csstools-has-"===t.slice(a,a+13)&&(c=!0),r+=u;continue}}for(var f=[],p=0;p<o.length;p++)-1===f.indexOf(o[p])&&f.push(o[p]);return f}(r.selectorText.toString());if(0===i.length)return;if(!n.mustPolyfill)return void r.deleteRule();for(var s=0;s<i.length;s++){var c=i[s];o.push({rule:r,selector:c,attributeName:t(c),nodes:[]})}}catch(e){n.debug&&console.error(e)}}else u(r)}))}catch(e){n.debug&&console.error(e)}}}}();
|
|
117
2
|
//# sourceMappingURL=browser-global.js.map
|