Skip to content

Commit

Permalink
feat(recipes): change className to be optional (#2715)
Browse files Browse the repository at this point in the history
  • Loading branch information
astahmer authored Jul 6, 2024
1 parent 933eef8 commit ec64819
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 5 deletions.
25 changes: 25 additions & 0 deletions .changeset/pretty-cameras-exist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
'@pandacss/parser': patch
'@pandacss/core': patch
'@pandacss/node': patch
---

Change recipes `className` to be optional, both for `recipes` and `slotRecipes`, with a fallback to its name.

```ts
import { defineConfig } from '@pandacss/core'

export default defineConfig({
recipes: {
button: {
className: 'button', // 👈 was mandatory, is now optional
variants: {
size: {
sm: { padding: '2', borderRadius: 'sm' },
md: { padding: '4', borderRadius: 'md' },
},
},
},
},
})
```
1 change: 1 addition & 0 deletions packages/core/__tests__/recipe.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ describe('recipe ruleset', () => {
expect(createGeneratorContext().recipes.details.find((r) => r.baseName === 'buttonStyle')).toMatchInlineSnapshot(`
{
"baseName": "buttonStyle",
"className": "buttonStyle",
"config": {
"base": {
"&:is(:hover, [data-hover])": {
Expand Down
1 change: 1 addition & 0 deletions packages/core/__tests__/slot-recipe.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ describe('slot recipe ruleset', () => {
expect(createGeneratorContext().recipes.details.find((r) => r.baseName === 'checkbox')).toMatchInlineSnapshot(`
{
"baseName": "checkbox",
"className": "checkbox",
"config": {
"base": {
"control": {
Expand Down
8 changes: 5 additions & 3 deletions packages/core/src/recipes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,11 @@ export class Recipes {
}

const match = createRegex(jsx)
const className = recipe.className ?? name

sharedState.nodes.set(name, {
...this.getNames(name),
className,
jsx,
type: 'recipe' as const,
variantKeys,
Expand Down Expand Up @@ -211,7 +213,6 @@ export class Recipes {

normalize = (name: string, config: RecipeConfig) => {
const {
className,
jsx = [capitalize(name)],
base = {},
variants = {},
Expand All @@ -221,6 +222,7 @@ export class Recipes {
staticCss = [],
} = config

const className = config.className ?? name
const recipe: Required<RecipeConfig> = {
...config,
deprecated: config.deprecated == null ? false : config.deprecated,
Expand All @@ -237,12 +239,12 @@ export class Recipes {
recipe.base = transformStyles(this.context, base, name)

sharedState.styles.set(name, recipe.base)
sharedState.classNames.set(name, className)
sharedState.classNames.set(name, recipe.className)

for (const [key, variant] of Object.entries(variants)) {
for (const [variantKey, styles] of Object.entries(variant)) {
const propKey = this.getPropKey(name, key, variantKey)
const className = this.getClassName(config.className, key, variantKey)
const className = this.getClassName(recipe.className, key, variantKey)

const styleObject = transformStyles(this.context, styles, className)

Expand Down
7 changes: 5 additions & 2 deletions packages/core/src/style-decoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,10 +208,13 @@ export class StyleDecoder {
const recipeConfig = this.context.recipes.getConfig(recipeName)
if (!recipeConfig) return

const recipeNode = this.context.recipes.getRecipe(recipeName)
if (!recipeNode) return

const className =
'slots' in recipeConfig && slot
? this.context.recipes.getSlotKey(recipeConfig.className, slot)
: recipeConfig.className
? this.context.recipes.getSlotKey(recipeNode.className, slot)
: recipeNode.className

const cached = this.recipe_base_cache.get(className)
if (cached) return cached
Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ export interface RecipeNode {
* The name of the recipe
*/
baseName: string
/**
* The class name of the recipe. Defaults to the baseName if not specified.
*/
className: string
/**
* Discriminant
*/
Expand Down
93 changes: 93 additions & 0 deletions packages/parser/__tests__/output.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3887,4 +3887,97 @@ describe('extract to css output pipeline', () => {
}"
`)
})

test('recipes default className based on key', () => {
const code = `
import { testRecipe } from "styled-system/recipes";
export const App = () => {
return <div className={testRecipe()} />
}
`
const result = parseAndExtract(code, {
theme: {
extend: {
recipes: {
testRecipe: {
base: {
display: 'flex',
},
},
},
},
},
})
expect(result.json).toMatchInlineSnapshot(`
[
{
"data": [
{},
],
"name": "testRecipe",
"type": "recipe",
},
]
`)

expect(result.css).toMatchInlineSnapshot(`
"@layer recipes {
@layer _base {
.testRecipe {
display: flex;
}
}
}"
`)
})

test('slotRecipes default className based on key', () => {
const code = `
import { testSlotRecipe } from "styled-system/recipes";
export const App = () => {
return <div className={testSlotRecipe()} />
}
`
const result = parseAndExtract(code, {
theme: {
extend: {
slotRecipes: {
testSlotRecipe: {
slots: ['root'],
base: {
root: {
display: 'flex',
},
},
},
},
},
},
})
expect(result.json).toMatchInlineSnapshot(`
[
{
"data": [
{},
],
"name": "testSlotRecipe",
"type": "recipe",
},
]
`)

expect(result.css).toMatchInlineSnapshot(`
"@layer recipes.slots {
@layer _base {
.testSlotRecipe__root {
display: flex;
}
}
}"
`)
})
})

0 comments on commit ec64819

Please sign in to comment.