Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve matchUtilities API and make it work with the AOT engine #4232

Merged
merged 16 commits into from May 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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',
}
)
}
}