Skip to content
This repository was archived by the owner on Jan 14, 2025. It is now read-only.

Commit f829e12

Browse files
태재영Matt Goo
authored andcommitted
fix(text-field): label isn't float when set value with setState (#934)
BREAKING CHANGE: handleValueChange is removed from Input's props.
1 parent cc06add commit f829e12

File tree

4 files changed

+33
-85
lines changed

4 files changed

+33
-85
lines changed

packages/text-field/Input.tsx

Lines changed: 12 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,6 @@ export interface InputProps<T extends HTMLElement = HTMLInputElement> {
2828
inputType?: 'input' | 'textarea';
2929
isValid?: boolean;
3030
foundation?: MDCTextFieldFoundation;
31-
handleValueChange?: (
32-
value: string | number | string[] | undefined,
33-
cb: () => void
34-
) => void;
3531
syncInput?: (inputInstance: Input<T>) => void;
3632
onBlur?: Pick<React.HTMLProps<T>, 'onBlur'>;
3733
onChange?: Pick<React.HTMLProps<T>, 'onChange'>;
@@ -91,7 +87,6 @@ export default class Input<
9187
inputType: 'input',
9288
disabled: false,
9389
id: '',
94-
handleValueChange: () => {},
9590
setDisabled: () => {},
9691
setInputId: () => {},
9792
handleFocusChange: () => {},
@@ -111,7 +106,6 @@ export default class Input<
111106
value,
112107
setInputId,
113108
setDisabled,
114-
handleValueChange,
115109
foundation,
116110
} = this.props;
117111
if (syncInput) {
@@ -123,11 +117,8 @@ export default class Input<
123117
if (setDisabled && disabled) {
124118
setDisabled(true);
125119
}
126-
if (handleValueChange && value) {
127-
handleValueChange(
128-
value,
129-
() => foundation && foundation.setValue(this.valueToString(value))
130-
);
120+
if (value && foundation) {
121+
foundation.setValue(this.valueToString(value));
131122
}
132123
this.setState({isMounted: true});
133124
}
@@ -139,7 +130,6 @@ export default class Input<
139130
value,
140131
disabled,
141132
isValid,
142-
handleValueChange,
143133
setInputId,
144134
setDisabled,
145135
} = this.props;
@@ -163,16 +153,14 @@ export default class Input<
163153
}
164154

165155
if (value !== prevProps.value) {
166-
handleValueChange &&
167-
handleValueChange(value, () => {
168-
// only call #foundation.setValue on programatic changes;
169-
// not changes by the user.
170-
if (this.state.wasUserTriggeredChange) {
171-
this.setState({wasUserTriggeredChange: false});
172-
} else {
173-
foundation && foundation.setValue(this.valueToString(value));
174-
}
175-
});
156+
const inputValue = this.valueToString(value);
157+
const notTriggeredChange = !this.state.wasUserTriggeredChange;
158+
// only call #foundation.setValue on programatic changes;
159+
// not changes by the user.
160+
if (notTriggeredChange) {
161+
foundation && foundation.setValue(inputValue);
162+
}
163+
this.setState({wasUserTriggeredChange: false});
176164
}
177165

178166
if (isValid !== prevProps.isValid && foundation) {
@@ -263,10 +251,8 @@ export default class Input<
263251
onTouchStart(evt);
264252
};
265253

