167 lines
5 KiB
JavaScript
167 lines
5 KiB
JavaScript
import _ from 'lodash'
|
|
import postcss from 'postcss'
|
|
import Node from 'postcss/lib/node'
|
|
import isFunction from 'lodash/isFunction'
|
|
import escapeClassName from '../util/escapeClassName'
|
|
import generateVariantFunction from '../util/generateVariantFunction'
|
|
import parseObjectStyles from '../util/parseObjectStyles'
|
|
import prefixSelector from '../util/prefixSelector'
|
|
import wrapWithVariants from '../util/wrapWithVariants'
|
|
import cloneNodes from '../util/cloneNodes'
|
|
import transformThemeValue from './transformThemeValue'
|
|
import nameClass from '../util/nameClass'
|
|
import isKeyframeRule from '../util/isKeyframeRule'
|
|
|
|
function parseStyles(styles) {
|
|
if (!Array.isArray(styles)) {
|
|
return parseStyles([styles])
|
|
}
|
|
|
|
return _.flatMap(styles, (style) => (style instanceof Node ? style : parseObjectStyles(style)))
|
|
}
|
|
|
|
function wrapWithLayer(rules, layer) {
|
|
return postcss
|
|
.atRule({
|
|
name: 'layer',
|
|
params: layer,
|
|
})
|
|
.append(cloneNodes(Array.isArray(rules) ? rules : [rules]))
|
|
}
|
|
|
|
export default function (plugins, config) {
|
|
const pluginBaseStyles = []
|
|
const pluginComponents = []
|
|
const pluginUtilities = []
|
|
const pluginVariantGenerators = {}
|
|
|
|
const applyConfiguredPrefix = (selector) => {
|
|
return prefixSelector(config.prefix, selector)
|
|
}
|
|
|
|
function addUtilities(utilities, options) {
|
|
const defaultOptions = {
|
|
variants: [],
|
|
respectPrefix: true,
|
|
respectImportant: true,
|
|
}
|
|
|
|
options = Array.isArray(options)
|
|
? Object.assign({}, defaultOptions, { variants: options })
|
|
: _.defaults(options, defaultOptions)
|
|
|
|
const styles = postcss.root({ nodes: parseStyles(utilities) })
|
|
|
|
styles.walkRules((rule) => {
|
|
if (options.respectPrefix && !isKeyframeRule(rule)) {
|
|
rule.selector = applyConfiguredPrefix(rule.selector)
|
|
}
|
|
|
|
if (options.respectImportant && config.important) {
|
|
rule.__tailwind = {
|
|
...rule.__tailwind,
|
|
important: config.important,
|
|
}
|
|
}
|
|
})
|
|
|
|
pluginUtilities.push(
|
|
wrapWithLayer(wrapWithVariants(styles.nodes, options.variants), 'utilities')
|
|
)
|
|
}
|
|
|
|
const getConfigValue = (path, defaultValue) => (path ? _.get(config, path, defaultValue) : config)
|
|
|
|
plugins.forEach((plugin) => {
|
|
if (plugin.__isOptionsFunction) {
|
|
plugin = plugin()
|
|
}
|
|
|
|
const handler = isFunction(plugin) ? plugin : _.get(plugin, 'handler', () => {})
|
|
|
|
handler({
|
|
postcss,
|
|
config: getConfigValue,
|
|
theme: (path, defaultValue) => {
|
|
const [pathRoot, ...subPaths] = _.toPath(path)
|
|
const value = getConfigValue(['theme', pathRoot, ...subPaths], defaultValue)
|
|
|
|
return transformThemeValue(pathRoot)(value)
|
|
},
|
|
corePlugins: (path) => {
|
|
if (Array.isArray(config.corePlugins)) {
|
|
return config.corePlugins.includes(path)
|
|
}
|
|
|
|
return getConfigValue(`corePlugins.${path}`, true)
|
|
},
|
|
variants: (path, defaultValue) => {
|
|
if (Array.isArray(config.variants)) {
|
|
return config.variants
|
|
}
|
|
|
|
return getConfigValue(`variants.${path}`, defaultValue)
|
|
},
|
|
e: escapeClassName,
|
|
prefix: applyConfiguredPrefix,
|
|
addUtilities,
|
|
matchUtilities: (matches, { values, variants, respectPrefix, respectImportant }) => {
|
|
let modifierValues = Object.entries(values || {})
|
|
|
|
let result = Object.entries(matches).flatMap(([name, utilityFunction]) => {
|
|
return modifierValues
|
|
.map(([modifier, value]) => {
|
|
let declarations = utilityFunction(value, {
|
|
includeRules(rules, options) {
|
|
addUtilities(rules, options)
|
|
},
|
|
})
|
|
|
|
if (!declarations) {
|
|
return null
|
|
}
|
|
|
|
return {
|
|
[nameClass(name, modifier)]: declarations,
|
|
}
|
|
})
|
|
.filter(Boolean)
|
|
})
|
|
|
|
addUtilities(result, { variants, respectPrefix, respectImportant })
|
|
},
|
|
addComponents: (components, options) => {
|
|
const defaultOptions = { variants: [], respectPrefix: true }
|
|
|
|
options = Array.isArray(options)
|
|
? Object.assign({}, defaultOptions, { variants: options })
|
|
: _.defaults(options, defaultOptions)
|
|
|
|
const styles = postcss.root({ nodes: parseStyles(components) })
|
|
|
|
styles.walkRules((rule) => {
|
|
if (options.respectPrefix && !isKeyframeRule(rule)) {
|
|
rule.selector = applyConfiguredPrefix(rule.selector)
|
|
}
|
|
})
|
|
|
|
pluginComponents.push(
|
|
wrapWithLayer(wrapWithVariants(styles.nodes, options.variants), 'components')
|
|
)
|
|
},
|
|
addBase: (baseStyles) => {
|
|
pluginBaseStyles.push(wrapWithLayer(parseStyles(baseStyles), 'base'))
|
|
},
|
|
addVariant: (name, generator, options = {}) => {
|
|
pluginVariantGenerators[name] = generateVariantFunction(generator, options)
|
|
},
|
|
})
|
|
})
|
|
|
|
return {
|
|
base: pluginBaseStyles,
|
|
components: pluginComponents,
|
|
utilities: pluginUtilities,
|
|
variantGenerators: pluginVariantGenerators,
|
|
}
|
|
}
|