Skip to content

Commit

Permalink
Improve matchUtilities API and make it work with the AOT engine (#4232
Browse files Browse the repository at this point in the history
)

* implement matchUtilities2

* ensure animation names without keyframes are not prefixed

* remove matchBase

* call addUtilities for each group individually

* WIP: Write plugins using matchUtilities2

* MORE

* Fix arbitrary value support for fontSize

* Fixes, update fixtures

* Rebuild fixtures

* Don't generate `divide` class with no modifier

* Fixes, rebuild fixtures

* Rename matchUtilities2 to matchUtilities

* Delete bad tests

* Remove temp files GROSS

* Clean stuff up

* Support no return in matchUtilities

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
  • Loading branch information
RobinMalfait and adamwathan committed May 7, 2021
1 parent e8d2619 commit 0c5c540
Show file tree
Hide file tree
Showing 70 changed files with 72,355 additions and 73,566 deletions.
7 changes: 1 addition & 6 deletions src/jit/lib/generateRules.js
Expand Up @@ -215,17 +215,12 @@ function* resolveMatches(candidate, context) {
// }

for (let matchedPlugins of resolveMatchedPlugins(classCandidate, context)) {
let pluginHelpers = {
candidate: classCandidate,
theme: context.tailwindConfig.theme,
}

let matches = []
let [plugins, modifier] = matchedPlugins

for (let [sort, plugin] of plugins) {
if (typeof plugin === 'function') {
for (let ruleSet of [].concat(plugin(modifier, pluginHelpers))) {
for (let ruleSet of [].concat(plugin(modifier))) {
let [rules, options] = parseRules(ruleSet, context.postCssNodeCache)
for (let rule of rules) {
matches.push([{ ...sort, options: { ...sort.options, ...options } }, rule])
Expand Down
69 changes: 29 additions & 40 deletions src/jit/lib/setupContext.js
Expand Up @@ -22,6 +22,9 @@ import corePlugins from '../corePlugins'
import isPlainObject from '../../util/isPlainObject'
import escapeClassName from '../../util/escapeClassName'

import nameClass from '../../util/nameClass'
import { coerceValue } from '../../util/pluginUtils'

import * as sharedState from './sharedState'

let contextMap = sharedState.contextMap
Expand Down Expand Up @@ -513,36 +516,7 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
.push([{ sort: offset, layer: 'utilities', options }, rule])
}
},
matchBase: function (base) {
let offset = offsets.base++

for (let identifier in base) {
let prefixedIdentifier = prefixIdentifier(identifier, options)
let rule = base[identifier]

let withOffsets = [{ sort: offset, layer: 'base' }, rule]

if (!context.candidateRuleMap.has(prefixedIdentifier)) {
context.candidateRuleMap.set(prefixedIdentifier, [])
}

context.candidateRuleMap.get(prefixedIdentifier).push(withOffsets)
}
},
matchUtilities: function (utilities, options) {
// TODO: Redesign this API to work like this so it's more end-user friendly
// matchUtilities({
// animate: (value, { includeRules }) => {
// let { name: animationName } = parseAnimationValue(value)

// if (keyframes[animationName] !== undefined) {
// includeRules(keyframes[animationName])
// }

// return { animation: value }
// },
// }, { values: [...], variants: [lol], ...otherStuff })

let defaultOptions = {
variants: [],
respectPrefix: true,
Expand All @@ -558,7 +532,32 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
let prefixedIdentifier = prefixIdentifier(identifier, options)
let rule = utilities[identifier]

let withOffsets = [{ sort: offset, layer: 'utilities', options }, rule]
function wrapped(modifier) {
let { type = 'any' } = options
let value = coerceValue(type, modifier, options.values)

if (value === undefined) {
return []
}

let includedRules = []
let ruleSets = []
.concat(
rule(value, {
includeRules(rules) {
includedRules.push(...rules)
},
})
)
.filter(Boolean)
.map((declaration) => ({
[nameClass(identifier, modifier)]: declaration,
}))

return [...includedRules, ...ruleSets]
}

let withOffsets = [{ sort: offset, layer: 'utilities', options }, wrapped]

if (!context.candidateRuleMap.has(prefixedIdentifier)) {
context.candidateRuleMap.set(prefixedIdentifier, [])
Expand All @@ -567,16 +566,6 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
context.candidateRuleMap.get(prefixedIdentifier).push(withOffsets)
}
},
// ---
jit: {
e: escapeClassName,
config: tailwindConfig,
theme: tailwindConfig.theme,
addVariant(variantName, applyVariant, options = {}) {
insertInto(variantList, variantName, options)
variantMap.set(variantName, applyVariant)
},
},
}
}

Expand Down
79 changes: 30 additions & 49 deletions src/plugins/animation.js
@@ -1,60 +1,41 @@
import _ from 'lodash'
import parseAnimationValue from '../util/parseAnimationValue'
import nameClass from '../util/nameClass'

export default function () {
return function ({ config, matchUtilities, addUtilities, theme, variants, prefix }) {
if (config('mode') === 'jit') {
let keyframes = Object.fromEntries(
Object.entries(theme('keyframes')).map(([key, value]) => {
return [
key,
[
{
[`@keyframes ${key}`]: value,
},
{ respectVariants: false },
],
]
})
)
return function ({ matchUtilities, theme, variants, prefix }) {
let prefixName = (name) => prefix(`.${name}`).slice(1)
let keyframes = Object.fromEntries(
Object.entries(theme('keyframes')).map(([key, value]) => {
return [
key,
[
{
[`@keyframes ${prefixName(key)}`]: value,
},
{ respectVariants: false },
],
]
})
)

matchUtilities({
animate: (modifier, { theme }) => {
let value = theme.animation[modifier]
matchUtilities(
{
animate: (value, { includeRules }) => {
let { name: animationName } = parseAnimationValue(value)

if (value === undefined) {
return []
if (keyframes[animationName] !== undefined) {
includeRules(keyframes[animationName], { respectImportant: false })
}

let { name: animationName } = parseAnimationValue(value)
if (animationName === undefined || keyframes[animationName] === undefined) {
return { animation: value }
}

return [
keyframes[animationName],
{ [nameClass('animate', modifier)]: { animation: value } },
].filter(Boolean)
return {
animation: value.replace(animationName, prefixName(animationName)),
}
},
})
} else {
const prefixName = (name) => prefix(`.${name}`).slice(1)
const keyframesConfig = theme('keyframes')
const keyframesStyles = _.mapKeys(
keyframesConfig,
(_keyframes, name) => `@keyframes ${prefixName(name)}`
)

addUtilities(keyframesStyles, { respectImportant: false })

const animationConfig = theme('animation')
const utilities = _.mapValues(
_.mapKeys(animationConfig, (_animation, suffix) => nameClass('animate', suffix)),
(animation) => {
const { name } = parseAnimationValue(animation)
if (name === undefined || keyframesConfig[name] === undefined) return { animation }
return { animation: animation.replace(name, prefixName(name)) }
}
)
addUtilities(utilities, variants('animation'))
}
},
{ values: theme('animation'), variants: variants('animation') }
)
}
}
46 changes: 12 additions & 34 deletions src/plugins/backdropBlur.js
@@ -1,38 +1,16 @@
import _ from 'lodash'
import nameClass from '../util/nameClass'
import { asValue } from '../util/pluginUtils'

export default function () {
return function ({ config, matchUtilities, addUtilities, theme, variants }) {
if (config('mode') === 'jit') {
matchUtilities({
'backdrop-blur': (modifier, { theme }) => {
let value = asValue(modifier, theme.backdropBlur)

if (value === undefined) {
return []
}

return {
[nameClass('backdrop-blur', modifier)]: { '--tw-backdrop-blur': `blur(${value})` },
}
return function ({ matchUtilities, theme, variants }) {
matchUtilities(
{
'backdrop-blur': (value) => {
return { '--tw-backdrop-blur': `blur(${value})` }
},
})
} else {
const utilities = _.fromPairs(
_.map(theme('backdropBlur'), (value, modifier) => {
return [
nameClass('backdrop-blur', modifier),
{
'--tw-backdrop-blur': Array.isArray(value)
? value.map((v) => `blur(${v})`).join(' ')
: `blur(${value})`,
},
]
})
)

addUtilities(utilities, variants('backdopBlur'))
}
},
{
values: theme('backdropBlur'),
variants: variants('backdropBlur'),
type: 'any',
}
)
}
}
46 changes: 12 additions & 34 deletions src/plugins/backdropBrightness.js
@@ -1,40 +1,18 @@
import _ from 'lodash'
import nameClass from '../util/nameClass'
import { asValue } from '../util/pluginUtils'

export default function () {
return function ({ config, matchUtilities, addUtilities, theme, variants }) {
if (config('mode') === 'jit') {
matchUtilities({
'backdrop-brightness': (modifier, { theme }) => {
let value = asValue(modifier, theme.backdropBrightness)

if (value === undefined) {
return []
}

return function ({ matchUtilities, theme, variants }) {
matchUtilities(
{
'backdrop-brightness': (value) => {
return {
[nameClass('backdrop-brightness', modifier)]: {
'--tw-backdrop-brightness': `brightness(${value})`,
},
'--tw-backdrop-brightness': `brightness(${value})`,
}
},
})
} else {
const utilities = _.fromPairs(
_.map(theme('backdropBrightness'), (value, modifier) => {
return [
nameClass('backdrop-brightness', modifier),
{
'--tw-backdrop-brightness': Array.isArray(value)
? value.map((v) => `brightness(${v})`).join(' ')
: `brightness(${value})`,
},
]
})
)

addUtilities(utilities, variants('backdropBrightness'))
}
},
{
values: theme('backdropBrightness'),
variants: variants('backdropBrightness'),
type: 'any',
}
)
}
}
48 changes: 12 additions & 36 deletions src/plugins/backdropContrast.js
@@ -1,40 +1,16 @@
import _ from 'lodash'
import nameClass from '../util/nameClass'
import { asValue } from '../util/pluginUtils'

export default function () {
return function ({ config, matchUtilities, addUtilities, theme, variants }) {
if (config('mode') === 'jit') {
matchUtilities({
'backdrop-contrast': (modifier, { theme }) => {
let value = asValue(modifier, theme.backdropContrast)

if (value === undefined) {
return []
}

return {
[nameClass('backdrop-contrast', modifier)]: {
'--tw-backdrop-contrast': `contrast(${value})`,
},
}
return function ({ matchUtilities, theme, variants }) {
matchUtilities(
{
'backdrop-contrast': (value) => {
return { '--tw-backdrop-contrast': `contrast(${value})` }
},
})
} else {
const utilities = _.fromPairs(
_.map(theme('backdropContrast'), (value, modifier) => {
return [
nameClass('backdrop-contrast', modifier),
{
'--tw-backdrop-contrast': Array.isArray(value)
? value.map((v) => `contrast(${v})`).join(' ')
: `contrast(${value})`,
},
]
})
)

addUtilities(utilities, variants('backdropContrast'))
}
},
{
values: theme('backdropContrast'),
variants: variants('backdropContrast'),
type: 'any',
}
)
}
}

0 comments on commit 0c5c540

Please sign in to comment.