Work on implementation

This commit is contained in:
Jordan Pittman 2023-06-14 12:48:02 -04:00 • committed by Robin Malfait
parent 3c38f0a391
commit 8809c6a7fb
No known key found for this signature in database
GPG key ID: 92F53D68B9041AFE
2 changed files with 157 additions and 23 deletions

View file

@ -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())
}

View file

@ -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;
}
`)
})