JIT: Add support for before/after pseudo-elements (#4461)
This commit is contained in:
parent
1badba55b7
commit
c8a5f816f4
12 changed files with 130 additions and 23 deletions
|
|
@ -1,8 +1,11 @@
|
|||
import * as plugins from './plugins/index.js'
|
||||
|
||||
import configurePlugins from './util/configurePlugins'
|
||||
|
||||
const jitOnlyPlugins = ['content']
|
||||
|
||||
export default function ({ corePlugins: corePluginConfig }) {
|
||||
corePluginConfig = corePluginConfig.filter((pluginName) => !jitOnlyPlugins.includes(pluginName))
|
||||
|
||||
return configurePlugins(corePluginConfig, Object.keys(plugins)).map((pluginName) => {
|
||||
return plugins[pluginName]()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -12,6 +12,50 @@ import {
|
|||
|
||||
export default {
|
||||
pseudoClassVariants: function ({ config, addVariant }) {
|
||||
addVariant(
|
||||
'before',
|
||||
transformAllSelectors(
|
||||
(selector) => {
|
||||
return updateAllClasses(selector, (className, { withPseudo }) => {
|
||||
return withPseudo(`before${config('separator')}${className}`, '::before')
|
||||
})
|
||||
},
|
||||
{
|
||||
withRule: (rule) => {
|
||||
let foundContent = false
|
||||
rule.walkDecls('content', () => {
|
||||
foundContent = true
|
||||
})
|
||||
if (!foundContent) {
|
||||
rule.prepend(postcss.decl({ prop: 'content', value: '""' }))
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
addVariant(
|
||||
'after',
|
||||
transformAllSelectors(
|
||||
(selector) => {
|
||||
return updateAllClasses(selector, (className, { withPseudo }) => {
|
||||
return withPseudo(`after${config('separator')}${className}`, '::after')
|
||||
})
|
||||
},
|
||||
{
|
||||
withRule: (rule) => {
|
||||
let foundContent = false
|
||||
rule.walkDecls('content', () => {
|
||||
foundContent = true
|
||||
})
|
||||
if (!foundContent) {
|
||||
rule.prepend(postcss.decl({ prop: 'content', value: '""' }))
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
let pseudoVariants = [
|
||||
['first', 'first-child'],
|
||||
['last', 'last-child'],
|
||||
|
|
@ -35,7 +79,7 @@ export default {
|
|||
addVariant(
|
||||
variantName,
|
||||
transformAllClasses((className, { withPseudo }) => {
|
||||
return withPseudo(`${variantName}${config('separator')}${className}`, state)
|
||||
return withPseudo(`${variantName}${config('separator')}${className}`, `:${state}`)
|
||||
})
|
||||
)
|
||||
}
|
||||
|
|
@ -95,11 +139,13 @@ export default {
|
|||
(className) => {
|
||||
return `motion-safe${config('separator')}${className}`
|
||||
},
|
||||
() =>
|
||||
postcss.atRule({
|
||||
name: 'media',
|
||||
params: '(prefers-reduced-motion: no-preference)',
|
||||
})
|
||||
{
|
||||
wrap: () =>
|
||||
postcss.atRule({
|
||||
name: 'media',
|
||||
params: '(prefers-reduced-motion: no-preference)',
|
||||
}),
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
|
|
@ -109,11 +155,13 @@ export default {
|
|||
(className) => {
|
||||
return `motion-reduce${config('separator')}${className}`
|
||||
},
|
||||
() =>
|
||||
postcss.atRule({
|
||||
name: 'media',
|
||||
params: '(prefers-reduced-motion: reduce)',
|
||||
})
|
||||
{
|
||||
wrap: () =>
|
||||
postcss.atRule({
|
||||
name: 'media',
|
||||
params: '(prefers-reduced-motion: reduce)',
|
||||
}),
|
||||
}
|
||||
)
|
||||
)
|
||||
},
|
||||
|
|
@ -142,11 +190,13 @@ export default {
|
|||
(className) => {
|
||||
return `dark${config('separator')}${className}`
|
||||
},
|
||||
() =>
|
||||
postcss.atRule({
|
||||
name: 'media',
|
||||
params: '(prefers-color-scheme: dark)',
|
||||
})
|
||||
{
|
||||
wrap: () =>
|
||||
postcss.atRule({
|
||||
name: 'media',
|
||||
params: '(prefers-color-scheme: dark)',
|
||||
}),
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
@ -162,7 +212,7 @@ export default {
|
|||
(className) => {
|
||||
return `${screen}${config('separator')}${className}`
|
||||
},
|
||||
() => postcss.atRule({ name: 'media', params: query })
|
||||
{ wrap: () => postcss.atRule({ name: 'media', params: query }) }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
5
src/plugins/content.js
Normal file
5
src/plugins/content.js
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
import createUtilityPlugin from '../util/createUtilityPlugin'
|
||||
|
||||
export default function () {
|
||||
return createUtilityPlugin('content')
|
||||
}
|
||||
|
|
@ -161,3 +161,5 @@ export { default as transitionProperty } from './transitionProperty'
|
|||
export { default as transitionDelay } from './transitionDelay'
|
||||
export { default as transitionDuration } from './transitionDuration'
|
||||
export { default as transitionTimingFunction } from './transitionTimingFunction'
|
||||
|
||||
export { default as content } from './content'
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ export function updateAllClasses(selectors, updateClass) {
|
|||
selectors.walkClasses((sel) => {
|
||||
let updatedClass = updateClass(sel.value, {
|
||||
withPseudo(className, pseudo) {
|
||||
sel.parent.insertAfter(sel, selectorParser.pseudo({ value: `:${pseudo}` }))
|
||||
sel.parent.insertAfter(sel, selectorParser.pseudo({ value: `${pseudo}` }))
|
||||
return className
|
||||
},
|
||||
})
|
||||
|
|
@ -36,7 +36,7 @@ export function updateLastClasses(selectors, updateClass) {
|
|||
|
||||
let updatedClass = updateClass(lastClass.value, {
|
||||
withPseudo(className, pseudo) {
|
||||
lastClass.parent.insertAfter(lastClass, selectorParser.pseudo({ value: `:${pseudo}` }))
|
||||
lastClass.parent.insertAfter(lastClass, selectorParser.pseudo({ value: `${pseudo}` }))
|
||||
return className
|
||||
},
|
||||
})
|
||||
|
|
@ -51,11 +51,14 @@ export function updateLastClasses(selectors, updateClass) {
|
|||
return result
|
||||
}
|
||||
|
||||
export function transformAllSelectors(transformSelector, wrap = null) {
|
||||
export function transformAllSelectors(transformSelector, { wrap, withRule } = {}) {
|
||||
return ({ container }) => {
|
||||
container.walkRules((rule) => {
|
||||
let transformed = rule.selector.split(',').map(transformSelector).join(',')
|
||||
rule.selector = transformed
|
||||
if (withRule) {
|
||||
withRule(rule)
|
||||
}
|
||||
return rule
|
||||
})
|
||||
|
||||
|
|
@ -67,23 +70,35 @@ export function transformAllSelectors(transformSelector, wrap = null) {
|
|||
}
|
||||
}
|
||||
|
||||
export function transformAllClasses(transformClass) {
|
||||
export function transformAllClasses(transformClass, { wrap, withRule } = {}) {
|
||||
return ({ container }) => {
|
||||
container.walkRules((rule) => {
|
||||
let selector = rule.selector
|
||||
let variantSelector = updateAllClasses(selector, transformClass)
|
||||
rule.selector = variantSelector
|
||||
if (withRule) {
|
||||
withRule(rule)
|
||||
}
|
||||
return rule
|
||||
})
|
||||
|
||||
if (wrap) {
|
||||
let wrapper = wrap()
|
||||
wrapper.append(container.nodes)
|
||||
container.append(wrapper)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function transformLastClasses(transformClass, wrap = null) {
|
||||
export function transformLastClasses(transformClass, { wrap, withRule } = {}) {
|
||||
return ({ container }) => {
|
||||
container.walkRules((rule) => {
|
||||
let selector = rule.selector
|
||||
let variantSelector = updateLastClasses(selector, transformClass)
|
||||
rule.selector = variantSelector
|
||||
if (withRule) {
|
||||
withRule(rule)
|
||||
}
|
||||
return rule
|
||||
})
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue