@tailwindcss/typography
Advanced tools
Comparing version 0.0.0-insiders.69d4b66 to 0.0.0-insiders.743b682
@@ -10,7 +10,34 @@ # Changelog | ||
- Nothing yet! | ||
## [0.5.7] - 2022-09-02 | ||
### Fixed | ||
- Update TypeScript types ([#284](https://github.com/tailwindlabs/tailwindcss-typography/pull/284/files)) | ||
## [0.5.6] - 2022-09-01 | ||
- Actually publish types ([a54c1a8](https://github.com/tailwindlabs/tailwindcss-typography/commit/a54c1a82a64efdf23aab57e62edaa369d1a857f1)) | ||
## [0.5.5] - 2022-09-01 | ||
### Added | ||
- Add typescript types ([#283](https://github.com/tailwindlabs/tailwindcss-typography/pull/283)) | ||
## [0.5.4] - 2022-07-12 | ||
### Fixed | ||
- Update `strong` and `code` color styles to inherit from parent ([#276](https://github.com/tailwindlabs/tailwindcss-typography/pull/276)) | ||
## [0.5.3] - 2022-07-07 | ||
### Added | ||
- Add styles for `tfoot` elements ([#243](https://github.com/tailwindlabs/tailwindcss-typography/pull/243)) | ||
- Add `prose-h5` and `prose-h6` variants ([#273](https://github.com/tailwindlabs/tailwindcss-typography/pull/273)) | ||
## Fixed | ||
### Fixed | ||
@@ -21,2 +48,4 @@ - Fix prose elements `legacy` mode ([#259](https://github.com/tailwindlabs/tailwindcss-typography/pull/259)) | ||
- Fix `figure` spacing ([#267](https://github.com/tailwindlabs/tailwindcss-typography/pull/267)) | ||
- Fix child combinator `:where` selectors ([#268](https://github.com/tailwindlabs/tailwindcss-typography/pull/267)) | ||
- Fix `prose-headings` variant to include `h5` and `h6` elements ([#273](https://github.com/tailwindlabs/tailwindcss-typography/pull/273)) | ||
@@ -128,3 +157,8 @@ ## [0.5.2] - 2022-02-14 | ||
[unreleased]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.2...HEAD | ||
[unreleased]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.7...HEAD | ||
[0.5.7]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.6...v0.5.7 | ||
[0.5.6]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.5...v0.5.6 | ||
[0.5.5]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.4...v0.5.5 | ||
[0.5.4]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.3...v0.5.4 | ||
[0.5.3]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.2...v0.5.3 | ||
[0.5.2]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.1...v0.5.2 | ||
@@ -131,0 +165,0 @@ [0.5.1]: https://github.com/tailwindlabs/tailwindcss-typography/compare/v0.5.0...v0.5.1 |
{ | ||
"name": "@tailwindcss/typography", | ||
"version": "0.0.0-insiders.69d4b66", | ||
"version": "0.0.0-insiders.743b682", | ||
"description": "A Tailwind CSS plugin for automatically styling plain HTML content with beautiful typographic defaults.", | ||
"main": "src/index.js", | ||
"types": "src/index.d.ts", | ||
"files": [ | ||
"src/*.js", | ||
"src/*.d.ts", | ||
"dist/" | ||
@@ -44,3 +46,3 @@ ], | ||
"react-dom": "^17.0.2", | ||
"tailwindcss": "^3.0.0-alpha.2" | ||
"tailwindcss": "^3.2.2" | ||
}, | ||
@@ -50,3 +52,4 @@ "dependencies": { | ||
"lodash.isplainobject": "^4.0.6", | ||
"lodash.merge": "^4.6.2" | ||
"lodash.merge": "^4.6.2", | ||
"postcss-selector-parser": "6.0.10" | ||
}, | ||
@@ -53,0 +56,0 @@ "jest": { |
@@ -5,2 +5,3 @@ const plugin = require('tailwindcss/plugin') | ||
const styles = require('./styles') | ||
const { commonTrailingPseudos } = require('./utils') | ||
@@ -16,23 +17,9 @@ const computed = { | ||
if (selector.endsWith('::before')) { | ||
return `:where(${selectorPrefix}${selector.slice( | ||
0, | ||
-8 | ||
)}):not(:where([class~="${prefixedNot}"] *))::before` | ||
} | ||
// Parse the selector, if every component ends in the same pseudo element(s) then move it to the end | ||
let [trailingPseudo, rebuiltSelector] = commonTrailingPseudos(selector) | ||
if (selector.endsWith('::after')) { | ||
return `:where(${selectorPrefix}${selector.slice( | ||
0, | ||
-7 | ||
)}):not(:where([class~="${prefixedNot}"] *))::after` | ||
if (trailingPseudo) { | ||
return `:where(${selectorPrefix}${rebuiltSelector}):not(:where([class~="${prefixedNot}"] *))${trailingPseudo}` | ||
} | ||
if (selector.endsWith('::marker')) { | ||
return `:where(${selectorPrefix}${selector.slice( | ||
0, | ||
-8 | ||
)}):not(:where([class~="${prefixedNot}"] *))::marker` | ||
} | ||
return `:where(${selectorPrefix}${selector}):not(:where([class~="${prefixedNot}"] *))` | ||
@@ -92,3 +79,3 @@ } | ||
for (let [name, ...selectors] of [ | ||
['headings', 'h1', 'h2', 'h3', 'h4', 'th'], | ||
['headings', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'th'], | ||
['h1'], | ||
@@ -98,2 +85,4 @@ ['h2'], | ||
['h4'], | ||
['h5'], | ||
['h6'], | ||
['p'], | ||
@@ -123,7 +112,9 @@ ['a'], | ||
let selector = target === 'legacy' | ||
? selectors.map(selector => `& ${selector}`) | ||
: selectors.join(', ') | ||
let selector = | ||
target === 'legacy' ? selectors.map((selector) => `& ${selector}`) : selectors.join(', ') | ||
addVariant(`${className}-${name}`, target === 'legacy' ? selector : `& :is(${inWhere(selector, options)})`) | ||
addVariant( | ||
`${className}-${name}`, | ||
target === 'legacy' ? selector : `& :is(${inWhere(selector, options)})` | ||
) | ||
} | ||
@@ -130,0 +121,0 @@ |
@@ -9,2 +9,48 @@ const path = require('path') | ||
let vars = ` | ||
--tw-border-spacing-x: 0; | ||
--tw-border-spacing-y: 0; | ||
--tw-translate-x: 0; | ||
--tw-translate-y: 0; | ||
--tw-rotate: 0; | ||
--tw-skew-x: 0; | ||
--tw-skew-y: 0; | ||
--tw-scale-x: 1; | ||
--tw-scale-y: 1; | ||
--tw-pan-x: ; | ||
--tw-pan-y: ; | ||
--tw-pinch-zoom: ; | ||
--tw-scroll-snap-strictness: proximity; | ||
--tw-ordinal: ; | ||
--tw-slashed-zero: ; | ||
--tw-numeric-figure: ; | ||
--tw-numeric-spacing: ; | ||
--tw-numeric-fraction: ; | ||
--tw-ring-inset: ; | ||
--tw-ring-offset-width: 0px; | ||
--tw-ring-offset-color: #fff; | ||
--tw-ring-color: rgb(59 130 246 / 0.5); | ||
--tw-ring-offset-shadow: 0 0 #0000; | ||
--tw-ring-shadow: 0 0 #0000; | ||
--tw-shadow: 0 0 #0000; | ||
--tw-shadow-colored: 0 0 #0000; | ||
--tw-blur: ; | ||
--tw-brightness: ; | ||
--tw-contrast: ; | ||
--tw-grayscale: ; | ||
--tw-hue-rotate: ; | ||
--tw-invert: ; | ||
--tw-saturate: ; | ||
--tw-sepia: ; | ||
--tw-drop-shadow: ; | ||
--tw-backdrop-blur: ; | ||
--tw-backdrop-brightness: ; | ||
--tw-backdrop-contrast: ; | ||
--tw-backdrop-grayscale: ; | ||
--tw-backdrop-hue-rotate: ; | ||
--tw-backdrop-invert: ; | ||
--tw-backdrop-opacity: ; | ||
--tw-backdrop-saturate: ; | ||
--tw-backdrop-sepia: ; | ||
` | ||
let defaults = css` | ||
@@ -14,45 +60,7 @@ *, | ||
::after { | ||
--tw-translate-x: 0; | ||
--tw-translate-y: 0; | ||
--tw-rotate: 0; | ||
--tw-skew-x: 0; | ||
--tw-skew-y: 0; | ||
--tw-scale-x: 1; | ||
--tw-scale-y: 1; | ||
--tw-pan-x: ; | ||
--tw-pan-y: ; | ||
--tw-pinch-zoom: ; | ||
--tw-scroll-snap-strictness: proximity; | ||
--tw-ordinal: ; | ||
--tw-slashed-zero: ; | ||
--tw-numeric-figure: ; | ||
--tw-numeric-spacing: ; | ||
--tw-numeric-fraction: ; | ||
--tw-ring-inset: ; | ||
--tw-ring-offset-width: 0px; | ||
--tw-ring-offset-color: #fff; | ||
--tw-ring-color: rgb(59 130 246 / 0.5); | ||
--tw-ring-offset-shadow: 0 0 #0000; | ||
--tw-ring-shadow: 0 0 #0000; | ||
--tw-shadow: 0 0 #0000; | ||
--tw-shadow-colored: 0 0 #0000; | ||
--tw-blur: ; | ||
--tw-brightness: ; | ||
--tw-contrast: ; | ||
--tw-grayscale: ; | ||
--tw-hue-rotate: ; | ||
--tw-invert: ; | ||
--tw-saturate: ; | ||
--tw-sepia: ; | ||
--tw-drop-shadow: ; | ||
--tw-backdrop-blur: ; | ||
--tw-backdrop-brightness: ; | ||
--tw-backdrop-contrast: ; | ||
--tw-backdrop-grayscale: ; | ||
--tw-backdrop-hue-rotate: ; | ||
--tw-backdrop-invert: ; | ||
--tw-backdrop-opacity: ; | ||
--tw-backdrop-saturate: ; | ||
--tw-backdrop-sepia: ; | ||
${vars} | ||
} | ||
::backdrop { | ||
${vars} | ||
} | ||
` | ||
@@ -340,3 +348,5 @@ | ||
plugins: [typographyPlugin({ target: 'legacy' })], | ||
content: [{ raw: html`<div class="prose prose-h1:text-center prose-headings:text-ellipsis"></div>` }], | ||
content: [ | ||
{ raw: html`<div class="prose prose-h1:text-center prose-headings:text-ellipsis"></div>` }, | ||
], | ||
theme: { | ||
@@ -441,2 +451,8 @@ typography: { | ||
} | ||
.prose-headings\:text-ellipsis h5 { | ||
text-overflow: ellipsis; | ||
} | ||
.prose-headings\:text-ellipsis h6 { | ||
text-overflow: ellipsis; | ||
} | ||
.prose-headings\:text-ellipsis th { | ||
@@ -628,3 +644,3 @@ text-overflow: ellipsis; | ||
.prose-headings\:underline | ||
:is(:where(h1, h2, h3, h4, th):not(:where([class~='not-prose'] *))) { | ||
:is(:where(h1, h2, h3, h4, h5, h6, th):not(:where([class~='not-prose'] *))) { | ||
text-decoration-line: underline; | ||
@@ -714,3 +730,3 @@ } | ||
} | ||
.prose-lead\:italic :is(:where([class~="lead"]):not(:where([class~="not-prose"] *))) { | ||
.prose-lead\:italic :is(:where([class~='lead']):not(:where([class~='not-prose'] *))) { | ||
font-style: italic; | ||
@@ -802,3 +818,3 @@ } | ||
.markdown-headings\:underline | ||
:is(:where(h1, h2, h3, h4, th):not(:where([class~='not-markdown'] *))) { | ||
:is(:where(h1, h2, h3, h4, h5, h6, th):not(:where([class~='not-markdown'] *))) { | ||
text-decoration-line: underline; | ||
@@ -890,3 +906,3 @@ } | ||
} | ||
.markdown-lead\:italic :is(:where([class~="lead"]):not(:where([class~="not-markdown"] *))) { | ||
.markdown-lead\:italic :is(:where([class~='lead']):not(:where([class~='not-markdown'] *))) { | ||
font-style: italic; | ||
@@ -981,1 +997,220 @@ } | ||
}) | ||
it('should be possible to specify custom h5 and h6 styles', () => { | ||
let config = { | ||
plugins: [typographyPlugin()], | ||
content: [ | ||
{ | ||
raw: html`<div class="prose prose-h5:text-sm prose-h6:text-xl"></div>`, | ||
}, | ||
], | ||
} | ||
return run(config).then((result) => { | ||
expect(result.css).toIncludeCss(css` | ||
.prose-h5\:text-sm :is(:where(h5):not(:where([class~='not-prose'] *))) { | ||
font-size: 0.875rem; | ||
line-height: 1.25rem; | ||
} | ||
.prose-h6\:text-xl :is(:where(h6):not(:where([class~='not-prose'] *))) { | ||
font-size: 1.25rem; | ||
line-height: 1.75rem; | ||
} | ||
`) | ||
}) | ||
}) | ||
it('should not break with multiple selectors with pseudo elements using variants', () => { | ||
let config = { | ||
darkMode: 'class', | ||
plugins: [typographyPlugin()], | ||
content: [ | ||
{ | ||
raw: html`<div class="dark:prose"></div>`, | ||
}, | ||
], | ||
theme: { | ||
typography: { | ||
DEFAULT: { | ||
css: { | ||
'ol li::before, ul li::before': { | ||
color: 'red', | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
return run(config).then((result) => { | ||
expect(result.css).toIncludeCss(css` | ||
.dark .dark\:prose :where(ol li, ul li):not(:where([class~='not-prose'] *))::before { | ||
color: red; | ||
} | ||
`) | ||
}) | ||
}) | ||
it('lifts all common, trailing pseudo elements when the same across all selectors', () => { | ||
let config = { | ||
darkMode: 'class', | ||
plugins: [typographyPlugin()], | ||
content: [ | ||
{ | ||
raw: html`<div class="prose dark:prose"></div>`, | ||
}, | ||
], | ||
theme: { | ||
typography: { | ||
DEFAULT: { | ||
css: { | ||
'ol li::marker::before, ul li::marker::before': { | ||
color: 'red', | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
return run(config).then((result) => { | ||
expect(result.css).toIncludeCss(css` | ||
.prose :where(ol li, ul li):not(:where([class~='not-prose'] *))::marker::before { | ||
color: red; | ||
} | ||
`) | ||
// TODO: The output here is a bug in tailwindcss variant selector rewriting | ||
// IT should be ::marker::before | ||
expect(result.css).toIncludeCss(css` | ||
.dark .dark\:prose :where(ol li, ul li):not(:where([class~='not-prose'] *))::before::marker { | ||
color: red; | ||
} | ||
`) | ||
}) | ||
}) | ||
it('does not modify selectors with differing pseudo elements', () => { | ||
let config = { | ||
darkMode: 'class', | ||
plugins: [typographyPlugin()], | ||
content: [ | ||
{ | ||
raw: html`<div class="prose dark:prose"></div>`, | ||
}, | ||
], | ||
theme: { | ||
typography: { | ||
DEFAULT: { | ||
css: { | ||
'ol li::before, ul li::after': { | ||
color: 'red', | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
return run(config).then((result) => { | ||
expect(result.css).toIncludeCss(css` | ||
.prose :where(ol li::before, ul li::after):not(:where([class~='not-prose'] *)) { | ||
color: red; | ||
} | ||
`) | ||
// TODO: The output here is a bug in tailwindcss variant selector rewriting | ||
expect(result.css).toIncludeCss(css` | ||
.dark .dark\:prose :where(ol li, ul li):not(:where([class~='not-prose'] *))::before, | ||
::after { | ||
color: red; | ||
} | ||
`) | ||
}) | ||
}) | ||
it('lifts only the common, trailing pseudo elements from selectors', () => { | ||
let config = { | ||
darkMode: 'class', | ||
plugins: [typographyPlugin()], | ||
content: [ | ||
{ | ||
raw: html`<div class="prose dark:prose"></div>`, | ||
}, | ||
], | ||
theme: { | ||
typography: { | ||
DEFAULT: { | ||
css: { | ||
'ol li::scroll-thumb::before, ul li::scroll-track::before': { | ||
color: 'red', | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
return run(config).then((result) => { | ||
expect(result.css).toIncludeCss(css` | ||
.prose | ||
:where(ol li::scroll-thumb, ul li::scroll-track):not(:where([class~='not-prose'] | ||
*))::before { | ||
color: red; | ||
} | ||
`) | ||
// TODO: The output here is a bug in tailwindcss variant selector rewriting | ||
expect(result.css).toIncludeCss(css` | ||
.dark .dark\:prose :where(ol li, ul li):not(:where([class~='not-prose'] *))::scroll-thumb, | ||
::scroll-track, | ||
::before { | ||
color: red; | ||
} | ||
`) | ||
}) | ||
}) | ||
it('ignores common non-trailing pseudo-elements in selectors', () => { | ||
let config = { | ||
darkMode: 'class', | ||
plugins: [typographyPlugin()], | ||
content: [ | ||
{ | ||
raw: html`<div class="prose dark:prose"></div>`, | ||
}, | ||
], | ||
theme: { | ||
typography: { | ||
DEFAULT: { | ||
css: { | ||
'ol li::before::scroll-thumb, ul li::before::scroll-track': { | ||
color: 'red', | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
return run(config).then((result) => { | ||
expect(result.css).toIncludeCss(css` | ||
.prose | ||
:where(ol li::before::scroll-thumb, ul | ||
li::before::scroll-track):not(:where([class~='not-prose'] *)) { | ||
color: red; | ||
} | ||
`) | ||
// TODO: The output here is a bug in tailwindcss variant selector rewriting | ||
expect(result.css).toIncludeCss(css` | ||
.dark | ||
.dark\:prose | ||
:where(ol li::scroll-thumb, ul li::scroll-track):not(:where([class~='not-prose'] | ||
*))::before, | ||
::before { | ||
color: red; | ||
} | ||
`) | ||
}) | ||
}) |
@@ -1252,2 +1252,11 @@ const colors = require('tailwindcss/colors') | ||
}, | ||
'a strong': { | ||
color: 'inherit', | ||
}, | ||
'blockquote strong': { | ||
color: 'inherit', | ||
}, | ||
'thead th strong': { | ||
color: 'inherit', | ||
}, | ||
ol: { | ||
@@ -1317,2 +1326,3 @@ listStyleType: 'decimal', | ||
fontWeight: '900', | ||
color: 'inherit', | ||
}, | ||
@@ -1325,2 +1335,3 @@ h2: { | ||
fontWeight: '800', | ||
color: 'inherit', | ||
}, | ||
@@ -1333,2 +1344,3 @@ h3: { | ||
fontWeight: '700', | ||
color: 'inherit', | ||
}, | ||
@@ -1341,2 +1353,3 @@ h4: { | ||
fontWeight: '700', | ||
color: 'inherit', | ||
}, | ||
@@ -1360,4 +1373,22 @@ // TODO: Figure out how to not need these, it's a merging issue | ||
'a code': { | ||
color: 'var(--tw-prose-links)', | ||
color: 'inherit', | ||
}, | ||
'h1 code': { | ||
color: 'inherit', | ||
}, | ||
'h2 code': { | ||
color: 'inherit', | ||
}, | ||
'h3 code': { | ||
color: 'inherit', | ||
}, | ||
'h4 code': { | ||
color: 'inherit', | ||
}, | ||
'blockquote code': { | ||
color: 'inherit', | ||
}, | ||
'thead th code': { | ||
color: 'inherit', | ||
}, | ||
pre: { | ||
@@ -1364,0 +1395,0 @@ color: 'var(--tw-prose-pre-code)', |
const isPlainObject = require('lodash.isplainobject') | ||
const parser = require('postcss-selector-parser') | ||
const parseSelector = parser() | ||
module.exports = { | ||
@@ -7,2 +10,54 @@ isUsableColor(color, values) { | ||
}, | ||
/** | ||
* @param {string} selector | ||
*/ | ||
commonTrailingPseudos(selector) { | ||
let ast = parseSelector.astSync(selector) | ||
/** @type {import('postcss-selector-parser').Pseudo[][]} */ | ||
let matrix = [] | ||
// Put the pseudo elements in reverse order in a sparse, column-major 2D array | ||
for (let [i, sel] of ast.nodes.entries()) { | ||
for (const [j, child] of [...sel.nodes].reverse().entries()) { | ||
// We only care about pseudo elements | ||
if (child.type !== 'pseudo' || !child.value.startsWith('::')) { | ||
break | ||
} | ||
matrix[j] = matrix[j] || [] | ||
matrix[j][i] = child | ||
} | ||
} | ||
let trailingPseudos = parser.selector() | ||
// At this point the pseudo elements are in a column-major 2D array | ||
// This means each row contains one "column" of pseudo elements from each selector | ||
// We can compare all the pseudo elements in a row to see if they are the same | ||
for (const pseudos of matrix) { | ||
// It's a sparse 2D array so there are going to be holes in the rows | ||
// We skip those | ||
if (!pseudos) { | ||
continue | ||
} | ||
let values = new Set([...pseudos.map((p) => p.value)]) | ||
// The pseudo elements are not the same | ||
if (values.size > 1) { | ||
break | ||
} | ||
pseudos.forEach((pseudo) => pseudo.remove()) | ||
trailingPseudos.prepend(pseudos[0]) | ||
} | ||
if (trailingPseudos.nodes.length) { | ||
return [trailingPseudos.toString(), ast.toString()] | ||
} | ||
return [null, selector] | ||
}, | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
90727
9
2761
5
+ Addedpostcss-selector-parser@6.0.10(transitive)
+ Addedyaml@2.7.0(transitive)
- Removedyaml@2.6.1(transitive)