Skip to content

Commit d321548

Browse files
ethansharInbal-Tish
authored andcommitted
Fix TextField color by state logic (#631)
* Fix TextField color by state logic * change disable state to disabled in TextField color states * fix docs comments * Defined const for default placeholder color * don't set default tintColor for icon buttons * use shared color states for placeholder and title colors
1 parent b675790 commit d321548

File tree

2 files changed

+74
-52
lines changed

2 files changed

+74
-52
lines changed

src/components/inputs/TextField.js

Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,22 @@ import Text from '../text';
1919
import TouchableOpacity from '../touchableOpacity';
2020

2121
const DEFAULT_COLOR_BY_STATE = {
22-
default: Colors.dark40,
23-
focus: Colors.blue30,
24-
error: Colors.red30
22+
default: Colors.grey10,
23+
focus: Colors.grey10,
24+
error: Colors.grey10,
25+
disabled: Colors.grey50
2526
};
2627
const DEFAULT_UNDERLINE_COLOR_BY_STATE = {
27-
default: Colors.dark70,
28+
default: Colors.grey50,
2829
focus: Colors.blue30,
2930
error: Colors.red30
3031
};
32+
33+
const DEFAULT_PLACEHOLDER_COLOR_BY_STATE = {
34+
default: Colors.grey30,
35+
focus: Colors.blue30
36+
};
37+
3138
const LABEL_TYPOGRAPHY = Typography.text80;
3239
const ICON_SIZE = 24;
3340
const ICON_RIGHT_PADDING = 3;
@@ -52,7 +59,7 @@ export default class TextField extends BaseInput {
5259
*/
5360
floatingPlaceholder: PropTypes.bool,
5461
/**
55-
* floating placeholder color as a string or object of states, ex. {default: 'black', error: 'red', focus: 'blue'}
62+
* floating placeholder color as a string or object of states, ex. {default: 'black', error: 'red', focus: 'blue', disabled: 'grey'}
5663
*/
5764
floatingPlaceholderColor: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
5865
/**
@@ -65,7 +72,7 @@ export default class TextField extends BaseInput {
6572
*/
6673
hideUnderline: PropTypes.bool,
6774
/**
68-
* underline color as a string or object of states, ex. {default: 'black', error: 'red', focus: 'blue'}
75+
* underline color as a string or object of states, ex. {default: 'black', error: 'red', focus: 'blue', disabled: 'grey'}
6976
*/
7077
underlineColor: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
7178
/**
@@ -115,7 +122,7 @@ export default class TextField extends BaseInput {
115122
*/
116123
title: PropTypes.string,
117124
/**
118-
* The title's color as a string or object of states, ex. {default: 'black', error: 'red', focus: 'blue'}
125+
* The title's color as a string or object of states, ex. {default: 'black', error: 'red', focus: 'blue', disabled: 'grey'}
119126
*/
120127
titleColor: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
121128
/**
@@ -225,34 +232,28 @@ export default class TextField extends BaseInput {
225232
return text;
226233
}
227234

228-
getStateColor(colorProp, isUnderline) {
235+
getStateColor(colorProp = {}) {
229236
const {focused} = this.state;
230-
const {disabledColor} = this.getThemeProps();
231237
const error = this.getErrorMessage();
232-
const colorByState = _.cloneDeep(isUnderline ? DEFAULT_UNDERLINE_COLOR_BY_STATE : DEFAULT_COLOR_BY_STATE);
233-
234-
if (this.isDisabled() && disabledColor) {
235-
return disabledColor;
236-
}
238+
const {disabledColor} = this.getThemeProps();
237239

238-
if (colorProp) {
239-
if (_.isString(colorProp)) {
240-
// use given color for any state
241-
return colorProp;
242-
} else if (_.isObject(colorProp)) {
243-
// set given colors by states
244-
_.merge(colorByState, colorProp);
240+
if (_.isString(colorProp)) {
241+
return colorProp || Colors.dark10;
242+
} else if (_.isPlainObject(colorProp)) {
243+
const mergedColorState = {...DEFAULT_COLOR_BY_STATE, ...colorProp};
244+
245+
if (this.isDisabled()) {
246+
return disabledColor || mergedColorState.disabled;
247+
} else if (error) {
248+
return mergedColorState.error;
249+
} else if (focused) {
250+
return mergedColorState.focus;
251+
} else {
252+
return mergedColorState.default;
245253
}
246254
}
247255

248-
// return the right color for the current state
249-
let color = colorByState.default;
250-
if (error && isUnderline) {
251-
color = colorByState.error;
252-
} else if (focused) {
253-
color = colorByState.focus;
254-
}
255-
return color;
256+
return colorProp || Colors.dark10;
256257
}
257258

258259
getCharCount() {
@@ -330,7 +331,7 @@ export default class TextField extends BaseInput {
330331
const {expandable, placeholder, placeholderTextColor, floatingPlaceholderColor, multiline}
331332
= this.getThemeProps();
332333
const typography = this.getTypography();
333-
const placeholderColor = this.getStateColor(placeholderTextColor || DEFAULT_COLOR_BY_STATE.default);
334+
const placeholderColor = this.getStateColor(placeholderTextColor || DEFAULT_PLACEHOLDER_COLOR_BY_STATE.default);
334335

335336
if (this.shouldFakePlaceholder()) {
336337
return (
@@ -351,7 +352,7 @@ export default class TextField extends BaseInput {
351352
}),
352353
color: floatingPlaceholderState.interpolate({
353354
inputRange: [0, 1],
354-
outputRange: [placeholderColor, this.getStateColor(floatingPlaceholderColor)]
355+
outputRange: [placeholderColor, this.getStateColor(floatingPlaceholderColor || DEFAULT_PLACEHOLDER_COLOR_BY_STATE)]
355356
}),
356357
lineHeight: this.shouldFloatPlaceholder() ? LABEL_TYPOGRAPHY.lineHeight : typography.lineHeight
357358
}
@@ -369,7 +370,7 @@ export default class TextField extends BaseInput {
369370

370371
renderTitle() {
371372
const {floatingPlaceholder, title, titleColor, titleStyle} = this.getThemeProps();
372-
const color = this.getStateColor(titleColor);
373+
const color = this.getStateColor(titleColor || DEFAULT_PLACEHOLDER_COLOR_BY_STATE);
373374

374375
if (!floatingPlaceholder && title) {
375376
return <Text style={[{color}, this.styles.topLabel, this.styles.label, titleStyle]}>{title}</Text>;
@@ -501,7 +502,7 @@ export default class TextField extends BaseInput {
501502
];
502503

503504
const placeholderText = this.getPlaceholderText();
504-
const placeholderColor = this.getStateColor(placeholderTextColor || DEFAULT_COLOR_BY_STATE.default);
505+
const placeholderColor = this.getStateColor(placeholderTextColor || DEFAULT_PLACEHOLDER_COLOR_BY_STATE.default);
505506
const isEditable = !this.isDisabled() && !expandable;
506507

507508
return (
@@ -562,7 +563,7 @@ export default class TextField extends BaseInput {
562563

563564
render() {
564565
const {expandable, containerStyle, underlineColor, useTopErrors, hideUnderline} = this.getThemeProps();
565-
const underlineStateColor = this.getStateColor(underlineColor, true);
566+
const underlineStateColor = this.getStateColor(underlineColor || DEFAULT_UNDERLINE_COLOR_BY_STATE);
566567

567568
return (
568569
<View style={[this.styles.container, containerStyle]} collapsable={false}>

src/components/inputs/__tests__/TextField.spec.js

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,33 +18,54 @@ describe('TextField', () => {
1818
});
1919

2020
describe('getStateColor', () => {
21-
it('should return dark70 when blur (inactive)', () => {
21+
it('should return grey10 when no color state or color was passed', () => {
2222
const uut = new TextField({});
23-
expect(uut.getStateColor(undefined, true)).toEqual(Colors.dark70);
23+
expect(uut.getStateColor(undefined)).toEqual(Colors.grey10);
2424
});
25-
it('should return red30 when error', () => {
26-
const uut = new TextField({error: 'test error'});
27-
expect(uut.getStateColor(undefined, true)).toEqual(Colors.red30);
25+
26+
it('should return the string color given as the first argument ', () => {
27+
const uut = new TextField({});
28+
expect(uut.getStateColor(Colors.blue30)).toEqual(Colors.blue30);
2829
});
29-
it('should return blue30 when focused', () => {
30+
31+
it('should return "default" color from the color states object passed', () => {
3032
const uut = new TextField({});
31-
uut.state = {focused: true};
32-
expect(uut.getStateColor(undefined, true)).toEqual(Colors.blue30);
33+
expect(uut.getStateColor({default: Colors.blue30})).toEqual(Colors.blue30);
3334
});
3435

35-
const underlines = {default: Colors.cyan40, focus: Colors.orange60, error: Colors.purple50};
36-
it('should return cyan40 when passing underlineColor and when blur (inactive)', () => {
37-
const uut = new TextField({underlineColor: underlines});
38-
expect(uut.getStateColor(uut.props.underlineColor, true)).toEqual(Colors.cyan40);
36+
it('should return "focus" color from the color states object passed when input is focused', () => {
37+
const uut = new TextField({});
38+
uut.state = {focused: true};
39+
expect(uut.getStateColor({default: Colors.grey10, focus: Colors.green30})).toEqual(Colors.green30);
3940
});
40-
it('should return purple50 when passing underlineColor and when error', () => {
41-
const uut = new TextField({underlineColor: underlines, error: 'test error'});
42-
expect(uut.getStateColor(uut.props.underlineColor, true)).toEqual(Colors.purple50);
41+
42+
it('should return default component state colors by default', () => {
43+
const uut = new TextField({});
44+
expect(uut.getStateColor()).toEqual(Colors.grey10);
45+
uut.state = {focused: true};
46+
expect(uut.getStateColor()).toEqual(Colors.grey10);
4347
});
44-
it('should return orange60 when passing underlineColor and when focused', () => {
45-
const uut = new TextField({underlineColor: underlines});
48+
49+
it('should return default component state colors by default even when given partial color state', () => {
50+
const uut = new TextField({});
51+
expect(uut.getStateColor({focus: Colors.blue30})).toEqual(Colors.grey10);
4652
uut.state = {focused: true};
47-
expect(uut.getStateColor(uut.props.underlineColor, true)).toEqual(Colors.orange60);
53+
expect(uut.getStateColor({default: Colors.dark20})).toEqual(Colors.grey10);
54+
});
55+
56+
it('should return default "error" state when there is an error', () => {
57+
const uut = new TextField({error: 'error'});
58+
expect(uut.getStateColor()).toEqual(Colors.grey10);
59+
});
60+
61+
it('should return given "error" state when there is an error', () => {
62+
const uut = new TextField({error: 'error'});
63+
expect(uut.getStateColor({default: Colors.grey10, error: Colors.red20})).toEqual(Colors.red20);
64+
});
65+
66+
it('should return disabled color when disabled', () => {
67+
const uut = new TextField({editable: false});
68+
expect(uut.getStateColor()).toEqual(Colors.grey50);
4869
});
4970
});
5071

0 commit comments

Comments
 (0)