From 4b47ae445b14271dffb28d0aba973b921758515b Mon Sep 17 00:00:00 2001 From: Hubert Bieszczad Date: Mon, 27 Jul 2026 08:25:28 +0200 Subject: [PATCH 1/3] fix: withUniwind remove className props on web after converting them --- packages/uniwind/src/hoc/withUniwind.tsx | 10 ++++-- .../tests/web/hoc/withUniwind.test.tsx | 33 ++++++++++++++----- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/packages/uniwind/src/hoc/withUniwind.tsx b/packages/uniwind/src/hoc/withUniwind.tsx index 533fc7fb..e1979007 100644 --- a/packages/uniwind/src/hoc/withUniwind.tsx +++ b/packages/uniwind/src/hoc/withUniwind.tsx @@ -20,8 +20,9 @@ export const withUniwind: WithUniwind = < ? withManualUniwind(Component, options) : withAutoUniwind(Component) -const withAutoUniwind = (Component: Component) => (props: AnyObject) => { +const withAutoUniwind = (Component: Component) => (originalProps: AnyObject) => { const uniwindContext = useUniwindContext() + const props = { ...originalProps } const { classNames, generatedProps } = Object.entries(props).reduce((acc, [propName, propValue]) => { if (isColorClassProperty(propName)) { @@ -45,6 +46,7 @@ const withAutoUniwind = (Component: Component) => (props: AnyObject) ? formatColor(color) : undefined acc.classNames += `${className} ` + delete props[propName] return acc } @@ -54,6 +56,7 @@ const withAutoUniwind = (Component: Component) => (props: AnyObject) acc.generatedProps[styleProp] ??= [] acc.generatedProps[styleProp][0] = { $$css: true, tailwind: propValue } + delete props[propName] return acc } @@ -61,6 +64,7 @@ const withAutoUniwind = (Component: Component) => (props: AnyObject) if (isStyleProperty(propName)) { acc.generatedProps[propName] ??= [] acc.generatedProps[propName][1] = propValue + delete props[propName] return acc } @@ -85,11 +89,13 @@ const withAutoUniwind = (Component: Component) => (props: AnyObject) ) } -const withManualUniwind = (Component: Component, options: Record) => (props: AnyObject) => { +const withManualUniwind = (Component: Component, options: Record) => (originalProps: AnyObject) => { const uniwindContext = useUniwindContext() + const props = { ...originalProps } const { generatedProps, classNames } = Object.entries(options).reduce((acc, [propName, option]) => { const className = props[option.fromClassName] + delete props[option.fromClassName] if (className === undefined) { return acc diff --git a/packages/uniwind/tests/web/hoc/withUniwind.test.tsx b/packages/uniwind/tests/web/hoc/withUniwind.test.tsx index 1e3511b9..0e784e13 100644 --- a/packages/uniwind/tests/web/hoc/withUniwind.test.tsx +++ b/packages/uniwind/tests/web/hoc/withUniwind.test.tsx @@ -20,7 +20,9 @@ describe('withUniwind', () => { }) test('[auto] Should map className to style', () => { - const AutoWithUniwind = withUniwind(Component) + ComponentWithSpy.mockClear() + + const AutoWithUniwind = withUniwind(ComponentWithSpy) const { getByTestId } = render( , @@ -30,6 +32,11 @@ describe('withUniwind', () => { expect(component).toBeInTheDocument() expect(component).toHaveClass('bg-red-500') + + const receivedProps = ComponentWithSpy.mock.calls[0][0] + + expect(receivedProps.style).toEqual([{ $$css: true, tailwind: 'bg-red-500' }]) + expect(receivedProps).not.toHaveProperty('className') }) test('[auto] Should map colorClassName to color', () => { @@ -43,7 +50,6 @@ describe('withUniwind', () => { render() expect(mockGetWebStyles).toHaveBeenCalledWith('accent-red-500', { - 'colorClassName': 'accent-red-500', 'testID': 'test-component', }, UNIWIND_CONTEXT_MOCK) @@ -51,6 +57,7 @@ describe('withUniwind', () => { expect(receivedProps).toHaveProperty('color') expect(receivedProps.color).toBe(TW_RED_500) + expect(receivedProps).not.toHaveProperty('colorClassName') }) test('[auto] Should add both inline style and className', () => { @@ -80,24 +87,31 @@ describe('withUniwind', () => { expect(receivedProps.color).toBe(TW_BLUE_500) }) - test('[manual] Should map testClassName to style', () => { - const ManualWithUniwind = withUniwind(Component, { + test('[manual] Should map className to style', () => { + ComponentWithSpy.mockClear() + + const ManualWithUniwind = withUniwind(ComponentWithSpy, { style: { - fromClassName: 'testClassName', + fromClassName: 'className', }, }) const { getByTestId } = render( - , + , ) const component = getByTestId('test-component') expect(component).toBeInTheDocument() expect(component).toHaveClass('bg-red-500') + + const receivedProps = ComponentWithSpy.mock.calls[0][0] + + expect(receivedProps.style).toEqual([{ $$css: true, tailwind: 'bg-red-500' }, undefined]) + expect(receivedProps).not.toHaveProperty('className') }) - test('[manual] Should map testClassName to color', () => { + test('[manual] Should map colorClassName to color', () => { const mockGetWebStyles = webCore.getWebStyles as jest.MockedFunction mockGetWebStyles.mockReturnValue({ fill: TW_RED_500 }) @@ -105,17 +119,18 @@ describe('withUniwind', () => { const ManualWithUniwind = withUniwind(ComponentWithSpy, { color: { - fromClassName: 'testClassName', + fromClassName: 'colorClassName', styleProperty: 'fill', }, }) - render() + render() const receivedProps = ComponentWithSpy.mock.calls[0][0] expect(receivedProps).toHaveProperty('color') expect(receivedProps.color).toBe(TW_RED_500) + expect(receivedProps).not.toHaveProperty('colorClassName') }) test('[manual] Should override colorClassName with inline color', () => { From b3625326a76d7e4bc9ba4e41d4fc52e76118eea9 Mon Sep 17 00:00:00 2001 From: Hubert Bieszczad Date: Mon, 27 Jul 2026 08:28:47 +0200 Subject: [PATCH 2/3] chore: rename to testClassNamne --- .../uniwind/tests/web/hoc/withUniwind.test.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/uniwind/tests/web/hoc/withUniwind.test.tsx b/packages/uniwind/tests/web/hoc/withUniwind.test.tsx index 0e784e13..721097f0 100644 --- a/packages/uniwind/tests/web/hoc/withUniwind.test.tsx +++ b/packages/uniwind/tests/web/hoc/withUniwind.test.tsx @@ -87,17 +87,17 @@ describe('withUniwind', () => { expect(receivedProps.color).toBe(TW_BLUE_500) }) - test('[manual] Should map className to style', () => { + test('[manual] Should map testClassName to style', () => { ComponentWithSpy.mockClear() const ManualWithUniwind = withUniwind(ComponentWithSpy, { style: { - fromClassName: 'className', + fromClassName: 'testClassName', }, }) const { getByTestId } = render( - , + , ) const component = getByTestId('test-component') @@ -108,10 +108,10 @@ describe('withUniwind', () => { const receivedProps = ComponentWithSpy.mock.calls[0][0] expect(receivedProps.style).toEqual([{ $$css: true, tailwind: 'bg-red-500' }, undefined]) - expect(receivedProps).not.toHaveProperty('className') + expect(receivedProps).not.toHaveProperty('testClassName') }) - test('[manual] Should map colorClassName to color', () => { + test('[manual] Should map testClassName to color', () => { const mockGetWebStyles = webCore.getWebStyles as jest.MockedFunction mockGetWebStyles.mockReturnValue({ fill: TW_RED_500 }) @@ -119,18 +119,18 @@ describe('withUniwind', () => { const ManualWithUniwind = withUniwind(ComponentWithSpy, { color: { - fromClassName: 'colorClassName', + fromClassName: 'testClassName', styleProperty: 'fill', }, }) - render() + render() const receivedProps = ComponentWithSpy.mock.calls[0][0] expect(receivedProps).toHaveProperty('color') expect(receivedProps.color).toBe(TW_RED_500) - expect(receivedProps).not.toHaveProperty('colorClassName') + expect(receivedProps).not.toHaveProperty('testClassName') }) test('[manual] Should override colorClassName with inline color', () => { From fba86dcbdedaecc6a663ad5c30d20c13299afd25 Mon Sep 17 00:00:00 2001 From: Hubert Bieszczad Date: Mon, 27 Jul 2026 12:36:54 +0200 Subject: [PATCH 3/3] chore: fixes --- packages/uniwind/src/hoc/withUniwind.tsx | 6 ++++-- packages/uniwind/tests/web/hoc/withUniwind.test.tsx | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/uniwind/src/hoc/withUniwind.tsx b/packages/uniwind/src/hoc/withUniwind.tsx index e1979007..29d78435 100644 --- a/packages/uniwind/src/hoc/withUniwind.tsx +++ b/packages/uniwind/src/hoc/withUniwind.tsx @@ -28,6 +28,8 @@ const withAutoUniwind = (Component: Component) => (originalProps: Any if (isColorClassProperty(propName)) { const colorProp = classToColor(propName) + delete props[propName] + if (props[colorProp] !== undefined) { return acc } @@ -46,7 +48,6 @@ const withAutoUniwind = (Component: Component) => (originalProps: Any ? formatColor(color) : undefined acc.classNames += `${className} ` - delete props[propName] return acc } @@ -94,7 +95,8 @@ const withManualUniwind = (Component: Component, options: Record { - const className = props[option.fromClassName] + // Read from original props because we're going to delete the prop from cloned props later + const className = originalProps[option.fromClassName] delete props[option.fromClassName] if (className === undefined) { diff --git a/packages/uniwind/tests/web/hoc/withUniwind.test.tsx b/packages/uniwind/tests/web/hoc/withUniwind.test.tsx index 721097f0..c7fdbd9d 100644 --- a/packages/uniwind/tests/web/hoc/withUniwind.test.tsx +++ b/packages/uniwind/tests/web/hoc/withUniwind.test.tsx @@ -85,6 +85,7 @@ describe('withUniwind', () => { expect(receivedProps).toHaveProperty('color') expect(receivedProps.color).toBe(TW_BLUE_500) + expect(receivedProps).not.toHaveProperty('colorClassName') }) test('[manual] Should map testClassName to style', () => { @@ -149,6 +150,7 @@ describe('withUniwind', () => { expect(receivedProps).toHaveProperty('color') expect(receivedProps.color).toBe(TW_BLUE_500) + expect(receivedProps).not.toHaveProperty('colorClassName') }) test('[manual] Should add both inline style and className', () => {