266-
// To stay in sync with the MDC React Text Field Component, handleValueChange()
267-
// is called to update MDC React Text Field's state. That state variable
268-
// is used to let other subcomponents and the foundation know what the current
269-
// value of the input is.
254+
// That state variable is used to let other subcomponents and
255+
// the foundation know what the current value of the input is.
270256
handleChange = (
271257
evt: React.FormEvent<
272258
T extends HTMLInputElement ? HTMLInputElement : HTMLTextAreaElement
@@ -332,7 +318,6 @@ export default class Input<
332318
isValid,
333319
value,
334320
handleFocusChange,
335-
handleValueChange,
336321
setDisabled,
337322
setInputId,
338323
onFocus,

packages/text-field/README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ inputType | string | HTML tag to be used to render input element. 'input' (defau
8383
className | String | Classes to be applied to the input element.
8484
disabled | Function | Disables the input and the parent text field.
8585
foundation | Function | The text field foundation.
86-
handleValueChange | Function | A callback function to update React Text Field's value.
8786
isValid | Boolean | If set, this value will override the native input's validation.
8887
id | String | The `<input>` id attribute.
8988
onBlur | Function | Blur event handler.

test/unit/text-field/Input.test.tsx

Lines changed: 2 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -180,24 +180,6 @@ test('#componentDidMount should not call any method if disabled and id do not ex
180180
td.verify(setDisabled(td.matchers.isA(Boolean)), {times: 0});
181181
});
182182

183-
test('#componentDidMount calls props.handleValueChange when the foundation initializes with a value', () => {
184-
const handleValueChange = td.func();
185-
const value = 'test value';
186-
const props: any = {handleValueChange, value};
187-
shallow(<Input {...props} />);
188-
td.verify(handleValueChange(value, td.matchers.isA(Function)), {times: 1});
189-
});
190-
191-
test('#componentDidMount does not call props.handleValueChange when there is no props.value', () => {
192-
const handleValueChange = td.func();
193-
const props: any = {handleValueChange};
194-
shallow(<Input {...props} />);
195-
td.verify(
196-
handleValueChange(td.matchers.anything(), td.matchers.isA(Function)),
197-
{times: 0}
198-
);
199-
});
200-
201183
test(
202184
'#props.handleFocusChange is called when props.autoFocus is true' +
203185
', there is a props.foundation, and component has mounted',
@@ -317,17 +299,6 @@ test(
317299
}
318300
);
319301

320-
test('#componentDidUpdate calls handleValueChange when the foundation initializes with a value', () => {
321-
const setValue = td.func();
322-
const handleValueChange = td.func();
323-
const props: any = {handleValueChange};
324-
const wrapper = shallow(<Input value='test value' {...props} />);
325-
wrapper.setProps({foundation: buildFoundation({setValue})});
326-
td.verify(handleValueChange('test value', td.matchers.isA(Function)), {
327-
times: 1,
328-
});
329-
});
330-
331302
test('#componentDidUpdate calls setUseNativeValidation when isValid changes to undefined', () => {
332303
const foundation: any = buildFoundation({setUseNativeValidation: td.func()});
333304
const wrapper = shallow(
@@ -354,27 +325,9 @@ test('#componentDidUpdate calls setValid when isValid changes', () => {
354325
td.verify(foundation.setValid(true), {times: 1});
355326
});
356327

357-
test('props.handleValueChange() is called if this.props.value updates', () => {
358-
const handleValueChange = td.func();
359-
const props: any = {handleValueChange};
360-
const wrapper = shallow(<Input {...props} />);
361-
wrapper.setProps({value: 'meow'});
362-
td.verify(handleValueChange('meow', td.matchers.isA(Function)), {times: 1});
363-
});
364-
365328
test('foundation.setValue() is called if this.props.value updates', () => {
366329
const foundation: any = buildFoundation({setValue: td.func()});
367-
const handleValueChange: (
368-
value: string | number | string[] | undefined,
369-
cb: () => void
370-
) => void = (value, cb) => value && cb();
371-
const wrapper = shallow(
372-
<Input
373-
value='test value'
374-
foundation={foundation}
375-
handleValueChange={handleValueChange}
376-
/>
377-
);
330+
const wrapper = shallow(<Input value='test value' foundation={foundation} />);
378331
wrapper.setProps({value: 'meow'});
379332
td.verify(foundation.setValue('meow'), {times: 1});
380333
});
@@ -466,16 +419,8 @@ test('#event.onChange calls props.onChange()', () => {
466419

467420
test('wasUserTriggeredChange test', () => {
468421
const foundation: any = buildFoundation();
469-
const handleValueChange = (
470-
value: string | number | string[] | undefined,
471-
cb: () => void
472-
) => value && cb();
473422
const wrapper = mount<Input<HTMLInputElement>>(
474-
<Input
475-
value='test value'
476-
foundation={foundation}
477-
handleValueChange={handleValueChange}
478-
/>
423+
<Input value='test value' foundation={foundation} />
479424
);
480425
wrapper.simulate('change');
481426
assert.isTrue(wrapper.instance().state.wasUserTriggeredChange);

test/unit/text-field/index.test.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,3 +770,22 @@ test('Input component sync test in TextField', () => {
770770
// and throw error because there is no inputComponent
771771
assert.doesNotThrow(() => wrapper.instance().setState({disabled: true}));
772772
});
773+
774+
test('FloatingLabel is floated even if value is changed programmatically', () => {
775+
class TestComponent extends React.Component {
776+
state = {value: ''};
777+
render() {
778+
return (
779+
<TextField label='my label'>
780+
<Input value={this.state.value} />
781+
</TextField>
782+
);
783+
}
784+
}
785+
const wrapper = mount<TestComponent>(<TestComponent />);
786+
const label = wrapper.find('.mdc-floating-label').getDOMNode();
787+
const floatClass = 'mdc-floating-label--float-above';
788+
assert.isFalse(label.className.includes(floatClass));
789+
wrapper.setState({value: 'Test!'});
790+
assert.isTrue(label.className.includes(floatClass));
791+
});

0 commit comments

Comments
 (0)