Refactor
This commit is contained in:
parent
a5305aa84e
commit
ba7d3be00e
2 changed files with 105 additions and 18 deletions
102
src/lib/parseCssConfig.js
Normal file
102
src/lib/parseCssConfig.js
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
// @ts-check
|
||||
|
||||
/**
|
||||
* Find and convert the `:theme` rule to a configuration object
|
||||
* This is merged with the user's JS config
|
||||
* It should take precedence over the JS config
|
||||
*
|
||||
* @param {import('postcss').Root} root
|
||||
*/
|
||||
export function parseCssConfig(root) {
|
||||
let config = { extend: { colors: {} } }
|
||||
|
||||
let theme = root.nodes.find(node => node.type === 'rule' && node.selector === ':theme')
|
||||
if (!theme) return config
|
||||
|
||||
theme.walkDecls((decl) => {
|
||||
if (decl.prop.startsWith('--')) {
|
||||
parseVariable(config, decl.prop.slice(2), decl.value)
|
||||
} else {
|
||||
// Only CSS variables are allowed in the theme rule
|
||||
// TODO: Maybe turn this into an error?
|
||||
decl.remove()
|
||||
}
|
||||
})
|
||||
|
||||
theme.remove()
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
let prefixPluginMap = {
|
||||
'colors': 'colors',
|
||||
'spacing': 'spacing',
|
||||
'font-family': 'fontFamily',
|
||||
'font-size': 'fontSize',
|
||||
'shadow': 'boxShadow',
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a key into one or more actions that modify the config and/or CSS
|
||||
*
|
||||
* @param {*} config
|
||||
* @param {string} name
|
||||
* @param {string} value
|
||||
*/
|
||||
function parseVariable(config, name, value) {
|
||||
// Parse the variable name into a config plugin and keypath
|
||||
let [plugin, keypath] = parseVariableName(name, value)
|
||||
|
||||
console.log({ name, plugin, keypath, value })
|
||||
|
||||
// We couldn't find a plugin for this variable, so we can't do anything with it
|
||||
if (plugin === null) return
|
||||
|
||||
if (keypath === null && value === 'unset') {
|
||||
// when using `--some-plugin: unset` we want to reset whatever the default value is
|
||||
config[plugin] = {}
|
||||
|
||||
// This also means there is no reason to keep the variable in the CSS
|
||||
decl.remove()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// When using `--some-plugin: initial` it should reset to the default value for that key
|
||||
// This effectively means removing it
|
||||
if (keypath === null && value === 'initial') {
|
||||
delete config[plugin]
|
||||
delete config.extend[plugin]
|
||||
|
||||
// This also means there is no reason to keep the variable in the CSS
|
||||
decl.remove()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// All other cases are config keys in a plugin
|
||||
config.extend[plugin] ??= {}
|
||||
config.extend[plugin][keypath] = value
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a key into one or more actions that modify the config and/or CSS
|
||||
*
|
||||
* @param {string} name
|
||||
* @param {string} value
|
||||
* @returns {[plugin: string|null, keypath: string|null]}
|
||||
*/
|
||||
function parseVariableName(name, value) {
|
||||
for (const [prefix, plugin] of Object.entries(prefixPluginMap)) {
|
||||
if (!name.startsWith(prefix)) continue
|
||||
|
||||
// The keypath is the part of the variable name after the prefix
|
||||
let keypath = name.slice(prefix.length)
|
||||
if (keypath.startsWith('-')) keypath = keypath.slice(1)
|
||||
if (keypath === '') keypath = null
|
||||
|
||||
return [plugin, keypath]
|
||||
}
|
||||
|
||||
return [null, null]
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import processTailwindFeatures from './processTailwindFeatures'
|
|||
import { env } from './lib/sharedState'
|
||||
import { findAtConfigPath } from './lib/findAtConfigPath'
|
||||
import { handleImportAtRules } from './lib/handleImportAtRules'
|
||||
import { parseCssConfig } from './lib/parseCssConfig'
|
||||
|
||||
module.exports = function tailwindcss(configOrPath) {
|
||||
return {
|
||||
|
|
@ -23,24 +24,8 @@ module.exports = function tailwindcss(configOrPath) {
|
|||
// path for the file being processed
|
||||
configOrPath = findAtConfigPath(root, result) ?? configOrPath
|
||||
|
||||
// Begin CSS-first theme configuration proof-of-concept
|
||||
let themeValues = { extend: { colors: {} } }
|
||||
|
||||
root.each((node) => {
|
||||
if (node.type === 'rule' && node.selector === ':theme') {
|
||||
// Walk :theme pseudo and extract values
|
||||
node.walkDecls((decl) => {
|
||||
if (decl.prop.startsWith('--colors-')) {
|
||||
themeValues.extend.colors[decl.prop.slice(9)] = decl.value
|
||||
}
|
||||
})
|
||||
|
||||
node.remove()
|
||||
}
|
||||
})
|
||||
|
||||
// context.tailwindConfig.theme
|
||||
// End CSS-first theme configuration proof-of-concept
|
||||
// Parse any CSS-based config values from `:theme` rules
|
||||
let themeValues = parseCssConfig(root)
|
||||
|
||||
let context = setupTrackingContext(configOrPath, themeValues)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue