` and `` ([#313](https://github.com/tailwindlabs/tailwindcss-typography/pull/313))
85 | - Remove typography styles from `not-prose` elements in addition to their children ([#301](https://github.com/tailwindlabs/tailwindcss-typography/pull/301))
86 | - Add `` styles ([#314](https://github.com/tailwindlabs/tailwindcss-typography/pull/314))
87 | - Fix `prose-invert` when used with colors in light mode ([#315](https://github.com/tailwindlabs/tailwindcss-typography/pull/315))
88 | - Add `` styles ([#317](https://github.com/tailwindlabs/tailwindcss-typography/pull/317))
89 | - Add description list (``, ``, ` `) styles ([#316](https://github.com/tailwindlabs/tailwindcss-typography/pull/316))
90 |
91 | ## [0.5.9] - 2023-01-10
92 |
93 | ### Fixed
94 |
95 | - Ensure `p` styles are inserted before `.lead` styles ([#294](https://github.com/tailwindlabs/tailwindcss-typography/pull/294))
96 |
97 | ## [0.5.8] - 2022-11-07
98 |
99 | ### Fixed
100 |
101 | - Fix selector when using a non-default class (e.g. `prose-sm`) ([#289](https://github.com/tailwindlabs/tailwindcss-typography/pull/289))
102 |
103 | ## [0.5.7] - 2022-09-02
104 |
105 | ### Fixed
106 |
107 | - Update TypeScript types ([#284](https://github.com/tailwindlabs/tailwindcss-typography/pull/284))
108 |
109 | ## [0.5.6] - 2022-09-01
110 |
111 | - Actually publish types ([a54c1a8](https://github.com/tailwindlabs/tailwindcss-typography/commit/a54c1a82a64efdf23aab57e62edaa369d1a857f1))
112 |
113 | ## [0.5.5] - 2022-09-01
114 |
115 | ### Added
116 |
117 | - Add typescript types ([#283](https://github.com/tailwindlabs/tailwindcss-typography/pull/283))
118 |
119 | ## [0.5.4] - 2022-07-12
120 |
121 | ### Fixed
122 |
123 | - Update `strong` and `code` color styles to inherit from parent ([#276](https://github.com/tailwindlabs/tailwindcss-typography/pull/276))
124 |
125 | ## [0.5.3] - 2022-07-07
126 |
127 | ### Added
128 |
129 | - Add styles for `tfoot` elements ([#243](https://github.com/tailwindlabs/tailwindcss-typography/pull/243))
130 | - Add `prose-h5` and `prose-h6` variants ([#273](https://github.com/tailwindlabs/tailwindcss-typography/pull/273))
131 |
132 | ### Fixed
133 |
134 | - Fix prose elements `legacy` mode ([#259](https://github.com/tailwindlabs/tailwindcss-typography/pull/259))
135 | - Allow `lead` class to override element styles ([#260](https://github.com/tailwindlabs/tailwindcss-typography/pull/260))
136 | - Fix generation of `prose-headings` variant ([#264](https://github.com/tailwindlabs/tailwindcss-typography/pull/264))
137 | - Fix `figure` spacing ([#267](https://github.com/tailwindlabs/tailwindcss-typography/pull/267))
138 | - Fix child combinator `:where` selectors ([#268](https://github.com/tailwindlabs/tailwindcss-typography/pull/267))
139 | - Fix `prose-headings` variant to include `h5` and `h6` elements ([#273](https://github.com/tailwindlabs/tailwindcss-typography/pull/273))
140 |
141 | ## [0.5.2] - 2022-02-14
142 |
143 | ### Fixed
144 |
145 | - Ensure nested selectors using `&:hover` work ([#246](https://github.com/tailwindlabs/tailwindcss-typography/pull/246))
146 |
147 | ## [0.5.1] - 2022-01-28
148 |
149 | ### Removed
150 |
151 | - Remove `dist` folder and related dependencies ([#226](https://github.com/tailwindlabs/tailwindcss-typography/pull/226))
152 |
153 | ### Fixed
154 |
155 | - Don't generate invalid CSS when given an array of property values ([#224](https://github.com/tailwindlabs/tailwindcss-typography/pull/224))
156 |
157 | ## [0.5.0] - 2021-12-09
158 |
159 | ## [0.5.0-alpha.3] - 2021-11-08
160 |
161 | ### Changes
162 |
163 | - Use `:where` to reduce specificity, making it possible to override prose children with utilities ([#203](https://github.com/tailwindlabs/tailwindcss-typography/pull/203))
164 | - Support "undoing" prose styles using the `not-prose` class on a group of child elements ([#205](https://github.com/tailwindlabs/tailwindcss-typography/pull/205))
165 | - Update color palette for v3 ([#206](https://github.com/tailwindlabs/tailwindcss-typography/pull/206))
166 | - Improve customization API, add alternate grays, add dark mode support, use `::marker` instead of pseudo-elements, and add child element variants (eg. `prose-h1:underline`)([#216](https://github.com/tailwindlabs/tailwindcss-typography/pull/216))
167 |
168 | ## [0.5.0-alpha.2] - 2021-11-08
169 |
170 | ## [0.5.0-alpha.1] - 2021-11-08
171 |
172 | ## [0.4.1] - 2021-05-24
173 |
174 | ### Fixed
175 |
176 | - Fix list-style modifier selectors ([#137](https://github.com/tailwindlabs/tailwindcss-typography/pull/137))
177 |
178 | ## [0.4.0] - 2021-01-15
179 |
180 | ### Fixed
181 |
182 | - Colors without `600` variant, breaks everything (#107)
183 | - Fix empty line in firefox for `pre code` tags (#125)
184 |
185 | ### Added
186 |
187 | - Add support for the `start` and `reversed` attribute on `ol` elements (#110)
188 | - Add support for the `type` on `ul` and `ol` elements (#126)
189 |
190 | ### Changed (internal)
191 |
192 | - Bumped dependencies (#103, #115)
193 | - Cleanup/improve readme (#95)
194 | - Reduce package size (#112)
195 |
196 | ## [0.3.0] - 2020-11-20
197 |
198 | ## Changed
199 |
200 | - Add support for Tailwind CSS v2.0 and drops support for v1.0 (#79, #82, #87)
201 | - Use `extend` for any overrides, assigning directly to `theme.typography` now completely overrides default configuration
202 | - Consistently use `::before` instead of `:before` ([ba33d77](https://github.com/tailwindlabs/tailwindcss-typography/commit/ba33d77f25ab0c239edd7d425349c86f317061e2))
203 | - Read color values from the user's theme instead of only the default theme
204 |
205 | ## Added
206 |
207 | - Add new `className` option for overriding `prose` class (#28)
208 | - Add color modifiers by default like `prose-blue` for setting link styles (#92)
209 |
210 | ## [0.2.0] - 2020-07-15
211 |
212 | ### Changes
213 |
214 | - Switches how variants are generated to use the new component variants API in Tailwind 1.5, dropping support for Tailwind < 1.5
215 |
216 | ## [0.1.4] - 2020-07-15
217 |
218 | ### Fixes
219 |
220 | - Fixes an issue where the `lead` class was not being applied correctly when used in conjunction with responsive variants
221 |
222 | ## [0.1.3] - 2020-07-14
223 |
224 | ### Fixes
225 |
226 | - Fixes an issue where the configured monospace font family was not used by default for `pre` and `code` blocks
227 |
228 | ## [0.1.2] - 2020-07-14
229 |
230 | ### Fixes
231 |
232 | - Fixes an issue in our internal rounding logic that would round values like `20` to `2` 👀
233 |
234 | ## [0.1.1] - 2020-07-14
235 |
236 | ### Fixes
237 |
238 | - Fixes an issue where the plugin was totally broken and didn't work at all because I deleted some code without even testing my changes 🧠
239 |
240 | ## [0.1.0] - 2020-07-14
241 |
242 | ### Added
243 |
244 | - Everything!
245 |
246 | [unreleased]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.19...HEAD
247 | [0.5.19]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.18...v0.5.19
248 | [0.5.18]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.17...v0.5.18
249 | [0.5.17]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.16...v0.5.17
250 | [0.5.16]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.15...v0.5.16
251 | [0.5.15]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.14...v0.5.15
252 | [0.5.14]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.13...v0.5.14
253 | [0.5.13]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.12...v0.5.13
254 | [0.5.12]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.11...v0.5.12
255 | [0.5.11]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.10...v0.5.11
256 | [0.5.10]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.9...v0.5.10
257 | [0.5.9]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.8...v0.5.9
258 | [0.5.8]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.7...v0.5.8
259 | [0.5.7]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.6...v0.5.7
260 | [0.5.6]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.5...v0.5.6
261 | [0.5.5]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.4...v0.5.5
262 | [0.5.4]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.3...v0.5.4
263 | [0.5.3]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.2...v0.5.3
264 | [0.5.2]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.1...v0.5.2
265 | [0.5.1]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.0...v0.5.1
266 | [0.5.0]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.0-alpha.3...v0.5.0
267 | [0.5.0-alpha.3]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.0-alpha.2...v0.5.0-alpha.3
268 | [0.5.0-alpha.2]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.0-alpha.1...v0.5.0-alpha.2
269 | [0.5.0-alpha.1]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.4.1...v0.5.0-alpha.1
270 | [0.4.1]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.4.0...v0.4.1
271 | [0.4.0]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.3.0...v0.4.0
272 | [0.3.0]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.2.0...v0.3.0
273 | [0.2.0]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.1.4...v0.2.0
274 | [0.1.4]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.1.3...v0.1.4
275 | [0.1.3]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.1.2...v0.1.3
276 | [0.1.2]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.1.1...v0.1.2
277 | [0.1.1]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.1.0...v0.1.1
278 | [0.1.0]: https://github.com/tailwindlabs/tailwindcss-typography/releases/tag/v0.1.0
279 |
--------------------------------------------------------------------------------
/demo/components/MarkdownSample.mdx:
--------------------------------------------------------------------------------
1 |
2 | Until now, trying to style an article, document, or blog post with Tailwind has been a tedious
3 | task that required a keen eye for typography and a lot of complex custom CSS.
4 |
5 |
6 | By default, Tailwind removes all of the default browser styling from paragraphs, headings, lists and more. This ends up being really useful for building application UIs because you spend less time undoing user-agent styles, but when you _really are_ just trying to style some content that came from a rich-text editor in a CMS or a markdown file, it can be surprising and unintuitive.
7 |
8 | We get lots of complaints about it actually, with people regularly asking us things like:
9 |
10 | > Why is Tailwind removing the default styles on my `h1` elements? How do I disable this? What do you mean I lose all the other base styles too?
11 |
12 | We hear you, but we're not convinced that simply disabling our base styles is what you really want. You don't want to have to remove annoying margins every time you use a `p` element in a piece of your dashboard UI. And I doubt you really want your blog posts to use the user-agent styles either — you want them to look _awesome_, not awful.
13 |
14 | The `@tailwindcss/typography` plugin is our attempt to give you what you _actually_ want, without any of the downsides of doing something stupid like disabling our base styles.
15 |
16 | It adds a new `prose` class that you can slap on any block of vanilla HTML content and turn it into a beautiful, well-formatted document:
17 |
18 | ```html
19 |
20 | Garlic bread with cheese: What the science tells us
21 |
22 | For years parents have espoused the health benefits of eating garlic bread with cheese to their
23 | children, with the food earning such an iconic status in our culture that kids will often dress
24 | up as warm, cheesy loaf for Halloween.
25 |
26 |
27 | But a recent study shows that the celebrated appetizer may be linked to a series of rabies cases
28 | springing up around the country.
29 |
30 |
31 |
32 | ```
33 |
34 | For more information about how to use the plugin and the features it includes, [read the documentation](https://github.com/tailwindcss/typography/blob/main/README.md).
35 |
36 | ---
37 |
38 | ## What to expect from here on out
39 |
40 | What follows from here is just a bunch of absolute nonsense I've written to dogfood the plugin itself. It includes every sensible typographic element I could think of, like **bold text**, unordered lists, ordered lists, code blocks, block quotes, _and even italics_.
41 |
42 | It's important to cover all of these use cases for a few reasons:
43 |
44 | 1. We want everything to look good out of the box.
45 | 2. Really just the first reason, that's the whole point of the plugin.
46 | 3. Here's a third pretend reason though a list with three items looks more realistic than a list with two items.
47 |
48 | Now we're going to try out another header style.
49 |
50 | ### Typography should be easy
51 |
52 | So that's a header for you — with any luck if we've done our job correctly that will look pretty reasonable.
53 |
54 | Something a wise person once told me about typography is:
55 |
56 | > Typography is pretty important if you don't want your stuff to look like trash. Make it good then it won't be bad.
57 |
58 | It's probably important that images look okay here by default as well:
59 |
60 |
61 |
65 |
66 | Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of
67 | classical Latin literature from 45 BC, making it over 2000 years old.
68 |
69 |
70 |
71 | Now I'm going to show you an example of an unordered list to make sure that looks good, too:
72 |
73 | - So here is the first item in this list.
74 | - In this example we're keeping the items short.
75 | - Later, we'll use longer, more complex list items.
76 |
77 | And that's the end of this section.
78 |
79 | ## What if we stack headings?
80 |
81 | ### We should make sure that looks good, too.
82 |
83 | Sometimes you have headings directly underneath each other. In those cases you often have to undo the top margin on the second heading because it usually looks better for the headings to be closer together than a paragraph followed by a heading should be.
84 |
85 | ### When a heading comes after a paragraph …
86 |
87 | When a heading comes after a paragraph, we need a bit more space, like I already mentioned above. Now let's see what a more complex list would look like.
88 |
89 | - **I often do this thing where list items have headings.**
90 |
91 | For some reason I think this looks cool which is unfortunate because it's pretty annoying to get the styles right.
92 |
93 | I often have two or three paragraphs in these list items, too, so the hard part is getting the spacing between the paragraphs, list item heading, and separate list items to all make sense. Pretty tough honestly, you could make a strong argument that you just shouldn't write this way.
94 |
95 | - **Since this is a list, I need at least two items.**
96 |
97 | I explained what I'm doing already in the previous list item, but a list wouldn't be a list if it only had one item, and we really want this to look realistic. That's why I've added this second list item so I actually have something to look at when writing the styles.
98 |
99 | - **It's not a bad idea to add a third item either.**
100 |
101 | I think it probably would've been fine to just use two items but three is definitely not worse, and since I seem to be having no trouble making up arbitrary things to type, I might as well include it. I'm going to press Enter now.
102 |
103 | After this sort of list I usually have a closing statement or paragraph, because it kinda looks weird jumping right to a heading.
104 |
105 | ## Code should look okay by default.
106 |
107 | I think most people are going to use [highlight.js](https://highlightjs.org/) or [Prism](https://prismjs.com/) or something if they want to style their code blocks but it wouldn't hurt to make them look _okay_ out of the box, even with no syntax highlighting.
108 |
109 | Here's what a default `tailwind.config.js` file looks like at the time of writing:
110 |
111 | ```js
112 | module.exports = {
113 | purge: [],
114 | theme: {
115 | extend: {},
116 | },
117 | variants: {},
118 | plugins: [],
119 | }
120 | ```
121 |
122 | Hopefully that looks good enough to you.
123 |
124 | ### What about nested lists?
125 |
126 | Nested lists basically always look bad which is why editors like Medium don't even let you do it, but I guess since some of you goofballs are going to do it we have to carry the burden of at least making it work.
127 |
128 | 1. **Nested lists are rarely a good idea.**
129 | - You might feel like you are being really "organized" or something but you are just creating a gross shape on the screen that is hard to read.
130 | - Nested navigation in UIs is a bad idea too, keep things as flat as possible.
131 | - Nesting tons of folders in your source code is also not helpful.
132 | 2. **Since we need to have more items, here's another one.**
133 | - I'm not sure if we'll bother styling more than two levels deep.
134 | - Two is already too much, three is guaranteed to be a bad idea.
135 | - If you nest four levels deep you belong in prison.
136 | 3. **Two items isn't really a list, three is good though.**
137 | - Again please don't nest lists if you want people to actually read your content.
138 | - Nobody wants to look at this.
139 | - I'm upset that we even have to bother styling this.
140 |
141 | The most annoying thing about lists in Markdown is that `` elements aren't given a child `` tag unless there are multiple paragraphs in the list item. That means I have to worry about styling that annoying situation too.
142 |
143 | - **For example, here's another nested list.**
144 |
145 | But this time with a second paragraph.
146 |
147 | - These list items won't have `
` tags
148 | - Because they are only one line each
149 |
150 | - **But in this second top-level list item, they will.**
151 |
152 | This is especially annoying because of the spacing on this paragraph.
153 |
154 | - As you can see here, because I've added a second line, this list item now has a `
` tag.
155 |
156 | This is the second line I'm talking about by the way.
157 |
158 | - Finally here's another list item so it's more like a list.
159 |
160 | - A closing list item, but with no nested list, because why not?
161 |
162 | And finally a sentence to close off this section.
163 |
164 | ## We didn't forget about description lists
165 |
166 | Well, that's not exactly true, we first released this plugin back in 2020 and it took three years before we added description lists. But they're here now, so let's just be happy about that…okay? They can be great for things like FAQs.
167 |
168 |
169 | Why do you never see elephants hiding in trees?
170 |
171 | Because they're so good at it. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas
172 | cupiditate laboriosam fugiat.
173 |
174 | What do you call someone with no body and no nose?
175 |
176 | Nobody knows. Lorem ipsum dolor sit amet consectetur adipisicing elit. Culpa, voluptas ipsa quia
177 | excepturi, quibusdam natus exercitationem sapiente tempore labore voluptatem.
178 |
179 | Why can't you hear a pterodactyl go to the bathroom?
180 |
181 | Because the pee is silent. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsam, quas
182 | voluptatibus ex culpa ipsum, aspernatur blanditiis fugiat ullam magnam suscipit deserunt illum
183 | natus facilis atque vero consequatur! Quisquam, debitis error.
184 |
185 |
186 |
187 | ## There are other elements we need to style
188 |
189 | I almost forgot to mention links, like [this link to the Tailwind CSS website](https://tailwindcss.com). We almost made them blue but that's so yesterday, so we went with dark gray, feels edgier.
190 |
191 | We even included table styles, check it out:
192 |
193 | | Wrestler | Origin | Finisher |
194 | | ----------------------- | ------------ | ------------------ |
195 | | Bret "The Hitman" Hart | Calgary, AB | Sharpshooter |
196 | | Stone Cold Steve Austin | Austin, TX | Stone Cold Stunner |
197 | | Randy Savage | Sarasota, FL | Elbow Drop |
198 | | Vader | Boulder, CO | Vader Bomb |
199 | | Razor Ramon | Chuluota, FL | Razor's Edge |
200 |
201 | We also need to make sure inline code looks good, like if I wanted to talk about `` elements or tell you the good news about `@tailwindcss/typography`.
202 |
203 | ### Sometimes I even use `code` in headings
204 |
205 | Even though it's probably a bad idea, and historically I've had a hard time making it look good. This _"wrap the code blocks in backticks"_ trick works pretty well though really.
206 |
207 | Another thing I've done in the past is put a `code` tag inside of a link, like if I wanted to tell you about the [`tailwindcss/docs`](https://github.com/tailwindcss/docs) repository. I don't love that there is an underline below the backticks but it is absolutely not worth the madness it would require to avoid it.
208 |
209 | #### We haven't used an `h4` yet
210 |
211 | But now we have. Please don't use `h5` or `h6` in your content, Medium only supports two heading levels for a reason, you animals. I honestly considered using a `before` pseudo-element to scream at you if you use an `h5` or `h6`.
212 |
213 | We don't style them at all out of the box because `h4` elements are already so small that they are the same size as the body copy. What are we supposed to do with an `h5`, make it _smaller_ than the body copy? No thanks.
214 |
215 | ### We still need to think about stacked headings though.
216 |
217 | #### Let's make sure we don't screw that up with `h4` elements, either.
218 |
219 | Phew, with any luck we have styled the headings above this text and they look pretty good.
220 |
221 | Let's add a closing paragraph here so things end with a decently sized block of text. I can't explain why I want things to end that way but I have to assume it's because I think things will look weird or unbalanced if there is a heading too close to the end of the document.
222 |
223 | What I've written here is probably long enough, but adding this final sentence can't hurt.
224 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | The official Tailwind CSS Typography plugin provides a set of `prose` classes you can use to add beautiful typographic defaults to any vanilla HTML you don’t control, like HTML rendered from Markdown, or pulled from a CMS.
12 |
13 | ```html
14 | {{ markdown }}
15 | ```
16 |
17 | To see what it looks like in action, check out our [live demo](https://play.tailwindcss.com/uj1vGACRJA?layout=preview) on Tailwind Play.
18 |
19 | ---
20 |
21 | ## Installation
22 |
23 | Install the plugin from npm:
24 |
25 | ```shell
26 | npm install -D @tailwindcss/typography
27 | ```
28 |
29 | Then add the plugin to your main `style.css` file:
30 |
31 | ```diff
32 | @import "tailwindcss";
33 | + @plugin "@tailwindcss/typography";
34 | ```
35 |
36 | If you are still using **Tailwind CSS v3**, add the plugin to your `tailwind.config.js` file:
37 |
38 | ```js
39 | // tailwind.config.js
40 | module.exports = {
41 | theme: {
42 | // ...
43 | },
44 | plugins: [
45 | require('@tailwindcss/typography'),
46 | // ...
47 | ],
48 | }
49 | ```
50 |
51 | ---
52 |
53 | ## Basic usage
54 |
55 | Now you can use the `prose` classes to add sensible typography styles to any vanilla HTML:
56 |
57 | ```html
58 |
59 | Garlic bread with cheese: What the science tells us
60 |
61 | For years parents have espoused the health benefits of eating garlic bread with cheese to their
62 | children, with the food earning such an iconic status in our culture that kids will often dress
63 | up as warm, cheesy loaf for Halloween.
64 |
65 |
66 | But a recent study shows that the celebrated appetizer may be linked to a series of rabies cases
67 | springing up around the country.
68 |
69 |
70 |
71 | ```
72 |
73 | ### Choosing a gray scale
74 |
75 | This plugin includes a modifier class for each of the five gray scales Tailwind includes by default so you can easily style your content to match the grays you're using in your project.
76 |
77 | ```html
78 | {{ markdown }}
79 | ```
80 |
81 | Here are the classes that are generated using a totally default Tailwind CSS v2.0 build:
82 |
83 | | Class | Gray scale |
84 | | ------------------------ | ---------- |
85 | | `prose-gray` _(default)_ | Gray |
86 | | `prose-slate` | Slate |
87 | | `prose-zinc` | Zinc |
88 | | `prose-neutral` | Neutral |
89 | | `prose-stone` | Stone |
90 |
91 | Modifier classes are designed to be used with the [multi-class modifier pattern](http://nicolasgallagher.com/about-html-semantics-front-end-architecture/#component-modifiers) and must be used in conjunction with the base `prose` class.
92 |
93 | > [!NOTE]
94 | > Always include the `prose` class when adding a gray scale modifier
95 |
96 | ```html
97 | {{ markdown }}
98 | ```
99 |
100 | To learn about creating your own color themes, read the [adding custom color themes](#adding-custom-color-themes) documentation.
101 |
102 | ### Applying a type scale
103 |
104 | Size modifiers allow you to adjust the overall size of your typography for different contexts.
105 |
106 | ```html
107 | {{ markdown }}
108 | ```
109 |
110 | Five different typography sizes are included out of the box:
111 |
112 | | Class | Body font size |
113 | | ------------------------ | ----------------- |
114 | | `prose-sm` | 0.875rem _(14px)_ |
115 | | `prose-base` _(default)_ | 1rem _(16px)_ |
116 | | `prose-lg` | 1.125rem _(18px)_ |
117 | | `prose-xl` | 1.25rem _(20px)_ |
118 | | `prose-2xl` | 1.5rem _(24px)_ |
119 |
120 | These can be used in combination with Tailwind's [breakpoint modifiers](https://tailwindcss.com/docs/responsive-design) to change the overall font size of a piece of content at different viewport sizes:
121 |
122 | ```html
123 | {{ markdown }}
124 | ```
125 |
126 | Everything about the provided size modifiers has been hand-tuned by professional designers to look as beautiful as possible, including the relationships between font sizes, heading spacing, code block padding, and more.
127 |
128 | Size modifiers are designed to be used with the [multi-class modifier pattern](http://nicolasgallagher.com/about-html-semantics-front-end-architecture/#component-modifiers) and must be used in conjunction with the base `prose` class.
129 |
130 | > [!NOTE]
131 | > Always include the `prose` class when adding a size modifier
132 |
133 | ```html
134 | {{ markdown }}
135 | ```
136 |
137 | To learn about customizing the included type scales, read the documentation on [customizing the CSS](#customizing-the-css).
138 |
139 | ### Adapting to dark mode
140 |
141 | Each default color theme includes a hand-designed dark mode version that you can trigger by adding the `prose-invert` class:
142 |
143 | ```html
144 | {{ markdown }}
145 | ```
146 |
147 | To learn about creating your own color themes, read the [adding custom color themes](#adding-custom-color-themes) documentation.
148 |
149 | ### Element modifiers
150 |
151 | Use element modifiers to customize the style of individual elements in your content directly in your HTML:
152 |
153 | ```html
154 |
155 | {{ markdown }}
156 |
157 | ```
158 |
159 | This makes it easy to do things like style links to match your brand, add a border radius to images, and tons more.
160 |
161 | Here's a complete list of available element modifiers:
162 |
163 | | Modifier | Target |
164 | | ---------------------------- | ---------------------------- |
165 | | `prose-headings:{utility}` | `h1`, `h2`, `h3`, `h4`, `th` |
166 | | `prose-lead:{utility}` | `[class~="lead"]` |
167 | | `prose-h1:{utility}` | `h1` |
168 | | `prose-h2:{utility}` | `h2` |
169 | | `prose-h3:{utility}` | `h3` |
170 | | `prose-h4:{utility}` | `h4` |
171 | | `prose-p:{utility}` | `p` |
172 | | `prose-a:{utility}` | `a` |
173 | | `prose-blockquote:{utility}` | `blockquote` |
174 | | `prose-figure:{utility}` | `figure` |
175 | | `prose-figcaption:{utility}` | `figcaption` |
176 | | `prose-strong:{utility}` | `strong` |
177 | | `prose-em:{utility}` | `em` |
178 | | `prose-kbd:{utility}` | `kbd` |
179 | | `prose-code:{utility}` | `code` |
180 | | `prose-pre:{utility}` | `pre` |
181 | | `prose-ol:{utility}` | `ol` |
182 | | `prose-ul:{utility}` | `ul` |
183 | | `prose-li:{utility}` | `li` |
184 | | `prose-dl:{utility}` | `dl` |
185 | | `prose-dt:{utility}` | `dt` |
186 | | `prose-dd:{utiddty}` | `dd` |
187 | | `prose-table:{utility}` | `table` |
188 | | `prose-thead:{utility}` | `thead` |
189 | | `prose-tr:{utility}` | `tr` |
190 | | `prose-th:{utility}` | `th` |
191 | | `prose-td:{utility}` | `td` |
192 | | `prose-img:{utility}` | `img` |
193 | | `prose-picture:{utility}` | `picture` |
194 | | `prose-video:{utility}` | `video` |
195 | | `prose-hr:{utility}` | `hr` |
196 |
197 | When stacking these modifiers with other modifiers like `hover`, you most likely want the other modifier to come last:
198 |
199 | ```html
200 | {{ markdown }}
201 | ```
202 |
203 | If you are still using in Tailwind CSS v3, the modifier order is the opposite:
204 |
205 | ```html
206 | {{ markdown }}
207 | ```
208 |
209 | Read the Tailwind CSS documentation on [stacked modifiers](https://tailwindcss.com/docs/hover-focus-and-other-states) to learn more.
210 |
211 | ### Overriding max-width
212 |
213 | Each size modifier comes with a baked in `max-width` designed to keep the content as readable as possible. This isn't always what you want though, and sometimes you'll want the content to just fill the width of its container.
214 |
215 | In those cases, all you need to do is add `max-w-none` to your content to override the embedded max-width:
216 |
217 | ```html
218 |
219 |
220 |
221 |
222 |
223 |
{{ markdown }}
224 |
225 |
226 | ```
227 |
228 | ---
229 |
230 | ## Advanced topics
231 |
232 | ### Undoing typography styles
233 |
234 | If you have a block of markup embedded in some content that shouldn't inherit the `prose` styles, use the `not-prose` class to sandbox it:
235 |
236 | ```html
237 |
238 | My Heading
239 | ...
240 |
241 |
242 |
243 |
244 |
245 | ...
246 |
247 |
248 | ```
249 |
250 | Note that you can't nest new `prose` instances within a `not-prose` block at this time.
251 |
252 | Even when using a prefix for your utilities `not-prose` should not have a prefix.
253 |
254 | ### Adding custom color themes
255 |
256 | To customize the color theme beyond simple CSS overrides, add a `@utility` directive to your CSS file:
257 |
258 | ```css
259 | @utility prose-pink {
260 | --tw-prose-body: var(--color-pink-800);
261 | --tw-prose-headings: var(--color-pink-900);
262 | --tw-prose-lead: var(--color-pink-700);
263 | --tw-prose-links: var(--color-pink-900);
264 | --tw-prose-bold: var(--color-pink-900);
265 | --tw-prose-counters: var(--color-pink-600);
266 | --tw-prose-bullets: var(--color-pink-400);
267 | --tw-prose-hr: var(--color-pink-300);
268 | --tw-prose-quotes: var(--color-pink-900);
269 | --tw-prose-quote-borders: var(--color-pink-300);
270 | --tw-prose-captions: var(--color-pink-700);
271 | --tw-prose-code: var(--color-pink-900);
272 | --tw-prose-pre-code: var(--color-pink-100);
273 | --tw-prose-pre-bg: var(--color-pink-900);
274 | --tw-prose-th-borders: var(--color-pink-300);
275 | --tw-prose-td-borders: var(--color-pink-200);
276 | --tw-prose-invert-body: var(--color-pink-200);
277 | --tw-prose-invert-headings: var(--color-white);
278 | --tw-prose-invert-lead: var(--color-pink-300);
279 | --tw-prose-invert-links: var(--color-white);
280 | --tw-prose-invert-bold: var(--color-white);
281 | --tw-prose-invert-counters: var(--color-pink-400);
282 | --tw-prose-invert-bullets: var(--color-pink-600);
283 | --tw-prose-invert-hr: var(--color-pink-700);
284 | --tw-prose-invert-quotes: var(--color-pink-100);
285 | --tw-prose-invert-quote-borders: var(--color-pink-700);
286 | --tw-prose-invert-captions: var(--color-pink-400);
287 | --tw-prose-invert-code: var(--color-white);
288 | --tw-prose-invert-pre-code: var(--color-pink-300);
289 | --tw-prose-invert-pre-bg: rgb(0 0 0 / 50%);
290 | --tw-prose-invert-th-borders: var(--color-pink-600);
291 | --tw-prose-invert-td-borders: var(--color-pink-700);
292 | }
293 | ```
294 |
295 | For Tailwind v3, update the `typography` section in the JavaScript config file and provide your colors under the `css` key:
296 |
297 | ```js {{ filename: 'tailwind.config.js' }}
298 | /** @type {import('tailwindcss').Config} */
299 | module.exports = {
300 | theme: {
301 | extend: {
302 | typography: () => ({
303 | pink: {
304 | css: {
305 | '--tw-prose-body': 'var(--color-pink-800)',
306 | '--tw-prose-headings': 'var(--color-pink-900)',
307 | '--tw-prose-lead': 'var(--color-pink-700)',
308 | '--tw-prose-links': 'var(--color-pink-900)',
309 | '--tw-prose-bold': 'var(--color-pink-900)',
310 | '--tw-prose-counters': 'var(--color-pink-600)',
311 | '--tw-prose-bullets': 'var(--color-pink-400)',
312 | '--tw-prose-hr': 'var(--color-pink-300)',
313 | '--tw-prose-quotes': 'var(--color-pink-900)',
314 | '--tw-prose-quote-borders': 'var(--color-pink-300)',
315 | '--tw-prose-captions': 'var(--color-pink-700)',
316 | '--tw-prose-code': 'var(--color-pink-900)',
317 | '--tw-prose-pre-code': 'var(--color-pink-100)',
318 | '--tw-prose-pre-bg': 'var(--color-pink-900)',
319 | '--tw-prose-th-borders': 'var(--color-pink-300)',
320 | '--tw-prose-td-borders': 'var(--color-pink-200)',
321 | '--tw-prose-invert-body': 'var(--color-pink-200)',
322 | '--tw-prose-invert-headings': 'var(--color-white)',
323 | '--tw-prose-invert-lead': 'var(--color-pink-300)',
324 | '--tw-prose-invert-links': 'var(--color-white)',
325 | '--tw-prose-invert-bold': 'var(--color-white)',
326 | '--tw-prose-invert-counters': 'var(--color-pink-400)',
327 | '--tw-prose-invert-bullets': 'var(--color-pink-600)',
328 | '--tw-prose-invert-hr': 'var(--color-pink-700)',
329 | '--tw-prose-invert-quotes': 'var(--color-pink-100)',
330 | '--tw-prose-invert-quote-borders': 'var(--color-pink-700)',
331 | '--tw-prose-invert-captions': 'var(--color-pink-400)',
332 | '--tw-prose-invert-code': 'var(--color-white)',
333 | '--tw-prose-invert-pre-code': 'var(--color-pink-300)',
334 | '--tw-prose-invert-pre-bg': 'rgb(0 0 0 / 50%)',
335 | '--tw-prose-invert-th-borders': 'var(--color-pink-600)',
336 | '--tw-prose-invert-td-borders': 'var(--color-pink-700)',
337 | },
338 | },
339 | }),
340 | },
341 | },
342 | }
343 | ```
344 |
345 | See our internal [style definitions](https://github.com/tailwindlabs/tailwindcss-typography/blob/main/src/styles.js) for some more examples.
346 |
347 | ### Changing the default class name
348 |
349 | If you need to use a class name other than `prose` for any reason, you can do so using the `className` option when registering the plugin:
350 |
351 | ```css
352 | @import 'tailwindcss';
353 | @plugin "@tailwindcss/typography" {
354 | className: wysiwyg;
355 | }
356 | ```
357 |
358 | Now every instance of `prose` in the default class names will be replaced by your custom class name:
359 |
360 | ```html
361 |
362 | My Heading
363 | ...
364 |
365 |
366 |
367 |
368 |
369 | ...
370 |
371 |
372 | ```
373 |
374 | ### Customizing the CSS
375 |
376 | If you want to customize the raw CSS generated by this plugin, you can use the JavaScript based theme API. To do that, use the `@config` directive:
377 |
378 | ```diff
379 | @import "tailwindcss";
380 | @plugin "@tailwindcss/typography";
381 | + @config "./tailwind.config.js";
382 | ```
383 |
384 | You can then create your own config by adding a new `tailwind.config.js` file with the `typography` section and providing your styles under the `css` key:
385 |
386 | ```js {{ filename: 'tailwind.config.js' }}
387 | /** @type {import('tailwindcss').Config} */
388 | module.exports = {
389 | theme: {
390 | extend: {
391 | typography: {
392 | DEFAULT: {
393 | css: {
394 | color: '#333',
395 | a: {
396 | color: '#3182ce',
397 | '&:hover': {
398 | color: '#2c5282',
399 | },
400 | },
401 | },
402 | },
403 | },
404 | },
405 | },
406 | }
407 | ```
408 |
409 | Like with all theme customizations in Tailwind, you can use CSS variables if you need access to access your theme configuration:
410 |
411 | ```js {{ filename: 'tailwind.config.js' }}
412 | /** @type {import('tailwindcss').Config} */
413 | module.exports = {
414 | theme: {
415 | extend: {
416 | typography: {
417 | DEFAULT: {
418 | css: {
419 | color: 'var(--color-gray-800)',
420 | // ...
421 | },
422 | },
423 | },
424 | },
425 | },
426 | }
427 | ```
428 |
429 | Customizations should be applied to a specific modifier like `DEFAULT` or `xl`, and must be added under the `css` property. Customizations are authored in the same [CSS-in-JS syntax](https://v3.tailwindcss.com/docs/plugins#css-in-js-syntax) used to write Tailwind v3 plugins.
430 |
431 | See [the default styles](https://github.com/tailwindlabs/tailwindcss-typography/blob/main/src/styles.js) for this plugin for more in-depth examples of configuring each modifier.
432 |
433 | ---
434 |
435 | ## Community
436 |
437 | For help, discussion about best practices, or any other conversation that would benefit from being searchable:
438 |
439 | [Discuss the Tailwind CSS Typography plugin on GitHub](https://github.com/tailwindlabs/tailwindcss/discussions)
440 |
441 | For casual chit-chat with others using the framework:
442 |
443 | [Join the Tailwind CSS Discord Server](https://tailwindcss.com/discord)
444 |
--------------------------------------------------------------------------------
/src/index.test.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const tailwind = require('tailwindcss')
3 | const postcss = require('postcss')
4 | const typographyPlugin = require('.')
5 |
6 | let html = String.raw
7 | let css = String.raw
8 |
9 | let vars = `
10 | --tw-border-spacing-x: 0;
11 | --tw-border-spacing-y: 0;
12 | --tw-translate-x: 0;
13 | --tw-translate-y: 0;
14 | --tw-rotate: 0;
15 | --tw-skew-x: 0;
16 | --tw-skew-y: 0;
17 | --tw-scale-x: 1;
18 | --tw-scale-y: 1;
19 | --tw-pan-x: ;
20 | --tw-pan-y: ;
21 | --tw-pinch-zoom: ;
22 | --tw-scroll-snap-strictness: proximity;
23 | --tw-ordinal: ;
24 | --tw-slashed-zero: ;
25 | --tw-numeric-figure: ;
26 | --tw-numeric-spacing: ;
27 | --tw-numeric-fraction: ;
28 | --tw-ring-inset: ;
29 | --tw-ring-offset-width: 0px;
30 | --tw-ring-offset-color: #fff;
31 | --tw-ring-color: rgb(59 130 246 / 0.5);
32 | --tw-ring-offset-shadow: 0 0 #0000;
33 | --tw-ring-shadow: 0 0 #0000;
34 | --tw-shadow: 0 0 #0000;
35 | --tw-shadow-colored: 0 0 #0000;
36 | --tw-blur: ;
37 | --tw-brightness: ;
38 | --tw-contrast: ;
39 | --tw-grayscale: ;
40 | --tw-hue-rotate: ;
41 | --tw-invert: ;
42 | --tw-saturate: ;
43 | --tw-sepia: ;
44 | --tw-drop-shadow: ;
45 | --tw-backdrop-blur: ;
46 | --tw-backdrop-brightness: ;
47 | --tw-backdrop-contrast: ;
48 | --tw-backdrop-grayscale: ;
49 | --tw-backdrop-hue-rotate: ;
50 | --tw-backdrop-invert: ;
51 | --tw-backdrop-opacity: ;
52 | --tw-backdrop-saturate: ;
53 | --tw-backdrop-sepia: ;
54 | `
55 | let defaults = css`
56 | *,
57 | ::before,
58 | ::after {
59 | ${vars}
60 | }
61 | ::backdrop {
62 | ${vars}
63 | }
64 | `
65 |
66 | function run(config, plugin = tailwind) {
67 | let { currentTestName } = expect.getState()
68 | config = {
69 | ...{ plugins: [typographyPlugin], corePlugins: { preflight: false } },
70 | ...config,
71 | }
72 |
73 | return postcss(plugin(config)).process(
74 | ['@tailwind base;', '@tailwind components;', '@tailwind utilities'].join('\n'),
75 | {
76 | from: `${path.resolve(__filename)}?test=${currentTestName}`,
77 | }
78 | )
79 | }
80 |
81 | test('specificity is reduced with :where', async () => {
82 | let config = {
83 | content: [{ raw: html`
` }],
84 | theme: {
85 | typography: {
86 | DEFAULT: {
87 | css: [
88 | {
89 | color: 'var(--tw-prose-body)',
90 | maxWidth: '65ch',
91 | '[class~="lead"]': {
92 | color: 'var(--tw-prose-lead)',
93 | },
94 | strong: {
95 | color: 'var(--tw-prose-bold)',
96 | fontWeight: '600',
97 | },
98 | 'ol[type="A"]': {
99 | listStyleType: 'upper-alpha',
100 | },
101 | 'blockquote p:first-of-type::before': {
102 | content: 'open-quote',
103 | },
104 | 'blockquote p:last-of-type::after': {
105 | content: 'close-quote',
106 | },
107 | 'h4 strong': {
108 | fontWeight: '700',
109 | },
110 | 'figure > *': {
111 | margin: 0,
112 | },
113 | 'ol > li::marker': {
114 | fontWeight: '400',
115 | color: 'var(--tw-prose-counters)',
116 | },
117 | '> ul > li p': {
118 | marginTop: '16px',
119 | marginBottom: '16px',
120 | },
121 | 'code::before': {
122 | content: '"`"',
123 | },
124 | 'code::after': {
125 | content: '"`"',
126 | },
127 | },
128 | ],
129 | },
130 | },
131 | },
132 | }
133 |
134 | return run(config).then((result) => {
135 | expect(result.css).toMatchFormattedCss(
136 | css`
137 | ${defaults}
138 |
139 | .prose {
140 | color: var(--tw-prose-body);
141 | max-width: 65ch;
142 | }
143 | .prose :where([class~='lead']):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
144 | color: var(--tw-prose-lead);
145 | }
146 | .prose :where(strong):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
147 | color: var(--tw-prose-bold);
148 | font-weight: 600;
149 | }
150 | .prose :where(ol[type='A']):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
151 | list-style-type: upper-alpha;
152 | }
153 | .prose
154 | :where(blockquote p:first-of-type):not(:where([class~='not-prose'], [class~='not-prose']
155 | *))::before {
156 | content: open-quote;
157 | }
158 | .prose
159 | :where(blockquote p:last-of-type):not(:where([class~='not-prose'], [class~='not-prose']
160 | *))::after {
161 | content: close-quote;
162 | }
163 | .prose :where(h4 strong):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
164 | font-weight: 700;
165 | }
166 | .prose :where(figure > *):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
167 | margin: 0;
168 | }
169 | .prose :where(ol > li):not(:where([class~='not-prose'], [class~='not-prose'] *))::marker {
170 | font-weight: 400;
171 | color: var(--tw-prose-counters);
172 | }
173 | .prose
174 | :where(.prose > ul > li p):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
175 | margin-top: 16px;
176 | margin-bottom: 16px;
177 | }
178 | .prose :where(code):not(:where([class~='not-prose'], [class~='not-prose'] *))::before {
179 | content: '`';
180 | }
181 | .prose :where(code):not(:where([class~='not-prose'], [class~='not-prose'] *))::after {
182 | content: '`';
183 | }
184 | `
185 | )
186 | })
187 | })
188 |
189 | test('variants', async () => {
190 | let config = {
191 | content: [{ raw: html`
` }],
192 | theme: {
193 | typography: {
194 | DEFAULT: {
195 | css: [
196 | {
197 | color: 'red',
198 | p: {
199 | color: 'lime',
200 | },
201 | '> ul > li': {
202 | color: 'purple',
203 | },
204 | },
205 | ],
206 | },
207 | lg: {
208 | css: {
209 | color: 'green',
210 | p: {
211 | color: 'tomato',
212 | },
213 | '> ul > li': {
214 | color: 'blue',
215 | },
216 | },
217 | },
218 | xl: {
219 | css: {
220 | color: 'yellow',
221 | '> ul > li': {
222 | color: 'hotpink',
223 | },
224 | },
225 | },
226 | },
227 | },
228 | }
229 |
230 | return run(config).then((result) => {
231 | expect(result.css).toMatchFormattedCss(
232 | css`
233 | ${defaults}
234 |
235 | .hover\:prose-lg:hover {
236 | color: green;
237 | }
238 | .hover\:prose-lg:hover :where(p):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
239 | color: tomato;
240 | }
241 | .hover\:prose-lg:hover
242 | :where(.hover\:prose-lg:hover
243 | > ul
244 | > li):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
245 | color: blue;
246 | }
247 | @media (min-width: 640px) {
248 | .sm\:prose {
249 | color: red;
250 | }
251 | .sm\:prose :where(p):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
252 | color: lime;
253 | }
254 | .sm\:prose
255 | :where(.sm\:prose > ul > li):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
256 | color: purple;
257 | }
258 | }
259 | @media (min-width: 1024px) {
260 | .lg\:prose-lg {
261 | color: green;
262 | }
263 | .lg\:prose-lg :where(p):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
264 | color: tomato;
265 | }
266 | .lg\:prose-lg
267 | :where(.lg\:prose-lg > ul > li):not(:where([class~='not-prose'], [class~='not-prose']
268 | *)) {
269 | color: blue;
270 | }
271 | }
272 | `
273 | )
274 | })
275 | })
276 |
277 | test('modifiers', async () => {
278 | let config = {
279 | content: [{ raw: html`
` }],
280 | theme: {
281 | typography: {
282 | DEFAULT: {
283 | css: [
284 | {
285 | color: 'var(--tw-prose-body)',
286 | maxWidth: '65ch',
287 | '[class~="lead"]': {
288 | color: 'var(--tw-prose-lead)',
289 | },
290 | strong: {
291 | color: 'var(--tw-prose-bold)',
292 | fontWeight: '600',
293 | },
294 | 'ol[type="A"]': {
295 | listStyleType: 'upper-alpha',
296 | },
297 | 'blockquote p:first-of-type::before': {
298 | content: 'open-quote',
299 | },
300 | 'blockquote p:last-of-type::after': {
301 | content: 'close-quote',
302 | },
303 | 'h4 strong': {
304 | fontWeight: '700',
305 | },
306 | 'figure > *': {
307 | margin: 0,
308 | },
309 | 'ol > li::marker': {
310 | fontWeight: '400',
311 | color: 'var(--tw-prose-counters)',
312 | },
313 | 'code::before': {
314 | content: '"`"',
315 | },
316 | 'code::after': {
317 | content: '"`"',
318 | },
319 | },
320 | ],
321 | },
322 | lg: {
323 | css: [
324 | {
325 | fontSize: '18px',
326 | lineHeight: '1.75',
327 | p: {
328 | marginTop: '24px',
329 | marginBottom: '24px',
330 | },
331 | '[class~="lead"]': {
332 | fontSize: '22px',
333 | },
334 | blockquote: {
335 | marginTop: '40px',
336 | marginBottom: '40px',
337 | },
338 | '> ul > li': {
339 | paddingLeft: '12px',
340 | },
341 | h1: {
342 | fontSize: '48px',
343 | marginTop: '0',
344 | marginBottom: '40px',
345 | },
346 | h2: {
347 | fontSize: '30px',
348 | marginTop: '56px',
349 | marginBottom: '32px',
350 | },
351 | h3: {
352 | fontSize: '24px',
353 | marginTop: '40px',
354 | marginBottom: '16px',
355 | },
356 | },
357 | ],
358 | },
359 | },
360 | },
361 | }
362 |
363 | return run(config).then((result) => {
364 | expect(result.css).toMatchFormattedCss(
365 | css`
366 | ${defaults}
367 |
368 | .prose {
369 | color: var(--tw-prose-body);
370 | max-width: 65ch;
371 | }
372 | .prose :where([class~='lead']):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
373 | color: var(--tw-prose-lead);
374 | }
375 | .prose :where(strong):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
376 | color: var(--tw-prose-bold);
377 | font-weight: 600;
378 | }
379 | .prose :where(ol[type='A']):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
380 | list-style-type: upper-alpha;
381 | }
382 | .prose
383 | :where(blockquote p:first-of-type):not(:where([class~='not-prose'], [class~='not-prose']
384 | *))::before {
385 | content: open-quote;
386 | }
387 | .prose
388 | :where(blockquote p:last-of-type):not(:where([class~='not-prose'], [class~='not-prose']
389 | *))::after {
390 | content: close-quote;
391 | }
392 | .prose :where(h4 strong):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
393 | font-weight: 700;
394 | }
395 | .prose :where(figure > *):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
396 | margin: 0;
397 | }
398 | .prose :where(ol > li):not(:where([class~='not-prose'], [class~='not-prose'] *))::marker {
399 | font-weight: 400;
400 | color: var(--tw-prose-counters);
401 | }
402 | .prose :where(code):not(:where([class~='not-prose'], [class~='not-prose'] *))::before {
403 | content: '`';
404 | }
405 | .prose :where(code):not(:where([class~='not-prose'], [class~='not-prose'] *))::after {
406 | content: '`';
407 | }
408 | .prose-lg {
409 | font-size: 18px;
410 | line-height: 1.75;
411 | }
412 | .prose-lg :where(p):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
413 | margin-top: 24px;
414 | margin-bottom: 24px;
415 | }
416 | .prose-lg
417 | :where([class~='lead']):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
418 | font-size: 22px;
419 | }
420 | .prose-lg :where(blockquote):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
421 | margin-top: 40px;
422 | margin-bottom: 40px;
423 | }
424 | .prose-lg
425 | :where(.prose-lg > ul > li):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
426 | padding-left: 12px;
427 | }
428 | .prose-lg :where(h1):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
429 | font-size: 48px;
430 | margin-top: 0;
431 | margin-bottom: 40px;
432 | }
433 | .prose-lg :where(h2):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
434 | font-size: 30px;
435 | margin-top: 56px;
436 | margin-bottom: 32px;
437 | }
438 | .prose-lg :where(h3):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
439 | font-size: 24px;
440 | margin-top: 40px;
441 | margin-bottom: 16px;
442 | }
443 | `
444 | )
445 | })
446 | })
447 |
448 | test('legacy target', async () => {
449 | let config = {
450 | plugins: [typographyPlugin({ target: 'legacy' })],
451 | content: [
452 | { raw: html`
` },
453 | ],
454 | theme: {
455 | typography: {
456 | DEFAULT: {
457 | css: [
458 | {
459 | color: 'var(--tw-prose-body)',
460 | maxWidth: '65ch',
461 | '[class~="lead"]': {
462 | color: 'var(--tw-prose-lead)',
463 | },
464 | strong: {
465 | color: 'var(--tw-prose-bold)',
466 | fontWeight: '600',
467 | },
468 | 'ol[type="A"]': {
469 | listStyleType: 'upper-alpha',
470 | },
471 | 'blockquote p:first-of-type::before': {
472 | content: 'open-quote',
473 | },
474 | 'blockquote p:last-of-type::after': {
475 | content: 'close-quote',
476 | },
477 | 'h4 strong': {
478 | fontWeight: '700',
479 | },
480 | 'figure > *': {
481 | margin: 0,
482 | },
483 | 'ol > li::marker': {
484 | fontWeight: '400',
485 | color: 'var(--tw-prose-counters)',
486 | },
487 | 'code::before': {
488 | content: '"`"',
489 | },
490 | 'code::after': {
491 | content: '"`"',
492 | },
493 | },
494 | ],
495 | },
496 | },
497 | },
498 | }
499 |
500 | return run(config).then((result) => {
501 | expect(result.css).toMatchFormattedCss(
502 | css`
503 | ${defaults}
504 |
505 | .prose {
506 | color: var(--tw-prose-body);
507 | max-width: 65ch;
508 | }
509 | .prose [class~='lead'] {
510 | color: var(--tw-prose-lead);
511 | }
512 | .prose strong {
513 | color: var(--tw-prose-bold);
514 | font-weight: 600;
515 | }
516 | .prose ol[type='A'] {
517 | list-style-type: upper-alpha;
518 | }
519 | .prose blockquote p:first-of-type::before {
520 | content: open-quote;
521 | }
522 | .prose blockquote p:last-of-type::after {
523 | content: close-quote;
524 | }
525 | .prose h4 strong {
526 | font-weight: 700;
527 | }
528 | .prose figure > * {
529 | margin: 0;
530 | }
531 | .prose ol > li::marker {
532 | font-weight: 400;
533 | color: var(--tw-prose-counters);
534 | }
535 | .prose code::before {
536 | content: '`';
537 | }
538 | .prose code::after {
539 | content: '`';
540 | }
541 | .prose-headings\:text-ellipsis h1 {
542 | text-overflow: ellipsis;
543 | }
544 | .prose-headings\:text-ellipsis h2 {
545 | text-overflow: ellipsis;
546 | }
547 | .prose-headings\:text-ellipsis h3 {
548 | text-overflow: ellipsis;
549 | }
550 | .prose-headings\:text-ellipsis h4 {
551 | text-overflow: ellipsis;
552 | }
553 | .prose-headings\:text-ellipsis h5 {
554 | text-overflow: ellipsis;
555 | }
556 | .prose-headings\:text-ellipsis h6 {
557 | text-overflow: ellipsis;
558 | }
559 | .prose-headings\:text-ellipsis th {
560 | text-overflow: ellipsis;
561 | }
562 | .prose-h1\:text-center h1 {
563 | text-align: center;
564 | }
565 | `
566 | )
567 | })
568 | })
569 |
570 | test('custom class name', async () => {
571 | let config = {
572 | plugins: [typographyPlugin({ className: 'markdown' })],
573 | content: [{ raw: html`
` }],
574 | theme: {
575 | typography: {
576 | DEFAULT: {
577 | css: [
578 | {
579 | color: 'var(--tw-prose-body)',
580 | maxWidth: '65ch',
581 | '[class~="lead"]': {
582 | color: 'var(--tw-prose-lead)',
583 | },
584 | strong: {
585 | color: 'var(--tw-prose-bold)',
586 | fontWeight: '600',
587 | },
588 | 'ol[type="A"]': {
589 | listStyleType: 'upper-alpha',
590 | },
591 | 'blockquote p:first-of-type::before': {
592 | content: 'open-quote',
593 | },
594 | 'blockquote p:last-of-type::after': {
595 | content: 'close-quote',
596 | },
597 | 'h4 strong': {
598 | fontWeight: '700',
599 | },
600 | 'figure > *': {
601 | margin: 0,
602 | },
603 | 'ol > li::marker': {
604 | fontWeight: '400',
605 | color: 'var(--tw-prose-counters)',
606 | },
607 | 'code::before': {
608 | content: '"`"',
609 | },
610 | 'code::after': {
611 | content: '"`"',
612 | },
613 | },
614 | ],
615 | },
616 | },
617 | },
618 | }
619 |
620 | return run(config).then((result) => {
621 | expect(result.css).toMatchFormattedCss(
622 | css`
623 | ${defaults}
624 |
625 | .markdown {
626 | color: var(--tw-prose-body);
627 | max-width: 65ch;
628 | }
629 | .markdown
630 | :where([class~='lead']):not(:where([class~='not-markdown'], [class~='not-markdown'] *)) {
631 | color: var(--tw-prose-lead);
632 | }
633 | .markdown :where(strong):not(:where([class~='not-markdown'], [class~='not-markdown'] *)) {
634 | color: var(--tw-prose-bold);
635 | font-weight: 600;
636 | }
637 | .markdown
638 | :where(ol[type='A']):not(:where([class~='not-markdown'], [class~='not-markdown'] *)) {
639 | list-style-type: upper-alpha;
640 | }
641 | .markdown
642 | :where(blockquote
643 | p:first-of-type):not(:where([class~='not-markdown'], [class~='not-markdown']
644 | *))::before {
645 | content: open-quote;
646 | }
647 | .markdown
648 | :where(blockquote
649 | p:last-of-type):not(:where([class~='not-markdown'], [class~='not-markdown'] *))::after {
650 | content: close-quote;
651 | }
652 | .markdown
653 | :where(h4 strong):not(:where([class~='not-markdown'], [class~='not-markdown'] *)) {
654 | font-weight: 700;
655 | }
656 | .markdown
657 | :where(figure > *):not(:where([class~='not-markdown'], [class~='not-markdown'] *)) {
658 | margin: 0;
659 | }
660 | .markdown
661 | :where(ol > li):not(:where([class~='not-markdown'], [class~='not-markdown'] *))::marker {
662 | font-weight: 400;
663 | color: var(--tw-prose-counters);
664 | }
665 | .markdown
666 | :where(code):not(:where([class~='not-markdown'], [class~='not-markdown'] *))::before {
667 | content: '`';
668 | }
669 | .markdown
670 | :where(code):not(:where([class~='not-markdown'], [class~='not-markdown'] *))::after {
671 | content: '`';
672 | }
673 | `
674 | )
675 | })
676 | })
677 |
678 | test('element variants', async () => {
679 | let config = {
680 | content: [
681 | {
682 | raw: html`
`,
718 | },
719 | ],
720 | theme: {
721 | typography: {
722 | DEFAULT: {
723 | css: [
724 | {
725 | color: 'var(--tw-prose-body)',
726 | '[class~="lead"]': {
727 | color: 'var(--tw-prose-lead)',
728 | },
729 | strong: {
730 | color: 'var(--tw-prose-bold)',
731 | fontWeight: '600',
732 | },
733 | 'h4 strong': {
734 | fontWeight: '700',
735 | },
736 | },
737 | ],
738 | },
739 | },
740 | },
741 | }
742 | return run(config).then((result) => {
743 | expect(result.css).toMatchFormattedCss(
744 | css`
745 | ${defaults}
746 |
747 | .prose {
748 | color: var(--tw-prose-body);
749 | }
750 | .prose :where([class~='lead']):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
751 | color: var(--tw-prose-lead);
752 | }
753 | .prose :where(strong):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
754 | color: var(--tw-prose-bold);
755 | font-weight: 600;
756 | }
757 | .prose :where(h4 strong):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
758 | font-weight: 700;
759 | }
760 | .prose-headings\:underline
761 | :is(:where(h1, h2, h3, h4, h5, h6, th):not(:where([class~='not-prose'], [class~='not-prose']
762 | *))) {
763 | text-decoration-line: underline;
764 | }
765 | .prose-h1\:text-3xl
766 | :is(:where(h1):not(:where([class~='not-prose'], [class~='not-prose'] *))) {
767 | font-size: 1.875rem;
768 | line-height: 2.25rem;
769 | }
770 | .prose-h2\:text-2xl
771 | :is(:where(h2):not(:where([class~='not-prose'], [class~='not-prose'] *))) {
772 | font-size: 1.5rem;
773 | line-height: 2rem;
774 | }
775 | .prose-h3\:text-xl
776 | :is(:where(h3):not(:where([class~='not-prose'], [class~='not-prose'] *))) {
777 | font-size: 1.25rem;
778 | line-height: 1.75rem;
779 | }
780 | .prose-h4\:text-lg
781 | :is(:where(h4):not(:where([class~='not-prose'], [class~='not-prose'] *))) {
782 | font-size: 1.125rem;
783 | line-height: 1.75rem;
784 | }
785 | .prose-p\:text-gray-700
786 | :is(:where(p):not(:where([class~='not-prose'], [class~='not-prose'] *))) {
787 | --tw-text-opacity: 1;
788 | color: rgb(55 65 81 / var(--tw-text-opacity));
789 | }
790 | .prose-a\:font-bold
791 | :is(:where(a):not(:where([class~='not-prose'], [class~='not-prose'] *))) {
792 | font-weight: 700;
793 | }
794 | .prose-blockquote\:italic
795 | :is(:where(blockquote):not(:where([class~='not-prose'], [class~='not-prose'] *))) {
796 | font-style: italic;
797 | }
798 | .prose-figure\:mx-auto
799 | :is(:where(figure):not(:where([class~='not-prose'], [class~='not-prose'] *))) {
800 | margin-left: auto;
801 | margin-right: auto;
802 | }
803 | .prose-figcaption\:opacity-75
804 | :is(:where(figcaption):not(:where([class~='not-prose'], [class~='not-prose'] *))) {
805 | opacity: 0.75;
806 | }
807 | .prose-strong\:font-medium
808 | :is(:where(strong):not(:where([class~='not-prose'], [class~='not-prose'] *))) {
809 | font-weight: 500;
810 | }
811 | .prose-em\:italic
812 | :is(:where(em):not(:where([class~='not-prose'], [class~='not-prose'] *))) {
813 | font-style: italic;
814 | }
815 | .prose-kbd\:border-b-2
816 | :is(:where(kbd):not(:where([class~='not-prose'], [class~='not-prose'] *))) {
817 | border-bottom-width: 2px;
818 | }
819 | .prose-code\:font-mono
820 | :is(:where(code):not(:where([class~='not-prose'], [class~='not-prose'] *))) {
821 | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono',
822 | 'Courier New', monospace;
823 | }
824 | .prose-pre\:font-mono
825 | :is(:where(pre):not(:where([class~='not-prose'], [class~='not-prose'] *))) {
826 | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono',
827 | 'Courier New', monospace;
828 | }
829 | .prose-ol\:pl-6 :is(:where(ol):not(:where([class~='not-prose'], [class~='not-prose'] *))) {
830 | padding-left: 1.5rem;
831 | }
832 | .prose-ul\:pl-8 :is(:where(ul):not(:where([class~='not-prose'], [class~='not-prose'] *))) {
833 | padding-left: 2rem;
834 | }
835 | .prose-li\:my-4 :is(:where(li):not(:where([class~='not-prose'], [class~='not-prose'] *))) {
836 | margin-top: 1rem;
837 | margin-bottom: 1rem;
838 | }
839 | .prose-dl\:pl-6 :is(:where(dl):not(:where([class~="not-prose"], [class~="not-prose"] *))) {
840 | padding-left: 1.5rem;
841 | }
842 | .prose-dt\:pl-8 :is(:where(dt):not(:where([class~="not-prose"], [class~="not-prose"] *))) {
843 | padding-left: 2rem;
844 | }
845 | .prose-dd\:my-4 :is(:where(dd):not(:where([class~="not-prose"], [class~="not-prose"] *))) {
846 | margin-top: 1rem;
847 | margin-bottom: 1rem;
848 | }
849 | .prose-table\:my-8
850 | :is(:where(table):not(:where([class~='not-prose'], [class~='not-prose'] *))) {
851 | margin-top: 2rem;
852 | margin-bottom: 2rem;
853 | }
854 | .prose-thead\:border-red-300
855 | :is(:where(thead):not(:where([class~='not-prose'], [class~='not-prose'] *))) {
856 | --tw-border-opacity: 1;
857 | border-color: rgb(252 165 165 / var(--tw-border-opacity));
858 | }
859 | .prose-tr\:border-red-200
860 | :is(:where(tr):not(:where([class~='not-prose'], [class~='not-prose'] *))) {
861 | --tw-border-opacity: 1;
862 | border-color: rgb(254 202 202 / var(--tw-border-opacity));
863 | }
864 | .prose-th\:text-left
865 | :is(:where(th):not(:where([class~='not-prose'], [class~='not-prose'] *))) {
866 | text-align: left;
867 | }
868 | .prose-img\:rounded-lg
869 | :is(:where(img):not(:where([class~='not-prose'], [class~='not-prose'] *))) {
870 | border-radius: 0.5rem;
871 | }
872 | .prose-picture\:my-8
873 | :is(:where(picture):not(:where([class~='not-prose'], [class~='not-prose'] *))) {
874 | margin-top: 2rem;
875 | margin-bottom: 2rem;
876 | }
877 | .prose-video\:my-12
878 | :is(:where(video):not(:where([class~='not-prose'], [class~='not-prose'] *))) {
879 | margin-top: 3rem;
880 | margin-bottom: 3rem;
881 | }
882 | .prose-hr\:border-t-2
883 | :is(:where(hr):not(:where([class~='not-prose'], [class~='not-prose'] *))) {
884 | border-top-width: 2px;
885 | }
886 | .prose-lead\:italic
887 | :is(:where([class~='lead']):not(:where([class~='not-prose'], [class~='not-prose'] *))) {
888 | font-style: italic;
889 | }
890 | `
891 | )
892 | })
893 | })
894 |
895 | test('element variants with custom class name', async () => {
896 | let config = {
897 | plugins: [typographyPlugin({ className: 'markdown' })],
898 | content: [
899 | {
900 | raw: html`
`,
932 | },
933 | ],
934 | theme: {
935 | typography: {
936 | DEFAULT: {
937 | css: [
938 | {
939 | color: 'var(--tw-prose-body)',
940 | '[class~="lead"]': {
941 | color: 'var(--tw-prose-lead)',
942 | },
943 | strong: {
944 | color: 'var(--tw-prose-bold)',
945 | fontWeight: '600',
946 | },
947 | 'h4 strong': {
948 | fontWeight: '700',
949 | },
950 | },
951 | ],
952 | },
953 | },
954 | },
955 | }
956 | return run(config).then((result) => {
957 | expect(result.css).toMatchFormattedCss(
958 | css`
959 | ${defaults}
960 |
961 | .markdown {
962 | color: var(--tw-prose-body);
963 | }
964 | .markdown
965 | :where([class~='lead']):not(:where([class~='not-markdown'], [class~='not-markdown'] *)) {
966 | color: var(--tw-prose-lead);
967 | }
968 | .markdown :where(strong):not(:where([class~='not-markdown'], [class~='not-markdown'] *)) {
969 | color: var(--tw-prose-bold);
970 | font-weight: 600;
971 | }
972 | .markdown
973 | :where(h4 strong):not(:where([class~='not-markdown'], [class~='not-markdown'] *)) {
974 | font-weight: 700;
975 | }
976 | .markdown-headings\:underline
977 | :is(:where(h1, h2, h3, h4, h5, h6, th):not(:where([class~='not-markdown'], [class~='not-markdown']
978 | *))) {
979 | text-decoration-line: underline;
980 | }
981 | .markdown-h1\:text-3xl
982 | :is(:where(h1):not(:where([class~='not-markdown'], [class~='not-markdown'] *))) {
983 | font-size: 1.875rem;
984 | line-height: 2.25rem;
985 | }
986 | .markdown-h2\:text-2xl
987 | :is(:where(h2):not(:where([class~='not-markdown'], [class~='not-markdown'] *))) {
988 | font-size: 1.5rem;
989 | line-height: 2rem;
990 | }
991 | .markdown-h3\:text-xl
992 | :is(:where(h3):not(:where([class~='not-markdown'], [class~='not-markdown'] *))) {
993 | font-size: 1.25rem;
994 | line-height: 1.75rem;
995 | }
996 | .markdown-h4\:text-lg
997 | :is(:where(h4):not(:where([class~='not-markdown'], [class~='not-markdown'] *))) {
998 | font-size: 1.125rem;
999 | line-height: 1.75rem;
1000 | }
1001 | .markdown-p\:text-gray-700
1002 | :is(:where(p):not(:where([class~='not-markdown'], [class~='not-markdown'] *))) {
1003 | --tw-text-opacity: 1;
1004 | color: rgb(55 65 81 / var(--tw-text-opacity));
1005 | }
1006 | .markdown-a\:font-bold
1007 | :is(:where(a):not(:where([class~='not-markdown'], [class~='not-markdown'] *))) {
1008 | font-weight: 700;
1009 | }
1010 | .markdown-blockquote\:italic
1011 | :is(:where(blockquote):not(:where([class~='not-markdown'], [class~='not-markdown'] *))) {
1012 | font-style: italic;
1013 | }
1014 | .markdown-figure\:mx-auto
1015 | :is(:where(figure):not(:where([class~='not-markdown'], [class~='not-markdown'] *))) {
1016 | margin-left: auto;
1017 | margin-right: auto;
1018 | }
1019 | .markdown-figcaption\:opacity-75
1020 | :is(:where(figcaption):not(:where([class~='not-markdown'], [class~='not-markdown'] *))) {
1021 | opacity: 0.75;
1022 | }
1023 | .markdown-strong\:font-medium
1024 | :is(:where(strong):not(:where([class~='not-markdown'], [class~='not-markdown'] *))) {
1025 | font-weight: 500;
1026 | }
1027 | .markdown-em\:italic
1028 | :is(:where(em):not(:where([class~='not-markdown'], [class~='not-markdown'] *))) {
1029 | font-style: italic;
1030 | }
1031 | .markdown-kbd\:border-b-2
1032 | :is(:where(kbd):not(:where([class~='not-markdown'], [class~='not-markdown'] *))) {
1033 | border-bottom-width: 2px;
1034 | }
1035 | .markdown-code\:font-mono
1036 | :is(:where(code):not(:where([class~='not-markdown'], [class~='not-markdown'] *))) {
1037 | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono',
1038 | 'Courier New', monospace;
1039 | }
1040 | .markdown-pre\:font-mono
1041 | :is(:where(pre):not(:where([class~='not-markdown'], [class~='not-markdown'] *))) {
1042 | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono',
1043 | 'Courier New', monospace;
1044 | }
1045 | .markdown-ol\:pl-6
1046 | :is(:where(ol):not(:where([class~='not-markdown'], [class~='not-markdown'] *))) {
1047 | padding-left: 1.5rem;
1048 | }
1049 | .markdown-ul\:pl-8
1050 | :is(:where(ul):not(:where([class~='not-markdown'], [class~='not-markdown'] *))) {
1051 | padding-left: 2rem;
1052 | }
1053 | .markdown-li\:my-4
1054 | :is(:where(li):not(:where([class~='not-markdown'], [class~='not-markdown'] *))) {
1055 | margin-top: 1rem;
1056 | margin-bottom: 1rem;
1057 | }
1058 | .markdown-table\:my-8
1059 | :is(:where(table):not(:where([class~='not-markdown'], [class~='not-markdown'] *))) {
1060 | margin-top: 2rem;
1061 | margin-bottom: 2rem;
1062 | }
1063 | .markdown-thead\:border-red-300
1064 | :is(:where(thead):not(:where([class~='not-markdown'], [class~='not-markdown'] *))) {
1065 | --tw-border-opacity: 1;
1066 | border-color: rgb(252 165 165 / var(--tw-border-opacity));
1067 | }
1068 | .markdown-tr\:border-red-200
1069 | :is(:where(tr):not(:where([class~='not-markdown'], [class~='not-markdown'] *))) {
1070 | --tw-border-opacity: 1;
1071 | border-color: rgb(254 202 202 / var(--tw-border-opacity));
1072 | }
1073 | .markdown-th\:text-left
1074 | :is(:where(th):not(:where([class~='not-markdown'], [class~='not-markdown'] *))) {
1075 | text-align: left;
1076 | }
1077 | .markdown-img\:rounded-lg
1078 | :is(:where(img):not(:where([class~='not-markdown'], [class~='not-markdown'] *))) {
1079 | border-radius: 0.5rem;
1080 | }
1081 | .markdown-video\:my-12
1082 | :is(:where(video):not(:where([class~='not-markdown'], [class~='not-markdown'] *))) {
1083 | margin-top: 3rem;
1084 | margin-bottom: 3rem;
1085 | }
1086 | .markdown-hr\:border-t-2
1087 | :is(:where(hr):not(:where([class~='not-markdown'], [class~='not-markdown'] *))) {
1088 | border-top-width: 2px;
1089 | }
1090 | .markdown-lead\:italic
1091 | :is(:where([class~='lead']):not(:where([class~='not-markdown'], [class~='not-markdown']
1092 | *))) {
1093 | font-style: italic;
1094 | }
1095 | `
1096 | )
1097 | })
1098 | })
1099 |
1100 | test('customizing defaults with multiple values does not result in invalid css', async () => {
1101 | let config = {
1102 | plugins: [typographyPlugin()],
1103 | content: [
1104 | {
1105 | raw: html`
`,
1106 | },
1107 | ],
1108 | theme: {
1109 | typography: {
1110 | DEFAULT: {
1111 | css: {
1112 | textAlign: ['-webkit-match-parent', 'match-parent'],
1113 | },
1114 | },
1115 | },
1116 | },
1117 | }
1118 | return run(config).then((result) => {
1119 | expect(result.css).toMatchFormattedCss(
1120 | css`
1121 | ${defaults}
1122 |
1123 | .prose {
1124 | text-align: -webkit-match-parent;
1125 | text-align: match-parent;
1126 | }
1127 | `
1128 | )
1129 | })
1130 | })
1131 |
1132 | it('should be possible to use nested syntax (&) when extending the config', () => {
1133 | let config = {
1134 | plugins: [typographyPlugin()],
1135 | content: [
1136 | {
1137 | raw: html`
`,
1138 | },
1139 | ],
1140 | theme: {
1141 | extend: {
1142 | typography: {
1143 | DEFAULT: {
1144 | css: {
1145 | color: '#000',
1146 | a: {
1147 | color: '#888',
1148 | '&:hover': {
1149 | color: '#ff0000',
1150 | },
1151 | },
1152 | },
1153 | },
1154 | },
1155 | },
1156 | },
1157 | }
1158 |
1159 | return run(config).then((result) => {
1160 | expect(result.css).toIncludeCss(css`
1161 | .prose {
1162 | color: #000;
1163 | max-width: 65ch;
1164 | }
1165 | `)
1166 |
1167 | expect(result.css).toIncludeCss(css`
1168 | .prose :where(a):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
1169 | color: #888;
1170 | text-decoration: underline;
1171 | font-weight: 500;
1172 | }
1173 | `)
1174 |
1175 | expect(result.css).toIncludeCss(css`
1176 | .prose :where(a):not(:where([class~='not-prose'], [class~='not-prose'] *)):hover {
1177 | color: #ff0000;
1178 | }
1179 | `)
1180 | })
1181 | })
1182 |
1183 | it('should be possible to specify custom h5 and h6 styles', () => {
1184 | let config = {
1185 | plugins: [typographyPlugin()],
1186 | content: [
1187 | {
1188 | raw: html`
`,
1189 | },
1190 | ],
1191 | }
1192 |
1193 | return run(config).then((result) => {
1194 | expect(result.css).toIncludeCss(css`
1195 | .prose-h5\:text-sm :is(:where(h5):not(:where([class~='not-prose'], [class~='not-prose'] *))) {
1196 | font-size: 0.875rem;
1197 | line-height: 1.25rem;
1198 | }
1199 | .prose-h6\:text-xl :is(:where(h6):not(:where([class~='not-prose'], [class~='not-prose'] *))) {
1200 | font-size: 1.25rem;
1201 | line-height: 1.75rem;
1202 | }
1203 | `)
1204 | })
1205 | })
1206 |
1207 | it('should not break with multiple selectors with pseudo elements using variants', () => {
1208 | let config = {
1209 | darkMode: 'class',
1210 | plugins: [typographyPlugin()],
1211 | content: [
1212 | {
1213 | raw: html`
`,
1214 | },
1215 | ],
1216 | theme: {
1217 | typography: {
1218 | DEFAULT: {
1219 | css: {
1220 | 'ol li::before, ul li::before': {
1221 | color: 'red',
1222 | },
1223 | },
1224 | },
1225 | },
1226 | },
1227 | }
1228 |
1229 | return run(config).then((result) => {
1230 | expect(result.css).toIncludeCss(css`
1231 | .dark
1232 | .dark\:prose
1233 | :where(ol li, ul li):not(:where([class~='not-prose'], [class~='not-prose'] *))::before {
1234 | color: red;
1235 | }
1236 | `)
1237 | })
1238 | })
1239 |
1240 | it('lifts all common, trailing pseudo elements when the same across all selectors', () => {
1241 | let config = {
1242 | darkMode: 'class',
1243 | plugins: [typographyPlugin()],
1244 | content: [
1245 | {
1246 | raw: html`
`,
1247 | },
1248 | ],
1249 | theme: {
1250 | typography: {
1251 | DEFAULT: {
1252 | css: {
1253 | 'ol li::marker::before, ul li::marker::before': {
1254 | color: 'red',
1255 | },
1256 | },
1257 | },
1258 | },
1259 | },
1260 | }
1261 |
1262 | return run(config).then((result) => {
1263 | expect(result.css).toIncludeCss(css`
1264 | .prose
1265 | :where(ol li, ul li):not(:where([class~='not-prose'], [class~='not-prose']
1266 | *))::marker::before {
1267 | color: red;
1268 | }
1269 | `)
1270 |
1271 | // TODO: The output here is a bug in tailwindcss variant selector rewriting
1272 | // IT should be ::marker::before
1273 | expect(result.css).toIncludeCss(css`
1274 | .dark
1275 | .dark\:prose
1276 | :where(ol li, ul li):not(:where([class~='not-prose'], [class~='not-prose']
1277 | *))::before::marker {
1278 | color: red;
1279 | }
1280 | `)
1281 | })
1282 | })
1283 |
1284 | it('does not modify selectors with differing pseudo elements', () => {
1285 | let config = {
1286 | darkMode: 'class',
1287 | plugins: [typographyPlugin()],
1288 | content: [
1289 | {
1290 | raw: html`
`,
1291 | },
1292 | ],
1293 | theme: {
1294 | typography: {
1295 | DEFAULT: {
1296 | css: {
1297 | 'ol li::before, ul li::after': {
1298 | color: 'red',
1299 | },
1300 | },
1301 | },
1302 | },
1303 | },
1304 | }
1305 |
1306 | return run(config).then((result) => {
1307 | expect(result.css).toIncludeCss(css`
1308 | .prose
1309 | :where(ol li::before, ul li::after):not(:where([class~='not-prose'], [class~='not-prose']
1310 | *)) {
1311 | color: red;
1312 | }
1313 | `)
1314 |
1315 | // TODO: The output here is a bug in tailwindcss variant selector rewriting
1316 | expect(result.css).toIncludeCss(css`
1317 | .dark
1318 | .dark\:prose
1319 | :where(ol li, ul li):not(:where([class~='not-prose'], [class~='not-prose'] *))::before,
1320 | ::after {
1321 | color: red;
1322 | }
1323 | `)
1324 | })
1325 | })
1326 |
1327 | it('lifts only the common, trailing pseudo elements from selectors', () => {
1328 | let config = {
1329 | darkMode: 'class',
1330 | plugins: [typographyPlugin()],
1331 | content: [
1332 | {
1333 | raw: html`
`,
1334 | },
1335 | ],
1336 | theme: {
1337 | typography: {
1338 | DEFAULT: {
1339 | css: {
1340 | 'ol li::scroll-thumb::before, ul li::scroll-track::before': {
1341 | color: 'red',
1342 | },
1343 | },
1344 | },
1345 | },
1346 | },
1347 | }
1348 |
1349 | return run(config).then((result) => {
1350 | expect(result.css).toIncludeCss(css`
1351 | .prose
1352 | :where(ol li::scroll-thumb, ul
1353 | li::scroll-track):not(:where([class~='not-prose'], [class~='not-prose'] *))::before {
1354 | color: red;
1355 | }
1356 | `)
1357 |
1358 | // TODO: The output here is a bug in tailwindcss variant selector rewriting
1359 | expect(result.css).toIncludeCss(css`
1360 | .dark
1361 | .dark\:prose
1362 | :where(ol li, ul li):not(:where([class~='not-prose'], [class~='not-prose']
1363 | *))::scroll-thumb,
1364 | ::scroll-track,
1365 | ::before {
1366 | color: red;
1367 | }
1368 | `)
1369 | })
1370 | })
1371 |
1372 | it('ignores common non-trailing pseudo-elements in selectors', () => {
1373 | let config = {
1374 | darkMode: 'class',
1375 | plugins: [typographyPlugin()],
1376 | content: [
1377 | {
1378 | raw: html`
`,
1379 | },
1380 | ],
1381 | theme: {
1382 | typography: {
1383 | DEFAULT: {
1384 | css: {
1385 | 'ol li::before::scroll-thumb, ul li::before::scroll-track': {
1386 | color: 'red',
1387 | },
1388 | },
1389 | },
1390 | },
1391 | },
1392 | }
1393 |
1394 | return run(config).then((result) => {
1395 | expect(result.css).toIncludeCss(css`
1396 | .prose
1397 | :where(ol li::before::scroll-thumb, ul
1398 | li::before::scroll-track):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
1399 | color: red;
1400 | }
1401 | `)
1402 |
1403 | // TODO: The output here is a bug in tailwindcss variant selector rewriting
1404 | expect(result.css).toIncludeCss(css`
1405 | .dark
1406 | .dark\:prose
1407 | :where(ol li::scroll-thumb, ul
1408 | li::scroll-track):not(:where([class~='not-prose'], [class~='not-prose'] *))::before,
1409 | ::before {
1410 | color: red;
1411 | }
1412 | `)
1413 | })
1414 | })
1415 |
1416 | test('lead styles are inserted after paragraph styles', async () => {
1417 | let config = {
1418 | content: [{ raw: html`
` }],
1419 | }
1420 |
1421 | return run(config).then((result) => {
1422 | expect(result.css).toIncludeCss(
1423 | css`
1424 | .prose {
1425 | color: var(--tw-prose-body);
1426 | max-width: 65ch;
1427 | }
1428 | .prose :where(p):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
1429 | margin-top: 1.25em;
1430 | margin-bottom: 1.25em;
1431 | }
1432 | .prose :where([class~='lead']):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
1433 | color: var(--tw-prose-lead);
1434 | font-size: 1.25em;
1435 | line-height: 1.6;
1436 | margin-top: 1.2em;
1437 | margin-bottom: 1.2em;
1438 | }
1439 | `
1440 | )
1441 | })
1442 | })
1443 |
--------------------------------------------------------------------------------
/src/styles.js:
--------------------------------------------------------------------------------
1 | const colors = require('tailwindcss/colors')
2 |
3 | const round = (num) =>
4 | num
5 | .toFixed(7)
6 | .replace(/(\.[0-9]+?)0+$/, '$1')
7 | .replace(/\.0$/, '')
8 | const rem = (px) => `${round(px / 16)}rem`
9 | const em = (px, base) => `${round(px / base)}em`
10 | const opacity = (color, opacity) => {
11 | // In v3, the colors are hex encoded and a previous typography plugin version
12 | // only handled these values. We keep the old behavior for backward
13 | // compatibility with v3 codebases but use color-mix for any other color
14 | // values.
15 | let hex = color.replace('#', '')
16 | hex = hex.length === 3 ? hex.replace(/./g, '$&$&') : hex
17 |
18 | let r = parseInt(hex.substring(0, 2), 16)
19 | let g = parseInt(hex.substring(2, 4), 16)
20 | let b = parseInt(hex.substring(4, 6), 16)
21 |
22 | if (Number.isNaN(r) || Number.isNaN(g) || Number.isNaN(b)) {
23 | return `color-mix(in oklab, ${color} ${opacity}, transparent)`
24 | }
25 |
26 | return `rgb(${r} ${g} ${b} / ${opacity})`
27 | }
28 |
29 | let defaultModifiers = {
30 | sm: {
31 | css: [
32 | {
33 | fontSize: rem(14),
34 | lineHeight: round(24 / 14),
35 | p: {
36 | marginTop: em(16, 14),
37 | marginBottom: em(16, 14),
38 | },
39 | '[class~="lead"]': {
40 | fontSize: em(18, 14),
41 | lineHeight: round(28 / 18),
42 | marginTop: em(16, 18),
43 | marginBottom: em(16, 18),
44 | },
45 | blockquote: {
46 | marginTop: em(24, 18),
47 | marginBottom: em(24, 18),
48 | paddingInlineStart: em(20, 18),
49 | },
50 | h1: {
51 | fontSize: em(30, 14),
52 | marginTop: '0',
53 | marginBottom: em(24, 30),
54 | lineHeight: round(36 / 30),
55 | },
56 | h2: {
57 | fontSize: em(20, 14),
58 | marginTop: em(32, 20),
59 | marginBottom: em(16, 20),
60 | lineHeight: round(28 / 20),
61 | },
62 | h3: {
63 | fontSize: em(18, 14),
64 | marginTop: em(28, 18),
65 | marginBottom: em(8, 18),
66 | lineHeight: round(28 / 18),
67 | },
68 | h4: {
69 | marginTop: em(20, 14),
70 | marginBottom: em(8, 14),
71 | lineHeight: round(20 / 14),
72 | },
73 | img: {
74 | marginTop: em(24, 14),
75 | marginBottom: em(24, 14),
76 | },
77 | picture: {
78 | marginTop: em(24, 14),
79 | marginBottom: em(24, 14),
80 | },
81 | 'picture > img': {
82 | marginTop: '0',
83 | marginBottom: '0',
84 | },
85 | video: {
86 | marginTop: em(24, 14),
87 | marginBottom: em(24, 14),
88 | },
89 | kbd: {
90 | fontSize: em(12, 14),
91 | borderRadius: rem(5),
92 | paddingTop: em(2, 14),
93 | paddingInlineEnd: em(5, 14),
94 | paddingBottom: em(2, 14),
95 | paddingInlineStart: em(5, 14),
96 | },
97 | code: {
98 | fontSize: em(12, 14),
99 | },
100 | 'h2 code': {
101 | fontSize: em(18, 20),
102 | },
103 | 'h3 code': {
104 | fontSize: em(16, 18),
105 | },
106 | pre: {
107 | fontSize: em(12, 14),
108 | lineHeight: round(20 / 12),
109 | marginTop: em(20, 12),
110 | marginBottom: em(20, 12),
111 | borderRadius: rem(4),
112 | paddingTop: em(8, 12),
113 | paddingInlineEnd: em(12, 12),
114 | paddingBottom: em(8, 12),
115 | paddingInlineStart: em(12, 12),
116 | },
117 | ol: {
118 | marginTop: em(16, 14),
119 | marginBottom: em(16, 14),
120 | paddingInlineStart: em(22, 14),
121 | },
122 | ul: {
123 | marginTop: em(16, 14),
124 | marginBottom: em(16, 14),
125 | paddingInlineStart: em(22, 14),
126 | },
127 | li: {
128 | marginTop: em(4, 14),
129 | marginBottom: em(4, 14),
130 | },
131 | 'ol > li': {
132 | paddingInlineStart: em(6, 14),
133 | },
134 | 'ul > li': {
135 | paddingInlineStart: em(6, 14),
136 | },
137 | '> ul > li p': {
138 | marginTop: em(8, 14),
139 | marginBottom: em(8, 14),
140 | },
141 | '> ul > li > p:first-child': {
142 | marginTop: em(16, 14),
143 | },
144 | '> ul > li > p:last-child': {
145 | marginBottom: em(16, 14),
146 | },
147 | '> ol > li > p:first-child': {
148 | marginTop: em(16, 14),
149 | },
150 | '> ol > li > p:last-child': {
151 | marginBottom: em(16, 14),
152 | },
153 | 'ul ul, ul ol, ol ul, ol ol': {
154 | marginTop: em(8, 14),
155 | marginBottom: em(8, 14),
156 | },
157 | dl: {
158 | marginTop: em(16, 14),
159 | marginBottom: em(16, 14),
160 | },
161 | dt: {
162 | marginTop: em(16, 14),
163 | },
164 | dd: {
165 | marginTop: em(4, 14),
166 | paddingInlineStart: em(22, 14),
167 | },
168 | hr: {
169 | marginTop: em(40, 14),
170 | marginBottom: em(40, 14),
171 | },
172 | 'hr + *': {
173 | marginTop: '0',
174 | },
175 | 'h2 + *': {
176 | marginTop: '0',
177 | },
178 | 'h3 + *': {
179 | marginTop: '0',
180 | },
181 | 'h4 + *': {
182 | marginTop: '0',
183 | },
184 | table: {
185 | fontSize: em(12, 14),
186 | lineHeight: round(18 / 12),
187 | },
188 | 'thead th': {
189 | paddingInlineEnd: em(12, 12),
190 | paddingBottom: em(8, 12),
191 | paddingInlineStart: em(12, 12),
192 | },
193 | 'thead th:first-child': {
194 | paddingInlineStart: '0',
195 | },
196 | 'thead th:last-child': {
197 | paddingInlineEnd: '0',
198 | },
199 | 'tbody td, tfoot td': {
200 | paddingTop: em(8, 12),
201 | paddingInlineEnd: em(12, 12),
202 | paddingBottom: em(8, 12),
203 | paddingInlineStart: em(12, 12),
204 | },
205 | 'tbody td:first-child, tfoot td:first-child': {
206 | paddingInlineStart: '0',
207 | },
208 | 'tbody td:last-child, tfoot td:last-child': {
209 | paddingInlineEnd: '0',
210 | },
211 | figure: {
212 | marginTop: em(24, 14),
213 | marginBottom: em(24, 14),
214 | },
215 | 'figure > *': {
216 | marginTop: '0',
217 | marginBottom: '0',
218 | },
219 | figcaption: {
220 | fontSize: em(12, 14),
221 | lineHeight: round(16 / 12),
222 | marginTop: em(8, 12),
223 | },
224 | },
225 | {
226 | '> :first-child': {
227 | marginTop: '0',
228 | },
229 | '> :last-child': {
230 | marginBottom: '0',
231 | },
232 | },
233 | ],
234 | },
235 | base: {
236 | css: [
237 | {
238 | fontSize: rem(16),
239 | lineHeight: round(28 / 16),
240 | p: {
241 | marginTop: em(20, 16),
242 | marginBottom: em(20, 16),
243 | },
244 | '[class~="lead"]': {
245 | fontSize: em(20, 16),
246 | lineHeight: round(32 / 20),
247 | marginTop: em(24, 20),
248 | marginBottom: em(24, 20),
249 | },
250 | blockquote: {
251 | marginTop: em(32, 20),
252 | marginBottom: em(32, 20),
253 | paddingInlineStart: em(20, 20),
254 | },
255 | h1: {
256 | fontSize: em(36, 16),
257 | marginTop: '0',
258 | marginBottom: em(32, 36),
259 | lineHeight: round(40 / 36),
260 | },
261 | h2: {
262 | fontSize: em(24, 16),
263 | marginTop: em(48, 24),
264 | marginBottom: em(24, 24),
265 | lineHeight: round(32 / 24),
266 | },
267 | h3: {
268 | fontSize: em(20, 16),
269 | marginTop: em(32, 20),
270 | marginBottom: em(12, 20),
271 | lineHeight: round(32 / 20),
272 | },
273 | h4: {
274 | marginTop: em(24, 16),
275 | marginBottom: em(8, 16),
276 | lineHeight: round(24 / 16),
277 | },
278 | img: {
279 | marginTop: em(32, 16),
280 | marginBottom: em(32, 16),
281 | },
282 | picture: {
283 | marginTop: em(32, 16),
284 | marginBottom: em(32, 16),
285 | },
286 | 'picture > img': {
287 | marginTop: '0',
288 | marginBottom: '0',
289 | },
290 | video: {
291 | marginTop: em(32, 16),
292 | marginBottom: em(32, 16),
293 | },
294 | kbd: {
295 | fontSize: em(14, 16),
296 | borderRadius: rem(5),
297 | paddingTop: em(3, 16),
298 | paddingInlineEnd: em(6, 16),
299 | paddingBottom: em(3, 16),
300 | paddingInlineStart: em(6, 16),
301 | },
302 | code: {
303 | fontSize: em(14, 16),
304 | },
305 | 'h2 code': {
306 | fontSize: em(21, 24),
307 | },
308 | 'h3 code': {
309 | fontSize: em(18, 20),
310 | },
311 | pre: {
312 | fontSize: em(14, 16),
313 | lineHeight: round(24 / 14),
314 | marginTop: em(24, 14),
315 | marginBottom: em(24, 14),
316 | borderRadius: rem(6),
317 | paddingTop: em(12, 14),
318 | paddingInlineEnd: em(16, 14),
319 | paddingBottom: em(12, 14),
320 | paddingInlineStart: em(16, 14),
321 | },
322 | ol: {
323 | marginTop: em(20, 16),
324 | marginBottom: em(20, 16),
325 | paddingInlineStart: em(26, 16),
326 | },
327 | ul: {
328 | marginTop: em(20, 16),
329 | marginBottom: em(20, 16),
330 | paddingInlineStart: em(26, 16),
331 | },
332 | li: {
333 | marginTop: em(8, 16),
334 | marginBottom: em(8, 16),
335 | },
336 | 'ol > li': {
337 | paddingInlineStart: em(6, 16),
338 | },
339 | 'ul > li': {
340 | paddingInlineStart: em(6, 16),
341 | },
342 | '> ul > li p': {
343 | marginTop: em(12, 16),
344 | marginBottom: em(12, 16),
345 | },
346 | '> ul > li > p:first-child': {
347 | marginTop: em(20, 16),
348 | },
349 | '> ul > li > p:last-child': {
350 | marginBottom: em(20, 16),
351 | },
352 | '> ol > li > p:first-child': {
353 | marginTop: em(20, 16),
354 | },
355 | '> ol > li > p:last-child': {
356 | marginBottom: em(20, 16),
357 | },
358 | 'ul ul, ul ol, ol ul, ol ol': {
359 | marginTop: em(12, 16),
360 | marginBottom: em(12, 16),
361 | },
362 | dl: {
363 | marginTop: em(20, 16),
364 | marginBottom: em(20, 16),
365 | },
366 | dt: {
367 | marginTop: em(20, 16),
368 | },
369 | dd: {
370 | marginTop: em(8, 16),
371 | paddingInlineStart: em(26, 16),
372 | },
373 | hr: {
374 | marginTop: em(48, 16),
375 | marginBottom: em(48, 16),
376 | },
377 | 'hr + *': {
378 | marginTop: '0',
379 | },
380 | 'h2 + *': {
381 | marginTop: '0',
382 | },
383 | 'h3 + *': {
384 | marginTop: '0',
385 | },
386 | 'h4 + *': {
387 | marginTop: '0',
388 | },
389 | table: {
390 | fontSize: em(14, 16),
391 | lineHeight: round(24 / 14),
392 | },
393 | 'thead th': {
394 | paddingInlineEnd: em(8, 14),
395 | paddingBottom: em(8, 14),
396 | paddingInlineStart: em(8, 14),
397 | },
398 | 'thead th:first-child': {
399 | paddingInlineStart: '0',
400 | },
401 | 'thead th:last-child': {
402 | paddingInlineEnd: '0',
403 | },
404 | 'tbody td, tfoot td': {
405 | paddingTop: em(8, 14),
406 | paddingInlineEnd: em(8, 14),
407 | paddingBottom: em(8, 14),
408 | paddingInlineStart: em(8, 14),
409 | },
410 | 'tbody td:first-child, tfoot td:first-child': {
411 | paddingInlineStart: '0',
412 | },
413 | 'tbody td:last-child, tfoot td:last-child': {
414 | paddingInlineEnd: '0',
415 | },
416 | figure: {
417 | marginTop: em(32, 16),
418 | marginBottom: em(32, 16),
419 | },
420 | 'figure > *': {
421 | marginTop: '0',
422 | marginBottom: '0',
423 | },
424 | figcaption: {
425 | fontSize: em(14, 16),
426 | lineHeight: round(20 / 14),
427 | marginTop: em(12, 14),
428 | },
429 | },
430 | {
431 | '> :first-child': {
432 | marginTop: '0',
433 | },
434 | '> :last-child': {
435 | marginBottom: '0',
436 | },
437 | },
438 | ],
439 | },
440 | lg: {
441 | css: [
442 | {
443 | fontSize: rem(18),
444 | lineHeight: round(32 / 18),
445 | p: {
446 | marginTop: em(24, 18),
447 | marginBottom: em(24, 18),
448 | },
449 | '[class~="lead"]': {
450 | fontSize: em(22, 18),
451 | lineHeight: round(32 / 22),
452 | marginTop: em(24, 22),
453 | marginBottom: em(24, 22),
454 | },
455 | blockquote: {
456 | marginTop: em(40, 24),
457 | marginBottom: em(40, 24),
458 | paddingInlineStart: em(24, 24),
459 | },
460 | h1: {
461 | fontSize: em(48, 18),
462 | marginTop: '0',
463 | marginBottom: em(40, 48),
464 | lineHeight: round(48 / 48),
465 | },
466 | h2: {
467 | fontSize: em(30, 18),
468 | marginTop: em(56, 30),
469 | marginBottom: em(32, 30),
470 | lineHeight: round(40 / 30),
471 | },
472 | h3: {
473 | fontSize: em(24, 18),
474 | marginTop: em(40, 24),
475 | marginBottom: em(16, 24),
476 | lineHeight: round(36 / 24),
477 | },
478 | h4: {
479 | marginTop: em(32, 18),
480 | marginBottom: em(8, 18),
481 | lineHeight: round(28 / 18),
482 | },
483 | img: {
484 | marginTop: em(32, 18),
485 | marginBottom: em(32, 18),
486 | },
487 | picture: {
488 | marginTop: em(32, 18),
489 | marginBottom: em(32, 18),
490 | },
491 | 'picture > img': {
492 | marginTop: '0',
493 | marginBottom: '0',
494 | },
495 | video: {
496 | marginTop: em(32, 18),
497 | marginBottom: em(32, 18),
498 | },
499 | kbd: {
500 | fontSize: em(16, 18),
501 | borderRadius: rem(5),
502 | paddingTop: em(4, 18),
503 | paddingInlineEnd: em(8, 18),
504 | paddingBottom: em(4, 18),
505 | paddingInlineStart: em(8, 18),
506 | },
507 | code: {
508 | fontSize: em(16, 18),
509 | },
510 | 'h2 code': {
511 | fontSize: em(26, 30),
512 | },
513 | 'h3 code': {
514 | fontSize: em(21, 24),
515 | },
516 | pre: {
517 | fontSize: em(16, 18),
518 | lineHeight: round(28 / 16),
519 | marginTop: em(32, 16),
520 | marginBottom: em(32, 16),
521 | borderRadius: rem(6),
522 | paddingTop: em(16, 16),
523 | paddingInlineEnd: em(24, 16),
524 | paddingBottom: em(16, 16),
525 | paddingInlineStart: em(24, 16),
526 | },
527 | ol: {
528 | marginTop: em(24, 18),
529 | marginBottom: em(24, 18),
530 | paddingInlineStart: em(28, 18),
531 | },
532 | ul: {
533 | marginTop: em(24, 18),
534 | marginBottom: em(24, 18),
535 | paddingInlineStart: em(28, 18),
536 | },
537 | li: {
538 | marginTop: em(12, 18),
539 | marginBottom: em(12, 18),
540 | },
541 | 'ol > li': {
542 | paddingInlineStart: em(8, 18),
543 | },
544 | 'ul > li': {
545 | paddingInlineStart: em(8, 18),
546 | },
547 | '> ul > li p': {
548 | marginTop: em(16, 18),
549 | marginBottom: em(16, 18),
550 | },
551 | '> ul > li > p:first-child': {
552 | marginTop: em(24, 18),
553 | },
554 | '> ul > li > p:last-child': {
555 | marginBottom: em(24, 18),
556 | },
557 | '> ol > li > p:first-child': {
558 | marginTop: em(24, 18),
559 | },
560 | '> ol > li > p:last-child': {
561 | marginBottom: em(24, 18),
562 | },
563 | 'ul ul, ul ol, ol ul, ol ol': {
564 | marginTop: em(16, 18),
565 | marginBottom: em(16, 18),
566 | },
567 | dl: {
568 | marginTop: em(24, 18),
569 | marginBottom: em(24, 18),
570 | },
571 | dt: {
572 | marginTop: em(24, 18),
573 | },
574 | dd: {
575 | marginTop: em(12, 18),
576 | paddingInlineStart: em(28, 18),
577 | },
578 | hr: {
579 | marginTop: em(56, 18),
580 | marginBottom: em(56, 18),
581 | },
582 | 'hr + *': {
583 | marginTop: '0',
584 | },
585 | 'h2 + *': {
586 | marginTop: '0',
587 | },
588 | 'h3 + *': {
589 | marginTop: '0',
590 | },
591 | 'h4 + *': {
592 | marginTop: '0',
593 | },
594 | table: {
595 | fontSize: em(16, 18),
596 | lineHeight: round(24 / 16),
597 | },
598 | 'thead th': {
599 | paddingInlineEnd: em(12, 16),
600 | paddingBottom: em(12, 16),
601 | paddingInlineStart: em(12, 16),
602 | },
603 | 'thead th:first-child': {
604 | paddingInlineStart: '0',
605 | },
606 | 'thead th:last-child': {
607 | paddingInlineEnd: '0',
608 | },
609 | 'tbody td, tfoot td': {
610 | paddingTop: em(12, 16),
611 | paddingInlineEnd: em(12, 16),
612 | paddingBottom: em(12, 16),
613 | paddingInlineStart: em(12, 16),
614 | },
615 | 'tbody td:first-child, tfoot td:first-child': {
616 | paddingInlineStart: '0',
617 | },
618 | 'tbody td:last-child, tfoot td:last-child': {
619 | paddingInlineEnd: '0',
620 | },
621 | figure: {
622 | marginTop: em(32, 18),
623 | marginBottom: em(32, 18),
624 | },
625 | 'figure > *': {
626 | marginTop: '0',
627 | marginBottom: '0',
628 | },
629 | figcaption: {
630 | fontSize: em(16, 18),
631 | lineHeight: round(24 / 16),
632 | marginTop: em(16, 16),
633 | },
634 | },
635 | {
636 | '> :first-child': {
637 | marginTop: '0',
638 | },
639 | '> :last-child': {
640 | marginBottom: '0',
641 | },
642 | },
643 | ],
644 | },
645 | xl: {
646 | css: [
647 | {
648 | fontSize: rem(20),
649 | lineHeight: round(36 / 20),
650 | p: {
651 | marginTop: em(24, 20),
652 | marginBottom: em(24, 20),
653 | },
654 | '[class~="lead"]': {
655 | fontSize: em(24, 20),
656 | lineHeight: round(36 / 24),
657 | marginTop: em(24, 24),
658 | marginBottom: em(24, 24),
659 | },
660 | blockquote: {
661 | marginTop: em(48, 30),
662 | marginBottom: em(48, 30),
663 | paddingInlineStart: em(32, 30),
664 | },
665 | h1: {
666 | fontSize: em(56, 20),
667 | marginTop: '0',
668 | marginBottom: em(48, 56),
669 | lineHeight: round(56 / 56),
670 | },
671 | h2: {
672 | fontSize: em(36, 20),
673 | marginTop: em(56, 36),
674 | marginBottom: em(32, 36),
675 | lineHeight: round(40 / 36),
676 | },
677 | h3: {
678 | fontSize: em(30, 20),
679 | marginTop: em(48, 30),
680 | marginBottom: em(20, 30),
681 | lineHeight: round(40 / 30),
682 | },
683 | h4: {
684 | marginTop: em(36, 20),
685 | marginBottom: em(12, 20),
686 | lineHeight: round(32 / 20),
687 | },
688 | img: {
689 | marginTop: em(40, 20),
690 | marginBottom: em(40, 20),
691 | },
692 | picture: {
693 | marginTop: em(40, 20),
694 | marginBottom: em(40, 20),
695 | },
696 | 'picture > img': {
697 | marginTop: '0',
698 | marginBottom: '0',
699 | },
700 | video: {
701 | marginTop: em(40, 20),
702 | marginBottom: em(40, 20),
703 | },
704 | kbd: {
705 | fontSize: em(18, 20),
706 | borderRadius: rem(5),
707 | paddingTop: em(5, 20),
708 | paddingInlineEnd: em(8, 20),
709 | paddingBottom: em(5, 20),
710 | paddingInlineStart: em(8, 20),
711 | },
712 | code: {
713 | fontSize: em(18, 20),
714 | },
715 | 'h2 code': {
716 | fontSize: em(31, 36),
717 | },
718 | 'h3 code': {
719 | fontSize: em(27, 30),
720 | },
721 | pre: {
722 | fontSize: em(18, 20),
723 | lineHeight: round(32 / 18),
724 | marginTop: em(36, 18),
725 | marginBottom: em(36, 18),
726 | borderRadius: rem(8),
727 | paddingTop: em(20, 18),
728 | paddingInlineEnd: em(24, 18),
729 | paddingBottom: em(20, 18),
730 | paddingInlineStart: em(24, 18),
731 | },
732 | ol: {
733 | marginTop: em(24, 20),
734 | marginBottom: em(24, 20),
735 | paddingInlineStart: em(32, 20),
736 | },
737 | ul: {
738 | marginTop: em(24, 20),
739 | marginBottom: em(24, 20),
740 | paddingInlineStart: em(32, 20),
741 | },
742 | li: {
743 | marginTop: em(12, 20),
744 | marginBottom: em(12, 20),
745 | },
746 | 'ol > li': {
747 | paddingInlineStart: em(8, 20),
748 | },
749 | 'ul > li': {
750 | paddingInlineStart: em(8, 20),
751 | },
752 | '> ul > li p': {
753 | marginTop: em(16, 20),
754 | marginBottom: em(16, 20),
755 | },
756 | '> ul > li > p:first-child': {
757 | marginTop: em(24, 20),
758 | },
759 | '> ul > li > p:last-child': {
760 | marginBottom: em(24, 20),
761 | },
762 | '> ol > li > p:first-child': {
763 | marginTop: em(24, 20),
764 | },
765 | '> ol > li > p:last-child': {
766 | marginBottom: em(24, 20),
767 | },
768 | 'ul ul, ul ol, ol ul, ol ol': {
769 | marginTop: em(16, 20),
770 | marginBottom: em(16, 20),
771 | },
772 | dl: {
773 | marginTop: em(24, 20),
774 | marginBottom: em(24, 20),
775 | },
776 | dt: {
777 | marginTop: em(24, 20),
778 | },
779 | dd: {
780 | marginTop: em(12, 20),
781 | paddingInlineStart: em(32, 20),
782 | },
783 | hr: {
784 | marginTop: em(56, 20),
785 | marginBottom: em(56, 20),
786 | },
787 | 'hr + *': {
788 | marginTop: '0',
789 | },
790 | 'h2 + *': {
791 | marginTop: '0',
792 | },
793 | 'h3 + *': {
794 | marginTop: '0',
795 | },
796 | 'h4 + *': {
797 | marginTop: '0',
798 | },
799 | table: {
800 | fontSize: em(18, 20),
801 | lineHeight: round(28 / 18),
802 | },
803 | 'thead th': {
804 | paddingInlineEnd: em(12, 18),
805 | paddingBottom: em(16, 18),
806 | paddingInlineStart: em(12, 18),
807 | },
808 | 'thead th:first-child': {
809 | paddingInlineStart: '0',
810 | },
811 | 'thead th:last-child': {
812 | paddingInlineEnd: '0',
813 | },
814 | 'tbody td, tfoot td': {
815 | paddingTop: em(16, 18),
816 | paddingInlineEnd: em(12, 18),
817 | paddingBottom: em(16, 18),
818 | paddingInlineStart: em(12, 18),
819 | },
820 | 'tbody td:first-child, tfoot td:first-child': {
821 | paddingInlineStart: '0',
822 | },
823 | 'tbody td:last-child, tfoot td:last-child': {
824 | paddingInlineEnd: '0',
825 | },
826 | figure: {
827 | marginTop: em(40, 20),
828 | marginBottom: em(40, 20),
829 | },
830 | 'figure > *': {
831 | marginTop: '0',
832 | marginBottom: '0',
833 | },
834 | figcaption: {
835 | fontSize: em(18, 20),
836 | lineHeight: round(28 / 18),
837 | marginTop: em(18, 18),
838 | },
839 | },
840 | {
841 | '> :first-child': {
842 | marginTop: '0',
843 | },
844 | '> :last-child': {
845 | marginBottom: '0',
846 | },
847 | },
848 | ],
849 | },
850 | '2xl': {
851 | css: [
852 | {
853 | fontSize: rem(24),
854 | lineHeight: round(40 / 24),
855 | p: {
856 | marginTop: em(32, 24),
857 | marginBottom: em(32, 24),
858 | },
859 | '[class~="lead"]': {
860 | fontSize: em(30, 24),
861 | lineHeight: round(44 / 30),
862 | marginTop: em(32, 30),
863 | marginBottom: em(32, 30),
864 | },
865 | blockquote: {
866 | marginTop: em(64, 36),
867 | marginBottom: em(64, 36),
868 | paddingInlineStart: em(40, 36),
869 | },
870 | h1: {
871 | fontSize: em(64, 24),
872 | marginTop: '0',
873 | marginBottom: em(56, 64),
874 | lineHeight: round(64 / 64),
875 | },
876 | h2: {
877 | fontSize: em(48, 24),
878 | marginTop: em(72, 48),
879 | marginBottom: em(40, 48),
880 | lineHeight: round(52 / 48),
881 | },
882 | h3: {
883 | fontSize: em(36, 24),
884 | marginTop: em(56, 36),
885 | marginBottom: em(24, 36),
886 | lineHeight: round(44 / 36),
887 | },
888 | h4: {
889 | marginTop: em(40, 24),
890 | marginBottom: em(16, 24),
891 | lineHeight: round(36 / 24),
892 | },
893 | img: {
894 | marginTop: em(48, 24),
895 | marginBottom: em(48, 24),
896 | },
897 | picture: {
898 | marginTop: em(48, 24),
899 | marginBottom: em(48, 24),
900 | },
901 | 'picture > img': {
902 | marginTop: '0',
903 | marginBottom: '0',
904 | },
905 | video: {
906 | marginTop: em(48, 24),
907 | marginBottom: em(48, 24),
908 | },
909 | kbd: {
910 | fontSize: em(20, 24),
911 | borderRadius: rem(6),
912 | paddingTop: em(6, 24),
913 | paddingInlineEnd: em(8, 24),
914 | paddingBottom: em(6, 24),
915 | paddingInlineStart: em(8, 24),
916 | },
917 | code: {
918 | fontSize: em(20, 24),
919 | },
920 | 'h2 code': {
921 | fontSize: em(42, 48),
922 | },
923 | 'h3 code': {
924 | fontSize: em(32, 36),
925 | },
926 | pre: {
927 | fontSize: em(20, 24),
928 | lineHeight: round(36 / 20),
929 | marginTop: em(40, 20),
930 | marginBottom: em(40, 20),
931 | borderRadius: rem(8),
932 | paddingTop: em(24, 20),
933 | paddingInlineEnd: em(32, 20),
934 | paddingBottom: em(24, 20),
935 | paddingInlineStart: em(32, 20),
936 | },
937 | ol: {
938 | marginTop: em(32, 24),
939 | marginBottom: em(32, 24),
940 | paddingInlineStart: em(38, 24),
941 | },
942 | ul: {
943 | marginTop: em(32, 24),
944 | marginBottom: em(32, 24),
945 | paddingInlineStart: em(38, 24),
946 | },
947 | li: {
948 | marginTop: em(12, 24),
949 | marginBottom: em(12, 24),
950 | },
951 | 'ol > li': {
952 | paddingInlineStart: em(10, 24),
953 | },
954 | 'ul > li': {
955 | paddingInlineStart: em(10, 24),
956 | },
957 | '> ul > li p': {
958 | marginTop: em(20, 24),
959 | marginBottom: em(20, 24),
960 | },
961 | '> ul > li > p:first-child': {
962 | marginTop: em(32, 24),
963 | },
964 | '> ul > li > p:last-child': {
965 | marginBottom: em(32, 24),
966 | },
967 | '> ol > li > p:first-child': {
968 | marginTop: em(32, 24),
969 | },
970 | '> ol > li > p:last-child': {
971 | marginBottom: em(32, 24),
972 | },
973 | 'ul ul, ul ol, ol ul, ol ol': {
974 | marginTop: em(16, 24),
975 | marginBottom: em(16, 24),
976 | },
977 | dl: {
978 | marginTop: em(32, 24),
979 | marginBottom: em(32, 24),
980 | },
981 | dt: {
982 | marginTop: em(32, 24),
983 | },
984 | dd: {
985 | marginTop: em(12, 24),
986 | paddingInlineStart: em(38, 24),
987 | },
988 | hr: {
989 | marginTop: em(72, 24),
990 | marginBottom: em(72, 24),
991 | },
992 | 'hr + *': {
993 | marginTop: '0',
994 | },
995 | 'h2 + *': {
996 | marginTop: '0',
997 | },
998 | 'h3 + *': {
999 | marginTop: '0',
1000 | },
1001 | 'h4 + *': {
1002 | marginTop: '0',
1003 | },
1004 | table: {
1005 | fontSize: em(20, 24),
1006 | lineHeight: round(28 / 20),
1007 | },
1008 | 'thead th': {
1009 | paddingInlineEnd: em(12, 20),
1010 | paddingBottom: em(16, 20),
1011 | paddingInlineStart: em(12, 20),
1012 | },
1013 | 'thead th:first-child': {
1014 | paddingInlineStart: '0',
1015 | },
1016 | 'thead th:last-child': {
1017 | paddingInlineEnd: '0',
1018 | },
1019 | 'tbody td, tfoot td': {
1020 | paddingTop: em(16, 20),
1021 | paddingInlineEnd: em(12, 20),
1022 | paddingBottom: em(16, 20),
1023 | paddingInlineStart: em(12, 20),
1024 | },
1025 | 'tbody td:first-child, tfoot td:first-child': {
1026 | paddingInlineStart: '0',
1027 | },
1028 | 'tbody td:last-child, tfoot td:last-child': {
1029 | paddingInlineEnd: '0',
1030 | },
1031 | figure: {
1032 | marginTop: em(48, 24),
1033 | marginBottom: em(48, 24),
1034 | },
1035 | 'figure > *': {
1036 | marginTop: '0',
1037 | marginBottom: '0',
1038 | },
1039 | figcaption: {
1040 | fontSize: em(20, 24),
1041 | lineHeight: round(32 / 20),
1042 | marginTop: em(20, 20),
1043 | },
1044 | },
1045 | {
1046 | '> :first-child': {
1047 | marginTop: '0',
1048 | },
1049 | '> :last-child': {
1050 | marginBottom: '0',
1051 | },
1052 | },
1053 | ],
1054 | },
1055 |
1056 | // Gray color themes
1057 |
1058 | slate: {
1059 | css: {
1060 | '--tw-prose-body': colors.slate[700],
1061 | '--tw-prose-headings': colors.slate[900],
1062 | '--tw-prose-lead': colors.slate[600],
1063 | '--tw-prose-links': colors.slate[900],
1064 | '--tw-prose-bold': colors.slate[900],
1065 | '--tw-prose-counters': colors.slate[500],
1066 | '--tw-prose-bullets': colors.slate[300],
1067 | '--tw-prose-hr': colors.slate[200],
1068 | '--tw-prose-quotes': colors.slate[900],
1069 | '--tw-prose-quote-borders': colors.slate[200],
1070 | '--tw-prose-captions': colors.slate[500],
1071 | '--tw-prose-kbd': colors.slate[900],
1072 | '--tw-prose-kbd-shadows': opacity(colors.slate[900], '10%'),
1073 | '--tw-prose-code': colors.slate[900],
1074 | '--tw-prose-pre-code': colors.slate[200],
1075 | '--tw-prose-pre-bg': colors.slate[800],
1076 | '--tw-prose-th-borders': colors.slate[300],
1077 | '--tw-prose-td-borders': colors.slate[200],
1078 | '--tw-prose-invert-body': colors.slate[300],
1079 | '--tw-prose-invert-headings': colors.white,
1080 | '--tw-prose-invert-lead': colors.slate[400],
1081 | '--tw-prose-invert-links': colors.white,
1082 | '--tw-prose-invert-bold': colors.white,
1083 | '--tw-prose-invert-counters': colors.slate[400],
1084 | '--tw-prose-invert-bullets': colors.slate[600],
1085 | '--tw-prose-invert-hr': colors.slate[700],
1086 | '--tw-prose-invert-quotes': colors.slate[100],
1087 | '--tw-prose-invert-quote-borders': colors.slate[700],
1088 | '--tw-prose-invert-captions': colors.slate[400],
1089 | '--tw-prose-invert-kbd': colors.white,
1090 | '--tw-prose-invert-kbd-shadows': opacity(colors.white, '10%'),
1091 | '--tw-prose-invert-code': colors.white,
1092 | '--tw-prose-invert-pre-code': colors.slate[300],
1093 | '--tw-prose-invert-pre-bg': 'rgb(0 0 0 / 50%)',
1094 | '--tw-prose-invert-th-borders': colors.slate[600],
1095 | '--tw-prose-invert-td-borders': colors.slate[700],
1096 | },
1097 | },
1098 |
1099 | gray: {
1100 | css: {
1101 | '--tw-prose-body': colors.gray[700],
1102 | '--tw-prose-headings': colors.gray[900],
1103 | '--tw-prose-lead': colors.gray[600],
1104 | '--tw-prose-links': colors.gray[900],
1105 | '--tw-prose-bold': colors.gray[900],
1106 | '--tw-prose-counters': colors.gray[500],
1107 | '--tw-prose-bullets': colors.gray[300],
1108 | '--tw-prose-hr': colors.gray[200],
1109 | '--tw-prose-quotes': colors.gray[900],
1110 | '--tw-prose-quote-borders': colors.gray[200],
1111 | '--tw-prose-captions': colors.gray[500],
1112 | '--tw-prose-kbd': colors.gray[900],
1113 | '--tw-prose-kbd-shadows': opacity(colors.gray[900], '10%'),
1114 | '--tw-prose-code': colors.gray[900],
1115 | '--tw-prose-pre-code': colors.gray[200],
1116 | '--tw-prose-pre-bg': colors.gray[800],
1117 | '--tw-prose-th-borders': colors.gray[300],
1118 | '--tw-prose-td-borders': colors.gray[200],
1119 | '--tw-prose-invert-body': colors.gray[300],
1120 | '--tw-prose-invert-headings': colors.white,
1121 | '--tw-prose-invert-lead': colors.gray[400],
1122 | '--tw-prose-invert-links': colors.white,
1123 | '--tw-prose-invert-bold': colors.white,
1124 | '--tw-prose-invert-counters': colors.gray[400],
1125 | '--tw-prose-invert-bullets': colors.gray[600],
1126 | '--tw-prose-invert-hr': colors.gray[700],
1127 | '--tw-prose-invert-quotes': colors.gray[100],
1128 | '--tw-prose-invert-quote-borders': colors.gray[700],
1129 | '--tw-prose-invert-captions': colors.gray[400],
1130 | '--tw-prose-invert-kbd': colors.white,
1131 | '--tw-prose-invert-kbd-shadows': opacity(colors.white, '10%'),
1132 | '--tw-prose-invert-code': colors.white,
1133 | '--tw-prose-invert-pre-code': colors.gray[300],
1134 | '--tw-prose-invert-pre-bg': 'rgb(0 0 0 / 50%)',
1135 | '--tw-prose-invert-th-borders': colors.gray[600],
1136 | '--tw-prose-invert-td-borders': colors.gray[700],
1137 | },
1138 | },
1139 |
1140 | zinc: {
1141 | css: {
1142 | '--tw-prose-body': colors.zinc[700],
1143 | '--tw-prose-headings': colors.zinc[900],
1144 | '--tw-prose-lead': colors.zinc[600],
1145 | '--tw-prose-links': colors.zinc[900],
1146 | '--tw-prose-bold': colors.zinc[900],
1147 | '--tw-prose-counters': colors.zinc[500],
1148 | '--tw-prose-bullets': colors.zinc[300],
1149 | '--tw-prose-hr': colors.zinc[200],
1150 | '--tw-prose-quotes': colors.zinc[900],
1151 | '--tw-prose-quote-borders': colors.zinc[200],
1152 | '--tw-prose-captions': colors.zinc[500],
1153 | '--tw-prose-kbd': colors.zinc[900],
1154 | '--tw-prose-kbd-shadows': opacity(colors.zinc[900], '10%'),
1155 | '--tw-prose-code': colors.zinc[900],
1156 | '--tw-prose-pre-code': colors.zinc[200],
1157 | '--tw-prose-pre-bg': colors.zinc[800],
1158 | '--tw-prose-th-borders': colors.zinc[300],
1159 | '--tw-prose-td-borders': colors.zinc[200],
1160 | '--tw-prose-invert-body': colors.zinc[300],
1161 | '--tw-prose-invert-headings': colors.white,
1162 | '--tw-prose-invert-lead': colors.zinc[400],
1163 | '--tw-prose-invert-links': colors.white,
1164 | '--tw-prose-invert-bold': colors.white,
1165 | '--tw-prose-invert-counters': colors.zinc[400],
1166 | '--tw-prose-invert-bullets': colors.zinc[600],
1167 | '--tw-prose-invert-hr': colors.zinc[700],
1168 | '--tw-prose-invert-quotes': colors.zinc[100],
1169 | '--tw-prose-invert-quote-borders': colors.zinc[700],
1170 | '--tw-prose-invert-captions': colors.zinc[400],
1171 | '--tw-prose-invert-kbd': colors.white,
1172 | '--tw-prose-invert-kbd-shadows': opacity(colors.white, '10%'),
1173 | '--tw-prose-invert-code': colors.white,
1174 | '--tw-prose-invert-pre-code': colors.zinc[300],
1175 | '--tw-prose-invert-pre-bg': 'rgb(0 0 0 / 50%)',
1176 | '--tw-prose-invert-th-borders': colors.zinc[600],
1177 | '--tw-prose-invert-td-borders': colors.zinc[700],
1178 | },
1179 | },
1180 |
1181 | neutral: {
1182 | css: {
1183 | '--tw-prose-body': colors.neutral[700],
1184 | '--tw-prose-headings': colors.neutral[900],
1185 | '--tw-prose-lead': colors.neutral[600],
1186 | '--tw-prose-links': colors.neutral[900],
1187 | '--tw-prose-bold': colors.neutral[900],
1188 | '--tw-prose-counters': colors.neutral[500],
1189 | '--tw-prose-bullets': colors.neutral[300],
1190 | '--tw-prose-hr': colors.neutral[200],
1191 | '--tw-prose-quotes': colors.neutral[900],
1192 | '--tw-prose-quote-borders': colors.neutral[200],
1193 | '--tw-prose-captions': colors.neutral[500],
1194 | '--tw-prose-kbd': colors.neutral[900],
1195 | '--tw-prose-kbd-shadows': opacity(colors.neutral[900], '10%'),
1196 | '--tw-prose-code': colors.neutral[900],
1197 | '--tw-prose-pre-code': colors.neutral[200],
1198 | '--tw-prose-pre-bg': colors.neutral[800],
1199 | '--tw-prose-th-borders': colors.neutral[300],
1200 | '--tw-prose-td-borders': colors.neutral[200],
1201 | '--tw-prose-invert-body': colors.neutral[300],
1202 | '--tw-prose-invert-headings': colors.white,
1203 | '--tw-prose-invert-lead': colors.neutral[400],
1204 | '--tw-prose-invert-links': colors.white,
1205 | '--tw-prose-invert-bold': colors.white,
1206 | '--tw-prose-invert-counters': colors.neutral[400],
1207 | '--tw-prose-invert-bullets': colors.neutral[600],
1208 | '--tw-prose-invert-hr': colors.neutral[700],
1209 | '--tw-prose-invert-quotes': colors.neutral[100],
1210 | '--tw-prose-invert-quote-borders': colors.neutral[700],
1211 | '--tw-prose-invert-captions': colors.neutral[400],
1212 | '--tw-prose-invert-kbd': colors.white,
1213 | '--tw-prose-invert-kbd-shadows': opacity(colors.white, '10%'),
1214 | '--tw-prose-invert-code': colors.white,
1215 | '--tw-prose-invert-pre-code': colors.neutral[300],
1216 | '--tw-prose-invert-pre-bg': 'rgb(0 0 0 / 50%)',
1217 | '--tw-prose-invert-th-borders': colors.neutral[600],
1218 | '--tw-prose-invert-td-borders': colors.neutral[700],
1219 | },
1220 | },
1221 |
1222 | stone: {
1223 | css: {
1224 | '--tw-prose-body': colors.stone[700],
1225 | '--tw-prose-headings': colors.stone[900],
1226 | '--tw-prose-lead': colors.stone[600],
1227 | '--tw-prose-links': colors.stone[900],
1228 | '--tw-prose-bold': colors.stone[900],
1229 | '--tw-prose-counters': colors.stone[500],
1230 | '--tw-prose-bullets': colors.stone[300],
1231 | '--tw-prose-hr': colors.stone[200],
1232 | '--tw-prose-quotes': colors.stone[900],
1233 | '--tw-prose-quote-borders': colors.stone[200],
1234 | '--tw-prose-captions': colors.stone[500],
1235 | '--tw-prose-kbd': colors.stone[900],
1236 | '--tw-prose-kbd-shadows': opacity(colors.stone[900], '10%'),
1237 | '--tw-prose-code': colors.stone[900],
1238 | '--tw-prose-pre-code': colors.stone[200],
1239 | '--tw-prose-pre-bg': colors.stone[800],
1240 | '--tw-prose-th-borders': colors.stone[300],
1241 | '--tw-prose-td-borders': colors.stone[200],
1242 | '--tw-prose-invert-body': colors.stone[300],
1243 | '--tw-prose-invert-headings': colors.white,
1244 | '--tw-prose-invert-lead': colors.stone[400],
1245 | '--tw-prose-invert-links': colors.white,
1246 | '--tw-prose-invert-bold': colors.white,
1247 | '--tw-prose-invert-counters': colors.stone[400],
1248 | '--tw-prose-invert-bullets': colors.stone[600],
1249 | '--tw-prose-invert-hr': colors.stone[700],
1250 | '--tw-prose-invert-quotes': colors.stone[100],
1251 | '--tw-prose-invert-quote-borders': colors.stone[700],
1252 | '--tw-prose-invert-captions': colors.stone[400],
1253 | '--tw-prose-invert-kbd': colors.white,
1254 | '--tw-prose-invert-kbd-shadows': opacity(colors.white, '10%'),
1255 | '--tw-prose-invert-code': colors.white,
1256 | '--tw-prose-invert-pre-code': colors.stone[300],
1257 | '--tw-prose-invert-pre-bg': 'rgb(0 0 0 / 50%)',
1258 | '--tw-prose-invert-th-borders': colors.stone[600],
1259 | '--tw-prose-invert-td-borders': colors.stone[700],
1260 | },
1261 | },
1262 |
1263 | // Link-only themes (for backward compatibility)
1264 |
1265 | red: {
1266 | css: {
1267 | '--tw-prose-links': colors.red[600],
1268 | '--tw-prose-invert-links': colors.red[500],
1269 | },
1270 | },
1271 |
1272 | orange: {
1273 | css: {
1274 | '--tw-prose-links': colors.orange[600],
1275 | '--tw-prose-invert-links': colors.orange[500],
1276 | },
1277 | },
1278 |
1279 | amber: {
1280 | css: {
1281 | '--tw-prose-links': colors.amber[600],
1282 | '--tw-prose-invert-links': colors.amber[500],
1283 | },
1284 | },
1285 |
1286 | yellow: {
1287 | css: {
1288 | '--tw-prose-links': colors.yellow[600],
1289 | '--tw-prose-invert-links': colors.yellow[500],
1290 | },
1291 | },
1292 |
1293 | lime: {
1294 | css: {
1295 | '--tw-prose-links': colors.lime[600],
1296 | '--tw-prose-invert-links': colors.lime[500],
1297 | },
1298 | },
1299 |
1300 | green: {
1301 | css: {
1302 | '--tw-prose-links': colors.green[600],
1303 | '--tw-prose-invert-links': colors.green[500],
1304 | },
1305 | },
1306 |
1307 | emerald: {
1308 | css: {
1309 | '--tw-prose-links': colors.emerald[600],
1310 | '--tw-prose-invert-links': colors.emerald[500],
1311 | },
1312 | },
1313 |
1314 | teal: {
1315 | css: {
1316 | '--tw-prose-links': colors.teal[600],
1317 | '--tw-prose-invert-links': colors.teal[500],
1318 | },
1319 | },
1320 |
1321 | cyan: {
1322 | css: {
1323 | '--tw-prose-links': colors.cyan[600],
1324 | '--tw-prose-invert-links': colors.cyan[500],
1325 | },
1326 | },
1327 |
1328 | sky: {
1329 | css: {
1330 | '--tw-prose-links': colors.sky[600],
1331 | '--tw-prose-invert-links': colors.sky[500],
1332 | },
1333 | },
1334 |
1335 | blue: {
1336 | css: {
1337 | '--tw-prose-links': colors.blue[600],
1338 | '--tw-prose-invert-links': colors.blue[500],
1339 | },
1340 | },
1341 |
1342 | indigo: {
1343 | css: {
1344 | '--tw-prose-links': colors.indigo[600],
1345 | '--tw-prose-invert-links': colors.indigo[500],
1346 | },
1347 | },
1348 |
1349 | violet: {
1350 | css: {
1351 | '--tw-prose-links': colors.violet[600],
1352 | '--tw-prose-invert-links': colors.violet[500],
1353 | },
1354 | },
1355 |
1356 | purple: {
1357 | css: {
1358 | '--tw-prose-links': colors.purple[600],
1359 | '--tw-prose-invert-links': colors.purple[500],
1360 | },
1361 | },
1362 |
1363 | fuchsia: {
1364 | css: {
1365 | '--tw-prose-links': colors.fuchsia[600],
1366 | '--tw-prose-invert-links': colors.fuchsia[500],
1367 | },
1368 | },
1369 |
1370 | pink: {
1371 | css: {
1372 | '--tw-prose-links': colors.pink[600],
1373 | '--tw-prose-invert-links': colors.pink[500],
1374 | },
1375 | },
1376 |
1377 | rose: {
1378 | css: {
1379 | '--tw-prose-links': colors.rose[600],
1380 | '--tw-prose-invert-links': colors.rose[500],
1381 | },
1382 | },
1383 |
1384 | // Invert (for dark mode)
1385 | invert: {
1386 | css: {
1387 | '--tw-prose-body': 'var(--tw-prose-invert-body)',
1388 | '--tw-prose-headings': 'var(--tw-prose-invert-headings)',
1389 | '--tw-prose-lead': 'var(--tw-prose-invert-lead)',
1390 | '--tw-prose-links': 'var(--tw-prose-invert-links)',
1391 | '--tw-prose-bold': 'var(--tw-prose-invert-bold)',
1392 | '--tw-prose-counters': 'var(--tw-prose-invert-counters)',
1393 | '--tw-prose-bullets': 'var(--tw-prose-invert-bullets)',
1394 | '--tw-prose-hr': 'var(--tw-prose-invert-hr)',
1395 | '--tw-prose-quotes': 'var(--tw-prose-invert-quotes)',
1396 | '--tw-prose-quote-borders': 'var(--tw-prose-invert-quote-borders)',
1397 | '--tw-prose-captions': 'var(--tw-prose-invert-captions)',
1398 | '--tw-prose-kbd': 'var(--tw-prose-invert-kbd)',
1399 | '--tw-prose-kbd-shadows': 'var(--tw-prose-invert-kbd-shadows)',
1400 | '--tw-prose-code': 'var(--tw-prose-invert-code)',
1401 | '--tw-prose-pre-code': 'var(--tw-prose-invert-pre-code)',
1402 | '--tw-prose-pre-bg': 'var(--tw-prose-invert-pre-bg)',
1403 | '--tw-prose-th-borders': 'var(--tw-prose-invert-th-borders)',
1404 | '--tw-prose-td-borders': 'var(--tw-prose-invert-td-borders)',
1405 | },
1406 | },
1407 | }
1408 |
1409 | module.exports = {
1410 | DEFAULT: {
1411 | css: [
1412 | {
1413 | color: 'var(--tw-prose-body)',
1414 | maxWidth: '65ch',
1415 | p: {}, // Required to maintain correct order when merging
1416 | '[class~="lead"]': {
1417 | color: 'var(--tw-prose-lead)',
1418 | },
1419 | a: {
1420 | color: 'var(--tw-prose-links)',
1421 | textDecoration: 'underline',
1422 | fontWeight: '500',
1423 | },
1424 | strong: {
1425 | color: 'var(--tw-prose-bold)',
1426 | fontWeight: '600',
1427 | },
1428 | 'a strong': {
1429 | color: 'inherit',
1430 | },
1431 | 'blockquote strong': {
1432 | color: 'inherit',
1433 | },
1434 | 'thead th strong': {
1435 | color: 'inherit',
1436 | },
1437 | ol: {
1438 | listStyleType: 'decimal',
1439 | },
1440 | 'ol[type="A"]': {
1441 | listStyleType: 'upper-alpha',
1442 | },
1443 | 'ol[type="a"]': {
1444 | listStyleType: 'lower-alpha',
1445 | },
1446 | 'ol[type="A" s]': {
1447 | listStyleType: 'upper-alpha',
1448 | },
1449 | 'ol[type="a" s]': {
1450 | listStyleType: 'lower-alpha',
1451 | },
1452 | 'ol[type="I"]': {
1453 | listStyleType: 'upper-roman',
1454 | },
1455 | 'ol[type="i"]': {
1456 | listStyleType: 'lower-roman',
1457 | },
1458 | 'ol[type="I" s]': {
1459 | listStyleType: 'upper-roman',
1460 | },
1461 | 'ol[type="i" s]': {
1462 | listStyleType: 'lower-roman',
1463 | },
1464 | 'ol[type="1"]': {
1465 | listStyleType: 'decimal',
1466 | },
1467 | ul: {
1468 | listStyleType: 'disc',
1469 | },
1470 | 'ol > li::marker': {
1471 | fontWeight: '400',
1472 | color: 'var(--tw-prose-counters)',
1473 | },
1474 | 'ul > li::marker': {
1475 | color: 'var(--tw-prose-bullets)',
1476 | },
1477 | dt: {
1478 | color: 'var(--tw-prose-headings)',
1479 | fontWeight: '600',
1480 | },
1481 | hr: {
1482 | borderColor: 'var(--tw-prose-hr)',
1483 | borderTopWidth: '1px',
1484 | },
1485 | blockquote: {
1486 | fontWeight: '500',
1487 | fontStyle: 'italic',
1488 | color: 'var(--tw-prose-quotes)',
1489 | borderInlineStartWidth: '0.25rem',
1490 | borderInlineStartColor: 'var(--tw-prose-quote-borders)',
1491 | quotes: '"\\201C""\\201D""\\2018""\\2019"',
1492 | },
1493 | 'blockquote p:first-of-type::before': {
1494 | content: 'open-quote',
1495 | },
1496 | 'blockquote p:last-of-type::after': {
1497 | content: 'close-quote',
1498 | },
1499 | h1: {
1500 | color: 'var(--tw-prose-headings)',
1501 | fontWeight: '800',
1502 | },
1503 | 'h1 strong': {
1504 | fontWeight: '900',
1505 | color: 'inherit',
1506 | },
1507 | h2: {
1508 | color: 'var(--tw-prose-headings)',
1509 | fontWeight: '700',
1510 | },
1511 | 'h2 strong': {
1512 | fontWeight: '800',
1513 | color: 'inherit',
1514 | },
1515 | h3: {
1516 | color: 'var(--tw-prose-headings)',
1517 | fontWeight: '600',
1518 | },
1519 | 'h3 strong': {
1520 | fontWeight: '700',
1521 | color: 'inherit',
1522 | },
1523 | h4: {
1524 | color: 'var(--tw-prose-headings)',
1525 | fontWeight: '600',
1526 | },
1527 | 'h4 strong': {
1528 | fontWeight: '700',
1529 | color: 'inherit',
1530 | },
1531 | img: {}, // Required to maintain correct order when merging
1532 | picture: {
1533 | display: 'block',
1534 | },
1535 | video: {}, // Required to maintain correct order when merging
1536 | kbd: {
1537 | fontWeight: '500',
1538 | fontFamily: 'inherit',
1539 | color: 'var(--tw-prose-kbd)',
1540 | boxShadow: '0 0 0 1px var(--tw-prose-kbd-shadows), 0 3px 0 var(--tw-prose-kbd-shadows)',
1541 | },
1542 | code: {
1543 | color: 'var(--tw-prose-code)',
1544 | fontWeight: '600',
1545 | },
1546 | 'code::before': {
1547 | content: '"`"',
1548 | },
1549 | 'code::after': {
1550 | content: '"`"',
1551 | },
1552 | 'a code': {
1553 | color: 'inherit',
1554 | },
1555 | 'h1 code': {
1556 | color: 'inherit',
1557 | },
1558 | 'h2 code': {
1559 | color: 'inherit',
1560 | },
1561 | 'h3 code': {
1562 | color: 'inherit',
1563 | },
1564 | 'h4 code': {
1565 | color: 'inherit',
1566 | },
1567 | 'blockquote code': {
1568 | color: 'inherit',
1569 | },
1570 | 'thead th code': {
1571 | color: 'inherit',
1572 | },
1573 | pre: {
1574 | color: 'var(--tw-prose-pre-code)',
1575 | backgroundColor: 'var(--tw-prose-pre-bg)',
1576 | overflowX: 'auto',
1577 | fontWeight: '400',
1578 | },
1579 | 'pre code': {
1580 | backgroundColor: 'transparent',
1581 | borderWidth: '0',
1582 | borderRadius: '0',
1583 | padding: '0',
1584 | fontWeight: 'inherit',
1585 | color: 'inherit',
1586 | fontSize: 'inherit',
1587 | fontFamily: 'inherit',
1588 | lineHeight: 'inherit',
1589 | },
1590 | 'pre code::before': {
1591 | content: 'none',
1592 | },
1593 | 'pre code::after': {
1594 | content: 'none',
1595 | },
1596 | table: {
1597 | width: '100%',
1598 | tableLayout: 'auto',
1599 | marginTop: em(32, 16),
1600 | marginBottom: em(32, 16),
1601 | },
1602 | thead: {
1603 | borderBottomWidth: '1px',
1604 | borderBottomColor: 'var(--tw-prose-th-borders)',
1605 | },
1606 | 'thead th': {
1607 | color: 'var(--tw-prose-headings)',
1608 | fontWeight: '600',
1609 | verticalAlign: 'bottom',
1610 | },
1611 | 'tbody tr': {
1612 | borderBottomWidth: '1px',
1613 | borderBottomColor: 'var(--tw-prose-td-borders)',
1614 | },
1615 | 'tbody tr:last-child': {
1616 | borderBottomWidth: '0',
1617 | },
1618 | 'tbody td': {
1619 | verticalAlign: 'baseline',
1620 | },
1621 | tfoot: {
1622 | borderTopWidth: '1px',
1623 | borderTopColor: 'var(--tw-prose-th-borders)',
1624 | },
1625 | 'tfoot td': {
1626 | verticalAlign: 'top',
1627 | },
1628 | 'th, td': {
1629 | textAlign: 'start',
1630 | },
1631 | 'figure > *': {}, // Required to maintain correct order when merging
1632 | figcaption: {
1633 | color: 'var(--tw-prose-captions)',
1634 | },
1635 | },
1636 | defaultModifiers.gray.css,
1637 | ...defaultModifiers.base.css,
1638 | ],
1639 | },
1640 | ...defaultModifiers,
1641 | }
1642 |
--------------------------------------------------------------------------------