├── .editorconfig ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── INSTALL.md ├── LICENSE.md ├── README.md ├── index.js ├── package.json └── test ├── _tape.js ├── basic.css ├── basic.expect.css ├── ignore.css ├── ignore.expect.css ├── remove.css ├── remove.expect.css ├── replace.css ├── replace.expect.css ├── substring.css ├── substring.expect.css ├── tags.css └── tags.expect.css /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_style = tab 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | indent_size = 4 10 | 11 | [*.{md,yml}] 12 | indent_size = 2 13 | indent_style = space 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | index.*.* 3 | package-lock.json 4 | yarn.lock 5 | *.log* 6 | *.code-workspace 7 | *.result.css 8 | /.eslintcache 9 | .vscode/launch.json 10 | .DS_Store 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "10" 4 | - "8" 5 | 6 | install: 7 | - npm install --ignore-scripts 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changes to PostCSS Editor Styles 2 | 3 | ### 0.5.0 (March 7, 2024) 4 | 5 | - Allow using `:where()` pseudo class in options to account for every `:where(*)` selectors. 6 | 7 | ### 0.4.0 (March 7, 2024) 8 | 9 | - Fixed a bug where some tags weren't getting scoped ([#5](https://github.com/m-e-h/postcss-editor-styles/pull/5)) thanks to @animeshk874 10 | 11 | ### 0.3.0 (October 10, 2019) 12 | 13 | - properly handle options as arrays. 14 | - only change the tag if it's at the end. 15 | - add some more editor specific tags to defaults. 16 | 17 | 18 | ### 0.1.0 (October 4, 2018) 19 | 20 | - Initial version 21 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to PostCSS Editor Styles 2 | 3 | You want to help? You rock! Now, take a moment to be sure your contributions 4 | make sense to everyone else. 5 | 6 | ## Reporting Issues 7 | 8 | Found a problem? Want a new feature? 9 | 10 | - See if your issue or idea has [already been reported]. 11 | - Provide a [reduced test case] or a [live example]. 12 | 13 | Remember, a bug is a _demonstrable problem_ caused by _our_ code. 14 | 15 | ## Submitting Pull Requests 16 | 17 | Pull requests are the greatest contributions, so be sure they are focused in 18 | scope and avoid unrelated commits. 19 | 20 | 1. To begin; [fork this project], clone your fork, and add our upstream. 21 | ```bash 22 | # Clone your fork of the repo into the current directory 23 | git clone git@github.com:YOUR_USER/postcss-editor-styles.git 24 | 25 | # Navigate to the newly cloned directory 26 | cd postcss-editor-styles 27 | 28 | # Assign the original repo to a remote called "upstream" 29 | git remote add upstream git@github.com:jonathantneal/postcss-editor-styles.git 30 | 31 | # Install the tools necessary for testing 32 | npm install 33 | ``` 34 | 35 | 2. Create a branch for your feature or fix: 36 | ```bash 37 | # Move into a new branch for your feature 38 | git checkout -b feature/thing 39 | ``` 40 | ```bash 41 | # Move into a new branch for your fix 42 | git checkout -b fix/something 43 | ``` 44 | 45 | 3. If your code follows our practices, then push your feature branch: 46 | ```bash 47 | # Test current code 48 | npm test 49 | ``` 50 | ```bash 51 | # Push the branch for your new feature 52 | git push origin feature/thing 53 | ``` 54 | ```bash 55 | # Or, push the branch for your update 56 | git push origin update/something 57 | ``` 58 | 59 | That’s it! Now [open a pull request] with a clear title and description. 60 | 61 | [already been reported]: issues 62 | [fork this project]: fork 63 | [live example]: https://codepen.io/pen 64 | [open a pull request]: https://help.github.com/articles/using-pull-requests/ 65 | [reduced test case]: https://css-tricks.com/reduced-test-cases/ 66 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | # Installing PostCSS Editor Styles 2 | 3 | [PostCSS Editor Styles] runs in all Node environments, with special instructions for: 4 | 5 | | [Node](#node) | [PostCSS CLI](#postcss-cli) | [Webpack](#webpack) | [Create React App](#create-react-app) | [Gulp](#gulp) | [Grunt](#grunt) | 6 | | ------------- | --------------------------- | ------------------- | ------------------------------------- | ------------- | --------------- | 7 | 8 | 9 | ## Node 10 | 11 | Add [PostCSS Editor Styles] to your project: 12 | 13 | ```bash 14 | npm install postcss-editor-styles --save-dev 15 | ``` 16 | 17 | Use [PostCSS Editor Styles] to process your CSS: 18 | 19 | ```js 20 | const postcssEditorStyles = require("postcss-editor-styles"); 21 | 22 | postcssEditorStyles.process(YOUR_CSS /*, processOptions, pluginOptions */); 23 | ``` 24 | 25 | Or use it as a [PostCSS] plugin: 26 | 27 | ```js 28 | const postcss = require("postcss"); 29 | const postcssEditorStyles = require("postcss-editor-styles"); 30 | 31 | postcss([postcssEditorStyles(/* pluginOptions */)]).process( 32 | YOUR_CSS /*, processOptions */ 33 | ); 34 | ``` 35 | 36 | ## PostCSS CLI 37 | 38 | Add [PostCSS CLI] to your project: 39 | 40 | ```bash 41 | npm install postcss-cli --save-dev 42 | ``` 43 | 44 | Use [PostCSS Editor Styles] in your `postcss.config.js` configuration file: 45 | 46 | ```js 47 | const postcssEditorStyles = require("postcss-editor-styles"); 48 | 49 | module.exports = { 50 | plugins: [postcssEditorStyles(/* pluginOptions */)] 51 | }; 52 | ``` 53 | 54 | ## Webpack 55 | 56 | Add [PostCSS Loader] to your project: 57 | 58 | ```bash 59 | npm install postcss-loader --save-dev 60 | ``` 61 | 62 | Use [PostCSS Editor Styles] in your Webpack configuration: 63 | 64 | ```js 65 | const postcssEditorStyles = require("postcss-editor-styles"); 66 | 67 | module.exports = { 68 | module: { 69 | rules: [ 70 | { 71 | test: /\.css$/, 72 | use: [ 73 | "style-loader", 74 | { loader: "css-loader", options: { importLoaders: 1 } }, 75 | { 76 | loader: "postcss-loader", 77 | options: { 78 | ident: "postcss", 79 | plugins: () => [ 80 | postcssEditorStyles(/* pluginOptions */) 81 | ] 82 | } 83 | } 84 | ] 85 | } 86 | ] 87 | } 88 | }; 89 | ``` 90 | 91 | ## Create React App 92 | 93 | Add [React App Rewired] and [React App Rewire PostCSS] to your project: 94 | 95 | ```bash 96 | npm install react-app-rewired react-app-rewire-postcss --save-dev 97 | ``` 98 | 99 | Use [React App Rewire PostCSS] and [PostCSS Editor Styles] in your 100 | `config-overrides.js` file: 101 | 102 | ```js 103 | const reactAppRewirePostcss = require("react-app-rewire-postcss"); 104 | const postcssEditorStyles = require("postcss-editor-styles"); 105 | 106 | module.exports = config => 107 | reactAppRewirePostcss(config, { 108 | plugins: () => [postcssEditorStyles(/* pluginOptions */)] 109 | }); 110 | ``` 111 | 112 | ## Gulp 113 | 114 | Add [Gulp PostCSS] to your project: 115 | 116 | ```bash 117 | npm install gulp-postcss --save-dev 118 | ``` 119 | 120 | Use [PostCSS Editor Styles] in your Gulpfile: 121 | 122 | ```js 123 | const postcss = require("gulp-postcss"); 124 | const postcssEditorStyles = require("postcss-editor-styles"); 125 | 126 | gulp.task("css", () => 127 | gulp 128 | .src("./src/*.css") 129 | .pipe(postcss([postcssEditorStyles(/* pluginOptions */)])) 130 | .pipe(gulp.dest(".")) 131 | ); 132 | ``` 133 | 134 | ## Grunt 135 | 136 | Add [Grunt PostCSS] to your project: 137 | 138 | ```bash 139 | npm install grunt-postcss --save-dev 140 | ``` 141 | 142 | Use [PostCSS Editor Styles] in your Gruntfile: 143 | 144 | ```js 145 | const postcssEditorStyles = require("postcss-editor-styles"); 146 | 147 | grunt.loadNpmTasks("grunt-postcss"); 148 | 149 | grunt.initConfig({ 150 | postcss: { 151 | options: { 152 | use: [postcssEditorStyles(/* pluginOptions */)] 153 | }, 154 | dist: { 155 | src: "*.css" 156 | } 157 | } 158 | }); 159 | ``` 160 | 161 | [gulp postcss]: https://github.com/postcss/gulp-postcss 162 | [grunt postcss]: https://github.com/nDmitry/grunt-postcss 163 | [postcss]: https://github.com/postcss/postcss 164 | [postcss cli]: https://github.com/postcss/postcss-cli 165 | [postcss loader]: https://github.com/postcss/postcss-loader 166 | [postcss editor styles]: https://github.com/m-e-h/postcss-editor-styles 167 | [react app rewire postcss]: https://github.com/csstools/react-app-rewire-postcss 168 | [react app rewired]: https://github.com/timarney/react-app-rewired 169 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | ### GNU GENERAL PUBLIC LICENSE 2 | 3 | Version 2, June 1991 4 | 5 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 6 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 7 | 8 | Everyone is permitted to copy and distribute verbatim copies 9 | of this license document, but changing it is not allowed. 10 | 11 | ### Preamble 12 | 13 | The licenses for most software are designed to take away your freedom 14 | to share and change it. By contrast, the GNU General Public License is 15 | intended to guarantee your freedom to share and change free 16 | software--to make sure the software is free for all its users. This 17 | General Public License applies to most of the Free Software 18 | Foundation's software and to any other program whose authors commit to 19 | using it. (Some other Free Software Foundation software is covered by 20 | the GNU Lesser General Public License instead.) You can apply it to 21 | your programs, too. 22 | 23 | When we speak of free software, we are referring to freedom, not 24 | price. Our General Public Licenses are designed to make sure that you 25 | have the freedom to distribute copies of free software (and charge for 26 | this service if you wish), that you receive source code or can get it 27 | if you want it, that you can change the software or use pieces of it 28 | in new free programs; and that you know you can do these things. 29 | 30 | To protect your rights, we need to make restrictions that forbid 31 | anyone to deny you these rights or to ask you to surrender the rights. 32 | These restrictions translate to certain responsibilities for you if 33 | you distribute copies of the software, or if you modify it. 34 | 35 | For example, if you distribute copies of such a program, whether 36 | gratis or for a fee, you must give the recipients all the rights that 37 | you have. You must make sure that they, too, receive or can get the 38 | source code. And you must show them these terms so they know their 39 | rights. 40 | 41 | We protect your rights with two steps: (1) copyright the software, and 42 | (2) offer you this license which gives you legal permission to copy, 43 | distribute and/or modify the software. 44 | 45 | Also, for each author's protection and ours, we want to make certain 46 | that everyone understands that there is no warranty for this free 47 | software. If the software is modified by someone else and passed on, 48 | we want its recipients to know that what they have is not the 49 | original, so that any problems introduced by others will not reflect 50 | on the original authors' reputations. 51 | 52 | Finally, any free program is threatened constantly by software 53 | patents. We wish to avoid the danger that redistributors of a free 54 | program will individually obtain patent licenses, in effect making the 55 | program proprietary. To prevent this, we have made it clear that any 56 | patent must be licensed for everyone's free use or not licensed at 57 | all. 58 | 59 | The precise terms and conditions for copying, distribution and 60 | modification follow. 61 | 62 | ### TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 63 | 64 | **0.** This License applies to any program or other work which 65 | contains a notice placed by the copyright holder saying it may be 66 | distributed under the terms of this General Public License. The 67 | "Program", below, refers to any such program or work, and a "work 68 | based on the Program" means either the Program or any derivative work 69 | under copyright law: that is to say, a work containing the Program or 70 | a portion of it, either verbatim or with modifications and/or 71 | translated into another language. (Hereinafter, translation is 72 | included without limitation in the term "modification".) Each licensee 73 | is addressed as "you". 74 | 75 | Activities other than copying, distribution and modification are not 76 | covered by this License; they are outside its scope. The act of 77 | running the Program is not restricted, and the output from the Program 78 | is covered only if its contents constitute a work based on the Program 79 | (independent of having been made by running the Program). Whether that 80 | is true depends on what the Program does. 81 | 82 | **1.** You may copy and distribute verbatim copies of the Program's 83 | source code as you receive it, in any medium, provided that you 84 | conspicuously and appropriately publish on each copy an appropriate 85 | copyright notice and disclaimer of warranty; keep intact all the 86 | notices that refer to this License and to the absence of any warranty; 87 | and give any other recipients of the Program a copy of this License 88 | along with the Program. 89 | 90 | You may charge a fee for the physical act of transferring a copy, and 91 | you may at your option offer warranty protection in exchange for a 92 | fee. 93 | 94 | **2.** You may modify your copy or copies of the Program or any 95 | portion of it, thus forming a work based on the Program, and copy and 96 | distribute such modifications or work under the terms of Section 1 97 | above, provided that you also meet all of these conditions: 98 | 99 | 100 | **a)** You must cause the modified files to carry prominent notices 101 | stating that you changed the files and the date of any change. 102 | 103 | 104 | **b)** You must cause any work that you distribute or publish, that in 105 | whole or in part contains or is derived from the Program or any part 106 | thereof, to be licensed as a whole at no charge to all third parties 107 | under the terms of this License. 108 | 109 | 110 | **c)** If the modified program normally reads commands interactively 111 | when run, you must cause it, when started running for such interactive 112 | use in the most ordinary way, to print or display an announcement 113 | including an appropriate copyright notice and a notice that there is 114 | no warranty (or else, saying that you provide a warranty) and that 115 | users may redistribute the program under these conditions, and telling 116 | the user how to view a copy of this License. (Exception: if the 117 | Program itself is interactive but does not normally print such an 118 | announcement, your work based on the Program is not required to print 119 | an announcement.) 120 | 121 | These requirements apply to the modified work as a whole. If 122 | identifiable sections of that work are not derived from the Program, 123 | and can be reasonably considered independent and separate works in 124 | themselves, then this License, and its terms, do not apply to those 125 | sections when you distribute them as separate works. But when you 126 | distribute the same sections as part of a whole which is a work based 127 | on the Program, the distribution of the whole must be on the terms of 128 | this License, whose permissions for other licensees extend to the 129 | entire whole, and thus to each and every part regardless of who wrote 130 | it. 131 | 132 | Thus, it is not the intent of this section to claim rights or contest 133 | your rights to work written entirely by you; rather, the intent is to 134 | exercise the right to control the distribution of derivative or 135 | collective works based on the Program. 136 | 137 | In addition, mere aggregation of another work not based on the Program 138 | with the Program (or with a work based on the Program) on a volume of 139 | a storage or distribution medium does not bring the other work under 140 | the scope of this License. 141 | 142 | **3.** You may copy and distribute the Program (or a work based on it, 143 | under Section 2) in object code or executable form under the terms of 144 | Sections 1 and 2 above provided that you also do one of the following: 145 | 146 | 147 | **a)** Accompany it with the complete corresponding machine-readable 148 | source code, which must be distributed under the terms of Sections 1 149 | and 2 above on a medium customarily used for software interchange; or, 150 | 151 | 152 | **b)** Accompany it with a written offer, valid for at least three 153 | years, to give any third party, for a charge no more than your cost of 154 | physically performing source distribution, a complete machine-readable 155 | copy of the corresponding source code, to be distributed under the 156 | terms of Sections 1 and 2 above on a medium customarily used for 157 | software interchange; or, 158 | 159 | 160 | **c)** Accompany it with the information you received as to the offer 161 | to distribute corresponding source code. (This alternative is allowed 162 | only for noncommercial distribution and only if you received the 163 | program in object code or executable form with such an offer, in 164 | accord with Subsection b above.) 165 | 166 | The source code for a work means the preferred form of the work for 167 | making modifications to it. For an executable work, complete source 168 | code means all the source code for all modules it contains, plus any 169 | associated interface definition files, plus the scripts used to 170 | control compilation and installation of the executable. However, as a 171 | special exception, the source code distributed need not include 172 | anything that is normally distributed (in either source or binary 173 | form) with the major components (compiler, kernel, and so on) of the 174 | operating system on which the executable runs, unless that component 175 | itself accompanies the executable. 176 | 177 | If distribution of executable or object code is made by offering 178 | access to copy from a designated place, then offering equivalent 179 | access to copy the source code from the same place counts as 180 | distribution of the source code, even though third parties are not 181 | compelled to copy the source along with the object code. 182 | 183 | **4.** You may not copy, modify, sublicense, or distribute the Program 184 | except as expressly provided under this License. Any attempt otherwise 185 | to copy, modify, sublicense or distribute the Program is void, and 186 | will automatically terminate your rights under this License. However, 187 | parties who have received copies, or rights, from you under this 188 | License will not have their licenses terminated so long as such 189 | parties remain in full compliance. 190 | 191 | **5.** You are not required to accept this License, since you have not 192 | signed it. However, nothing else grants you permission to modify or 193 | distribute the Program or its derivative works. These actions are 194 | prohibited by law if you do not accept this License. Therefore, by 195 | modifying or distributing the Program (or any work based on the 196 | Program), you indicate your acceptance of this License to do so, and 197 | all its terms and conditions for copying, distributing or modifying 198 | the Program or works based on it. 199 | 200 | **6.** Each time you redistribute the Program (or any work based on 201 | the Program), the recipient automatically receives a license from the 202 | original licensor to copy, distribute or modify the Program subject to 203 | these terms and conditions. You may not impose any further 204 | restrictions on the recipients' exercise of the rights granted herein. 205 | You are not responsible for enforcing compliance by third parties to 206 | this License. 207 | 208 | **7.** If, as a consequence of a court judgment or allegation of 209 | patent infringement or for any other reason (not limited to patent 210 | issues), conditions are imposed on you (whether by court order, 211 | agreement or otherwise) that contradict the conditions of this 212 | License, they do not excuse you from the conditions of this License. 213 | If you cannot distribute so as to satisfy simultaneously your 214 | obligations under this License and any other pertinent obligations, 215 | then as a consequence you may not distribute the Program at all. For 216 | example, if a patent license would not permit royalty-free 217 | redistribution of the Program by all those who receive copies directly 218 | or indirectly through you, then the only way you could satisfy both it 219 | and this License would be to refrain entirely from distribution of the 220 | Program. 221 | 222 | If any portion of this section is held invalid or unenforceable under 223 | any particular circumstance, the balance of the section is intended to 224 | apply and the section as a whole is intended to apply in other 225 | circumstances. 226 | 227 | It is not the purpose of this section to induce you to infringe any 228 | patents or other property right claims or to contest validity of any 229 | such claims; this section has the sole purpose of protecting the 230 | integrity of the free software distribution system, which is 231 | implemented by public license practices. Many people have made 232 | generous contributions to the wide range of software distributed 233 | through that system in reliance on consistent application of that 234 | system; it is up to the author/donor to decide if he or she is willing 235 | to distribute software through any other system and a licensee cannot 236 | impose that choice. 237 | 238 | This section is intended to make thoroughly clear what is believed to 239 | be a consequence of the rest of this License. 240 | 241 | **8.** If the distribution and/or use of the Program is restricted in 242 | certain countries either by patents or by copyrighted interfaces, the 243 | original copyright holder who places the Program under this License 244 | may add an explicit geographical distribution limitation excluding 245 | those countries, so that distribution is permitted only in or among 246 | countries not thus excluded. In such case, this License incorporates 247 | the limitation as if written in the body of this License. 248 | 249 | **9.** The Free Software Foundation may publish revised and/or new 250 | versions of the General Public License from time to time. Such new 251 | versions will be similar in spirit to the present version, but may 252 | differ in detail to address new problems or concerns. 253 | 254 | Each version is given a distinguishing version number. If the Program 255 | specifies a version number of this License which applies to it and 256 | "any later version", you have the option of following the terms and 257 | conditions either of that version or of any later version published by 258 | the Free Software Foundation. If the Program does not specify a 259 | version number of this License, you may choose any version ever 260 | published by the Free Software Foundation. 261 | 262 | **10.** If you wish to incorporate parts of the Program into other 263 | free programs whose distribution conditions are different, write to 264 | the author to ask for permission. For software which is copyrighted by 265 | the Free Software Foundation, write to the Free Software Foundation; 266 | we sometimes make exceptions for this. Our decision will be guided by 267 | the two goals of preserving the free status of all derivatives of our 268 | free software and of promoting the sharing and reuse of software 269 | generally. 270 | 271 | **NO WARRANTY** 272 | 273 | **11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO 274 | WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 275 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 276 | OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY 277 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 278 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 279 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 280 | PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME 281 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 282 | 283 | **12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 284 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 285 | AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU 286 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 287 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 288 | PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 289 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 290 | FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF 291 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 292 | DAMAGES. 293 | 294 | ### END OF TERMS AND CONDITIONS 295 | 296 | ### How to Apply These Terms to Your New Programs 297 | 298 | If you develop a new program, and you want it to be of the greatest 299 | possible use to the public, the best way to achieve this is to make it 300 | free software which everyone can redistribute and change under these 301 | terms. 302 | 303 | To do so, attach the following notices to the program. It is safest to 304 | attach them to the start of each source file to most effectively 305 | convey the exclusion of warranty; and each file should have at least 306 | the "copyright" line and a pointer to where the full notice is found. 307 | 308 | one line to give the program's name and an idea of what it does. 309 | Copyright (C) yyyy name of author 310 | 311 | This program is free software; you can redistribute it and/or 312 | modify it under the terms of the GNU General Public License 313 | as published by the Free Software Foundation; either version 2 314 | of the License, or (at your option) any later version. 315 | 316 | This program is distributed in the hope that it will be useful, 317 | but WITHOUT ANY WARRANTY; without even the implied warranty of 318 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 319 | GNU General Public License for more details. 320 | 321 | You should have received a copy of the GNU General Public License 322 | along with this program; if not, write to the Free Software 323 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 324 | 325 | Also add information on how to contact you by electronic and paper 326 | mail. 327 | 328 | If the program is interactive, make it output a short notice like this 329 | when it starts in an interactive mode: 330 | 331 | Gnomovision version 69, Copyright (C) year name of author 332 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details 333 | type `show w'. This is free software, and you are welcome 334 | to redistribute it under certain conditions; type `show c' 335 | for details. 336 | 337 | The hypothetical commands \`show w' and \`show c' should show the 338 | appropriate parts of the General Public License. Of course, the 339 | commands you use may be called something other than \`show w' and 340 | \`show c'; they could even be mouse-clicks or menu items--whatever 341 | suits your program. 342 | 343 | You should also get your employer (if you work as a programmer) or 344 | your school, if any, to sign a "copyright disclaimer" for the program, 345 | if necessary. Here is a sample; alter the names: 346 | 347 | Yoyodyne, Inc., hereby disclaims all copyright 348 | interest in the program `Gnomovision' 349 | (which makes passes at compilers) written 350 | by James Hacker. 351 | 352 | signature of Ty Coon, 1 April 1989 353 | Ty Coon, President of Vice 354 | 355 | This General Public License does not permit incorporating your program 356 | into proprietary programs. If your program is a subroutine library, 357 | you may consider it more useful to permit linking proprietary 358 | applications with the library. If this is what you want to do, use the 359 | [GNU Lesser General Public 360 | License](https://www.gnu.org/licenses/lgpl.html) instead of this 361 | License. 362 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PostCSS Editor Styles [PostCSS][postcss] 2 | 3 | [![NPM Version][npm-img]][npm-url] 4 | 5 | PostCSS Editor Styles lets you do this in CSS. 6 | 7 | ```css 8 | :root { /* ignored */ 9 | --color-text: #24292e; 10 | } 11 | 12 | html { /* removed */ 13 | font-family: sans-serif; 14 | } 15 | 16 | body { /* replaced */ 17 | color: var(--color-text); 18 | } 19 | 20 | button { /* scoped and negated */ 21 | min-height: 1.5rem; 22 | } 23 | 24 | .block-heading { /* scoped */ 25 | background-color: #eee; 26 | } 27 | 28 | /* becomes */ 29 | 30 | :root { 31 | --color-text: #24292e; 32 | } 33 | 34 | .editor-styles-wrapper { 35 | color: var(--color-text); 36 | } 37 | 38 | .editor-styles-wrapper button:not([class^="components-"]):not([class^="editor-"]):not([class^="block-"]):not([aria-owns]) { 39 | min-height: 1.5rem; 40 | } 41 | 42 | .editor-styles-wrapper .block-heading { 43 | background-color: #eee; 44 | } 45 | ``` 46 | 47 | ## Usage 48 | 49 | Add PostCSS Editor Styles to your project: 50 | 51 | ```bash 52 | npm install postcss-editor-styles --save-dev 53 | ``` 54 | 55 | Use PostCSS Editor Styles to process your CSS: 56 | 57 | ```js 58 | const postcssEditorStyles = require("postcss-editor-styles"); 59 | 60 | postcssEditorStyles.process(YOUR_CSS /*, processOptions, pluginOptions */); 61 | ``` 62 | 63 | Or use it as a [PostCSS] plugin: 64 | 65 | ```js 66 | const postcss = require("postcss"); 67 | const postcssEditorStyles = require("postcss-editor-styles"); 68 | 69 | postcss([postcssEditorStyles(/* pluginOptions */)]).process( 70 | YOUR_CSS /*, processOptions */ 71 | ); 72 | ``` 73 | 74 | ## Options 75 | defaults: 76 | ```js 77 | // The selector we're working within. 78 | scopeTo: '.editor-styles-wrapper', 79 | 80 | // Increase specificity by repeating the selector. 81 | repeat: 1, 82 | 83 | remove: ['html'], 84 | 85 | replace: ['body'], 86 | 87 | ignore: [':root'], 88 | 89 | tags: ['a', 'button', 'input', 'label', 'select', 'textarea', 'form'], 90 | 91 | tagSuffix: ':not([class^="components-"]):not([class^="editor-"]):not([class^="block-"]):not([aria-owns])' 92 | ``` 93 | 94 | 95 | PostCSS Editor Styles runs in all Node environments, with special instructions for: 96 | 97 | | [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) | 98 | | ----------------------- | ------------------------------------- | ----------------------------- | ----------------------------------------------- | ----------------------- | ------------------------- | 99 | 100 | 101 | [npm-img]: https://img.shields.io/npm/v/postcss-editor-styles.svg 102 | [npm-url]: https://www.npmjs.com/package/postcss-editor-styles 103 | [postcss]: https://github.com/postcss/postcss 104 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = (options = {}) => { 2 | const defaults = { 3 | // The selector we're working within. 4 | scopeTo: '.editor-styles-wrapper', 5 | 6 | // Increase specificity by repeating the selector. 7 | repeat: 1, 8 | 9 | remove: ['html'], 10 | 11 | replace: ['body'], 12 | 13 | ignore: [':root'], 14 | 15 | tags: [ 16 | 'a', 17 | 'svg', 18 | 'a:hover', 19 | 'a:focus', 20 | 'button', 21 | 'button:hover', 22 | 'button:focus', 23 | 'input', 24 | 'label', 25 | 'select', 26 | 'textarea', 27 | 'form', 28 | 'input[type="button"]', 29 | 'input[type="submit"]', 30 | 'input[type="reset"]', 31 | '[type="button"]', 32 | '[type="submit"]', 33 | '[type="reset"]' 34 | ], 35 | 36 | tagSuffix: 37 | ':not([class^="components-"]):not([class^="editor-"]):not([class^="block-"]):not([aria-owns]):not([id^="mceu_"])' 38 | }; 39 | 40 | const opts = { ...defaults, ...options }; 41 | 42 | // Detect if there is a :where() pseudo class in the selectors. 43 | const hasWherePseudo = (optionsVal, selectors) => { 44 | let optionHasWhere = false; 45 | 46 | if (typeof optionsVal === 'string') { 47 | optionHasWhere = ':where()' === optionsVal; 48 | } else if (Array.isArray(optionsVal)) { 49 | optionHasWhere = optionsVal.find((el) => el === ':where()'); 50 | } 51 | 52 | if (!optionHasWhere) { 53 | return false; 54 | } 55 | 56 | return selectors.find((el) => el.startsWith(':where(')); 57 | } 58 | 59 | const firstOrLastSelector = (optsArray, selectorArray) => { 60 | let firstSelector = selectorArray[0]; 61 | let lastSelector = selectorArray[selectorArray.length - 1]; 62 | const whereMatch = hasWherePseudo(optsArray, [firstSelector, lastSelector]); 63 | 64 | var selectorIn = []; 65 | 66 | if(whereMatch) { 67 | selectorIn.push(whereMatch); 68 | } else if (-1 !== optsArray.indexOf(firstSelector)) { 69 | selectorIn.push(firstSelector); 70 | } else if (-1 !== optsArray.indexOf(lastSelector)) { 71 | selectorIn.push(lastSelector); 72 | } else { 73 | return false; 74 | } 75 | return selectorIn; 76 | }; 77 | 78 | return { 79 | postcssPlugin: 'postcss-editor-styles', 80 | Root (root, postcss) { 81 | root.walkRules(rule => { 82 | rule.selectors = rule.selectors.map(selector => { 83 | const selectArr = selector.split(' '); 84 | let firstSelector = selectArr[0]; 85 | let lastSelector = selectArr[selectArr.length - 1]; 86 | 87 | if ( 88 | rule.parent.type === 'atrule' && 89 | rule.parent.name === 'keyframes' 90 | ) { 91 | return selector; 92 | } 93 | 94 | if (firstOrLastSelector(opts.remove, selectArr)) { 95 | return rule.remove(); 96 | } 97 | 98 | if (firstOrLastSelector(opts.replace, selectArr)) { 99 | const hasReplaceOpt = firstOrLastSelector( 100 | opts.replace, 101 | selectArr 102 | ); 103 | 104 | return selector.replace( 105 | RegExp(hasReplaceOpt, 'g'), 106 | opts.scopeTo.repeat(opts.repeat) 107 | ); 108 | } 109 | 110 | if (firstOrLastSelector(opts.ignore, selectArr)) { 111 | return selector; 112 | } 113 | 114 | if (-1 != opts.tags.indexOf(lastSelector)) { 115 | return `${opts.scopeTo.repeat(opts.repeat)} ${selector}${ 116 | opts.tagSuffix 117 | }`; 118 | } 119 | 120 | if (firstOrLastSelector([opts.scopeTo], selectArr)) { 121 | return selector; 122 | } 123 | 124 | // For anything else add it before the selector. 125 | return `${opts.scopeTo.repeat(opts.repeat)} ${selector}`; 126 | }); 127 | }); 128 | } 129 | }; 130 | }; 131 | 132 | module.exports.postcss = true; 133 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "postcss-editor-styles", 3 | "version": "0.5.0", 4 | "description": "Remove your editor-styles from the global scope ", 5 | "author": "m-e-h ", 6 | "license": "GPL-2.0+", 7 | "repository": "m-e-h/postcss-editor-styles", 8 | "homepage": "https://github.com/m-e-h/postcss-editor-styles#readme", 9 | "bugs": "https://github.com/m-e-h/postcss-editor-styles/issues", 10 | "main": "index.js", 11 | "scripts": { 12 | "test": "node --test", 13 | "release": "np" 14 | }, 15 | "engines": { 16 | "node": "^16 || >=18" 17 | }, 18 | "peerDependencies": { 19 | "postcss": "^8.4.35" 20 | }, 21 | "devDependencies": { 22 | "@csstools/postcss-tape": "*", 23 | "eslint": "^8.56.0", 24 | "np": "^10.0.0" 25 | }, 26 | "eslintConfig": { 27 | "parserOptions": { 28 | "ecmaVersion": 2018 29 | }, 30 | "env": { 31 | "node": true, 32 | "es6": true 33 | }, 34 | "extends": [ 35 | "eslint:recommended" 36 | ] 37 | }, 38 | "keywords": [ 39 | "postcss", 40 | "css", 41 | "postcss-plugin", 42 | "wordpress", 43 | "gutenberg" 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /test/_tape.js: -------------------------------------------------------------------------------- 1 | const { postcssTape } = require('@csstools/postcss-tape'); 2 | const plugin = require('../index.js'); 3 | 4 | postcssTape(plugin)({ 5 | basic: { 6 | message: 'supports basic usage', 7 | options: { 8 | ignore: [':root', ':where()'], 9 | } 10 | }, 11 | remove: { 12 | message: 'supports remove usage' 13 | }, 14 | replace: { 15 | message: 'supports replace usage' 16 | }, 17 | ignore: { 18 | message: 'supports ignore usage' 19 | }, 20 | tags: { 21 | message: 'supports tags usage' 22 | }, 23 | substring: { 24 | message: 'supports selectors that are a substring of scopeTo', 25 | options: { 26 | scopeTo: `.component-library`, 27 | tags: [], 28 | } 29 | } 30 | }); 31 | -------------------------------------------------------------------------------- /test/basic.css: -------------------------------------------------------------------------------- 1 | :where(.wp-site-blocks) li { 2 | border-bottom: 1px solid #e1e4e8; 3 | } 4 | 5 | :root { 6 | --color-text: #24292e; 7 | } 8 | 9 | html { 10 | font-family: sans-serif; 11 | } 12 | 13 | body { 14 | color: var(--color-text); 15 | } 16 | 17 | a { 18 | text-decoration: underline; 19 | } 20 | 21 | main a { 22 | text-decoration: none; 23 | } 24 | 25 | .editor-styles-wrapper { 26 | background-color: green; 27 | } 28 | 29 | .block-heading { 30 | background-color: #eee; 31 | } 32 | 33 | button, 34 | input, 35 | select, 36 | textarea { 37 | font-family: inherit; 38 | } 39 | 40 | [type="button"], 41 | [type="reset"], 42 | [type="submit"], 43 | button { 44 | -webkit-appearance: button; 45 | } 46 | 47 | 48 | 49 | #my_id { 50 | display: flex; 51 | } 52 | 53 | *, 54 | ::after, 55 | ::before { 56 | box-sizing: border-box; 57 | } 58 | 59 | @keyframes spinner { 60 | 0% { 61 | transform: rotate(0deg); 62 | } 63 | 100% { 64 | transform: rotate(360deg); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /test/basic.expect.css: -------------------------------------------------------------------------------- 1 | :where(.wp-site-blocks) li { 2 | border-bottom: 1px solid #e1e4e8; 3 | } 4 | 5 | :root { 6 | --color-text: #24292e; 7 | } 8 | 9 | .editor-styles-wrapper { 10 | color: var(--color-text); 11 | } 12 | 13 | .editor-styles-wrapper a:not([class^="components-"]):not([class^="editor-"]):not([class^="block-"]):not([aria-owns]):not([id^="mceu_"]) { 14 | text-decoration: underline; 15 | } 16 | 17 | .editor-styles-wrapper main a:not([class^="components-"]):not([class^="editor-"]):not([class^="block-"]):not([aria-owns]):not([id^="mceu_"]) { 18 | text-decoration: none; 19 | } 20 | 21 | .editor-styles-wrapper { 22 | background-color: green; 23 | } 24 | 25 | .editor-styles-wrapper .block-heading { 26 | background-color: #eee; 27 | } 28 | 29 | .editor-styles-wrapper button:not([class^="components-"]):not([class^="editor-"]):not([class^="block-"]):not([aria-owns]):not([id^="mceu_"]), 30 | .editor-styles-wrapper input:not([class^="components-"]):not([class^="editor-"]):not([class^="block-"]):not([aria-owns]):not([id^="mceu_"]), 31 | .editor-styles-wrapper select:not([class^="components-"]):not([class^="editor-"]):not([class^="block-"]):not([aria-owns]):not([id^="mceu_"]), 32 | .editor-styles-wrapper textarea:not([class^="components-"]):not([class^="editor-"]):not([class^="block-"]):not([aria-owns]):not([id^="mceu_"]) { 33 | font-family: inherit; 34 | } 35 | 36 | .editor-styles-wrapper [type="button"]:not([class^="components-"]):not([class^="editor-"]):not([class^="block-"]):not([aria-owns]):not([id^="mceu_"]), 37 | .editor-styles-wrapper [type="reset"]:not([class^="components-"]):not([class^="editor-"]):not([class^="block-"]):not([aria-owns]):not([id^="mceu_"]), 38 | .editor-styles-wrapper [type="submit"]:not([class^="components-"]):not([class^="editor-"]):not([class^="block-"]):not([aria-owns]):not([id^="mceu_"]), 39 | .editor-styles-wrapper button:not([class^="components-"]):not([class^="editor-"]):not([class^="block-"]):not([aria-owns]):not([id^="mceu_"]) { 40 | -webkit-appearance: button; 41 | } 42 | 43 | 44 | 45 | .editor-styles-wrapper #my_id { 46 | display: flex; 47 | } 48 | 49 | .editor-styles-wrapper *, 50 | .editor-styles-wrapper ::after, 51 | .editor-styles-wrapper ::before { 52 | box-sizing: border-box; 53 | } 54 | 55 | @keyframes spinner { 56 | 0% { 57 | transform: rotate(0deg); 58 | } 59 | 100% { 60 | transform: rotate(360deg); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /test/ignore.css: -------------------------------------------------------------------------------- 1 | :root .button__link { 2 | color: blue; 3 | } 4 | 5 | :root { 6 | --css-var: #000; 7 | } 8 | -------------------------------------------------------------------------------- /test/ignore.expect.css: -------------------------------------------------------------------------------- 1 | :root .button__link { 2 | color: blue; 3 | } 4 | 5 | :root { 6 | --css-var: #000; 7 | } 8 | -------------------------------------------------------------------------------- /test/remove.css: -------------------------------------------------------------------------------- 1 | html { 2 | font-family: sans-serif; 3 | } 4 | 5 | html .block { 6 | background-color: #000; 7 | } 8 | 9 | html { 10 | font-family: serif; 11 | } 12 | -------------------------------------------------------------------------------- /test/remove.expect.css: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test/replace.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: black; 3 | } 4 | 5 | body .block { 6 | color: blue; 7 | } 8 | 9 | body.block { 10 | background-color: red; 11 | } 12 | 13 | body article { 14 | margin: 0; 15 | } 16 | -------------------------------------------------------------------------------- /test/replace.expect.css: -------------------------------------------------------------------------------- 1 | .editor-styles-wrapper { 2 | color: black; 3 | } 4 | 5 | .editor-styles-wrapper .block { 6 | color: blue; 7 | } 8 | 9 | .editor-styles-wrapper body.block { 10 | background-color: red; 11 | } 12 | 13 | .editor-styles-wrapper article { 14 | margin: 0; 15 | } 16 | -------------------------------------------------------------------------------- /test/substring.css: -------------------------------------------------------------------------------- 1 | h1 { 2 | font-size: 2rem; 3 | } 4 | 5 | b { 6 | font-weight: 600; 7 | } 8 | 9 | li { 10 | padding-left: 4px; 11 | } 12 | 13 | button { 14 | outline: none; 15 | } 16 | 17 | a { 18 | text-decoration: none; 19 | } 20 | -------------------------------------------------------------------------------- /test/substring.expect.css: -------------------------------------------------------------------------------- 1 | .component-library h1 { 2 | font-size: 2rem; 3 | } 4 | 5 | .component-library b { 6 | font-weight: 600; 7 | } 8 | 9 | .component-library li { 10 | padding-left: 4px; 11 | } 12 | 13 | .component-library button { 14 | outline: none; 15 | } 16 | 17 | .component-library a { 18 | text-decoration: none; 19 | } 20 | -------------------------------------------------------------------------------- /test/tags.css: -------------------------------------------------------------------------------- 1 | button { 2 | box-shadow: inset 0 0 0 20rem rgba(189, 196, 201, 0.3); 3 | } 4 | 5 | button:focus, 6 | button:hover { 7 | box-shadow: none; 8 | } 9 | 10 | .some button { 11 | font-family: icons; 12 | } 13 | 14 | form a { 15 | color: red; 16 | } 17 | 18 | a { 19 | font-weight: 700; 20 | } 21 | 22 | h1 { 23 | font-size: 2em; 24 | } 25 | 26 | hr { 27 | overflow: visible; 28 | } 29 | 30 | input[type="submit"] { 31 | display: block; 32 | } 33 | 34 | nav ol, 35 | nav ul { 36 | list-style: none; 37 | } 38 | 39 | [type="submit"] { 40 | font-size: 1em; 41 | } 42 | 43 | input[type="submit"] { 44 | font-size: 1em; 45 | } 46 | 47 | abbr[title] { 48 | text-decoration: underline dotted; 49 | } 50 | 51 | td, 52 | th, 53 | tr { 54 | color: #b2b2b2; 55 | } 56 | -------------------------------------------------------------------------------- /test/tags.expect.css: -------------------------------------------------------------------------------- 1 | .editor-styles-wrapper button:not([class^="components-"]):not([class^="editor-"]):not([class^="block-"]):not([aria-owns]):not([id^="mceu_"]) { 2 | box-shadow: inset 0 0 0 20rem rgba(189, 196, 201, 0.3); 3 | } 4 | 5 | .editor-styles-wrapper button:focus:not([class^="components-"]):not([class^="editor-"]):not([class^="block-"]):not([aria-owns]):not([id^="mceu_"]), 6 | .editor-styles-wrapper button:hover:not([class^="components-"]):not([class^="editor-"]):not([class^="block-"]):not([aria-owns]):not([id^="mceu_"]) { 7 | box-shadow: none; 8 | } 9 | 10 | .editor-styles-wrapper .some button:not([class^="components-"]):not([class^="editor-"]):not([class^="block-"]):not([aria-owns]):not([id^="mceu_"]) { 11 | font-family: icons; 12 | } 13 | 14 | .editor-styles-wrapper form a:not([class^="components-"]):not([class^="editor-"]):not([class^="block-"]):not([aria-owns]):not([id^="mceu_"]) { 15 | color: red; 16 | } 17 | 18 | .editor-styles-wrapper a:not([class^="components-"]):not([class^="editor-"]):not([class^="block-"]):not([aria-owns]):not([id^="mceu_"]) { 19 | font-weight: 700; 20 | } 21 | 22 | .editor-styles-wrapper h1 { 23 | font-size: 2em; 24 | } 25 | 26 | .editor-styles-wrapper hr { 27 | overflow: visible; 28 | } 29 | 30 | .editor-styles-wrapper input[type="submit"]:not([class^="components-"]):not([class^="editor-"]):not([class^="block-"]):not([aria-owns]):not([id^="mceu_"]) { 31 | display: block; 32 | } 33 | 34 | .editor-styles-wrapper nav ol, 35 | .editor-styles-wrapper nav ul { 36 | list-style: none; 37 | } 38 | 39 | .editor-styles-wrapper [type="submit"]:not([class^="components-"]):not([class^="editor-"]):not([class^="block-"]):not([aria-owns]):not([id^="mceu_"]) { 40 | font-size: 1em; 41 | } 42 | 43 | .editor-styles-wrapper input[type="submit"]:not([class^="components-"]):not([class^="editor-"]):not([class^="block-"]):not([aria-owns]):not([id^="mceu_"]) { 44 | font-size: 1em; 45 | } 46 | 47 | .editor-styles-wrapper abbr[title] { 48 | text-decoration: underline dotted; 49 | } 50 | 51 | .editor-styles-wrapper td, 52 | .editor-styles-wrapper th, 53 | .editor-styles-wrapper tr { 54 | color: #b2b2b2; 55 | } 56 | --------------------------------------------------------------------------------