From 4576a60d0849a2fc5d9fbfb9f01543f66f22d7ac Mon Sep 17 00:00:00 2001
From: Alexandre Stahmer <47224540+astahmer@users.noreply.github.com>
Date: Sun, 10 Mar 2024 03:55:48 +0100
Subject: [PATCH] fix: remove extraneous classes on nested styled composition
(#2341)
* fix: remove extraneous classes on nested styled composition
* chore: add changeset
---
.changeset/few-dragons-retire.md | 28 +++++++++++++++++++
.../preact-jsx/jsx.string-literal.ts | 11 ++++----
.../generator/src/artifacts/preact-jsx/jsx.ts | 7 +++--
.../artifacts/qwik-jsx/jsx.string-literal.ts | 17 +++++------
.../generator/src/artifacts/qwik-jsx/jsx.ts | 7 +++--
.../artifacts/react-jsx/jsx.string-literal.ts | 15 +++++-----
.../generator/src/artifacts/react-jsx/jsx.ts | 7 +++--
packages/studio/styled-system/jsx/factory.mjs | 7 +++--
.../frameworks/preact.styled-factory.test.tsx | 4 +--
.../frameworks/qwik.styled-factory.test.tsx | 4 +--
10 files changed, 71 insertions(+), 36 deletions(-)
create mode 100644 .changeset/few-dragons-retire.md
diff --git a/.changeset/few-dragons-retire.md b/.changeset/few-dragons-retire.md
new file mode 100644
index 000000000..73f81cbc8
--- /dev/null
+++ b/.changeset/few-dragons-retire.md
@@ -0,0 +1,28 @@
+---
+'@pandacss/generator': patch
+'@pandacss/studio': patch
+---
+
+Fix nested `styled` factory composition
+
+```tsx
+import { styled } from '../styled-system/jsx'
+
+const BasicBox = styled('div', { base: { fontSize: '10px' } })
+const ExtendedBox1 = styled(BasicBox, { base: { fontSize: '20px' } })
+const ExtendedBox2 = styled(ExtendedBox1, { base: { fontSize: '30px' } })
+
+export const App = () => {
+ return (
+ <>
+ {/* ✅ fs_10px */}
+ text1
+ {/* ✅ fs_20px */}
+ text2
+ {/* BEFORE: ❌ fs_10px fs_30px */}
+ {/* NOW: ✅ fs_30px */}
+ text3
+ >
+ )
+}
+```
diff --git a/packages/generator/src/artifacts/preact-jsx/jsx.string-literal.ts b/packages/generator/src/artifacts/preact-jsx/jsx.string-literal.ts
index 2cd955270..ba798b93a 100644
--- a/packages/generator/src/artifacts/preact-jsx/jsx.string-literal.ts
+++ b/packages/generator/src/artifacts/preact-jsx/jsx.string-literal.ts
@@ -12,12 +12,13 @@ export function generatePreactJsxStringLiteralFactory(ctx: Context) {
${ctx.file.import('css, cx', '../css/index')}
function createStyledFn(Dynamic) {
+ const __base__ = Dynamic.__base__ || Dynamic
return function styledFn(template) {
const styles = css.raw(template)
const ${componentName} = /* @__PURE__ */ forwardRef(function ${componentName}(props, ref) {
- const { as: Element = Dynamic.__base__ || Dynamic, ...elementProps } = props
-
+ const { as: Element = __base__, ...elementProps } = props
+
function classes() {
return cx(css(Dynamic.__styles__, styles), elementProps.className)
}
@@ -29,11 +30,11 @@ export function generatePreactJsxStringLiteralFactory(ctx: Context) {
})
})
- const name = getDisplayName(Dynamic)
-
+ const name = getDisplayName(__base__)
+
${componentName}.displayName = \`${factoryName}.\${name}\`
${componentName}.__styles__ = styles
- ${componentName}.__base__ = Dynamic
+ ${componentName}.__base__ = __base__
return ${componentName}
}
diff --git a/packages/generator/src/artifacts/preact-jsx/jsx.ts b/packages/generator/src/artifacts/preact-jsx/jsx.ts
index 3423ff0f8..8bf31217a 100644
--- a/packages/generator/src/artifacts/preact-jsx/jsx.ts
+++ b/packages/generator/src/artifacts/preact-jsx/jsx.ts
@@ -30,9 +30,10 @@ export function generatePreactJsxFactory(ctx: Context) {
const __cvaFn__ = composeCvaFn(Dynamic.__cva__, cvaFn)
const __shouldForwardProps__ = composeShouldForwardProps(Dynamic, shouldForwardProp)
+ const __base__ = Dynamic.__base__ || Dynamic
const ${componentName} = /* @__PURE__ */ forwardRef(function ${componentName}(props, ref) {
- const { as: Element = Dynamic.__base__ || Dynamic, children, ...restProps } = props
+ const { as: Element = __base__, children, ...restProps } = props
const combinedProps = useMemo(() => Object.assign({}, defaultProps, restProps), [restProps])
@@ -64,11 +65,11 @@ export function generatePreactJsxFactory(ctx: Context) {
}, combinedProps.children ?? children)
})
- const name = getDisplayName(Dynamic)
+ const name = getDisplayName(__base__)
${componentName}.displayName = \`${factoryName}.\${name}\`
${componentName}.__cva__ = __cvaFn__
- ${componentName}.__base__ = Dynamic
+ ${componentName}.__base__ = __base__
${componentName}.__shouldForwardProps__ = shouldForwardProp
return ${componentName}
diff --git a/packages/generator/src/artifacts/qwik-jsx/jsx.string-literal.ts b/packages/generator/src/artifacts/qwik-jsx/jsx.string-literal.ts
index 60f1b2543..88c30ac68 100644
--- a/packages/generator/src/artifacts/qwik-jsx/jsx.string-literal.ts
+++ b/packages/generator/src/artifacts/qwik-jsx/jsx.string-literal.ts
@@ -11,14 +11,15 @@ export function generateQwikJsxStringLiteralFactory(ctx: Context) {
${ctx.file.import('css, cx', '../css/index')}
function createStyledFn(Dynamic) {
+ const __base__ = Dynamic.__base__ || Dynamic
return function styledFn(template) {
const styles = css.raw(template)
-
+
const ${componentName} = (props) => {
- const { as: Element = Dynamic.__base__ || Dynamic, ...elementProps } = props
-
+ const { as: Element = __base__, ...elementProps } = props
+
function classes() {
- return cx(css(Dynamic.__styles__, styles), elementProps.className)
+ return cx(css(__base__.__styles__, styles), elementProps.className)
}
return h(Element, {
@@ -27,12 +28,12 @@ export function generateQwikJsxStringLiteralFactory(ctx: Context) {
})
}
- const name = getDisplayName(Dynamic)
-
+ const name = getDisplayName(__base__)
+
${componentName}.displayName = \`${factoryName}.\${name}\`
${componentName}.__styles__ = styles
- ${componentName}.__base__ = Dynamic
-
+ ${componentName}.__base__ = __base__
+
return ${componentName}
}
}
diff --git a/packages/generator/src/artifacts/qwik-jsx/jsx.ts b/packages/generator/src/artifacts/qwik-jsx/jsx.ts
index 71c2e94f0..7335b0fcd 100644
--- a/packages/generator/src/artifacts/qwik-jsx/jsx.ts
+++ b/packages/generator/src/artifacts/qwik-jsx/jsx.ts
@@ -28,9 +28,10 @@ export function generateQwikJsxFactory(ctx: Context) {
const __cvaFn__ = composeCvaFn(Dynamic.__cva__, cvaFn)
const __shouldForwardProps__ = composeShouldForwardProps(Dynamic, shouldForwardProp)
+ const __base__ = Dynamic.__base__ || Dynamic
const ${componentName} = function ${componentName}(props) {
- const { as: Element = Dynamic.__base__ || Dynamic, children, className, ...restProps } = props
+ const { as: Element = __base__, children, className, ...restProps } = props
const combinedProps = Object.assign({}, defaultProps, restProps)
@@ -61,11 +62,11 @@ export function generateQwikJsxFactory(ctx: Context) {
}, combinedProps.children ?? children)
}
- const name = getDisplayName(Dynamic)
+ const name = getDisplayName(__base__)
${componentName}.displayName = \`${factoryName}.\${name}\`
${componentName}.__cva__ = __cvaFn__
- ${componentName}.__base__ = Dynamic
+ ${componentName}.__base__ = __base__
${componentName}.__shouldForwardProps__ = shouldForwardProp
return ${componentName}
diff --git a/packages/generator/src/artifacts/react-jsx/jsx.string-literal.ts b/packages/generator/src/artifacts/react-jsx/jsx.string-literal.ts
index 8b85ca722..44276d6d7 100644
--- a/packages/generator/src/artifacts/react-jsx/jsx.string-literal.ts
+++ b/packages/generator/src/artifacts/react-jsx/jsx.string-literal.ts
@@ -11,14 +11,15 @@ export function generateReactJsxStringLiteralFactory(ctx: Context) {
${ctx.file.import('css, cx', '../css/index')}
function createStyledFn(Dynamic) {
+ const __base__ = Dynamic.__base__ || Dynamic
return function styledFn(template) {
const styles = css.raw(template)
const ${componentName} = /* @__PURE__ */ forwardRef(function ${componentName}(props, ref) {
- const { as: Element = Dynamic.__base__ || Dynamic, ...elementProps } = props
-
+ const { as: Element = __base__, ...elementProps } = props
+
function classes() {
- return cx(css(Dynamic.__styles__, styles), elementProps.className)
+ return cx(css(__base__.__styles__, styles), elementProps.className)
}
return createElement(Element, {
@@ -28,12 +29,12 @@ export function generateReactJsxStringLiteralFactory(ctx: Context) {
})
})
- const name = getDisplayName(Dynamic)
-
+ const name = getDisplayName(__base__)
+
${componentName}.displayName = \`${factoryName}.\${name}\`
${componentName}.__styles__ = styles
- ${componentName}.__base__ = Dynamic
-
+ ${componentName}.__base__ = __base__
+
return ${componentName}
}
}
diff --git a/packages/generator/src/artifacts/react-jsx/jsx.ts b/packages/generator/src/artifacts/react-jsx/jsx.ts
index dd2f8c260..31f5e1501 100644
--- a/packages/generator/src/artifacts/react-jsx/jsx.ts
+++ b/packages/generator/src/artifacts/react-jsx/jsx.ts
@@ -28,9 +28,10 @@ export function generateReactJsxFactory(ctx: Context) {
const __cvaFn__ = composeCvaFn(Dynamic.__cva__, cvaFn)
const __shouldForwardProps__ = composeShouldForwardProps(Dynamic, shouldForwardProp)
+ const __base__ = Dynamic.__base__ || Dynamic
const ${componentName} = /* @__PURE__ */ forwardRef(function ${componentName}(props, ref) {
- const { as: Element = Dynamic.__base__ || Dynamic, children, ...restProps } = props
+ const { as: Element = __base__, children, ...restProps } = props
const combinedProps = useMemo(() => Object.assign({}, defaultProps, restProps), [restProps])
@@ -61,11 +62,11 @@ export function generateReactJsxFactory(ctx: Context) {
}, combinedProps.children ?? children)
})
- const name = getDisplayName(Dynamic)
+ const name = getDisplayName(__base__)
${componentName}.displayName = \`${factoryName}.\${name}\`
${componentName}.__cva__ = __cvaFn__
- ${componentName}.__base__ = Dynamic
+ ${componentName}.__base__ = __base__
${componentName}.__shouldForwardProps__ = shouldForwardProp
return ${componentName}
diff --git a/packages/studio/styled-system/jsx/factory.mjs b/packages/studio/styled-system/jsx/factory.mjs
index f47df1a7d..89afe1581 100644
--- a/packages/studio/styled-system/jsx/factory.mjs
+++ b/packages/studio/styled-system/jsx/factory.mjs
@@ -17,9 +17,10 @@ function styledFn(Dynamic, configOrCva = {}, options = {}) {
const __cvaFn__ = composeCvaFn(Dynamic.__cva__, cvaFn)
const __shouldForwardProps__ = composeShouldForwardProps(Dynamic, shouldForwardProp)
+ const __base__ = Dynamic.__base__ || Dynamic
const PandaComponent = /* @__PURE__ */ forwardRef(function PandaComponent(props, ref) {
- const { as: Element = Dynamic.__base__ || Dynamic, children, ...restProps } = props
+ const { as: Element = __base__, children, ...restProps } = props
const combinedProps = useMemo(() => Object.assign({}, defaultProps, restProps), [restProps])
@@ -50,11 +51,11 @@ function styledFn(Dynamic, configOrCva = {}, options = {}) {
}, combinedProps.children ?? children)
})
- const name = getDisplayName(Dynamic)
+ const name = getDisplayName(__base__)
PandaComponent.displayName = `panda.${name}`
PandaComponent.__cva__ = __cvaFn__
- PandaComponent.__base__ = Dynamic
+ PandaComponent.__base__ = __base__
PandaComponent.__shouldForwardProps__ = shouldForwardProp
return PandaComponent
diff --git a/sandbox/codegen/__tests__/frameworks/preact.styled-factory.test.tsx b/sandbox/codegen/__tests__/frameworks/preact.styled-factory.test.tsx
index a10defbe9..5ccf7c7dc 100644
--- a/sandbox/codegen/__tests__/frameworks/preact.styled-factory.test.tsx
+++ b/sandbox/codegen/__tests__/frameworks/preact.styled-factory.test.tsx
@@ -187,7 +187,7 @@ describe('styled factory - cva', () => {
const { firstChild } = container as HTMLElement
expect(firstChild).toMatchInlineSnapshot(`
@@ -201,7 +201,7 @@ describe('styled factory - cva', () => {
).container.firstChild,
).toMatchInlineSnapshot(`
diff --git a/sandbox/codegen/__tests__/frameworks/qwik.styled-factory.test.tsx b/sandbox/codegen/__tests__/frameworks/qwik.styled-factory.test.tsx
index 984137ca1..9154f32fc 100644
--- a/sandbox/codegen/__tests__/frameworks/qwik.styled-factory.test.tsx
+++ b/sandbox/codegen/__tests__/frameworks/qwik.styled-factory.test.tsx
@@ -199,7 +199,7 @@ describe('styled factory - cva', async () => {
,
)
const container = screen.querySelector('button')!
- expect(container.outerHTML).toMatchInlineSnapshot(`""`)
+ expect(container.outerHTML).toMatchInlineSnapshot(`""`)
const second = await createDOM()
await second.render(
@@ -208,7 +208,7 @@ describe('styled factory - cva', async () => {
,
)
const container2 = second.screen.querySelector('button')!
- expect(container2.outerHTML).toMatchInlineSnapshot(`""`)
+ expect(container2.outerHTML).toMatchInlineSnapshot(`""`)
})
test('html props', async () => {