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
5 changes: 4 additions & 1 deletion packages/uniwind/src/core/native/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,11 @@ class UniwindStoreBuilder {
let dependencySum = 0
const bestBreakpoints = new Map<string, Style>()
const isScopedTheme = uniwindContext.scopedTheme !== null
const classNameTokens = classNames.includes('\n')
? classNames.split(/\s+/).filter(Boolean)
: classNames.split(' ')
Comment on lines +111 to +113

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Non-Newline Whitespace Joins Classes

When a native className uses tabs without a newline, such as bg-red-500\tborder-2, this condition selects the space-only split and treats both classes as one unknown token. Native rendering then silently omits both styles, while the web resolver accepts the same whitespace-separated input.

Suggested change
const classNameTokens = classNames.includes('\n')
? classNames.split(/\s+/).filter(Boolean)
: classNames.split(' ')
const classNameTokens = classNames.split(/\s+/).filter(Boolean)

Fix in Claude Code Fix in Codex

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will resolve in performance drop

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a fair point — split(/\s+/).filter(Boolean) is measurably slower than split(' ') on the hot path. Given that the PR already benchmarks the overhead carefully, always using the regex split would undermine that work.

A middle ground: extend the fast-path condition to also cover tabs, keeping the regex split only for non-space whitespace:

Suggested change
const classNameTokens = classNames.includes('\n')
? classNames.split(/\s+/).filter(Boolean)
: classNames.split(' ')
const classNameTokens = classNames.includes('\n') || classNames.includes('\t')
? classNames.split(/\s+/).filter(Boolean)
: classNames.split(' ')

This preserves the fast split(' ') path for the common case while still correctly handling tab-separated class names. If tabs in className strings are genuinely not a concern in your usage (i.e. always space- or newline-separated), then the original code is fine as-is.

Tip: You can customize Greptile's behavior for this repo with .greptile/rules.md and .greptile/config.json.


for (const className of classNames.split(' ')) {
for (const className of classNameTokens) {
Comment thread
coderabbitai[bot] marked this conversation as resolved.
if (!(className in this.stylesheet)) {
continue
}
Expand Down
20 changes: 20 additions & 0 deletions packages/uniwind/tests/native/styles-parsing/multiline.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import * as React from 'react'
import View from '../../../src/components/native/View'
import { TW_RED_500 } from '../../consts'
import { renderUniwind } from '../utils'

describe('Multiline', () => {
test('Multiline classes are handled', () => {
const { getStylesFromId } = renderUniwind(
<View
className={`bg-red-500
border-2`}
testID="multiline"
/>,
)

const multilineStyles = getStylesFromId('multiline')
expect(multilineStyles.backgroundColor).toBe(TW_RED_500)
expect(multilineStyles.borderWidth).toBe(2)
})
})