postcss-focus-within 5.0.4 → 6.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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changes to PostCSS Focus Within
2
2
 
3
+ ### 6.0.0 (July 8, 2022)
4
+
5
+ - Breaking: Changed generated classes so it prepends `.js-focus-within` to the
6
+ generated class so CSS is applied when the polyfill is known to be running.
7
+ - Added: Now bundling browser polyfill.
8
+
3
9
  ### 5.0.4 (February 5, 2022)
4
10
 
5
11
  - Improved `es module` and `commonjs` compatibility
package/README.md CHANGED
@@ -1,36 +1,28 @@
1
1
  # PostCSS Focus Within [<img src="https://postcss.github.io/postcss/logo.svg" alt="PostCSS Logo" width="90" height="90" align="right">][postcss]
2
2
 
3
- [<img alt="npm version" src="https://img.shields.io/npm/v/postcss-focus-within.svg" height="20">][npm-url]
4
- [<img alt="CSS Standard Status" src="https://cssdb.org/images/badges/focus-within-pseudo-class.svg" height="20">][css-url]
5
- [<img alt="Build Status" src="https://github.com/csstools/postcss-plugins/tree/main/postcss-focus-within/workflows/test/badge.svg" height="20">][cli-url]
6
- [<img alt="Discord" src="https://shields.io/badge/Discord-5865F2?logo=discord&logoColor=white">][discord]
3
+ [<img alt="npm version" src="https://img.shields.io/npm/v/postcss-focus-within.svg" height="20">][npm-url] [<img alt="CSS Standard Status" src="https://cssdb.org/images/badges/focus-within-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]
7
4
 
8
- [PostCSS Focus Within] lets you use the `:focus-within` pseudo-class in CSS,
5
+ [PostCSS Focus Within] lets you use the `:focus-within` pseudo-class in CSS,
9
6
  following the [Selectors Level 4 specification].
10
7
 
11
- It is the companion to the [focus-within polyfill].
12
-
13
- [!['Can I use' table](https://caniuse.bitsofco.de/image/css-focus-within.png)](https://caniuse.com/#feat=css-focus-within)
14
-
15
- ```css
8
+ ```pcss
16
9
  .my-form-field:focus-within label {
17
- background-color: yellow;
10
+ background-color: yellow;
18
11
  }
19
12
 
20
13
  /* becomes */
21
14
 
22
- .my-form-field[focus-within] label {
23
- background-color: yellow;
15
+ .my-form-field[focus-within].js-focus-within label, .js-focus-within .my-form-field[focus-within] label {
16
+ background-color: yellow;
24
17
  }
25
-
26
18
  .my-form-field:focus-within label {
27
- background-color: yellow;
19
+ background-color: yellow;
28
20
  }
29
21
  ```
30
22
 
31
23
  [PostCSS Focus Within] duplicates rules using the `:focus-within` pseudo-class
32
24
  with a `[focus-within]` attribute selector, the same selector used by the
33
- [focus-within polyfill]. This replacement selector can be changed using the
25
+ focus-within polyfill. This replacement selector can be changed using the
34
26
  `replaceWith` option. Also, the preservation of the original `:focus-within`
35
27
  rule can be disabled using the `preserve` option.
36
28
 
@@ -42,22 +34,14 @@ Add [PostCSS Focus Within] to your project:
42
34
  npm install postcss postcss-focus-within --save-dev
43
35
  ```
44
36
 
45
- Use [PostCSS Focus Within] to process your CSS:
46
-
47
- ```js
48
- const postcssFocusWithin = require('postcss-focus-within');
49
-
50
- postcssFocusWithin.process(YOUR_CSS /*, processOptions, pluginOptions */);
51
- ```
52
-
53
- Or use it as a [PostCSS] plugin:
37
+ Use it as a [PostCSS] plugin:
54
38
 
55
39
  ```js
56
40
  const postcss = require('postcss');
57
41
  const postcssFocusWithin = require('postcss-focus-within');
58
42
 
59
43
  postcss([
60
- postcssFocusWithin(/* pluginOptions */)
44
+ postcssFocusWithin(/* pluginOptions */)
61
45
  ]).process(YOUR_CSS /*, processOptions */);
62
46
  ```
63
47
 
@@ -71,22 +55,22 @@ instructions for:
71
55
 
72
56
  ### preserve
73
57
 
74
- The `preserve` option defines whether the original selector should remain. By
75
- default, the original selector is preserved.
58
+ The `preserve` option determines whether the original notation
59
+ is preserved. By default, it is preserved.
76
60
 
77
61
  ```js
78
- focusWithin({ preserve: false });
62
+ postcssFocusWithin({ preserve: false })
79
63
  ```
80
64
 
81
- ```css
65
+ ```pcss
82
66
  .my-form-field:focus-within label {
83
- background-color: yellow;
67
+ background-color: yellow;
84
68
  }
85
69
 
86
70
  /* becomes */
87
71
 
88
- .my-form-field[focus-within] label {
89
- background-color: yellow;
72
+ .my-form-field[focus-within].js-focus-within label, .js-focus-within .my-form-field[focus-within] label {
73
+ background-color: yellow;
90
74
  }
91
75
  ```
92
76
 
@@ -94,36 +78,82 @@ focusWithin({ preserve: false });
94
78
 
95
79
  The `replaceWith` option defines the selector to replace `:focus-within`. By
96
80
  default, the replacement selector is `[focus-within]`.
81
+ Please note that using a class, leverages `classList` under the hood which
82
+ might not be supported on some old browsers such as IE9, so you may need
83
+ to polyfill `classList` in those cases.
97
84
 
98
85
  ```js
99
- focusWithin({ replaceWith: '.focus-within' });
86
+ postcssFocusWithin({ replaceWith: '.focus-within' });
100
87
  ```
101
88
 
102
- ```css
89
+ ```pcss
103
90
  .my-form-field:focus-within label {
104
- background-color: yellow;
91
+ background-color: yellow;
105
92
  }
106
93
 
107
94
  /* becomes */
108
95
 
109
- .my-form-field.focus-within label {
110
- background-color: yellow;
96
+ .my-form-field.focus-within.js-focus-within label, .js-focus-within .my-form-field.focus-within label {
97
+ background-color: yellow;
111
98
  }
112
-
113
99
  .my-form-field:focus-within label {
114
- background-color: yellow;
100
+ background-color: yellow;
115
101
  }
116
102
  ```
117
103
 
104
+ Note that changing this option implies that it needs to be passed to the
105
+ browser polyfill as well.
106
+
107
+ ## Browser
108
+
109
+ ```js
110
+ import focusWithinInit from 'postcss-focus-within/browser';
111
+
112
+ focusWithinInit();
113
+ ```
114
+
115
+ or
116
+
117
+ ```html
118
+ <!-- When using a CDN url you will have to manually update the version number -->
119
+ <script src="https://unpkg.com/postcss-focus-within@5.0.4/dist/browser-global.js"></script>
120
+ <script>focusWithinInit()</script>
121
+ ```
122
+
123
+ [PostCSS Focus Within] works in all major browsers, including Safari 6+ and
124
+ Internet Explorer 9+ without any additional polyfills.
125
+
126
+ ### Browser Usage
127
+
128
+ #### force
129
+
130
+ The `force` option determines whether the library runs even if the browser
131
+ supports the selector or not. By default, it won't run if the browser does
132
+ support the selector.
133
+
134
+ ```js
135
+ focusWithinInit({ force: true });
136
+ ```
137
+
138
+ #### replaceWith
139
+
140
+ Similar to the option for the PostCSS Plugin, `replaceWith` determines the
141
+ attribute or class to apply to an element when it's considered to be `:focus-within`.
142
+
143
+ ```js
144
+ focusWithinInit({ replaceWith: '.focus-within });
145
+ ```
146
+
147
+ This option should be used if it was changed at PostCSS configuration level.
148
+
149
+ [cli-url]: https://github.com/csstools/postcss-plugins/actions/workflows/test.yml?query=workflow/test
118
150
  [css-url]: https://cssdb.org/#focus-within-pseudo-class
119
- [cli-url]: https://github.com/csstools/postcss-plugins/tree/main/postcss-focus-within/actions/workflows/test.yml?query=workflow/test
120
151
  [discord]: https://discord.gg/bUadyRwkJS
121
152
  [npm-url]: https://www.npmjs.com/package/postcss-focus-within
122
153
 
123
- [focus-within polyfill]: https://github.com/jsxtools/focus-within
124
154
  [Gulp PostCSS]: https://github.com/postcss/gulp-postcss
125
155
  [Grunt PostCSS]: https://github.com/nDmitry/grunt-postcss
126
156
  [PostCSS]: https://github.com/postcss/postcss
127
- [PostCSS Focus Within]: https://github.com/csstools/postcss-plugins/tree/main/postcss-focus-within
128
157
  [PostCSS Loader]: https://github.com/postcss/postcss-loader
158
+ [PostCSS Focus Within]: https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-focus-within
129
159
  [Selectors Level 4 specification]: https://www.w3.org/TR/selectors-4/#the-focus-within-pseudo
@@ -0,0 +1,2 @@
1
+ !function(){var e=[" ",">","~",":","+","@","#","(",")"];self.focusWithinInit=function(t){var n={force:!1,replaceWith:"[focus-within]"};if(void 0!==t&&"force"in t&&(n.force=t.force),void 0!==t&&"replaceWith"in t&&(n.replaceWith=t.replaceWith),!function(t){for(var n=!0,c=0,i=e.length;c<i&&n;c++)t.indexOf(e[c])>-1&&(n=!1);return n}(n.replaceWith))throw new Error(n.replaceWith+" is not a valid replacement since it can't be applied to single elements.");try{if(document.querySelector(":focus-within"),!n.force)return}catch(e){}var c,i,o,r,u,a=(c=n.replaceWith,u=[],"."===c[0]?(i=c.slice(1),o=function(e){return e.classList.remove(i)},r=function(e){return e.classList.add(i)}):(i=c.slice(1,-1),o=function(e){return e.removeAttribute(i,"")},r=function(e){return e.setAttribute(i,"")}),function(){u.forEach((function(e){return o(e)})),u.length=0;var e=document.activeElement;if(!/^(#document|HTML|BODY)$/.test(Object(e).nodeName))for(;e&&1===e.nodeType;)r(e),u.push(e),e=e.parentNode}),d=function(){document.documentElement.className.indexOf("js-focus-within")>-1||(document.documentElement.className=document.documentElement.className+" js-focus-within",document.addEventListener("focus",a,!0),document.addEventListener("blur",a,!0))};"complete"===document.readyState?d():document.addEventListener("DOMContentLoaded",d)}}();
2
+ //# sourceMappingURL=browser-global.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-global.js","sources":["../src/is-valid-replacement.mjs","../src/browser-global.js","../src/browser.js"],"sourcesContent":["const INVALID_SELECTOR_CHAR = [\n\t' ', // Can't use child selector\n\t'>', // Can't use direct child selector\n\t'~', // Can't use sibling selector\n\t':', // Can't use pseudo selector\n\t'+', // Can't use adjacent selector\n\t'@', // Can't use at\n\t'#', // Can't use id selector\n\t'(', // Can't use parenthesis\n\t')', // Can't use parenthesis\n];\n\nexport default function isValidReplacement(selector) {\n\tlet isValid = true;\n\n\t// Purposely archaic so it's interoperable in old browsers\n\tfor (let i = 0, length = INVALID_SELECTOR_CHAR.length; i < length && isValid; i++) {\n\t\tif (selector.indexOf(INVALID_SELECTOR_CHAR[i]) > -1) {\n\t\t\tisValid = false;\n\t\t}\n\t}\n\n\treturn isValid;\n}\n","/* global self */\nimport { default as focusWithinInit } from './browser';\nself.focusWithinInit = focusWithinInit;\n","/* global document */\nimport isValidReplacement from './is-valid-replacement.mjs';\nfunction generateHandler(replaceWith) {\n\tlet selector;\n\tlet remove;\n\tlet add;\n\tconst lastElements = [];\n\n\tif (replaceWith[0] === '.') {\n\t\tselector = replaceWith.slice(1);\n\t\tremove = (el) => el.classList.remove(selector);\n\t\tadd = (el) => el.classList.add(selector);\n\t} else {\n\t\t// A bit naive\n\t\tselector = replaceWith.slice(1, -1);\n\t\tremove = (el) => el.removeAttribute(selector, '');\n\t\tadd = (el) => el.setAttribute(selector, '');\n\t}\n\n\treturn function handleFocusChange() {\n\t\tlastElements.forEach(lastElement => remove(lastElement));\n\t\tlastElements.length = 0;\n\n\t\tlet activeElement = document.activeElement;\n\n\t\t// only add focus if it has not been added and is not the document element\n\t\tif (!/^(#document|HTML|BODY)$/.test(Object(activeElement).nodeName)) {\n\t\t\twhile (activeElement && activeElement.nodeType === 1) {\n\t\t\t\tadd(activeElement);\n\t\t\t\tlastElements.push(activeElement);\n\n\t\t\t\tactiveElement = activeElement.parentNode;\n\t\t\t}\n\t\t}\n\t};\n}\n\nexport default function focusWithin(opts) {\n\t// configuration\n\tconst options = {\n\t\tforce: false,\n\t\treplaceWith: '[focus-within]',\n\t};\n\n\tif (typeof opts !== 'undefined' && 'force' in opts) {\n\t\toptions.force = opts.force;\n\t}\n\n\tif (typeof opts !== 'undefined' && 'replaceWith' in opts) {\n\t\toptions.replaceWith = opts.replaceWith;\n\t}\n\n\tif (!isValidReplacement(options.replaceWith)) {\n\t\tthrow new Error(`${options.replaceWith} is not a valid replacement since it can't be applied to single elements.`);\n\t}\n\n\ttry {\n\t\tdocument.querySelector(':focus-within');\n\n\t\tif (!options.force) {\n\t\t\treturn;\n\t\t}\n\t} catch (ignoredError) { /* do nothing and continue */ }\n\n\tconst handleFocusChange = generateHandler(options.replaceWith);\n\n\tconst initialize = function initializeEventListeners() {\n\t\tif (document.documentElement.className.indexOf('js-focus-within') > -1) {\n\t\t\treturn;\n\t\t}\n\n\t\tdocument.documentElement.className = document.documentElement.className + ' js-focus-within';\n\t\tdocument.addEventListener('focus', handleFocusChange, true);\n\t\tdocument.addEventListener('blur', handleFocusChange, true);\n\t};\n\n\tif (document.readyState === 'complete') {\n\t\tinitialize();\n\t} else {\n\t\tdocument.addEventListener('DOMContentLoaded', initialize);\n\t}\n}\n"],"names":["INVALID_SELECTOR_CHAR","self","focusWithinInit","opts","options","force","replaceWith","selector","isValid","i","length","indexOf","isValidReplacement","Error","document","querySelector","ignoredError","remove","add","lastElements","handleFocusChange","slice","el","classList","removeAttribute","setAttribute","forEach","lastElement","activeElement","test","Object","nodeName","nodeType","push","parentNode","initialize","documentElement","className","addEventListener","readyState"],"mappings":"YAAA,IAAMA,EAAwB,CAC7B,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,KCPDC,KAAKC,gBCmCU,SAAqBC,GAEnC,IAAMC,EAAU,CACfC,OAAO,EACPC,YAAa,kBAWd,QARoB,IAATH,GAAwB,UAAWA,IAC7CC,EAAQC,MAAQF,EAAKE,YAGF,IAATF,GAAwB,gBAAiBA,IACnDC,EAAQE,YAAcH,EAAKG,cFrCd,SAA4BC,GAI1C,IAHA,IAAIC,GAAU,EAGLC,EAAI,EAAGC,EAASV,EAAsBU,OAAQD,EAAIC,GAAUF,EAASC,IACzEF,EAASI,QAAQX,EAAsBS,KAAO,IACjDD,GAAU,GAIZ,OAAOA,EE8BFI,CAAmBR,EAAQE,aAC/B,MAAM,IAAIO,MAAST,EAAQE,YAA3B,6EAGD,IAGC,GAFAQ,SAASC,cAAc,kBAElBX,EAAQC,MACZ,OAEA,MAAOW,IAET,IA9DwBV,EACpBC,EACAU,EACAC,EACEC,EA0DAC,GA9DkBd,EA8DkBF,EAAQE,YA1D5Ca,EAAe,GAEE,MAAnBb,EAAY,IACfC,EAAWD,EAAYe,MAAM,GAC7BJ,EAAS,SAACK,GAAD,OAAQA,EAAGC,UAAUN,OAAOV,IACrCW,EAAM,SAACI,GAAD,OAAQA,EAAGC,UAAUL,IAAIX,MAG/BA,EAAWD,EAAYe,MAAM,GAAI,GACjCJ,EAAS,SAACK,GAAD,OAAQA,EAAGE,gBAAgBjB,EAAU,KAC9CW,EAAM,SAACI,GAAD,OAAQA,EAAGG,aAAalB,EAAU,MAGlC,WACNY,EAAaO,SAAQ,SAAAC,GAAW,OAAIV,EAAOU,MAC3CR,EAAaT,OAAS,EAEtB,IAAIkB,EAAgBd,SAASc,cAG7B,IAAK,0BAA0BC,KAAKC,OAAOF,GAAeG,UACzD,KAAOH,GAA4C,IAA3BA,EAAcI,UACrCd,EAAIU,GACJT,EAAac,KAAKL,GAElBA,EAAgBA,EAAcM,aAmC3BC,EAAa,WACdrB,SAASsB,gBAAgBC,UAAU1B,QAAQ,oBAAsB,IAIrEG,SAASsB,gBAAgBC,UAAYvB,SAASsB,gBAAgBC,UAAY,mBAC1EvB,SAASwB,iBAAiB,QAASlB,GAAmB,GACtDN,SAASwB,iBAAiB,OAAQlB,GAAmB,KAG1B,aAAxBN,SAASyB,WACZJ,IAEArB,SAASwB,iBAAiB,mBAAoBH"}
@@ -0,0 +1,2 @@
1
+ var e=[" ",">","~",":","+","@","#","(",")"];module.exports=function(t){var n={force:!1,replaceWith:"[focus-within]"};if(void 0!==t&&"force"in t&&(n.force=t.force),void 0!==t&&"replaceWith"in t&&(n.replaceWith=t.replaceWith),!function(t){for(var n=!0,c=0,r=e.length;c<r&&n;c++)t.indexOf(e[c])>-1&&(n=!1);return n}(n.replaceWith))throw new Error(n.replaceWith+" is not a valid replacement since it can't be applied to single elements.");try{if(document.querySelector(":focus-within"),!n.force)return}catch(e){}var c,r,o,i,u,a=(c=n.replaceWith,u=[],"."===c[0]?(r=c.slice(1),o=function(e){return e.classList.remove(r)},i=function(e){return e.classList.add(r)}):(r=c.slice(1,-1),o=function(e){return e.removeAttribute(r,"")},i=function(e){return e.setAttribute(r,"")}),function(){u.forEach((function(e){return o(e)})),u.length=0;var e=document.activeElement;if(!/^(#document|HTML|BODY)$/.test(Object(e).nodeName))for(;e&&1===e.nodeType;)i(e),u.push(e),e=e.parentNode}),d=function(){document.documentElement.className.indexOf("js-focus-within")>-1||(document.documentElement.className=document.documentElement.className+" js-focus-within",document.addEventListener("focus",a,!0),document.addEventListener("blur",a,!0))};"complete"===document.readyState?d():document.addEventListener("DOMContentLoaded",d)};
2
+ //# sourceMappingURL=browser.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.cjs","sources":["../src/is-valid-replacement.mjs","../src/browser.js"],"sourcesContent":["const INVALID_SELECTOR_CHAR = [\n\t' ', // Can't use child selector\n\t'>', // Can't use direct child selector\n\t'~', // Can't use sibling selector\n\t':', // Can't use pseudo selector\n\t'+', // Can't use adjacent selector\n\t'@', // Can't use at\n\t'#', // Can't use id selector\n\t'(', // Can't use parenthesis\n\t')', // Can't use parenthesis\n];\n\nexport default function isValidReplacement(selector) {\n\tlet isValid = true;\n\n\t// Purposely archaic so it's interoperable in old browsers\n\tfor (let i = 0, length = INVALID_SELECTOR_CHAR.length; i < length && isValid; i++) {\n\t\tif (selector.indexOf(INVALID_SELECTOR_CHAR[i]) > -1) {\n\t\t\tisValid = false;\n\t\t}\n\t}\n\n\treturn isValid;\n}\n","/* global document */\nimport isValidReplacement from './is-valid-replacement.mjs';\nfunction generateHandler(replaceWith) {\n\tlet selector;\n\tlet remove;\n\tlet add;\n\tconst lastElements = [];\n\n\tif (replaceWith[0] === '.') {\n\t\tselector = replaceWith.slice(1);\n\t\tremove = (el) => el.classList.remove(selector);\n\t\tadd = (el) => el.classList.add(selector);\n\t} else {\n\t\t// A bit naive\n\t\tselector = replaceWith.slice(1, -1);\n\t\tremove = (el) => el.removeAttribute(selector, '');\n\t\tadd = (el) => el.setAttribute(selector, '');\n\t}\n\n\treturn function handleFocusChange() {\n\t\tlastElements.forEach(lastElement => remove(lastElement));\n\t\tlastElements.length = 0;\n\n\t\tlet activeElement = document.activeElement;\n\n\t\t// only add focus if it has not been added and is not the document element\n\t\tif (!/^(#document|HTML|BODY)$/.test(Object(activeElement).nodeName)) {\n\t\t\twhile (activeElement && activeElement.nodeType === 1) {\n\t\t\t\tadd(activeElement);\n\t\t\t\tlastElements.push(activeElement);\n\n\t\t\t\tactiveElement = activeElement.parentNode;\n\t\t\t}\n\t\t}\n\t};\n}\n\nexport default function focusWithin(opts) {\n\t// configuration\n\tconst options = {\n\t\tforce: false,\n\t\treplaceWith: '[focus-within]',\n\t};\n\n\tif (typeof opts !== 'undefined' && 'force' in opts) {\n\t\toptions.force = opts.force;\n\t}\n\n\tif (typeof opts !== 'undefined' && 'replaceWith' in opts) {\n\t\toptions.replaceWith = opts.replaceWith;\n\t}\n\n\tif (!isValidReplacement(options.replaceWith)) {\n\t\tthrow new Error(`${options.replaceWith} is not a valid replacement since it can't be applied to single elements.`);\n\t}\n\n\ttry {\n\t\tdocument.querySelector(':focus-within');\n\n\t\tif (!options.force) {\n\t\t\treturn;\n\t\t}\n\t} catch (ignoredError) { /* do nothing and continue */ }\n\n\tconst handleFocusChange = generateHandler(options.replaceWith);\n\n\tconst initialize = function initializeEventListeners() {\n\t\tif (document.documentElement.className.indexOf('js-focus-within') > -1) {\n\t\t\treturn;\n\t\t}\n\n\t\tdocument.documentElement.className = document.documentElement.className + ' js-focus-within';\n\t\tdocument.addEventListener('focus', handleFocusChange, true);\n\t\tdocument.addEventListener('blur', handleFocusChange, true);\n\t};\n\n\tif (document.readyState === 'complete') {\n\t\tinitialize();\n\t} else {\n\t\tdocument.addEventListener('DOMContentLoaded', initialize);\n\t}\n}\n"],"names":["INVALID_SELECTOR_CHAR","opts","options","force","replaceWith","selector","isValid","i","length","indexOf","isValidReplacement","Error","document","querySelector","ignoredError","remove","add","lastElements","handleFocusChange","slice","el","classList","removeAttribute","setAttribute","forEach","lastElement","activeElement","test","Object","nodeName","nodeType","push","parentNode","initialize","documentElement","className","addEventListener","readyState"],"mappings":"AAAA,IAAMA,EAAwB,CAC7B,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,oBC4Bc,SAAqBC,GAEnC,IAAMC,EAAU,CACfC,OAAO,EACPC,YAAa,kBAWd,QARoB,IAATH,GAAwB,UAAWA,IAC7CC,EAAQC,MAAQF,EAAKE,YAGF,IAATF,GAAwB,gBAAiBA,IACnDC,EAAQE,YAAcH,EAAKG,cDrCd,SAA4BC,GAI1C,IAHA,IAAIC,GAAU,EAGLC,EAAI,EAAGC,EAASR,EAAsBQ,OAAQD,EAAIC,GAAUF,EAASC,IACzEF,EAASI,QAAQT,EAAsBO,KAAO,IACjDD,GAAU,GAIZ,OAAOA,EC8BFI,CAAmBR,EAAQE,aAC/B,MAAM,IAAIO,MAAST,EAAQE,YAA3B,6EAGD,IAGC,GAFAQ,SAASC,cAAc,kBAElBX,EAAQC,MACZ,OAEA,MAAOW,IAET,IA9DwBV,EACpBC,EACAU,EACAC,EACEC,EA0DAC,GA9DkBd,EA8DkBF,EAAQE,YA1D5Ca,EAAe,GAEE,MAAnBb,EAAY,IACfC,EAAWD,EAAYe,MAAM,GAC7BJ,EAAS,SAACK,GAAD,OAAQA,EAAGC,UAAUN,OAAOV,IACrCW,EAAM,SAACI,GAAD,OAAQA,EAAGC,UAAUL,IAAIX,MAG/BA,EAAWD,EAAYe,MAAM,GAAI,GACjCJ,EAAS,SAACK,GAAD,OAAQA,EAAGE,gBAAgBjB,EAAU,KAC9CW,EAAM,SAACI,GAAD,OAAQA,EAAGG,aAAalB,EAAU,MAGlC,WACNY,EAAaO,SAAQ,SAAAC,GAAW,OAAIV,EAAOU,MAC3CR,EAAaT,OAAS,EAEtB,IAAIkB,EAAgBd,SAASc,cAG7B,IAAK,0BAA0BC,KAAKC,OAAOF,GAAeG,UACzD,KAAOH,GAA4C,IAA3BA,EAAcI,UACrCd,EAAIU,GACJT,EAAac,KAAKL,GAElBA,EAAgBA,EAAcM,aAmC3BC,EAAa,WACdrB,SAASsB,gBAAgBC,UAAU1B,QAAQ,oBAAsB,IAIrEG,SAASsB,gBAAgBC,UAAYvB,SAASsB,gBAAgBC,UAAY,mBAC1EvB,SAASwB,iBAAiB,QAASlB,GAAmB,GACtDN,SAASwB,iBAAiB,OAAQlB,GAAmB,KAG1B,aAAxBN,SAASyB,WACZJ,IAEArB,SAASwB,iBAAiB,mBAAoBH"}
@@ -0,0 +1,2 @@
1
+ var e=[" ",">","~",":","+","@","#","(",")"];function t(t){var n={force:!1,replaceWith:"[focus-within]"};if(void 0!==t&&"force"in t&&(n.force=t.force),void 0!==t&&"replaceWith"in t&&(n.replaceWith=t.replaceWith),!function(t){for(var n=!0,c=0,r=e.length;c<r&&n;c++)t.indexOf(e[c])>-1&&(n=!1);return n}(n.replaceWith))throw new Error(n.replaceWith+" is not a valid replacement since it can't be applied to single elements.");try{if(document.querySelector(":focus-within"),!n.force)return}catch(e){}var c,r,o,i,u,a=(c=n.replaceWith,u=[],"."===c[0]?(r=c.slice(1),o=function(e){return e.classList.remove(r)},i=function(e){return e.classList.add(r)}):(r=c.slice(1,-1),o=function(e){return e.removeAttribute(r,"")},i=function(e){return e.setAttribute(r,"")}),function(){u.forEach((function(e){return o(e)})),u.length=0;var e=document.activeElement;if(!/^(#document|HTML|BODY)$/.test(Object(e).nodeName))for(;e&&1===e.nodeType;)i(e),u.push(e),e=e.parentNode}),d=function(){document.documentElement.className.indexOf("js-focus-within")>-1||(document.documentElement.className=document.documentElement.className+" js-focus-within",document.addEventListener("focus",a,!0),document.addEventListener("blur",a,!0))};"complete"===document.readyState?d():document.addEventListener("DOMContentLoaded",d)}export{t as default};
2
+ //# sourceMappingURL=browser.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.mjs","sources":["../src/is-valid-replacement.mjs","../src/browser.js"],"sourcesContent":["const INVALID_SELECTOR_CHAR = [\n\t' ', // Can't use child selector\n\t'>', // Can't use direct child selector\n\t'~', // Can't use sibling selector\n\t':', // Can't use pseudo selector\n\t'+', // Can't use adjacent selector\n\t'@', // Can't use at\n\t'#', // Can't use id selector\n\t'(', // Can't use parenthesis\n\t')', // Can't use parenthesis\n];\n\nexport default function isValidReplacement(selector) {\n\tlet isValid = true;\n\n\t// Purposely archaic so it's interoperable in old browsers\n\tfor (let i = 0, length = INVALID_SELECTOR_CHAR.length; i < length && isValid; i++) {\n\t\tif (selector.indexOf(INVALID_SELECTOR_CHAR[i]) > -1) {\n\t\t\tisValid = false;\n\t\t}\n\t}\n\n\treturn isValid;\n}\n","/* global document */\nimport isValidReplacement from './is-valid-replacement.mjs';\nfunction generateHandler(replaceWith) {\n\tlet selector;\n\tlet remove;\n\tlet add;\n\tconst lastElements = [];\n\n\tif (replaceWith[0] === '.') {\n\t\tselector = replaceWith.slice(1);\n\t\tremove = (el) => el.classList.remove(selector);\n\t\tadd = (el) => el.classList.add(selector);\n\t} else {\n\t\t// A bit naive\n\t\tselector = replaceWith.slice(1, -1);\n\t\tremove = (el) => el.removeAttribute(selector, '');\n\t\tadd = (el) => el.setAttribute(selector, '');\n\t}\n\n\treturn function handleFocusChange() {\n\t\tlastElements.forEach(lastElement => remove(lastElement));\n\t\tlastElements.length = 0;\n\n\t\tlet activeElement = document.activeElement;\n\n\t\t// only add focus if it has not been added and is not the document element\n\t\tif (!/^(#document|HTML|BODY)$/.test(Object(activeElement).nodeName)) {\n\t\t\twhile (activeElement && activeElement.nodeType === 1) {\n\t\t\t\tadd(activeElement);\n\t\t\t\tlastElements.push(activeElement);\n\n\t\t\t\tactiveElement = activeElement.parentNode;\n\t\t\t}\n\t\t}\n\t};\n}\n\nexport default function focusWithin(opts) {\n\t// configuration\n\tconst options = {\n\t\tforce: false,\n\t\treplaceWith: '[focus-within]',\n\t};\n\n\tif (typeof opts !== 'undefined' && 'force' in opts) {\n\t\toptions.force = opts.force;\n\t}\n\n\tif (typeof opts !== 'undefined' && 'replaceWith' in opts) {\n\t\toptions.replaceWith = opts.replaceWith;\n\t}\n\n\tif (!isValidReplacement(options.replaceWith)) {\n\t\tthrow new Error(`${options.replaceWith} is not a valid replacement since it can't be applied to single elements.`);\n\t}\n\n\ttry {\n\t\tdocument.querySelector(':focus-within');\n\n\t\tif (!options.force) {\n\t\t\treturn;\n\t\t}\n\t} catch (ignoredError) { /* do nothing and continue */ }\n\n\tconst handleFocusChange = generateHandler(options.replaceWith);\n\n\tconst initialize = function initializeEventListeners() {\n\t\tif (document.documentElement.className.indexOf('js-focus-within') > -1) {\n\t\t\treturn;\n\t\t}\n\n\t\tdocument.documentElement.className = document.documentElement.className + ' js-focus-within';\n\t\tdocument.addEventListener('focus', handleFocusChange, true);\n\t\tdocument.addEventListener('blur', handleFocusChange, true);\n\t};\n\n\tif (document.readyState === 'complete') {\n\t\tinitialize();\n\t} else {\n\t\tdocument.addEventListener('DOMContentLoaded', initialize);\n\t}\n}\n"],"names":["INVALID_SELECTOR_CHAR","focusWithin","opts","options","force","replaceWith","selector","isValid","i","length","indexOf","isValidReplacement","Error","document","querySelector","ignoredError","remove","add","lastElements","handleFocusChange","slice","el","classList","removeAttribute","setAttribute","forEach","lastElement","activeElement","test","Object","nodeName","nodeType","push","parentNode","initialize","documentElement","className","addEventListener","readyState"],"mappings":"AAAA,IAAMA,EAAwB,CAC7B,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,KC4Bc,SAASC,EAAYC,GAEnC,IAAMC,EAAU,CACfC,OAAO,EACPC,YAAa,kBAWd,QARoB,IAATH,GAAwB,UAAWA,IAC7CC,EAAQC,MAAQF,EAAKE,YAGF,IAATF,GAAwB,gBAAiBA,IACnDC,EAAQE,YAAcH,EAAKG,cDrCd,SAA4BC,GAI1C,IAHA,IAAIC,GAAU,EAGLC,EAAI,EAAGC,EAAST,EAAsBS,OAAQD,EAAIC,GAAUF,EAASC,IACzEF,EAASI,QAAQV,EAAsBQ,KAAO,IACjDD,GAAU,GAIZ,OAAOA,EC8BFI,CAAmBR,EAAQE,aAC/B,MAAM,IAAIO,MAAST,EAAQE,YAA3B,6EAGD,IAGC,GAFAQ,SAASC,cAAc,kBAElBX,EAAQC,MACZ,OAEA,MAAOW,IAET,IA9DwBV,EACpBC,EACAU,EACAC,EACEC,EA0DAC,GA9DkBd,EA8DkBF,EAAQE,YA1D5Ca,EAAe,GAEE,MAAnBb,EAAY,IACfC,EAAWD,EAAYe,MAAM,GAC7BJ,EAAS,SAACK,GAAD,OAAQA,EAAGC,UAAUN,OAAOV,IACrCW,EAAM,SAACI,GAAD,OAAQA,EAAGC,UAAUL,IAAIX,MAG/BA,EAAWD,EAAYe,MAAM,GAAI,GACjCJ,EAAS,SAACK,GAAD,OAAQA,EAAGE,gBAAgBjB,EAAU,KAC9CW,EAAM,SAACI,GAAD,OAAQA,EAAGG,aAAalB,EAAU,MAGlC,WACNY,EAAaO,SAAQ,SAAAC,GAAW,OAAIV,EAAOU,MAC3CR,EAAaT,OAAS,EAEtB,IAAIkB,EAAgBd,SAASc,cAG7B,IAAK,0BAA0BC,KAAKC,OAAOF,GAAeG,UACzD,KAAOH,GAA4C,IAA3BA,EAAcI,UACrCd,EAAIU,GACJT,EAAac,KAAKL,GAElBA,EAAgBA,EAAcM,aAmC3BC,EAAa,WACdrB,SAASsB,gBAAgBC,UAAU1B,QAAQ,oBAAsB,IAIrEG,SAASsB,gBAAgBC,UAAYvB,SAASsB,gBAAgBC,UAAY,mBAC1EvB,SAASwB,iBAAiB,QAASlB,GAAmB,GACtDN,SAASwB,iBAAiB,OAAQlB,GAAmB,KAG1B,aAAxBN,SAASyB,WACZJ,IAEArB,SAASwB,iBAAiB,mBAAoBH"}
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";function e(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var t=e(require("postcss-selector-parser"));const s=e=>{const s=String(Object(e).replaceWith||"[focus-within]"),r=Boolean(!("preserve"in Object(e))||e.preserve),o=t.default().astSync(s);return{postcssPlugin:"postcss-focus-within",Rule:(e,{result:s})=>{if(!e.selector.includes(":focus-within"))return;let c;try{const s=t.default((e=>{e.walkPseudos((e=>{":focus-within"===e.value&&(e.nodes&&e.nodes.length||e.replaceWith(o.clone({})))}))})).processSync(e.selector);c=String(s)}catch(t){return void e.warn(s,`Failed to parse selector : ${e.selector}`)}if(void 0===c)return;if(c===e.selector)return;const n=e.clone({selector:c});r?e.before(n):e.replaceWith(n)}}};s.postcss=!0,module.exports=s;
1
+ "use strict";function e(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var s=e(require("postcss-selector-parser"));const t=[" ",">","~",":","+","@","#","(",")"];const n=":focus-within",o=e=>{const o=Object.assign({preserve:!0,replaceWith:"[focus-within]"},e),l=s.default().astSync(o.replaceWith);return function(e){let s=!0;for(let n=0,o=t.length;n<o&&s;n++)e.indexOf(t[n])>-1&&(s=!1);return s}(o.replaceWith)?{postcssPlugin:"postcss-focus-within",Rule(e,{result:t}){if(!e.selector.toLowerCase().includes(n))return;const r=e.selectors.flatMap((o=>{if(!o.toLowerCase().includes(n))return[o];let r;try{r=s.default().astSync(o)}catch(s){return e.warn(t,`Failed to parse selector : ${o}`),o}if(void 0===r)return[o];let c=!1;if(r.walkPseudos((e=>{e.value.toLowerCase()===n&&(e.nodes&&e.nodes.length||(c=!0,e.replaceWith(l.clone({}))))})),!c)return[o];const i=r.clone();var a,u,d,f,p;if(null!=(a=r.nodes)&&null!=(u=a[0])&&null!=(d=u.nodes)&&d.length)for(let e=0;e<r.nodes[0].nodes.length;e++){const t=r.nodes[0].nodes[e];if("combinator"===t.type||s.default.isPseudoElement(t)){r.nodes[0].insertBefore(t,s.default.className({value:"js-focus-within"}));break}if(e===r.nodes[0].nodes.length-1){r.nodes[0].append(s.default.className({value:"js-focus-within"}));break}}return null!=(f=r.nodes)&&null!=(p=f[0])&&p.nodes&&(i.nodes[0].prepend(s.default.combinator({value:" "})),i.nodes[0].prepend(s.default.className({value:"js-focus-within"}))),[r.toString(),i.toString()]}));r.join(",")!==e.selectors.join(",")&&(e.cloneBefore({selectors:r}),o.preserve||e.remove())}}:{postcssPlugin:"postcss-focus-within",Once:(e,{result:s})=>{e.warn(s,`${o.replaceWith} is not a valid replacement since it can't be applied to single elements.`)}}};o.postcss=!0,module.exports=o;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { PluginCreator } from 'postcss';
2
- declare const creator: PluginCreator<{
2
+ declare type pluginOptions = {
3
3
  preserve?: boolean;
4
4
  replaceWith?: string;
5
- }>;
5
+ };
6
+ declare const creator: PluginCreator<pluginOptions>;
6
7
  export default creator;
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import e from"postcss-selector-parser";const s=s=>{const t=String(Object(s).replaceWith||"[focus-within]"),r=Boolean(!("preserve"in Object(s))||s.preserve),o=e().astSync(t);return{postcssPlugin:"postcss-focus-within",Rule:(s,{result:t})=>{if(!s.selector.includes(":focus-within"))return;let c;try{const t=e((e=>{e.walkPseudos((e=>{":focus-within"===e.value&&(e.nodes&&e.nodes.length||e.replaceWith(o.clone({})))}))})).processSync(s.selector);c=String(t)}catch(e){return void s.warn(t,`Failed to parse selector : ${s.selector}`)}if(void 0===c)return;if(c===s.selector)return;const n=s.clone({selector:c});r?s.before(n):s.replaceWith(n)}}};s.postcss=!0;export{s as default};
1
+ import e from"postcss-selector-parser";const s=[" ",">","~",":","+","@","#","(",")"];const n=":focus-within",t=t=>{const o=Object.assign({preserve:!0,replaceWith:"[focus-within]"},t),r=e().astSync(o.replaceWith);return function(e){let n=!0;for(let t=0,o=s.length;t<o&&n;t++)e.indexOf(s[t])>-1&&(n=!1);return n}(o.replaceWith)?{postcssPlugin:"postcss-focus-within",Rule(s,{result:t}){if(!s.selector.toLowerCase().includes(n))return;const l=s.selectors.flatMap((o=>{if(!o.toLowerCase().includes(n))return[o];let l;try{l=e().astSync(o)}catch(e){return s.warn(t,`Failed to parse selector : ${o}`),o}if(void 0===l)return[o];let c=!1;if(l.walkPseudos((e=>{e.value.toLowerCase()===n&&(e.nodes&&e.nodes.length||(c=!0,e.replaceWith(r.clone({}))))})),!c)return[o];const i=l.clone();var a,u,d,p,f;if(null!=(a=l.nodes)&&null!=(u=a[0])&&null!=(d=u.nodes)&&d.length)for(let s=0;s<l.nodes[0].nodes.length;s++){const n=l.nodes[0].nodes[s];if("combinator"===n.type||e.isPseudoElement(n)){l.nodes[0].insertBefore(n,e.className({value:"js-focus-within"}));break}if(s===l.nodes[0].nodes.length-1){l.nodes[0].append(e.className({value:"js-focus-within"}));break}}return null!=(p=l.nodes)&&null!=(f=p[0])&&f.nodes&&(i.nodes[0].prepend(e.combinator({value:" "})),i.nodes[0].prepend(e.className({value:"js-focus-within"}))),[l.toString(),i.toString()]}));l.join(",")!==s.selectors.join(",")&&(s.cloneBefore({selectors:l}),o.preserve||s.remove())}}:{postcssPlugin:"postcss-focus-within",Once:(e,{result:s})=>{e.warn(s,`${o.replaceWith} is not a valid replacement since it can't be applied to single elements.`)}}};t.postcss=!0;export{t as default};
package/package.json CHANGED
@@ -1,69 +1,101 @@
1
1
  {
2
- "name": "postcss-focus-within",
3
- "version": "5.0.4",
4
- "description": "Use the :focus-within pseudo-selector in CSS",
5
- "author": "Jonathan Neal <jonathantneal@hotmail.com>",
6
- "license": "CC0-1.0",
7
- "homepage": "https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-focus-within#readme",
8
- "bugs": "https://github.com/csstools/postcss-plugins/issues",
9
- "main": "dist/index.cjs",
10
- "module": "dist/index.mjs",
11
- "types": "dist/index.d.ts",
12
- "exports": {
13
- ".": {
14
- "import": "./dist/index.mjs",
15
- "require": "./dist/index.cjs",
16
- "default": "./dist/index.mjs"
17
- }
18
- },
19
- "files": [
20
- "CHANGELOG.md",
21
- "LICENSE.md",
22
- "README.md",
23
- "dist"
24
- ],
25
- "scripts": {
26
- "build": "rollup -c ../../rollup/default.js",
27
- "clean": "node -e \"fs.rmSync('./dist', { recursive: true, force: true });\"",
28
- "lint": "eslint ./src --ext .js --ext .ts --ext .mjs --no-error-on-unmatched-pattern",
29
- "prepublishOnly": "npm run clean && npm run build && npm run test",
30
- "stryker": "stryker run --logLevel error",
31
- "test": "postcss-tape --ci && npm run test:exports",
32
- "test:exports": "node ./test/_import.mjs && node ./test/_require.cjs"
33
- },
34
- "engines": {
35
- "node": "^12 || ^14 || >=16"
36
- },
37
- "dependencies": {
38
- "postcss-selector-parser": "^6.0.9"
39
- },
40
- "devDependencies": {
41
- "postcss": "^8.3.6",
42
- "postcss-tape": "^6.0.1"
43
- },
44
- "peerDependencies": {
45
- "postcss": "^8.4"
46
- },
47
- "keywords": [
48
- "postcss",
49
- "css",
50
- "postcss-plugin",
51
- "focus",
52
- "within",
53
- "polyfill",
54
- "pseudos",
55
- "selectors",
56
- "accessibility",
57
- "a11y",
58
- "descendants",
59
- "ancestors"
60
- ],
61
- "repository": {
62
- "type": "git",
63
- "url": "https://github.com/csstools/postcss-plugins.git",
64
- "directory": "plugins/postcss-focus-within"
65
- },
66
- "volta": {
67
- "extends": "../../package.json"
68
- }
2
+ "name": "postcss-focus-within",
3
+ "description": "Use the :focus-within pseudo-selector in CSS",
4
+ "version": "6.0.0",
5
+ "contributors": [
6
+ {
7
+ "name": "Antonio Laguna",
8
+ "email": "antonio@laguna.es",
9
+ "url": "https://antonio.laguna.es"
10
+ },
11
+ {
12
+ "name": "Romain Menke",
13
+ "email": "romainmenke@gmail.com"
14
+ },
15
+ {
16
+ "name": "Jonathan Neal",
17
+ "email": "jonathantneal@hotmail.com"
18
+ }
19
+ ],
20
+ "license": "CC0-1.0",
21
+ "funding": {
22
+ "type": "opencollective",
23
+ "url": "https://opencollective.com/csstools"
24
+ },
25
+ "engines": {
26
+ "node": "^12 || ^14 || >=16"
27
+ },
28
+ "main": "dist/index.cjs",
29
+ "module": "dist/index.mjs",
30
+ "types": "dist/index.d.ts",
31
+ "exports": {
32
+ ".": {
33
+ "import": "./dist/index.mjs",
34
+ "require": "./dist/index.cjs",
35
+ "default": "./dist/index.mjs"
36
+ },
37
+ "./browser": {
38
+ "import": "./dist/browser.mjs",
39
+ "require": "./dist/browser.cjs",
40
+ "default": "./dist/browser.mjs"
41
+ },
42
+ "./browser-global": {
43
+ "default": "./dist/browser-global.js"
44
+ }
45
+ },
46
+ "files": [
47
+ "CHANGELOG.md",
48
+ "LICENSE.md",
49
+ "README.md",
50
+ "dist"
51
+ ],
52
+ "dependencies": {
53
+ "postcss-selector-parser": "^6.0.10"
54
+ },
55
+ "peerDependencies": {
56
+ "postcss": "^8.2"
57
+ },
58
+ "scripts": {
59
+ "build": "rollup -c ../../rollup/default.js",
60
+ "clean": "node -e \"fs.rmSync('./dist', { recursive: true, force: true });\"",
61
+ "docs": "node ../../.github/bin/generate-docs/install.mjs && node ../../.github/bin/generate-docs/readme.mjs",
62
+ "lint": "npm run lint:eslint && npm run lint:package-json",
63
+ "lint:eslint": "eslint ./src --ext .js --ext .ts --ext .mjs --no-error-on-unmatched-pattern",
64
+ "lint:package-json": "node ../../.github/bin/format-package-json.mjs",
65
+ "prepublishOnly": "npm run clean && npm run build && npm run test",
66
+ "test": "node .tape.mjs && npm run test:exports",
67
+ "test:browser": "node ./test/_browser.mjs",
68
+ "test:exports": "node ./test/_import.mjs && node ./test/_require.cjs",
69
+ "test:rewrite-expects": "REWRITE_EXPECTS=true node .tape.mjs"
70
+ },
71
+ "homepage": "https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-focus-within#readme",
72
+ "repository": {
73
+ "type": "git",
74
+ "url": "https://github.com/csstools/postcss-plugins.git",
75
+ "directory": "plugins/postcss-focus-within"
76
+ },
77
+ "bugs": "https://github.com/csstools/postcss-plugins/issues",
78
+ "keywords": [
79
+ "a11y",
80
+ "accessibility",
81
+ "ancestors",
82
+ "css",
83
+ "descendants",
84
+ "focus",
85
+ "polyfill",
86
+ "postcss",
87
+ "postcss-plugin",
88
+ "pseudos",
89
+ "selectors",
90
+ "within"
91
+ ],
92
+ "csstools": {
93
+ "cssdbId": "focus-within-pseudo-class",
94
+ "exportName": "postcssFocusWithin",
95
+ "humanReadableName": "PostCSS Focus Within",
96
+ "specUrl": "https://www.w3.org/TR/selectors-4/#the-focus-within-pseudo"
97
+ },
98
+ "volta": {
99
+ "extends": "../../package.json"
100
+ }
69
101
  }