Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions src/__tests__/native/className-with-style.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { render } from "@testing-library/react-native";
import { Text } from "react-native-css/components/Text";
import { registerCSS, testID } from "react-native-css/jest";

test("className with inline style props should coexist when different properties", () => {
registerCSS(`.text-red { color: red; }`);

const component = render(
<Text testID={testID} className="text-red" style={{ fontSize: 16 }} />,
).getByTestId(testID);

// Both className and style props should be applied as array
expect(component.props.style).toEqual([
{ color: "#f00" }, // Changed from "red" to "#f00"
{ fontSize: 16 },
]);
});

test("className with inline style props should favor inline when same property", () => {
registerCSS(`.text-red { color: red; }`);

const component = render(
<Text testID={testID} className="text-red" style={{ color: "blue" }} />,
).getByTestId(testID);

// When same property exists, inline style should win (not array)
expect(component.props.style).toEqual({ color: "blue" });
});

test("only className should not create array", () => {
registerCSS(`.text-red { color: red; }`);

const component = render(
<Text testID={testID} className="text-red" />,
).getByTestId(testID);

// Only className should be a flat object
expect(component.props.style).toEqual({ color: "#f00" }); // Changed from "red" to "#f00"
});

test("only inline style should not create array", () => {
const component = render(
<Text testID={testID} style={{ color: "blue" }} />,
).getByTestId(testID);

// Only inline style should be a flat object
expect(component.props.style).toEqual({ color: "blue" });
});
36 changes: 35 additions & 1 deletion src/native/styles/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,41 @@ function deepMergeConfig(
return { ...left };
}

let result = config.target ? Object.assign({}, left, right) : { ...left };
// Handle style merging to support both className and inline style props
let result: Record<string, any>;
if (config.target) {
if (
Array.isArray(config.target) &&
config.target.length === 1 &&
config.target[0] === "style"
) {
// Special handling for style target when we have inline styles
result = { ...left, ...right };
// More performant approach - check for non-overlapping properties without Sets
if (left?.style && right?.style && rightIsInline) {
const leftStyle = left.style;
const rightStyle = right.style;

// Quick check: do any left properties NOT exist in right?
let hasNonOverlappingProperties = false;
for (const key in leftStyle) {
if (!(key in rightStyle)) {
hasNonOverlappingProperties = true;
break; // Early exit for performance
}
}

if (hasNonOverlappingProperties) {
result.style = [leftStyle, rightStyle];
}
// Otherwise, Object.assign above will handle the override correctly
}
} else {
result = Object.assign({}, left, right);
}
} else {
result = { ...left };
}

if (
right &&
Expand Down