Fix support for declaration fallbacks in plugins (#14265)

This PR fixes support for "fallback" values for declarations in plugins.

A plugin using `addUtilities`, `matchUtilities`, `addComponents`, etc…
should be able to specify "fallback" values for declarations by passing
an array as the value of a declaration however this does not currently
work in v4 (but it does in v3):

```js
export default {
  plugins: [
    function ({ addUtilities }) {
      addUtilities({
        '.outlined': {
          outline: ['1px solid ButtonText', '1px auto -webkit-focus-ring-color'],
        },
      })
    },
  ],
};
```

After this PR the candidate `outlined` will now produce the following
CSS — like it does in v3:

```css
.outlined {
  outline: 1px solid ButtonText;
  outline: 1px auto -webkit-focus-ring-color;
}
```
This commit is contained in:
Jordan Pittman 2024-08-27 06:18:53 -04:00 committed by GitHub
parent f5499aac95
commit fa8253e42a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 39 additions and 1 deletions

View File

@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Correctly merge tuple values when using the plugin API ([#14260](https://github.com/tailwindlabs/tailwindcss/pull/14260))
- Handle arrays in the CSS `theme()` function when using plugins ([#14262](https://github.com/tailwindlabs/tailwindcss/pull/14262))
- Fix fallback values when using the CSS `theme()` function ([#14262](https://github.com/tailwindlabs/tailwindcss/pull/14262))
- Fix support for declaration fallbacks in plugins ([#14265](https://github.com/tailwindlabs/tailwindcss/pull/14265))
## [4.0.0-alpha.20] - 2024-08-23

View File

@ -976,6 +976,35 @@ describe('addUtilities()', () => {
`)
})
test('utilities can use arrays for fallback declaration values', async () => {
let compiled = await compile(
css`
@plugin "my-plugin";
@tailwind utilities;
`,
{
async loadPlugin() {
return ({ addUtilities }: PluginAPI) => {
addUtilities([
{
'.outlined': {
outline: ['1px solid ButtonText', '1px auto -webkit-focus-ring-color'],
},
},
])
}
},
},
)
expect(optimizeCss(compiled.build(['outlined'])).trim()).toMatchInlineSnapshot(`
".outlined {
outline: 1px solid buttontext;
outline: 1px auto -webkit-focus-ring-color;
}"
`)
})
test('camel case properties are converted to kebab-case', async () => {
let compiled = await compile(
css`

View File

@ -290,7 +290,7 @@ function buildPluginApi(
return api
}
export type CssInJs = { [key: string]: string | CssInJs | CssInJs[] }
export type CssInJs = { [key: string]: string | string[] | CssInJs | CssInJs[] }
function objectToAst(rules: CssInJs | CssInJs[]): AstNode[] {
let ast: AstNode[] = []
@ -310,6 +310,14 @@ function objectToAst(rules: CssInJs | CssInJs[]): AstNode[] {
ast.push(decl(name, String(value)))
}
} else if (Array.isArray(value)) {
for (let item of value) {
if (typeof item === 'string') {
ast.push(decl(name, item))
} else {
ast.push(rule(name, objectToAst(item)))
}
}
} else if (value !== null) {
ast.push(rule(name, objectToAst(value)))
}