├── .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]
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 |
--------------------------------------------------------------------------------