UNPKG

8.24 kBJSXView Raw
1import React from 'react';
2import PropTypes from 'prop-types';
3import { forbidExtraProps, nonNegativeInteger } from 'airbnb-prop-types';
4import { withStyles, withStylesPropTypes } from 'react-with-styles';
5
6import { SingleDatePickerInputPhrases } from '../defaultPhrases';
7import getPhrasePropTypes from '../utils/getPhrasePropTypes';
8import noflip from '../utils/noflip';
9
10import DateInput from './DateInput';
11import IconPositionShape from '../shapes/IconPositionShape';
12
13import CloseButton from './CloseButton';
14import CalendarIcon from './CalendarIcon';
15
16import openDirectionShape from '../shapes/OpenDirectionShape';
17import { ICON_BEFORE_POSITION, ICON_AFTER_POSITION, OPEN_DOWN } from '../constants';
18
19const propTypes = forbidExtraProps({
20 ...withStylesPropTypes,
21 id: PropTypes.string.isRequired,
22 children: PropTypes.node,
23 placeholder: PropTypes.string,
24 ariaLabel: PropTypes.string,
25 displayValue: PropTypes.string,
26 screenReaderMessage: PropTypes.string,
27 focused: PropTypes.bool,
28 isFocused: PropTypes.bool, // describes actual DOM focus
29 disabled: PropTypes.bool,
30 required: PropTypes.bool,
31 readOnly: PropTypes.bool,
32 openDirection: openDirectionShape,
33 showCaret: PropTypes.bool,
34 showClearDate: PropTypes.bool,
35 customCloseIcon: PropTypes.node,
36 showDefaultInputIcon: PropTypes.bool,
37 inputIconPosition: IconPositionShape,
38 customInputIcon: PropTypes.node,
39 isRTL: PropTypes.bool,
40 noBorder: PropTypes.bool,
41 block: PropTypes.bool,
42 small: PropTypes.bool,
43 regular: PropTypes.bool,
44 verticalSpacing: nonNegativeInteger,
45
46 onChange: PropTypes.func,
47 onClearDate: PropTypes.func,
48 onFocus: PropTypes.func,
49 onKeyDownShiftTab: PropTypes.func,
50 onKeyDownTab: PropTypes.func,
51 onKeyDownArrowDown: PropTypes.func,
52 onKeyDownQuestionMark: PropTypes.func,
53
54 // i18n
55 phrases: PropTypes.shape(getPhrasePropTypes(SingleDatePickerInputPhrases)),
56});
57
58const defaultProps = {
59 children: null,
60 placeholder: 'Select Date',
61 ariaLabel: undefined,
62 displayValue: '',
63 screenReaderMessage: '',
64 focused: false,
65 isFocused: false,
66 disabled: false,
67 required: false,
68 readOnly: false,
69 openDirection: OPEN_DOWN,
70 showCaret: false,
71 showClearDate: false,
72 showDefaultInputIcon: false,
73 inputIconPosition: ICON_BEFORE_POSITION,
74 customCloseIcon: null,
75 customInputIcon: null,
76 isRTL: false,
77 noBorder: false,
78 block: false,
79 small: false,
80 regular: false,
81 verticalSpacing: undefined,
82
83 onChange() {},
84 onClearDate() {},
85 onFocus() {},
86 onKeyDownShiftTab() {},
87 onKeyDownTab() {},
88 onKeyDownArrowDown() {},
89 onKeyDownQuestionMark() {},
90
91 // i18n
92 phrases: SingleDatePickerInputPhrases,
93};
94
95function SingleDatePickerInput({
96 id,
97 children,
98 css,
99 placeholder,
100 ariaLabel,
101 displayValue,
102 focused,
103 isFocused,
104 disabled,
105 required,
106 readOnly,
107 showCaret,
108 showClearDate,
109 showDefaultInputIcon,
110 inputIconPosition,
111 phrases,
112 onClearDate,
113 onChange,
114 onFocus,
115 onKeyDownShiftTab,
116 onKeyDownTab,
117 onKeyDownArrowDown,
118 onKeyDownQuestionMark,
119 screenReaderMessage,
120 customCloseIcon,
121 customInputIcon,
122 openDirection,
123 isRTL,
124 noBorder,
125 block,
126 small,
127 regular,
128 verticalSpacing,
129 styles,
130}) {
131 const calendarIcon = customInputIcon || (
132 <CalendarIcon {...css(styles.SingleDatePickerInput_calendarIcon_svg)} />
133 );
134 const closeIcon = customCloseIcon || (
135 <CloseButton
136 {...css(
137 styles.SingleDatePickerInput_clearDate_svg,
138 small && styles.SingleDatePickerInput_clearDate_svg__small,
139 )}
140 />
141 );
142
143 const screenReaderText = screenReaderMessage || phrases.keyboardForwardNavigationInstructions;
144 const inputIcon = (showDefaultInputIcon || customInputIcon !== null) && (
145 <button
146 {...css(styles.SingleDatePickerInput_calendarIcon)}
147 type="button"
148 disabled={disabled}
149 aria-label={phrases.focusStartDate}
150 onClick={onFocus}
151 >
152 {calendarIcon}
153 </button>
154 );
155
156 return (
157 <div
158 {...css(
159 styles.SingleDatePickerInput,
160 disabled && styles.SingleDatePickerInput__disabled,
161 isRTL && styles.SingleDatePickerInput__rtl,
162 !noBorder && styles.SingleDatePickerInput__withBorder,
163 block && styles.SingleDatePickerInput__block,
164 showClearDate && styles.SingleDatePickerInput__showClearDate,
165 )}
166 >
167 {inputIconPosition === ICON_BEFORE_POSITION && inputIcon}
168
169 <DateInput
170 id={id}
171 placeholder={placeholder}
172 ariaLabel={ariaLabel}
173 displayValue={displayValue}
174 screenReaderMessage={screenReaderText}
175 focused={focused}
176 isFocused={isFocused}
177 disabled={disabled}
178 required={required}
179 readOnly={readOnly}
180 showCaret={showCaret}
181 onChange={onChange}
182 onFocus={onFocus}
183 onKeyDownShiftTab={onKeyDownShiftTab}
184 onKeyDownTab={onKeyDownTab}
185 onKeyDownArrowDown={onKeyDownArrowDown}
186 onKeyDownQuestionMark={onKeyDownQuestionMark}
187 openDirection={openDirection}
188 verticalSpacing={verticalSpacing}
189 small={small}
190 regular={regular}
191 block={block}
192 />
193
194 {children}
195
196 {showClearDate && (
197 <button
198 {...css(
199 styles.SingleDatePickerInput_clearDate,
200 small && styles.SingleDatePickerInput_clearDate__small,
201 !customCloseIcon && styles.SingleDatePickerInput_clearDate__default,
202 !displayValue && styles.SingleDatePickerInput_clearDate__hide,
203 )}
204 type="button"
205 aria-label={phrases.clearDate}
206 disabled={disabled}
207 onClick={onClearDate}
208 >
209 {closeIcon}
210 </button>
211 )}
212
213 {inputIconPosition === ICON_AFTER_POSITION && inputIcon}
214
215 </div>
216 );
217}
218
219SingleDatePickerInput.propTypes = propTypes;
220SingleDatePickerInput.defaultProps = defaultProps;
221
222export default withStyles(({ reactDates: { border, color } }) => ({
223 SingleDatePickerInput: {
224 display: 'inline-block',
225 backgroundColor: color.background,
226 },
227
228 SingleDatePickerInput__withBorder: {
229 borderColor: color.border,
230 borderWidth: border.pickerInput.borderWidth,
231 borderStyle: border.pickerInput.borderStyle,
232 borderRadius: border.pickerInput.borderRadius,
233 },
234
235 SingleDatePickerInput__rtl: {
236 direction: noflip('rtl'),
237 },
238
239 SingleDatePickerInput__disabled: {
240 backgroundColor: color.disabled,
241 },
242
243 SingleDatePickerInput__block: {
244 display: 'block',
245 },
246
247 SingleDatePickerInput__showClearDate: {
248 paddingRight: 30, // TODO: should be noflip wrapped and handled by an isRTL prop
249 },
250
251 SingleDatePickerInput_clearDate: {
252 background: 'none',
253 border: 0,
254 color: 'inherit',
255 font: 'inherit',
256 lineHeight: 'normal',
257 overflow: 'visible',
258
259 cursor: 'pointer',
260 padding: 10,
261 margin: '0 10px 0 5px', // TODO: should be noflip wrapped and handled by an isRTL prop
262 position: 'absolute',
263 right: 0, // TODO: should be noflip wrapped and handled by an isRTL prop
264 top: '50%',
265 transform: 'translateY(-50%)',
266 },
267
268 SingleDatePickerInput_clearDate__default: {
269 ':focus': {
270 background: color.core.border,
271 borderRadius: '50%',
272 },
273
274 ':hover': {
275 background: color.core.border,
276 borderRadius: '50%',
277 },
278 },
279
280 SingleDatePickerInput_clearDate__small: {
281 padding: 6,
282 },
283
284 SingleDatePickerInput_clearDate__hide: {
285 visibility: 'hidden',
286 },
287
288 SingleDatePickerInput_clearDate_svg: {
289 fill: color.core.grayLight,
290 height: 12,
291 width: 15,
292 verticalAlign: 'middle',
293 },
294
295 SingleDatePickerInput_clearDate_svg__small: {
296 height: 9,
297 },
298
299 SingleDatePickerInput_calendarIcon: {
300 background: 'none',
301 border: 0,
302 color: 'inherit',
303 font: 'inherit',
304 lineHeight: 'normal',
305 overflow: 'visible',
306
307 cursor: 'pointer',
308 display: 'inline-block',
309 verticalAlign: 'middle',
310 padding: 10,
311 margin: '0 5px 0 10px', // TODO: should be noflip wrapped and handled by an isRTL prop
312 },
313
314 SingleDatePickerInput_calendarIcon_svg: {
315 fill: color.core.grayLight,
316 height: 15,
317 width: 14,
318 verticalAlign: 'middle',
319 },
320}), { pureComponent: typeof React.PureComponent !== 'undefined' })(SingleDatePickerInput);