| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157 |
120x
120x
120x
120x
21x
21x
21x
21x
21x
21x
21x
21x
21x
21x
| import _ from 'lodash';
import React, { createElement } from 'react';
import { lucidClassNames } from '../../util/style-helpers';
import { createClass, getFirst, omitProps } from '../../util/component-types';
import TextField from '../TextField/TextField';
import SearchIcon from '../Icon/SearchIcon/SearchIcon';
import reducers from './SearchField.reducers';
const cx = lucidClassNames.bind('&-SearchField');
const {
bool,
func,
node,
number,
oneOfType,
string,
} = React.PropTypes;
/**
* {"categories": ["controls", "text"], "madeFrom": ["TextField", "SearchIcon"]}
*
* This is a wrapper around TextField that styles it for a search use-case. The
* icon and TextField are customizable through child components.
*/
const SearchField = createClass({
displayName: 'SearchField',
components: {
/**
* Allows for full control over the TextField that's used under the hood.
*/
TextField,
/**
* Icon this is displayed on the right side of the SearchField. Any of the
* lucid `*Icon` components should work.
*/
Icon: createClass({
displayName: 'SearchField.Icon',
propName: 'Icon',
}),
},
reducers,
propTypes: {
/**
* Fires an event every time the user types text into the TextField.
*
* Signature: `(value, { event, props }) => {}`
*/
onChange: func,
/**
* Fires an event when the user hits "enter" from the SearchField.
*
* Signature: `(value, { event, props }) => {}`
*/
onSubmit: func,
/**
* Set the value of the input.
*/
value: oneOfType([
number,
string,
]),
/**
* Controls the highlighting of the search icon. Should be passed `true` when
* the search text is valid, e.g. contains enough characters to perform a search.
*/
isValid: bool,
/**
* Disables the SearchField by greying it out.
*/
isDisabled: bool,
/**
* placeholder value
*/
placeholder: string,
/**
* Appended to the component-specific class names set on the root
* element.
*/
className: string,
/**
* Passed through to the root element.
*/
Icon: node,
},
getDefaultProps() {
return {
isDisabled: false,
onChange: _.noop,
onSubmit: _.noop,
value: '',
};
},
render() {
const {
props,
props: {
className,
isDisabled,
isValid,
onChange,
onSubmit,
placeholder,
value,
...passThroughs,
},
} = this;
const {
Icon,
TextField,
} = SearchField;
const textFieldProps = {
isDisabled,
onChange,
onSubmit,
placeholder,
isMultiLine: false,
value,
};
const textFieldElement = getFirst(props, TextField, <TextField {...textFieldProps} />);
const isIconActive = _.isUndefined(isValid) ? !_.isEmpty(_.get(textFieldElement, 'props.value')) : isValid;
const defaultIcon = <SearchIcon className={cx('&-Icon', { '&-Icon-active': isIconActive })} />;
const iconElement = getFirst(props, Icon);
const iconChildren = _.get(iconElement, 'props.children');
const icon = iconChildren ? createElement(iconChildren.type, {
...iconChildren.props,
className: cx('&-Icon', { '&-Icon-active': isIconActive }, iconChildren.props.className),
}) : defaultIcon;
return (
<div
{...omitProps(passThroughs, SearchField)}
className={cx('&', className)}
>
{textFieldElement}
<div className={cx('&-Icon-container')}>
{icon}
</div>
</div>
);
},
});
export default SearchField;
|