mirror of
https://github.com/tailwindlabs/tailwindcss.git
synced 2025-12-08 21:36:08 +00:00
Merge pull request #1268 from tailwindcss/plugin-function
Add new `plugin` and `plugin.withOptions` functions for creating plugins
This commit is contained in:
commit
293900a28c
@ -1,6 +1,8 @@
|
||||
import _ from 'lodash'
|
||||
import _postcss from 'postcss'
|
||||
import tailwind from '../src/index'
|
||||
import processPlugins from '../src/util/processPlugins'
|
||||
import createPlugin from '../src/util/createPlugin'
|
||||
|
||||
function css(nodes) {
|
||||
return _postcss.root({ nodes }).toString()
|
||||
@ -1287,3 +1289,284 @@ test('plugins can provide a config but no handler', () => {
|
||||
}
|
||||
`)
|
||||
})
|
||||
|
||||
test('plugins can be created using the `createPlugin` function', () => {
|
||||
const plugin = createPlugin(
|
||||
function({ addUtilities, theme, variants }) {
|
||||
const utilities = _.fromPairs(
|
||||
_.toPairs(theme('testPlugin')).map(([k, v]) => [`.test-${k}`, { testProperty: v }])
|
||||
)
|
||||
|
||||
addUtilities(utilities, variants('testPlugin'))
|
||||
},
|
||||
{
|
||||
theme: {
|
||||
testPlugin: {
|
||||
sm: '1rem',
|
||||
md: '2rem',
|
||||
lg: '3rem',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
testPlugin: ['responsive', 'hover'],
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
return _postcss([
|
||||
tailwind({
|
||||
corePlugins: [],
|
||||
theme: {
|
||||
screens: {
|
||||
sm: '400px',
|
||||
},
|
||||
},
|
||||
plugins: [plugin],
|
||||
}),
|
||||
])
|
||||
.process(
|
||||
`
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
`,
|
||||
{ from: undefined }
|
||||
)
|
||||
.then(result => {
|
||||
const expected = `
|
||||
.test-sm {
|
||||
test-property: 1rem
|
||||
}
|
||||
.test-md {
|
||||
test-property: 2rem
|
||||
}
|
||||
.test-lg {
|
||||
test-property: 3rem
|
||||
}
|
||||
.hover\\:test-sm:hover {
|
||||
test-property: 1rem
|
||||
}
|
||||
.hover\\:test-md:hover {
|
||||
test-property: 2rem
|
||||
}
|
||||
.hover\\:test-lg:hover {
|
||||
test-property: 3rem
|
||||
}
|
||||
|
||||
@media (min-width: 400px) {
|
||||
.sm\\:test-sm {
|
||||
test-property: 1rem
|
||||
}
|
||||
.sm\\:test-md {
|
||||
test-property: 2rem
|
||||
}
|
||||
.sm\\:test-lg {
|
||||
test-property: 3rem
|
||||
}
|
||||
.sm\\:hover\\:test-sm:hover {
|
||||
test-property: 1rem
|
||||
}
|
||||
.sm\\:hover\\:test-md:hover {
|
||||
test-property: 2rem
|
||||
}
|
||||
.sm\\:hover\\:test-lg:hover {
|
||||
test-property: 3rem
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
expect(result.css).toMatchCss(expected)
|
||||
})
|
||||
})
|
||||
|
||||
test('plugins with extra options can be created using the `createPlugin.withOptions` function', () => {
|
||||
const plugin = createPlugin.withOptions(
|
||||
function({ className }) {
|
||||
return function({ addUtilities, theme, variants }) {
|
||||
const utilities = _.fromPairs(
|
||||
_.toPairs(theme('testPlugin')).map(([k, v]) => [
|
||||
`.${className}-${k}`,
|
||||
{ testProperty: v },
|
||||
])
|
||||
)
|
||||
|
||||
addUtilities(utilities, variants('testPlugin'))
|
||||
}
|
||||
},
|
||||
function() {
|
||||
return {
|
||||
theme: {
|
||||
testPlugin: {
|
||||
sm: '1rem',
|
||||
md: '2rem',
|
||||
lg: '3rem',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
testPlugin: ['responsive', 'hover'],
|
||||
},
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
return _postcss([
|
||||
tailwind({
|
||||
corePlugins: [],
|
||||
theme: {
|
||||
screens: {
|
||||
sm: '400px',
|
||||
},
|
||||
},
|
||||
plugins: [plugin({ className: 'banana' })],
|
||||
}),
|
||||
])
|
||||
.process(
|
||||
`
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
`,
|
||||
{ from: undefined }
|
||||
)
|
||||
.then(result => {
|
||||
const expected = `
|
||||
.banana-sm {
|
||||
test-property: 1rem
|
||||
}
|
||||
.banana-md {
|
||||
test-property: 2rem
|
||||
}
|
||||
.banana-lg {
|
||||
test-property: 3rem
|
||||
}
|
||||
.hover\\:banana-sm:hover {
|
||||
test-property: 1rem
|
||||
}
|
||||
.hover\\:banana-md:hover {
|
||||
test-property: 2rem
|
||||
}
|
||||
.hover\\:banana-lg:hover {
|
||||
test-property: 3rem
|
||||
}
|
||||
|
||||
@media (min-width: 400px) {
|
||||
.sm\\:banana-sm {
|
||||
test-property: 1rem
|
||||
}
|
||||
.sm\\:banana-md {
|
||||
test-property: 2rem
|
||||
}
|
||||
.sm\\:banana-lg {
|
||||
test-property: 3rem
|
||||
}
|
||||
.sm\\:hover\\:banana-sm:hover {
|
||||
test-property: 1rem
|
||||
}
|
||||
.sm\\:hover\\:banana-md:hover {
|
||||
test-property: 2rem
|
||||
}
|
||||
.sm\\:hover\\:banana-lg:hover {
|
||||
test-property: 3rem
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
expect(result.css).toMatchCss(expected)
|
||||
})
|
||||
})
|
||||
|
||||
test('plugins created using `createPlugin.withOptions` do not need to be invoked if the user wants to use the default options', () => {
|
||||
const plugin = createPlugin.withOptions(
|
||||
function({ className } = { className: 'banana' }) {
|
||||
return function({ addUtilities, theme, variants }) {
|
||||
const utilities = _.fromPairs(
|
||||
_.toPairs(theme('testPlugin')).map(([k, v]) => [
|
||||
`.${className}-${k}`,
|
||||
{ testProperty: v },
|
||||
])
|
||||
)
|
||||
|
||||
addUtilities(utilities, variants('testPlugin'))
|
||||
}
|
||||
},
|
||||
function() {
|
||||
return {
|
||||
theme: {
|
||||
testPlugin: {
|
||||
sm: '1rem',
|
||||
md: '2rem',
|
||||
lg: '3rem',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
testPlugin: ['responsive', 'hover'],
|
||||
},
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
return _postcss([
|
||||
tailwind({
|
||||
corePlugins: [],
|
||||
theme: {
|
||||
screens: {
|
||||
sm: '400px',
|
||||
},
|
||||
},
|
||||
plugins: [plugin],
|
||||
}),
|
||||
])
|
||||
.process(
|
||||
`
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
`,
|
||||
{ from: undefined }
|
||||
)
|
||||
.then(result => {
|
||||
const expected = `
|
||||
.banana-sm {
|
||||
test-property: 1rem
|
||||
}
|
||||
.banana-md {
|
||||
test-property: 2rem
|
||||
}
|
||||
.banana-lg {
|
||||
test-property: 3rem
|
||||
}
|
||||
.hover\\:banana-sm:hover {
|
||||
test-property: 1rem
|
||||
}
|
||||
.hover\\:banana-md:hover {
|
||||
test-property: 2rem
|
||||
}
|
||||
.hover\\:banana-lg:hover {
|
||||
test-property: 3rem
|
||||
}
|
||||
|
||||
@media (min-width: 400px) {
|
||||
.sm\\:banana-sm {
|
||||
test-property: 1rem
|
||||
}
|
||||
.sm\\:banana-md {
|
||||
test-property: 2rem
|
||||
}
|
||||
.sm\\:banana-lg {
|
||||
test-property: 3rem
|
||||
}
|
||||
.sm\\:hover\\:banana-sm:hover {
|
||||
test-property: 1rem
|
||||
}
|
||||
.sm\\:hover\\:banana-md:hover {
|
||||
test-property: 2rem
|
||||
}
|
||||
.sm\\:hover\\:banana-lg:hover {
|
||||
test-property: 3rem
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
expect(result.css).toMatchCss(expected)
|
||||
})
|
||||
})
|
||||
|
||||
3
plugin.js
Normal file
3
plugin.js
Normal file
@ -0,0 +1,3 @@
|
||||
const createPlugin = require('./lib/util/createPlugin').default
|
||||
|
||||
module.exports = createPlugin
|
||||
21
src/util/createPlugin.js
Normal file
21
src/util/createPlugin.js
Normal file
@ -0,0 +1,21 @@
|
||||
function createPlugin(plugin, config) {
|
||||
return {
|
||||
handler: plugin,
|
||||
config,
|
||||
}
|
||||
}
|
||||
|
||||
createPlugin.withOptions = function(pluginFunction, configFunction) {
|
||||
const optionsFunction = function(options) {
|
||||
return {
|
||||
handler: pluginFunction(options),
|
||||
config: configFunction(options),
|
||||
}
|
||||
}
|
||||
|
||||
optionsFunction.__isOptionsFunction = true
|
||||
|
||||
return optionsFunction
|
||||
}
|
||||
|
||||
export default createPlugin
|
||||
@ -29,6 +29,10 @@ export default function(plugins, config) {
|
||||
const getConfigValue = (path, defaultValue) => _.get(config, path, defaultValue)
|
||||
|
||||
plugins.forEach(plugin => {
|
||||
if (plugin.__isOptionsFunction) {
|
||||
plugin = plugin()
|
||||
}
|
||||
|
||||
const handler = isFunction(plugin) ? plugin : _.get(plugin, 'handler', () => {})
|
||||
|
||||
handler({
|
||||
|
||||
@ -107,6 +107,9 @@ function extractPluginConfigs(configs) {
|
||||
}
|
||||
|
||||
plugins.forEach(plugin => {
|
||||
if (plugin.__isOptionsFunction) {
|
||||
plugin = plugin()
|
||||
}
|
||||
allConfigs = [...allConfigs, ...extractPluginConfigs([get(plugin, 'config', {})])]
|
||||
})
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user