Skip to content

Commit 761e3cb

Browse files
authored
fix: set input min width (callstack#3941)
1 parent 36ce39b commit 761e3cb

File tree

7 files changed

+130
-4
lines changed

7 files changed

+130
-4
lines changed

example/src/Examples/TextInputExample.tsx

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,57 @@ const TextInputExample = () => {
697697
/>
698698
</View>
699699
) : null}
700+
<View style={styles.row}>
701+
<TextInput
702+
mode="outlined"
703+
label="CVV"
704+
placeholder="CVV"
705+
keyboardType="phone-pad"
706+
maxLength={3}
707+
/>
708+
</View>
709+
<View style={styles.row}>
710+
<TextInput
711+
mode="flat"
712+
label="CVV"
713+
placeholder="CVV"
714+
keyboardType="phone-pad"
715+
maxLength={3}
716+
/>
717+
</View>
718+
<View style={styles.row}>
719+
<TextInput
720+
mode="outlined"
721+
label="Code"
722+
placeholder="Code"
723+
keyboardType="phone-pad"
724+
maxLength={4}
725+
/>
726+
</View>
727+
<View style={styles.row}>
728+
<TextInput
729+
mode="flat"
730+
label="Code"
731+
placeholder="Code"
732+
keyboardType="phone-pad"
733+
maxLength={4}
734+
/>
735+
</View>
736+
<View style={styles.row}>
737+
<TextInput
738+
mode="flat"
739+
label="Month"
740+
placeholder="Month"
741+
style={styles.month}
742+
/>
743+
<TextInput
744+
mode="flat"
745+
label="Year"
746+
placeholder="Year"
747+
keyboardType="phone-pad"
748+
style={styles.year}
749+
/>
750+
</View>
700751
</List.Accordion>
701752
</List.AccordionGroup>
702753
</ScreenWrapper>
@@ -745,6 +796,19 @@ const styles = StyleSheet.create({
745796
fixedHeight: {
746797
height: 100,
747798
},
799+
row: {
800+
margin: 8,
801+
justifyContent: 'space-between',
802+
flexDirection: 'row',
803+
},
804+
month: {
805+
flex: 1,
806+
marginRight: 4,
807+
},
808+
year: {
809+
flex: 1,
810+
marginLeft: 4,
811+
},
748812
});
749813

750814
export default TextInputExample;

src/components/TextInput/Label/InputLabel.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react';
2-
import { Animated, StyleSheet } from 'react-native';
2+
import { Animated, StyleSheet, Dimensions } from 'react-native';
33

