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 () => {