1 | import React from 'react';
|
2 | import PropTypes from 'prop-types';
|
3 | import momentPropTypes from 'react-moment-proptypes';
|
4 | import { forbidExtraProps, nonNegativeInteger } from 'airbnb-prop-types';
|
5 | import { withStyles, withStylesPropTypes } from 'react-with-styles';
|
6 | import moment from 'moment';
|
7 | import raf from 'raf';
|
8 |
|
9 | import { CalendarDayPhrases } from '../defaultPhrases';
|
10 | import getPhrasePropTypes from '../utils/getPhrasePropTypes';
|
11 | import getCalendarDaySettings from '../utils/getCalendarDaySettings';
|
12 | import ModifiersShape from '../shapes/ModifiersShape';
|
13 |
|
14 | import { DAY_SIZE } from '../constants';
|
15 |
|
16 | const propTypes = forbidExtraProps({
|
17 | ...withStylesPropTypes,
|
18 | day: momentPropTypes.momentObj,
|
19 | daySize: nonNegativeInteger,
|
20 | isOutsideDay: PropTypes.bool,
|
21 | modifiers: ModifiersShape,
|
22 | isFocused: PropTypes.bool,
|
23 | tabIndex: PropTypes.oneOf([0, -1]),
|
24 | onDayClick: PropTypes.func,
|
25 | onDayMouseEnter: PropTypes.func,
|
26 | onDayMouseLeave: PropTypes.func,
|
27 | renderDayContents: PropTypes.func,
|
28 | ariaLabelFormat: PropTypes.string,
|
29 |
|
30 |
|
31 | phrases: PropTypes.shape(getPhrasePropTypes(CalendarDayPhrases)),
|
32 | });
|
33 |
|
34 | const defaultProps = {
|
35 | day: moment(),
|
36 | daySize: DAY_SIZE,
|
37 | isOutsideDay: false,
|
38 | modifiers: new Set(),
|
39 | isFocused: false,
|
40 | tabIndex: -1,
|
41 | onDayClick() {},
|
42 | onDayMouseEnter() {},
|
43 | onDayMouseLeave() {},
|
44 | renderDayContents: null,
|
45 | ariaLabelFormat: 'dddd, LL',
|
46 |
|
47 |
|
48 | phrases: CalendarDayPhrases,
|
49 | };
|
50 |
|
51 | class CalendarDay extends React.PureComponent {
|
52 | constructor(...args) {
|
53 | super(...args);
|
54 |
|
55 | this.setButtonRef = this.setButtonRef.bind(this);
|
56 | }
|
57 |
|
58 | componentDidUpdate(prevProps) {
|
59 | const { isFocused, tabIndex } = this.props;
|
60 | if (tabIndex === 0) {
|
61 | if (isFocused || tabIndex !== prevProps.tabIndex) {
|
62 | raf(() => {
|
63 | if (this.buttonRef) {
|
64 | this.buttonRef.focus();
|
65 | }
|
66 | });
|
67 | }
|
68 | }
|
69 | }
|
70 |
|
71 | onDayClick(day, e) {
|
72 | const { onDayClick } = this.props;
|
73 | onDayClick(day, e);
|
74 | }
|
75 |
|
76 | onDayMouseEnter(day, e) {
|
77 | const { onDayMouseEnter } = this.props;
|
78 | onDayMouseEnter(day, e);
|
79 | }
|
80 |
|
81 | onDayMouseLeave(day, e) {
|
82 | const { onDayMouseLeave } = this.props;
|
83 | onDayMouseLeave(day, e);
|
84 | }
|
85 |
|
86 | onKeyDown(day, e) {
|
87 | const { onDayClick } = this.props;
|
88 |
|
89 | const { key } = e;
|
90 | if (key === 'Enter' || key === ' ') {
|
91 | onDayClick(day, e);
|
92 | }
|
93 | }
|
94 |
|
95 | setButtonRef(ref) {
|
96 | this.buttonRef = ref;
|
97 | }
|
98 |
|
99 | render() {
|
100 | const {
|
101 | day,
|
102 | ariaLabelFormat,
|
103 | daySize,
|
104 | isOutsideDay,
|
105 | modifiers,
|
106 | renderDayContents,
|
107 | tabIndex,
|
108 | styles,
|
109 | phrases,
|
110 | css,
|
111 | } = this.props;
|
112 |
|
113 | if (!day) return <td />;
|
114 |
|
115 | const {
|
116 | daySizeStyles,
|
117 | useDefaultCursor,
|
118 | selected,
|
119 | hoveredSpan,
|
120 | isOutsideRange,
|
121 | ariaLabel,
|
122 | } = getCalendarDaySettings(day, ariaLabelFormat, daySize, modifiers, phrases);
|
123 |
|
124 | return (
|
125 | <td
|
126 | {...css(
|
127 | styles.CalendarDay,
|
128 | useDefaultCursor && styles.CalendarDay__defaultCursor,
|
129 | styles.CalendarDay__default,
|
130 | isOutsideDay && styles.CalendarDay__outside,
|
131 | modifiers.has('today') && styles.CalendarDay__today,
|
132 | modifiers.has('first-day-of-week') && styles.CalendarDay__firstDayOfWeek,
|
133 | modifiers.has('last-day-of-week') && styles.CalendarDay__lastDayOfWeek,
|
134 | modifiers.has('hovered-offset') && styles.CalendarDay__hovered_offset,
|
135 | modifiers.has('hovered-start-first-possible-end') && styles.CalendarDay__hovered_start_first_possible_end,
|
136 | modifiers.has('hovered-start-blocked-minimum-nights') && styles.CalendarDay__hovered_start_blocked_min_nights,
|
137 | modifiers.has('highlighted-calendar') && styles.CalendarDay__highlighted_calendar,
|
138 | modifiers.has('blocked-minimum-nights') && styles.CalendarDay__blocked_minimum_nights,
|
139 | modifiers.has('blocked-calendar') && styles.CalendarDay__blocked_calendar,
|
140 | hoveredSpan && styles.CalendarDay__hovered_span,
|
141 | modifiers.has('selected-span') && styles.CalendarDay__selected_span,
|
142 | modifiers.has('selected-start') && styles.CalendarDay__selected_start,
|
143 | modifiers.has('selected-end') && styles.CalendarDay__selected_end,
|
144 | selected && !modifiers.has('selected-span') && styles.CalendarDay__selected,
|
145 | isOutsideRange && styles.CalendarDay__blocked_out_of_range,
|
146 | daySizeStyles,
|
147 | )}
|
148 | role="button" // eslint-disable-line jsx-a11y/no-noninteractive-element-to-interactive-role
|
149 | ref={this.setButtonRef}
|
150 | aria-disabled={modifiers.has('blocked')}
|
151 | aria-label={ariaLabel}
|
152 | onMouseEnter={(e) => { this.onDayMouseEnter(day, e); }}
|
153 | onMouseLeave={(e) => { this.onDayMouseLeave(day, e); }}
|
154 | onMouseUp={(e) => { e.currentTarget.blur(); }}
|
155 | onClick={(e) => { this.onDayClick(day, e); }}
|
156 | onKeyDown={(e) => { this.onKeyDown(day, e); }}
|
157 | tabIndex={tabIndex}
|
158 | >
|
159 | {renderDayContents ? renderDayContents(day, modifiers) : day.format('D')}
|
160 | </td>
|
161 | );
|
162 | }
|
163 | }
|
164 |
|
165 | CalendarDay.propTypes = propTypes;
|
166 | CalendarDay.defaultProps = defaultProps;
|
167 |
|
168 | export { CalendarDay as PureCalendarDay };
|
169 | export default withStyles(({ reactDates: { color, font } }) => ({
|
170 | CalendarDay: {
|
171 | boxSizing: 'border-box',
|
172 | cursor: 'pointer',
|
173 | fontSize: font.size,
|
174 | textAlign: 'center',
|
175 |
|
176 | ':active': {
|
177 | outline: 0,
|
178 | },
|
179 | },
|
180 |
|
181 | CalendarDay__defaultCursor: {
|
182 | cursor: 'default',
|
183 | },
|
184 |
|
185 | CalendarDay__default: {
|
186 | border: `1px solid ${color.core.borderLight}`,
|
187 | color: color.text,
|
188 | background: color.background,
|
189 |
|
190 | ':hover': {
|
191 | background: color.core.borderLight,
|
192 | border: `1px solid ${color.core.borderLight}`,
|
193 | color: 'inherit',
|
194 | },
|
195 | },
|
196 |
|
197 | CalendarDay__hovered_offset: {
|
198 | background: color.core.borderBright,
|
199 | border: `1px double ${color.core.borderLight}`,
|
200 | color: 'inherit',
|
201 | },
|
202 |
|
203 | CalendarDay__outside: {
|
204 | border: 0,
|
205 | background: color.outside.backgroundColor,
|
206 | color: color.outside.color,
|
207 |
|
208 | ':hover': {
|
209 | border: 0,
|
210 | },
|
211 | },
|
212 |
|
213 | CalendarDay__blocked_minimum_nights: {
|
214 | background: color.minimumNights.backgroundColor,
|
215 | border: `1px solid ${color.minimumNights.borderColor}`,
|
216 | color: color.minimumNights.color,
|
217 |
|
218 | ':hover': {
|
219 | background: color.minimumNights.backgroundColor_hover,
|
220 | color: color.minimumNights.color_active,
|
221 | },
|
222 |
|
223 | ':active': {
|
224 | background: color.minimumNights.backgroundColor_active,
|
225 | color: color.minimumNights.color_active,
|
226 | },
|
227 | },
|
228 |
|
229 | CalendarDay__highlighted_calendar: {
|
230 | background: color.highlighted.backgroundColor,
|
231 | color: color.highlighted.color,
|
232 |
|
233 | ':hover': {
|
234 | background: color.highlighted.backgroundColor_hover,
|
235 | color: color.highlighted.color_active,
|
236 | },
|
237 |
|
238 | ':active': {
|
239 | background: color.highlighted.backgroundColor_active,
|
240 | color: color.highlighted.color_active,
|
241 | },
|
242 | },
|
243 |
|
244 | CalendarDay__selected_span: {
|
245 | background: color.selectedSpan.backgroundColor,
|
246 | border: `1px double ${color.selectedSpan.borderColor}`,
|
247 | color: color.selectedSpan.color,
|
248 |
|
249 | ':hover': {
|
250 | background: color.selectedSpan.backgroundColor_hover,
|
251 | border: `1px double ${color.selectedSpan.borderColor}`,
|
252 | color: color.selectedSpan.color_active,
|
253 | },
|
254 |
|
255 | ':active': {
|
256 | background: color.selectedSpan.backgroundColor_active,
|
257 | border: `1px double ${color.selectedSpan.borderColor}`,
|
258 | color: color.selectedSpan.color_active,
|
259 | },
|
260 | },
|
261 |
|
262 | CalendarDay__selected: {
|
263 | background: color.selected.backgroundColor,
|
264 | border: `1px double ${color.selected.borderColor}`,
|
265 | color: color.selected.color,
|
266 |
|
267 | ':hover': {
|
268 | background: color.selected.backgroundColor_hover,
|
269 | border: `1px double ${color.selected.borderColor}`,
|
270 | color: color.selected.color_active,
|
271 | },
|
272 |
|
273 | ':active': {
|
274 | background: color.selected.backgroundColor_active,
|
275 | border: `1px double ${color.selected.borderColor}`,
|
276 | color: color.selected.color_active,
|
277 | },
|
278 | },
|
279 |
|
280 | CalendarDay__hovered_span: {
|
281 | background: color.hoveredSpan.backgroundColor,
|
282 | border: `1px double ${color.hoveredSpan.borderColor}`,
|
283 | color: color.hoveredSpan.color,
|
284 |
|
285 | ':hover': {
|
286 | background: color.hoveredSpan.backgroundColor_hover,
|
287 | border: `1px double ${color.hoveredSpan.borderColor}`,
|
288 | color: color.hoveredSpan.color_active,
|
289 | },
|
290 |
|
291 | ':active': {
|
292 | background: color.hoveredSpan.backgroundColor_active,
|
293 | border: `1px double ${color.hoveredSpan.borderColor}`,
|
294 | color: color.hoveredSpan.color_active,
|
295 | },
|
296 | },
|
297 |
|
298 | CalendarDay__blocked_calendar: {
|
299 | background: color.blocked_calendar.backgroundColor,
|
300 | border: `1px solid ${color.blocked_calendar.borderColor}`,
|
301 | color: color.blocked_calendar.color,
|
302 |
|
303 | ':hover': {
|
304 | background: color.blocked_calendar.backgroundColor_hover,
|
305 | border: `1px solid ${color.blocked_calendar.borderColor}`,
|
306 | color: color.blocked_calendar.color_active,
|
307 | },
|
308 |
|
309 | ':active': {
|
310 | background: color.blocked_calendar.backgroundColor_active,
|
311 | border: `1px solid ${color.blocked_calendar.borderColor}`,
|
312 | color: color.blocked_calendar.color_active,
|
313 | },
|
314 | },
|
315 |
|
316 | CalendarDay__blocked_out_of_range: {
|
317 | background: color.blocked_out_of_range.backgroundColor,
|
318 | border: `1px solid ${color.blocked_out_of_range.borderColor}`,
|
319 | color: color.blocked_out_of_range.color,
|
320 |
|
321 | ':hover': {
|
322 | background: color.blocked_out_of_range.backgroundColor_hover,
|
323 | border: `1px solid ${color.blocked_out_of_range.borderColor}`,
|
324 | color: color.blocked_out_of_range.color_active,
|
325 | },
|
326 |
|
327 | ':active': {
|
328 | background: color.blocked_out_of_range.backgroundColor_active,
|
329 | border: `1px solid ${color.blocked_out_of_range.borderColor}`,
|
330 | color: color.blocked_out_of_range.color_active,
|
331 | },
|
332 | },
|
333 |
|
334 | CalendarDay__hovered_start_first_possible_end: {
|
335 | background: color.core.borderLighter,
|
336 | border: `1px double ${color.core.borderLighter}`,
|
337 | },
|
338 |
|
339 | CalendarDay__hovered_start_blocked_min_nights: {
|
340 | background: color.core.borderLighter,
|
341 | border: `1px double ${color.core.borderLight}`,
|
342 | },
|
343 |
|
344 | CalendarDay__selected_start: {},
|
345 | CalendarDay__selected_end: {},
|
346 | CalendarDay__today: {},
|
347 | CalendarDay__firstDayOfWeek: {},
|
348 | CalendarDay__lastDayOfWeek: {},
|
349 | }), { pureComponent: typeof React.PureComponent !== 'undefined' })(CalendarDay);
|
350 |
|
\ | No newline at end of file |