44
import AnimatedText from '../../Typography/AnimatedText';
55
import type { InputLabelProps } from '../types';
@@ -16,6 +16,7 @@ const InputLabel = (props: InputLabelProps) => {
1616
label,
1717
labelError,
1818
onLayoutAnimatedText,
19+
onLabelTextLayout,
1920
hasActiveOutline,
2021
activeColor,
2122
placeholderStyle,
@@ -40,6 +41,8 @@ const InputLabel = (props: InputLabelProps) => {
4041
testID,
4142
} = props;
4243

44+
const { width } = Dimensions.get('window');
45+
4346
const paddingOffset =
4447
paddingLeft && paddingRight ? { paddingLeft, paddingRight } : {};
4548

@@ -107,7 +110,7 @@ const InputLabel = (props: InputLabelProps) => {
107110
style={[
108111
StyleSheet.absoluteFill,
109112
styles.labelContainer,
110-
{ opacity },
113+
{ opacity, width },
111114
labelTranslationX,
112115
]}
113116
>
@@ -127,6 +130,7 @@ const InputLabel = (props: InputLabelProps) => {
127130
<AnimatedText
128131
variant="bodySmall"
129132
onLayout={onLayoutAnimatedText}
133+
onTextLayout={onLabelTextLayout}
130134
style={[
131135
placeholderStyle,
132136
{

src/components/TextInput/TextInput.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import {
66
TextInput as NativeTextInput,
77
TextStyle,
88
ViewStyle,
9+
NativeSyntheticEvent,
10+
TextLayoutEventData,
911
} from 'react-native';
1012

1113
import TextInputAffix, {
@@ -248,6 +250,10 @@ const TextInput = forwardRef<TextInputHandles, Props>(
248250
// Use value from props instead of local state when input is controlled
249251
const value = isControlled ? rest.value : uncontrolledValue;
250252

253+
const [labelTextLayout, setLabelTextLayout] = React.useState({
254+
width: 33,
255+
});
256+
251257
const [labelLayout, setLabelLayout] = React.useState<{
252258
measured: boolean;
253259
width: number;
@@ -447,6 +453,18 @@ const TextInput = forwardRef<TextInputHandles, Props>(
447453
[labelLayout.height, labelLayout.width]
448454
);
449455

456+
const handleLabelTextLayout = React.useCallback(
457+
({ nativeEvent }: NativeSyntheticEvent<TextLayoutEventData>) => {
458+
setLabelTextLayout({
459+
width: nativeEvent.lines.reduce(
460+
(acc, line) => acc + Math.ceil(line.width),
461+
0
462+
),
463+
});
464+
},
465+
[]
466+
);
467+
450468
const forceFocus = React.useCallback(() => root.current?.focus(), []);
451469

452470
const { maxFontSizeMultiplier = 1.5 } = rest;
@@ -469,6 +487,7 @@ const TextInput = forwardRef<TextInputHandles, Props>(
469487
focused,
470488
placeholder,
471489
value,
490+
labelTextLayout,
472491
labelLayout,
473492
leftLayout,
474493
rightLayout,
@@ -481,6 +500,7 @@ const TextInput = forwardRef<TextInputHandles, Props>(
481500
onBlur={handleBlur}
482501
onChangeText={handleChangeText}
483502
onLayoutAnimatedText={handleLayoutAnimatedText}
503+
onLabelTextLayout={handleLabelTextLayout}
484504
onLeftAffixLayoutChange={onLeftAffixLayoutChange}
485505
onRightAffixLayoutChange={onRightAffixLayoutChange}
486506
maxFontSizeMultiplier={maxFontSizeMultiplier}
@@ -506,6 +526,7 @@ const TextInput = forwardRef<TextInputHandles, Props>(
506526
focused,
507527
placeholder,
508528
value,
529+
labelTextLayout,
509530
labelLayout,
510531
leftLayout,
511532
rightLayout,
@@ -518,6 +539,7 @@ const TextInput = forwardRef<TextInputHandles, Props>(
518539
onBlur={handleBlur}
519540
onChangeText={handleChangeText}
520541
onLayoutAnimatedText={handleLayoutAnimatedText}
542+
onLabelTextLayout={handleLabelTextLayout}
521543
onLeftAffixLayoutChange={onLeftAffixLayoutChange}
522544
onRightAffixLayoutChange={onRightAffixLayoutChange}
523545
maxFontSizeMultiplier={maxFontSizeMultiplier}

src/components/TextInput/TextInputFlat.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ const TextInputFlat = ({
6565
onBlur,
6666
onChangeText,
6767
onLayoutAnimatedText,
68+
onLabelTextLayout,
6869
onLeftAffixLayoutChange,
6970
onRightAffixLayoutChange,
7071
left,
@@ -254,6 +255,7 @@ const TextInputFlat = ({
254255
const labelProps = {
255256
label,
256257
onLayoutAnimatedText,
258+
onLabelTextLayout,
257259
placeholderOpacity,
258260
labelError: error,
259261
placeholderStyle: styles.placeholder,
@@ -405,6 +407,8 @@ const TextInputFlat = ({
405407
: I18nManager.getConstants().isRTL
406408
? 'right'
407409
: 'left',
410+
minWidth:
411+
parentState.labelTextLayout.width + 2 * FLAT_INPUT_OFFSET,
408412
},
409413
Platform.OS === 'web' && { outline: 'none' },
410414
adornmentStyleAdjustmentForNativeInput,

src/components/TextInput/TextInputOutlined.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ const TextInputOutlined = ({
6565
onBlur,
6666
onChangeText,
6767
onLayoutAnimatedText,
68+
onLabelTextLayout,
6869
onLeftAffixLayoutChange,
6970
onRightAffixLayoutChange,
7071
left,
@@ -200,6 +201,7 @@ const TextInputOutlined = ({
200201
const labelProps = {
201202
label,
202203
onLayoutAnimatedText,
204+
onLabelTextLayout,
203205
placeholderOpacity,
204206
labelError: error,
205207
placeholderStyle,
@@ -376,6 +378,9 @@ const TextInputOutlined = ({
376378
? 'right'
377379
: 'left',
378380
paddingHorizontal: INPUT_PADDING_HORIZONTAL,
381+
minWidth:
382+
parentState.labelTextLayout.width +
383+
2 * INPUT_PADDING_HORIZONTAL,
379384
},
380385
Platform.OS === 'web' && { outline: 'none' },
381386
adornmentStyleAdjustmentForNativeInput,
@@ -398,7 +403,6 @@ const styles = StyleSheet.create({
398403
},
399404
input: {
400405
margin: 0,
401-
zIndex: 1,
402406
},
403407
inputOutlined: {
404408
paddingTop: 8,

src/components/TextInput/types.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import type {
88
StyleProp,
99
ViewProps,
1010
ViewStyle,
11+
NativeSyntheticEvent,
12+
TextLayoutEventData,
1113
} from 'react-native';
1214

1315
import type { $Omit, InternalTheme, ThemeProp } from './../../types';
@@ -70,6 +72,7 @@ export type State = {
7072
focused: boolean;
7173
placeholder?: string;
7274
value?: string;
75+
labelTextLayout: { width: number };
7376
labelLayout: { measured: boolean; width: number; height: number };
7477
leftLayout: { height: number | null; width: number | null };
7578
rightLayout: { height: number | null; width: number | null };
@@ -83,6 +86,7 @@ export type ChildTextInputProps = {
8386
forceFocus: () => void;
8487
onChangeText?: (value: string) => void;
8588
onLayoutAnimatedText: (args: any) => void;
89+
onLabelTextLayout: (event: NativeSyntheticEvent<TextLayoutEventData>) => void;
8690
onLeftAffixLayoutChange: (event: LayoutChangeEvent) => void;
8791
onRightAffixLayoutChange: (event: LayoutChangeEvent) => void;
8892
} & $Omit<TextInputTypesWithoutMode, 'theme'> & { theme: InternalTheme };
@@ -114,6 +118,7 @@ export type LabelProps = {
114118
errorColor?: string;
115119
labelError?: boolean | null;
116120
onLayoutAnimatedText: (args: any) => void;
121+
onLabelTextLayout: (event: NativeSyntheticEvent<TextLayoutEventData>) => void;
117122
roundness: number;
118123
maxFontSizeMultiplier?: number | undefined | null;
119124
testID?: string;

0 commit comments

Comments
 (0)