Migrate static plugins with options to CSS (#14700)
This PR extends our JS configuration to CSS migration by also allowing `plugins` with options.
An example of such config would be:
```js
import { type Config } from 'tailwindcss'
import myPlugin from "./myPlugin";
export default {
plugins: [
myPlugin({
class: "tw",
}),
],
} satisfies Config;
```
If the option object contains only values allowed in our CSS API, we can convert this to CSS entirely:
```css
@plugin './myPlugin' {
class: 'tw';
}
```
This commit is contained in:
parent
3e7695fb2c
commit
3da49f9837
6 changed files with 78 additions and 10 deletions
|
|
@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
- Nothing yet!
|
||||
### Added
|
||||
|
||||
- _Upgrade (experimental)_: Migrate `plugins` with options to CSS ([#14700](https://github.com/tailwindlabs/tailwindcss/pull/14700))
|
||||
|
||||
## [4.0.0-alpha.28] - 2024-10-17
|
||||
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ test(
|
|||
|
||||
--font-family-sans: Inter, system-ui, sans-serif;
|
||||
--font-family-display: Cabinet Grotesk, ui-sans-serif, system-ui, sans-serif,
|
||||
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
||||
|
||||
--radius-4xl: 2rem;
|
||||
|
||||
|
|
@ -155,14 +155,33 @@ test(
|
|||
import customPlugin from './custom-plugin'
|
||||
|
||||
export default {
|
||||
plugins: [typography, customPlugin],
|
||||
plugins: [
|
||||
typography,
|
||||
customPlugin({
|
||||
'is-null': null,
|
||||
'is-true': true,
|
||||
'is-false': false,
|
||||
'is-int': 1234567,
|
||||
'is-float': 1.35,
|
||||
'is-sci': 1.35e-5,
|
||||
'is-str-null': 'null',
|
||||
'is-str-true': 'true',
|
||||
'is-str-false': 'false',
|
||||
'is-str-int': '1234567',
|
||||
'is-str-float': '1.35',
|
||||
'is-str-sci': '1.35e-5',
|
||||
'is-arr': ['foo', 'bar'],
|
||||
'is-arr-mixed': [null, true, false, 1234567, 1.35, 'foo', 'bar', 'true'],
|
||||
}),
|
||||
],
|
||||
} satisfies Config
|
||||
`,
|
||||
'custom-plugin.js': ts`
|
||||
export default function ({ addVariant }) {
|
||||
import plugin from 'tailwindcss/plugin'
|
||||
export default plugin.withOptions((_options) => ({ addVariant }) => {
|
||||
addVariant('inverted', '@media (inverted-colors: inverted)')
|
||||
addVariant('hocus', ['&:focus', '&:hover'])
|
||||
}
|
||||
})
|
||||
`,
|
||||
'src/input.css': css`
|
||||
@tailwind base;
|
||||
|
|
@ -180,7 +199,22 @@ test(
|
|||
@import 'tailwindcss';
|
||||
|
||||
@plugin '@tailwindcss/typography';
|
||||
@plugin '../custom-plugin';
|
||||
@plugin '../custom-plugin' {
|
||||
is-null: null;
|
||||
is-true: true;
|
||||
is-false: false;
|
||||
is-int: 1234567;
|
||||
is-float: 1.35;
|
||||
is-sci: 0.0000135;
|
||||
is-str-null: 'null';
|
||||
is-str-true: 'true';
|
||||
is-str-false: 'false';
|
||||
is-str-int: '1234567';
|
||||
is-str-float: '1.35';
|
||||
is-str-sci: '1.35e-5';
|
||||
is-arr: 'foo', 'bar';
|
||||
is-arr-mixed: null, true, false, 1234567, 1.35, 'foo', 'bar', 'true';
|
||||
}
|
||||
"
|
||||
`)
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,15 @@ export function formatNodes(): Plugin {
|
|||
// Format the nodes
|
||||
await Promise.all(
|
||||
nodesToFormat.map(async (node) => {
|
||||
node.replaceWith(parse(await format(node.toString(), { parser: 'css', semi: true })))
|
||||
node.replaceWith(
|
||||
parse(
|
||||
await format(node.toString(), {
|
||||
parser: 'css',
|
||||
semi: true,
|
||||
singleQuote: true,
|
||||
}),
|
||||
),
|
||||
)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -413,7 +413,7 @@ it('should migrate classes with attribute selectors', async () => {
|
|||
`),
|
||||
).toMatchInlineSnapshot(`
|
||||
"@utility no-scrollbar {
|
||||
&[data-checked=""] {
|
||||
&[data-checked=''] {
|
||||
display: none;
|
||||
}
|
||||
}"
|
||||
|
|
|
|||
|
|
@ -63,7 +63,27 @@ export function migrateConfig(
|
|||
plugin.path[0] === '.'
|
||||
? relativeToStylesheet(sheet, path.resolve(plugin.base, plugin.path))
|
||||
: plugin.path
|
||||
css += `@plugin '${relative}';\n`
|
||||
|
||||
if (plugin.options === null) {
|
||||
css += `@plugin '${relative}';\n`
|
||||
} else {
|
||||
css += `@plugin '${relative}' {\n`
|
||||
for (let [property, value] of Object.entries(plugin.options)) {
|
||||
let cssValue = ''
|
||||
if (typeof value === 'string') {
|
||||
cssValue = quoteString(value)
|
||||
} else if (Array.isArray(value)) {
|
||||
cssValue = value
|
||||
.map((v) => (typeof v === 'string' ? quoteString(v) : '' + v))
|
||||
.join(', ')
|
||||
} else {
|
||||
cssValue = '' + value
|
||||
}
|
||||
|
||||
css += ` ${property}: ${cssValue};\n`
|
||||
}
|
||||
css += '}\n'
|
||||
}
|
||||
}
|
||||
if (jsConfigMigration.plugins.length > 0) {
|
||||
css = css + '\n'
|
||||
|
|
@ -149,3 +169,7 @@ function relativeToStylesheet(sheet: Stylesheet, absolute: string) {
|
|||
// glob.
|
||||
return normalizePath(relative)
|
||||
}
|
||||
|
||||
function quoteString(value: string): string {
|
||||
return `'${value.replace(/\\/g, '\\\\').replace(/'/g, "\\'")}'`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ export type JSConfigMigration =
|
|||
// Could not convert the config file, need to inject it as-is in a @config directive
|
||||
null | {
|
||||
sources: { base: string; pattern: string }[]
|
||||
plugins: { base: string; path: string }[]
|
||||
plugins: { base: string; path: string; options: null | StaticPluginOptions }[]
|
||||
css: string
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue