Skip to content
Open
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
25 changes: 23 additions & 2 deletions src/components/TextInput/TextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,21 @@ const TextInput = forwardRef<TextInputHandles, Props>(

const scaledLabel = !!(value || focused);

const defaultLineHeight = 24;

const lineHeight =
// MD3 fonts use `bodyLarge`
(theme.fonts as any)?.bodyLarge?.lineHeight ??
// MD2 fonts use `regular` (no lineHeight, so rely on size * 1.3)
((theme.fonts as any)?.regular?.lineHeight ||
(theme.fonts as any)?.regular?.fontSize * 1.3) ??
defaultLineHeight;

const autoHeight =
multiline && rest.numberOfLines
? rest.numberOfLines * lineHeight + 8 // + padding
: undefined;
Copy link

Choose a reason for hiding this comment

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

Bug: Style Precedence: minHeight vs. numberOfLines

When a user provides minHeight in contentStyle and numberOfLines is also specified, the auto-calculated minHeight from numberOfLines overrides the user's explicit minHeight value. This happens because both values are placed in an array where the auto-calculated value comes last, causing it to take precedence in React Native's style merging. The auto-height should only apply when the user hasn't specified their own minHeight or height.

Fix in Cursor Fix in Web


if (mode === 'outlined') {
return (
<TextInputOutlined
Expand Down Expand Up @@ -519,7 +534,10 @@ const TextInput = forwardRef<TextInputHandles, Props>(
onLeftAffixLayoutChange={onLeftAffixLayoutChange}
onRightAffixLayoutChange={onRightAffixLayoutChange}
maxFontSizeMultiplier={maxFontSizeMultiplier}
contentStyle={contentStyle}
contentStyle={[
contentStyle,
autoHeight ? { minHeight: autoHeight } : undefined,
].filter(Boolean)}
Copy link

Choose a reason for hiding this comment

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

Bug: Prop Structure: Unnecessary Array Nesting

The contentStyle prop is always wrapped in an array via .filter(Boolean), creating unnecessary nesting. When a user provides contentStyle as an object and autoHeight is undefined, the result is [contentStyle] instead of contentStyle, causing the child components to receive a nested array structure. While React Native flattens nested arrays, this changes the prop structure and could cause issues with type checking or other tooling. The same issue occurs at lines 582-585 for the flat variant.

Fix in Cursor Fix in Web

scaledLabel={scaledLabel}
/>
);
Expand Down Expand Up @@ -561,7 +579,10 @@ const TextInput = forwardRef<TextInputHandles, Props>(
onLeftAffixLayoutChange={onLeftAffixLayoutChange}
onRightAffixLayoutChange={onRightAffixLayoutChange}
maxFontSizeMultiplier={maxFontSizeMultiplier}
contentStyle={contentStyle}
contentStyle={[
contentStyle,
autoHeight ? { minHeight: autoHeight } : undefined,
].filter(Boolean)}
scaledLabel={scaledLabel}
/>
);
Expand Down
24 changes: 13 additions & 11 deletions src/components/__tests__/__snapshots__/TextInput.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ exports[`call onPress when affix adornment pressed 1`] = `
"marginLeft": 0,
"paddingLeft": 40,
},
undefined,
[],
]
}
testID="text-input-flat"
Expand Down Expand Up @@ -545,7 +545,7 @@ exports[`correctly applies a component as the text label 1`] = `
[
{},
],
undefined,
[],
]
}
testID="text-input-flat"
Expand Down Expand Up @@ -779,7 +779,7 @@ exports[`correctly applies cursorColor prop 1`] = `
[
{},
],
undefined,
[],
]
}
testID="text-input-flat"
Expand Down Expand Up @@ -1013,7 +1013,7 @@ exports[`correctly applies default textAlign based on default RTL 1`] = `
[
{},
],
undefined,
[],
]
}
testID="text-input-flat"
Expand Down Expand Up @@ -1272,7 +1272,7 @@ exports[`correctly applies height to multiline Outline TextInput 1`] = `
[
{},
],
undefined,
[],
]
}
testID="text-input-outlined"
Expand Down Expand Up @@ -1506,9 +1506,11 @@ exports[`correctly applies paddingLeft from contentStyleProp 1`] = `
[
{},
],
{
"paddingLeft": 20,
},
[
{
"paddingLeft": 20,
},
],
]
}
testID="text-input-flat"
Expand Down Expand Up @@ -1742,7 +1744,7 @@ exports[`correctly applies textAlign center 1`] = `
[
{},
],
undefined,
[],
]
}
testID="text-input-flat"
Expand Down Expand Up @@ -1979,7 +1981,7 @@ exports[`correctly renders left-side affix adornment, and right-side icon adornm
"paddingLeft": 40,
"paddingRight": 16,
},
undefined,
[],
]
}
testID="text-input-flat"
Expand Down Expand Up @@ -2406,7 +2408,7 @@ exports[`correctly renders left-side icon adornment, and right-side affix adornm
"paddingLeft": 16,
"paddingRight": 40,
},
undefined,
[],
]
}
testID="text-input-flat"
Expand Down