Work on implementation
This commit is contained in:
parent
3c38f0a391
commit
8809c6a7fb
2 changed files with 157 additions and 23 deletions
|
|
@ -15,7 +15,7 @@ export function parseCssConfig(root) {
|
|||
|
||||
theme.walkDecls((decl) => {
|
||||
if (decl.prop.startsWith('--')) {
|
||||
parseVariable(config, decl.prop.slice(2), decl.value)
|
||||
parseVariable(config, decl)
|
||||
} else {
|
||||
// Only CSS variables are allowed in the theme rule
|
||||
// TODO: Maybe turn this into an error?
|
||||
|
|
@ -41,14 +41,12 @@ let prefixPluginMap = {
|
|||
* Parse a key into one or more actions that modify the config and/or CSS
|
||||
*
|
||||
* @param {*} config
|
||||
* @param {string} name
|
||||
* @param {string} value
|
||||
* @param {import('postcss').Declaration} decl
|
||||
*/
|
||||
function parseVariable(config, name, value) {
|
||||
function parseVariable(config, decl) {
|
||||
// Parse the variable name into a config plugin and keypath
|
||||
let [plugin, keypath] = parseVariableName(name, value)
|
||||
|
||||
console.log({ name, plugin, keypath, value })
|
||||
let [name, value] = [decl.prop.slice(2), decl.value]
|
||||
let [plugin, keypath, option] = parseVariableName(name)
|
||||
|
||||
// We couldn't find a plugin for this variable, so we can't do anything with it
|
||||
if (plugin === null) return
|
||||
|
|
@ -75,29 +73,78 @@ function parseVariable(config, name, value) {
|
|||
return
|
||||
}
|
||||
|
||||
// TODO: Can this happen
|
||||
if (keypath === null) {
|
||||
return
|
||||
}
|
||||
|
||||
// All other cases are config keys in a plugin
|
||||
config.extend[plugin] ??= {}
|
||||
config.extend[plugin][keypath] = value
|
||||
|
||||
if (!option) {
|
||||
config.extend[plugin][keypath] = value
|
||||
return
|
||||
}
|
||||
|
||||
if (!Array.isArray(config.extend[plugin][keypath])) {
|
||||
config.extend[plugin][keypath] = [
|
||||
config.extend[plugin][keypath],
|
||||
{}
|
||||
]
|
||||
}
|
||||
|
||||
config.extend[plugin][keypath][1][option] = 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]}
|
||||
* @returns {[plugin: string|null, keypath: string|null, option: string|null]}
|
||||
*/
|
||||
function parseVariableName(name, value) {
|
||||
function parseVariableName(name) {
|
||||
// Unescape the name if needed
|
||||
// This is needed for CSS variables that contain special characters
|
||||
name = name.replace(/\\/g, '')
|
||||
|
||||
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
|
||||
let option = null
|
||||
|
||||
return [plugin, keypath]
|
||||
let optionStart = keypath.indexOf('--')
|
||||
if (optionStart !== -1) {
|
||||
option = keypath.slice(optionStart+2)
|
||||
keypath = keypath.slice(0, optionStart)
|
||||
}
|
||||
|
||||
if (keypath == '' && option === 'default') {
|
||||
keypath = 'DEFAULT'
|
||||
option = null
|
||||
} else if (keypath.startsWith('-')) {
|
||||
keypath = keypath.slice(1)
|
||||
}
|
||||
|
||||
if (keypath === '') {
|
||||
return [plugin, null, null]
|
||||
}
|
||||
|
||||
console.log({
|
||||
opt: option ? camelize(option) : option,
|
||||
})
|
||||
|
||||
return [plugin, keypath, option === null ? null : camelize(option)]
|
||||
}
|
||||
|
||||
return [null, null]
|
||||
return [null, null, null]
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} str
|
||||
* @returns {string}
|
||||
*/
|
||||
function camelize(str) {
|
||||
return str.replace(/-([a-zA-Z])/g, (v) => v.slice(1).toUpperCase())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,25 @@ test('it does something', () => {
|
|||
content: [
|
||||
{
|
||||
raw: html`
|
||||
<!-- Not emitted, default colors have been removed -->
|
||||
<div class="text-black"></div>
|
||||
<div class="text-potato"></div>
|
||||
<!-- Not emitted, does not exist -->
|
||||
<div class="text-mint-100"></div>
|
||||
|
||||
<!-- Below are all emitted -->
|
||||
<div class="text-mint-50"></div>
|
||||
<div class="text-mint-900"></div>
|
||||
<div class="text-plum-50"></div>
|
||||
<div class="text-plum-900"></div>
|
||||
<div class="text-primary"></div>
|
||||
<div class="text-10xl"></div>
|
||||
<div class="text-10xl/sm"></div>
|
||||
<div class="font-display"></div>
|
||||
<div class="px-1/4"></div>
|
||||
<div class="px-1/2"></div>
|
||||
<div class="px-3/4"></div>
|
||||
<div class="shadow"></div>
|
||||
<div class="animate-flash"></div>
|
||||
`,
|
||||
},
|
||||
],
|
||||
|
|
@ -18,22 +35,92 @@ test('it does something', () => {
|
|||
@tailwind utilities;
|
||||
|
||||
:theme {
|
||||
--colors-potato: #facade;
|
||||
--colors: unset;
|
||||
--colors-mint-50: #f3fdfb;
|
||||
--colors-mint-900: #043820;
|
||||
--colors-plum-50: #f8f6fe;
|
||||
--colors-plum-900: #120c64;
|
||||
--colors-primary: theme(colors.mint-50);
|
||||
|
||||
--font-family-display: Graphik, sans-serif;
|
||||
--font-family-display--font-feature-settings: "cv11", "ss01";
|
||||
|
||||
--font-size-10xl: 10rem;
|
||||
--font-size-10xl--line-height: 10rem;
|
||||
|
||||
--spacing-1\/4: 25%;
|
||||
--spacing-1\/2: 50%;
|
||||
--spacing-3\/4: 75%;
|
||||
|
||||
--shadow--default: 0 3px 5px -2px hsl(220 3% 15% / 4%), 0 7px 14px -5px hsl(220
|
||||
3% 15% / 6%);
|
||||
|
||||
--animation-flash: flash 1s;
|
||||
}
|
||||
`,
|
||||
config
|
||||
).then((result) => {
|
||||
expect(result.css).toMatchFormattedCss(css`
|
||||
.text-black {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(0 0 0 / var(--tw-text-opacity));
|
||||
.px-1\/2 {
|
||||
padding-left: 50%;
|
||||
padding-right: 50%;
|
||||
}
|
||||
.text-potato {
|
||||
.px-1\/4 {
|
||||
padding-left: 25%;
|
||||
padding-right: 25%;
|
||||
}
|
||||
.px-3\/4 {
|
||||
padding-left: 75%;
|
||||
padding-right: 75%;
|
||||
}
|
||||
.font-display {
|
||||
font-feature-settings: "cv11", "ss01";
|
||||
font-family: Graphik, sans-serif;
|
||||
}
|
||||
.text-10xl {
|
||||
font-size: 10rem;
|
||||
line-height: 10rem;
|
||||
}
|
||||
.text-mint-50 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(250 202 222 / var(--tw-text-opacity));
|
||||
color: rgb(243 253 251 / var(--tw-text-opacity));
|
||||
}
|
||||
.text-mint-900 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(4 56 32 / var(--tw-text-opacity));
|
||||
}
|
||||
.text-plum-50 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(248 246 254 / var(--tw-text-opacity));
|
||||
}
|
||||
.text-plum-900 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(18 12 100 / var(--tw-text-opacity));
|
||||
}
|
||||
.text-primary {
|
||||
color: #f3fdfb;
|
||||
}
|
||||
.shadow {
|
||||
--tw-shadow: 0 3px 5px -2px #2526270a, 0 7px 14px -5px #2526270f;
|
||||
--tw-shadow-colored: 0 3px 5px -2px var(--tw-shadow-color), 0 7px 14px -5px var(--tw-shadow-color);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000),
|
||||
var(--tw-shadow);
|
||||
}
|
||||
:root {
|
||||
--colors-potato: #facade;
|
||||
--colors-mint-50: #f3fdfb;
|
||||
--colors-mint-900: #043820;
|
||||
--colors-plum-50: #f8f6fe;
|
||||
--colors-plum-900: #120c64;
|
||||
--colors-primary: #f3fdfb;
|
||||
--font-family-display: Graphik, sans-serif;
|
||||
--font-family-display--font-feature-settings: "cv11", "ss01";
|
||||
--font-size-10xl: 10rem;
|
||||
--font-size-10xl--line-height: 10rem;
|
||||
--spacing-1\/4: 25%;
|
||||
--spacing-1\/2: 50%;
|
||||
--spacing-3\/4: 75%;
|
||||
--shadow--default: 0 3px 5px -2px #2526270a, 0 7px 14px -5px #2526270f;
|
||||
--animation-flash: flash 1s;
|
||||
}
|
||||
`)
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue