|
const plugin = require('tailwindcss/plugin') |
|
const merge = require('lodash.merge') |
|
const castArray = require('lodash.castarray') |
|
const styles = require('./styles') |
|
const { commonTrailingPseudos } = require('./utils') |
|
|
|
const computed = { |
|
|
|
|
|
} |
|
|
|
function inWhere(selector, { className, modifier, prefix }) { |
|
let prefixedNot = prefix(`.not-${className}`).slice(1) |
|
let selectorPrefix = selector.startsWith('>') |
|
? `${modifier === 'DEFAULT' ? `.${className}` : `.${className}-${modifier}`} ` |
|
: '' |
|
|
|
|
|
let [trailingPseudo, rebuiltSelector] = commonTrailingPseudos(selector) |
|
|
|
if (trailingPseudo) { |
|
return `:where(${selectorPrefix}${rebuiltSelector}):not(:where([class~="${prefixedNot}"],[class~="${prefixedNot}"] *))${trailingPseudo}` |
|
} |
|
|
|
return `:where(${selectorPrefix}${selector}):not(:where([class~="${prefixedNot}"],[class~="${prefixedNot}"] *))` |
|
} |
|
|
|
function isObject(value) { |
|
return typeof value === 'object' && value !== null |
|
} |
|
|
|
function configToCss(config = {}, { target, className, modifier, prefix }) { |
|
function updateSelector(k, v) { |
|
if (target === 'legacy') { |
|
return [k, v] |
|
} |
|
|
|
if (Array.isArray(v)) { |
|
return [k, v] |
|
} |
|
|
|
if (isObject(v)) { |
|
let nested = Object.values(v).some(isObject) |
|
if (nested) { |
|
return [ |
|
inWhere(k, { className, modifier, prefix }), |
|
v, |
|
Object.fromEntries(Object.entries(v).map(([k, v]) => updateSelector(k, v))), |
|
] |
|
} |
|
|
|
return [inWhere(k, { className, modifier, prefix }), v] |
|
} |
|
|
|
return [k, v] |
|
} |
|
|
|
return Object.fromEntries( |
|
Object.entries( |
|
merge( |
|
{}, |
|
...Object.keys(config) |
|
.filter((key) => computed[key]) |
|
.map((key) => computed[key](config[key])), |
|
...castArray(config.css || {}) |
|
) |
|
).map(([k, v]) => updateSelector(k, v)) |
|
) |
|
} |
|
|
|
module.exports = plugin.withOptions( |
|
({ className = 'prose', target = 'modern' } = {}) => { |
|
return function ({ addVariant, addComponents, theme, prefix }) { |
|
let modifiers = theme('typography') |
|
|
|
let options = { className, prefix } |
|
|
|
for (let [name, ...selectors] of [ |
|
['headings', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'th'], |
|
['h1'], |
|
['h2'], |
|
['h3'], |
|
['h4'], |
|
['h5'], |
|
['h6'], |
|
['p'], |
|
['a'], |
|
['blockquote'], |
|
['figure'], |
|
['figcaption'], |
|
['strong'], |
|
['em'], |
|
['kbd'], |
|
['code'], |
|
['pre'], |
|
['ol'], |
|
['ul'], |
|
['li'], |
|
['table'], |
|
['thead'], |
|
['tr'], |
|
['th'], |
|
['td'], |
|
['img'], |
|
['video'], |
|
['hr'], |
|
['lead', '[class~="lead"]'], |
|
]) { |
|
selectors = selectors.length === 0 ? [name] : selectors |
|
|
|
let selector = |
|
target === 'legacy' ? selectors.map((selector) => `& ${selector}`) : selectors.join(', ') |
|
|
|
addVariant( |
|
`${className}-${name}`, |
|
target === 'legacy' ? selector : `& :is(${inWhere(selector, options)})` |
|
) |
|
} |
|
|
|
addComponents( |
|
Object.keys(modifiers).map((modifier) => ({ |
|
[modifier === 'DEFAULT' ? `.${className}` : `.${className}-${modifier}`]: configToCss( |
|
modifiers[modifier], |
|
{ |
|
target, |
|
className, |
|
modifier, |
|
prefix, |
|
} |
|
), |
|
})) |
|
) |
|
} |
|
}, |
|
() => { |
|
return { |
|
theme: { typography: styles }, |
|
} |
|
} |
|
) |
|
|