@zendeskgarden/react-datepickers 9.0.0-next.6 → 9.0.0-next.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/elements/DatePicker/DatePicker.js +169 -0
- package/dist/esm/elements/DatePicker/components/Calendar.js +125 -0
- package/dist/esm/elements/DatePicker/components/Input.js +75 -0
- package/dist/esm/elements/DatePicker/components/MonthSelector.js +61 -0
- package/dist/esm/elements/DatePicker/utils/date-picker-reducer.js +187 -0
- package/dist/esm/elements/DatePicker/utils/useDatePickerContext.js +14 -0
- package/dist/esm/elements/DatePickerRange/DatePickerRange.js +101 -0
- package/dist/esm/elements/DatePickerRange/components/Calendar.js +42 -0
- package/dist/esm/elements/DatePickerRange/components/End.js +79 -0
- package/dist/esm/elements/DatePickerRange/components/Month.js +270 -0
- package/dist/esm/elements/DatePickerRange/components/Start.js +79 -0
- package/dist/esm/elements/DatePickerRange/utils/date-picker-range-reducer.js +319 -0
- package/dist/esm/elements/DatePickerRange/utils/useDatePickerRangeContext.js +14 -0
- package/dist/esm/index.js +8 -0
- package/dist/esm/node_modules/@zendeskgarden/svg-icons/src/16/chevron-left-stroke.svg.js +25 -0
- package/dist/esm/node_modules/@zendeskgarden/svg-icons/src/16/chevron-right-stroke.svg.js +25 -0
- package/dist/esm/styled/StyledCalendar.js +21 -0
- package/dist/esm/styled/StyledCalendarItem.js +34 -0
- package/dist/esm/styled/StyledDatePicker.js +32 -0
- package/dist/esm/styled/StyledDay.js +54 -0
- package/dist/esm/styled/StyledDayLabel.js +21 -0
- package/dist/esm/styled/StyledHeader.js +21 -0
- package/dist/esm/styled/StyledHeaderLabel.js +21 -0
- package/dist/esm/styled/StyledHeaderPaddle.js +38 -0
- package/dist/esm/styled/StyledHighlight.js +50 -0
- package/dist/esm/styled/StyledMenu.js +22 -0
- package/dist/esm/styled/StyledMenuWrapper.js +27 -0
- package/dist/esm/styled/StyledRangeCalendar.js +22 -0
- package/dist/esm/types/index.js +12 -0
- package/dist/esm/utils/calendar-utils.js +88 -0
- package/dist/index.cjs.js +12 -28
- package/package.json +5 -5
- package/dist/index.esm.js +0 -1687
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Zendesk, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Use of this source code is governed under the Apache License, Version 2.0
|
|
5
|
+
* found at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
*/
|
|
7
|
+
import React__default, { forwardRef, useContext, useCallback, useReducer, useRef, useState, useMemo, useEffect } from 'react';
|
|
8
|
+
import PropTypes from 'prop-types';
|
|
9
|
+
import { mergeRefs } from 'react-merge-refs';
|
|
10
|
+
import { ThemeContext } from 'styled-components';
|
|
11
|
+
import { useFloating, platform, autoPlacement, flip, autoUpdate } from '@floating-ui/react-dom';
|
|
12
|
+
import { WEEK_STARTS_ON, PLACEMENT } from '../../types/index.js';
|
|
13
|
+
import { Calendar } from './components/Calendar.js';
|
|
14
|
+
import { datepickerReducer, retrieveInitialState } from './utils/date-picker-reducer.js';
|
|
15
|
+
import { DatePickerContext } from './utils/useDatePickerContext.js';
|
|
16
|
+
import { StyledMenu } from '../../styled/StyledMenu.js';
|
|
17
|
+
import { StyledMenuWrapper } from '../../styled/StyledMenuWrapper.js';
|
|
18
|
+
import '../../styled/StyledDatePicker.js';
|
|
19
|
+
import '../../styled/StyledRangeCalendar.js';
|
|
20
|
+
import '../../styled/StyledHeader.js';
|
|
21
|
+
import '../../styled/StyledHeaderPaddle.js';
|
|
22
|
+
import '../../styled/StyledHeaderLabel.js';
|
|
23
|
+
import '../../styled/StyledCalendar.js';
|
|
24
|
+
import '../../styled/StyledCalendarItem.js';
|
|
25
|
+
import '../../styled/StyledDayLabel.js';
|
|
26
|
+
import '../../styled/StyledHighlight.js';
|
|
27
|
+
import '../../styled/StyledDay.js';
|
|
28
|
+
import { DEFAULT_THEME, getFloatingPlacements } from '@zendeskgarden/react-theming';
|
|
29
|
+
import { Input } from './components/Input.js';
|
|
30
|
+
|
|
31
|
+
const PLACEMENT_DEFAULT = 'bottom-start';
|
|
32
|
+
const DatePicker = forwardRef((props, calendarRef) => {
|
|
33
|
+
const {
|
|
34
|
+
children,
|
|
35
|
+
placement: _placement,
|
|
36
|
+
zIndex,
|
|
37
|
+
isAnimated,
|
|
38
|
+
refKey,
|
|
39
|
+
value,
|
|
40
|
+
isCompact,
|
|
41
|
+
onChange,
|
|
42
|
+
formatDate,
|
|
43
|
+
minValue,
|
|
44
|
+
maxValue,
|
|
45
|
+
locale,
|
|
46
|
+
weekStartsOn,
|
|
47
|
+
customParseDate,
|
|
48
|
+
...menuProps
|
|
49
|
+
} = props;
|
|
50
|
+
const theme = useContext(ThemeContext) || DEFAULT_THEME;
|
|
51
|
+
const memoizedReducer = useCallback(datepickerReducer({
|
|
52
|
+
value,
|
|
53
|
+
formatDate,
|
|
54
|
+
locale,
|
|
55
|
+
customParseDate,
|
|
56
|
+
onChange
|
|
57
|
+
}), [value, formatDate, locale, onChange, customParseDate]);
|
|
58
|
+
const [state, dispatch] = useReducer(memoizedReducer, retrieveInitialState(props));
|
|
59
|
+
const triggerRef = useRef(null);
|
|
60
|
+
const floatingRef = useRef(null);
|
|
61
|
+
const [isVisible, setIsVisible] = useState(state.isOpen);
|
|
62
|
+
const contextValue = useMemo(() => ({
|
|
63
|
+
state,
|
|
64
|
+
dispatch
|
|
65
|
+
}), [state, dispatch]);
|
|
66
|
+
const [floatingPlacement] = getFloatingPlacements(theme, _placement === 'auto' ? PLACEMENT_DEFAULT : _placement);
|
|
67
|
+
const {
|
|
68
|
+
refs,
|
|
69
|
+
placement,
|
|
70
|
+
update,
|
|
71
|
+
floatingStyles: {
|
|
72
|
+
transform
|
|
73
|
+
}
|
|
74
|
+
} = useFloating({
|
|
75
|
+
platform: {
|
|
76
|
+
...platform,
|
|
77
|
+
isRTL: () => theme.rtl
|
|
78
|
+
},
|
|
79
|
+
elements: {
|
|
80
|
+
reference: triggerRef?.current,
|
|
81
|
+
floating: floatingRef?.current
|
|
82
|
+
},
|
|
83
|
+
placement: floatingPlacement,
|
|
84
|
+
middleware: [_placement === 'auto' ? autoPlacement() : flip()]
|
|
85
|
+
});
|
|
86
|
+
const Child = React__default.Children.only(children);
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
let cleanup;
|
|
89
|
+
if (state.isOpen && refs.reference.current && refs.floating.current) {
|
|
90
|
+
cleanup = autoUpdate(refs.reference.current, refs.floating.current, update, {
|
|
91
|
+
elementResize: typeof ResizeObserver === 'function'
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
return () => cleanup && cleanup();
|
|
95
|
+
}, [state.isOpen, refs.reference, refs.floating, update]);
|
|
96
|
+
useEffect(() => {
|
|
97
|
+
let timeout;
|
|
98
|
+
if (state.isOpen) {
|
|
99
|
+
setIsVisible(true);
|
|
100
|
+
} else if (isAnimated) {
|
|
101
|
+
timeout = setTimeout(() => setIsVisible(false), 200);
|
|
102
|
+
} else {
|
|
103
|
+
setIsVisible(false);
|
|
104
|
+
}
|
|
105
|
+
return () => clearTimeout(timeout);
|
|
106
|
+
}, [state.isOpen, isAnimated]);
|
|
107
|
+
useEffect(() => {
|
|
108
|
+
dispatch({
|
|
109
|
+
type: 'CONTROLLED_VALUE_CHANGE',
|
|
110
|
+
value
|
|
111
|
+
});
|
|
112
|
+
}, [value]);
|
|
113
|
+
useEffect(() => {
|
|
114
|
+
dispatch({
|
|
115
|
+
type: 'CONTROLLED_LOCALE_CHANGE'
|
|
116
|
+
});
|
|
117
|
+
}, [locale]);
|
|
118
|
+
return React__default.createElement(React__default.Fragment, null, React__default.createElement(Input, {
|
|
119
|
+
element: Child,
|
|
120
|
+
dispatch: dispatch,
|
|
121
|
+
state: state,
|
|
122
|
+
refKey: refKey,
|
|
123
|
+
ref: mergeRefs([triggerRef, Child.ref ? Child.ref : null])
|
|
124
|
+
}), React__default.createElement(DatePickerContext.Provider, {
|
|
125
|
+
value: contextValue
|
|
126
|
+
}, React__default.createElement(StyledMenuWrapper, {
|
|
127
|
+
ref: floatingRef,
|
|
128
|
+
style: {
|
|
129
|
+
transform
|
|
130
|
+
},
|
|
131
|
+
isHidden: !state.isOpen,
|
|
132
|
+
isAnimated: isAnimated && (state.isOpen || isVisible),
|
|
133
|
+
placement: placement,
|
|
134
|
+
zIndex: zIndex
|
|
135
|
+
}, (state.isOpen || isVisible) && React__default.createElement(StyledMenu, menuProps, React__default.createElement(Calendar, {
|
|
136
|
+
ref: calendarRef,
|
|
137
|
+
isCompact: isCompact,
|
|
138
|
+
value: value,
|
|
139
|
+
minValue: minValue,
|
|
140
|
+
maxValue: maxValue,
|
|
141
|
+
locale: locale,
|
|
142
|
+
weekStartsOn: weekStartsOn
|
|
143
|
+
})))));
|
|
144
|
+
});
|
|
145
|
+
DatePicker.displayName = 'DatePicker';
|
|
146
|
+
DatePicker.propTypes = {
|
|
147
|
+
value: PropTypes.any,
|
|
148
|
+
onChange: PropTypes.any,
|
|
149
|
+
formatDate: PropTypes.func,
|
|
150
|
+
locale: PropTypes.any,
|
|
151
|
+
weekStartsOn: PropTypes.oneOf(WEEK_STARTS_ON),
|
|
152
|
+
minValue: PropTypes.any,
|
|
153
|
+
maxValue: PropTypes.any,
|
|
154
|
+
isCompact: PropTypes.bool,
|
|
155
|
+
customParseDate: PropTypes.any,
|
|
156
|
+
refKey: PropTypes.string,
|
|
157
|
+
placement: PropTypes.oneOf(PLACEMENT),
|
|
158
|
+
isAnimated: PropTypes.bool,
|
|
159
|
+
zIndex: PropTypes.number
|
|
160
|
+
};
|
|
161
|
+
DatePicker.defaultProps = {
|
|
162
|
+
placement: PLACEMENT_DEFAULT,
|
|
163
|
+
refKey: 'ref',
|
|
164
|
+
isAnimated: true,
|
|
165
|
+
zIndex: 1000,
|
|
166
|
+
locale: 'en-US'
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
export { DatePicker };
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Zendesk, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Use of this source code is governed under the Apache License, Version 2.0
|
|
5
|
+
* found at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
*/
|
|
7
|
+
import React__default, { forwardRef, useCallback } from 'react';
|
|
8
|
+
import { startOfMonth } from 'date-fns/startOfMonth';
|
|
9
|
+
import { endOfMonth } from 'date-fns/endOfMonth';
|
|
10
|
+
import { startOfWeek } from 'date-fns/startOfWeek';
|
|
11
|
+
import { endOfWeek } from 'date-fns/endOfWeek';
|
|
12
|
+
import { eachDayOfInterval } from 'date-fns/eachDayOfInterval';
|
|
13
|
+
import { addDays } from 'date-fns/addDays';
|
|
14
|
+
import { isToday } from 'date-fns/isToday';
|
|
15
|
+
import { isSameDay } from 'date-fns/isSameDay';
|
|
16
|
+
import { isSameMonth } from 'date-fns/isSameMonth';
|
|
17
|
+
import { isBefore } from 'date-fns/isBefore';
|
|
18
|
+
import { isAfter } from 'date-fns/isAfter';
|
|
19
|
+
import { getDate } from 'date-fns/getDate';
|
|
20
|
+
import '../../../styled/StyledMenu.js';
|
|
21
|
+
import '../../../styled/StyledMenuWrapper.js';
|
|
22
|
+
import { StyledDatePicker } from '../../../styled/StyledDatePicker.js';
|
|
23
|
+
import '../../../styled/StyledRangeCalendar.js';
|
|
24
|
+
import '../../../styled/StyledHeader.js';
|
|
25
|
+
import '../../../styled/StyledHeaderPaddle.js';
|
|
26
|
+
import '../../../styled/StyledHeaderLabel.js';
|
|
27
|
+
import { StyledCalendar } from '../../../styled/StyledCalendar.js';
|
|
28
|
+
import { StyledCalendarItem } from '../../../styled/StyledCalendarItem.js';
|
|
29
|
+
import { StyledDayLabel } from '../../../styled/StyledDayLabel.js';
|
|
30
|
+
import '../../../styled/StyledHighlight.js';
|
|
31
|
+
import { StyledDay } from '../../../styled/StyledDay.js';
|
|
32
|
+
import useDatePickerContext from '../utils/useDatePickerContext.js';
|
|
33
|
+
import { getStartOfWeek } from '../../../utils/calendar-utils.js';
|
|
34
|
+
import { MonthSelector } from './MonthSelector.js';
|
|
35
|
+
|
|
36
|
+
const Calendar = forwardRef((_ref, ref) => {
|
|
37
|
+
let {
|
|
38
|
+
value,
|
|
39
|
+
minValue,
|
|
40
|
+
maxValue,
|
|
41
|
+
isCompact,
|
|
42
|
+
locale,
|
|
43
|
+
weekStartsOn
|
|
44
|
+
} = _ref;
|
|
45
|
+
const {
|
|
46
|
+
state,
|
|
47
|
+
dispatch
|
|
48
|
+
} = useDatePickerContext();
|
|
49
|
+
const preferredWeekStartsOn = weekStartsOn || getStartOfWeek(locale);
|
|
50
|
+
const monthStartDate = startOfMonth(state.previewDate);
|
|
51
|
+
const monthEndDate = endOfMonth(monthStartDate);
|
|
52
|
+
const startDate = startOfWeek(monthStartDate, {
|
|
53
|
+
weekStartsOn: preferredWeekStartsOn
|
|
54
|
+
});
|
|
55
|
+
const endDate = endOfWeek(monthEndDate, {
|
|
56
|
+
weekStartsOn: preferredWeekStartsOn
|
|
57
|
+
});
|
|
58
|
+
const dayLabelFormatter = useCallback(date => {
|
|
59
|
+
const formatter = new Intl.DateTimeFormat(locale, {
|
|
60
|
+
weekday: 'short'
|
|
61
|
+
});
|
|
62
|
+
return formatter.format(date);
|
|
63
|
+
}, [locale]);
|
|
64
|
+
const dayLabels = eachDayOfInterval({
|
|
65
|
+
start: startDate,
|
|
66
|
+
end: addDays(startDate, 6)
|
|
67
|
+
}).map(date => {
|
|
68
|
+
const formattedDayLabel = dayLabelFormatter(date);
|
|
69
|
+
return React__default.createElement(StyledCalendarItem, {
|
|
70
|
+
key: `day-label-${formattedDayLabel}`,
|
|
71
|
+
isCompact: isCompact
|
|
72
|
+
}, React__default.createElement(StyledDayLabel, {
|
|
73
|
+
isCompact: isCompact
|
|
74
|
+
}, formattedDayLabel));
|
|
75
|
+
});
|
|
76
|
+
const items = eachDayOfInterval({
|
|
77
|
+
start: startDate,
|
|
78
|
+
end: endDate
|
|
79
|
+
}).map((date, itemsIndex) => {
|
|
80
|
+
const formattedDayLabel = getDate(date);
|
|
81
|
+
const isCurrentDate = isToday(date);
|
|
82
|
+
const isPreviousMonth = !isSameMonth(date, state.previewDate);
|
|
83
|
+
const isSelected = value && isSameDay(date, value);
|
|
84
|
+
let isDisabled = false;
|
|
85
|
+
if (minValue !== undefined) {
|
|
86
|
+
isDisabled = isBefore(date, minValue) && !isSameDay(date, minValue);
|
|
87
|
+
}
|
|
88
|
+
if (maxValue !== undefined) {
|
|
89
|
+
isDisabled = isDisabled || isAfter(date, maxValue) && !isSameDay(date, maxValue);
|
|
90
|
+
}
|
|
91
|
+
return React__default.createElement(StyledCalendarItem, {
|
|
92
|
+
key: `day-${itemsIndex}`,
|
|
93
|
+
isCompact: isCompact
|
|
94
|
+
}, React__default.createElement(StyledDay, {
|
|
95
|
+
isToday: isCurrentDate,
|
|
96
|
+
isPreviousMonth: isPreviousMonth,
|
|
97
|
+
isSelected: isSelected,
|
|
98
|
+
isDisabled: isDisabled,
|
|
99
|
+
isCompact: isCompact,
|
|
100
|
+
onClick: () => {
|
|
101
|
+
if (!isDisabled) {
|
|
102
|
+
dispatch({
|
|
103
|
+
type: 'SELECT_DATE',
|
|
104
|
+
value: date
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}, formattedDayLabel));
|
|
109
|
+
});
|
|
110
|
+
return React__default.createElement(StyledDatePicker, {
|
|
111
|
+
ref: ref,
|
|
112
|
+
isCompact: isCompact,
|
|
113
|
+
onMouseDown: e => {
|
|
114
|
+
e.preventDefault();
|
|
115
|
+
}
|
|
116
|
+
}, React__default.createElement(MonthSelector, {
|
|
117
|
+
locale: locale,
|
|
118
|
+
isCompact: isCompact
|
|
119
|
+
}), React__default.createElement(StyledCalendar, {
|
|
120
|
+
isCompact: isCompact
|
|
121
|
+
}, dayLabels, items));
|
|
122
|
+
});
|
|
123
|
+
Calendar.displayName = 'Calendar';
|
|
124
|
+
|
|
125
|
+
export { Calendar };
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Zendesk, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Use of this source code is governed under the Apache License, Version 2.0
|
|
5
|
+
* found at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
*/
|
|
7
|
+
import { forwardRef, useRef, cloneElement } from 'react';
|
|
8
|
+
import { composeEventHandlers, KEYS } from '@zendeskgarden/container-utilities';
|
|
9
|
+
|
|
10
|
+
const Input = forwardRef((_ref, ref) => {
|
|
11
|
+
let {
|
|
12
|
+
element,
|
|
13
|
+
dispatch,
|
|
14
|
+
state,
|
|
15
|
+
refKey
|
|
16
|
+
} = _ref;
|
|
17
|
+
const isInputMouseDownRef = useRef(false);
|
|
18
|
+
const handleBlur = () => {
|
|
19
|
+
dispatch({
|
|
20
|
+
type: 'CLOSE'
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
const handleChange = e => {
|
|
24
|
+
dispatch({
|
|
25
|
+
type: 'MANUALLY_UPDATE_INPUT',
|
|
26
|
+
value: e.target.value
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
const handleClick = () => {
|
|
30
|
+
if (isInputMouseDownRef.current && !state.isOpen) {
|
|
31
|
+
dispatch({
|
|
32
|
+
type: 'OPEN'
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
const handleKeyDown = e => {
|
|
37
|
+
switch (e.key) {
|
|
38
|
+
case KEYS.ESCAPE:
|
|
39
|
+
case KEYS.ENTER:
|
|
40
|
+
dispatch({
|
|
41
|
+
type: 'CLOSE'
|
|
42
|
+
});
|
|
43
|
+
break;
|
|
44
|
+
case KEYS.UP:
|
|
45
|
+
case KEYS.DOWN:
|
|
46
|
+
case KEYS.SPACE:
|
|
47
|
+
dispatch({
|
|
48
|
+
type: 'OPEN'
|
|
49
|
+
});
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
const handleMouseDown = () => {
|
|
54
|
+
isInputMouseDownRef.current = true;
|
|
55
|
+
};
|
|
56
|
+
const handleMouseUp = () => {
|
|
57
|
+
setTimeout(() => {
|
|
58
|
+
isInputMouseDownRef.current = false;
|
|
59
|
+
}, 0);
|
|
60
|
+
};
|
|
61
|
+
return cloneElement(element, {
|
|
62
|
+
[refKey]: ref,
|
|
63
|
+
onMouseDown: composeEventHandlers(element.props.onMouseDown, handleMouseDown),
|
|
64
|
+
onMouseUp: composeEventHandlers(element.props.onMouseUp, handleMouseUp),
|
|
65
|
+
onClick: composeEventHandlers(element.props.onClick, handleClick),
|
|
66
|
+
onBlur: composeEventHandlers(element.props.onBlur, handleBlur),
|
|
67
|
+
onChange: composeEventHandlers(element.props.onChange, handleChange),
|
|
68
|
+
onKeyDown: composeEventHandlers(element.props.onKeyDown, handleKeyDown),
|
|
69
|
+
autoComplete: 'off',
|
|
70
|
+
value: state.inputValue
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
Input.displayName = 'Input';
|
|
74
|
+
|
|
75
|
+
export { Input };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Zendesk, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Use of this source code is governed under the Apache License, Version 2.0
|
|
5
|
+
* found at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
*/
|
|
7
|
+
import React__default, { useCallback } from 'react';
|
|
8
|
+
import '../../../styled/StyledMenu.js';
|
|
9
|
+
import '../../../styled/StyledMenuWrapper.js';
|
|
10
|
+
import '../../../styled/StyledDatePicker.js';
|
|
11
|
+
import '../../../styled/StyledRangeCalendar.js';
|
|
12
|
+
import { StyledHeader } from '../../../styled/StyledHeader.js';
|
|
13
|
+
import { StyledHeaderPaddle } from '../../../styled/StyledHeaderPaddle.js';
|
|
14
|
+
import { StyledHeaderLabel } from '../../../styled/StyledHeaderLabel.js';
|
|
15
|
+
import '../../../styled/StyledCalendar.js';
|
|
16
|
+
import '../../../styled/StyledCalendarItem.js';
|
|
17
|
+
import '../../../styled/StyledDayLabel.js';
|
|
18
|
+
import '../../../styled/StyledHighlight.js';
|
|
19
|
+
import '../../../styled/StyledDay.js';
|
|
20
|
+
import useDatePickerContext from '../utils/useDatePickerContext.js';
|
|
21
|
+
import SvgChevronLeftStroke from '../../../node_modules/@zendeskgarden/svg-icons/src/16/chevron-left-stroke.svg.js';
|
|
22
|
+
import SvgChevronRightStroke from '../../../node_modules/@zendeskgarden/svg-icons/src/16/chevron-right-stroke.svg.js';
|
|
23
|
+
|
|
24
|
+
const MonthSelector = _ref => {
|
|
25
|
+
let {
|
|
26
|
+
locale,
|
|
27
|
+
isCompact
|
|
28
|
+
} = _ref;
|
|
29
|
+
const {
|
|
30
|
+
state,
|
|
31
|
+
dispatch
|
|
32
|
+
} = useDatePickerContext();
|
|
33
|
+
const headerLabelFormatter = useCallback(date => {
|
|
34
|
+
const formatter = new Intl.DateTimeFormat(locale, {
|
|
35
|
+
month: 'long',
|
|
36
|
+
year: 'numeric'
|
|
37
|
+
});
|
|
38
|
+
return formatter.format(date);
|
|
39
|
+
}, [locale]);
|
|
40
|
+
return React__default.createElement(StyledHeader, {
|
|
41
|
+
isCompact: isCompact
|
|
42
|
+
}, React__default.createElement(StyledHeaderPaddle, {
|
|
43
|
+
isCompact: isCompact,
|
|
44
|
+
onClick: () => {
|
|
45
|
+
dispatch({
|
|
46
|
+
type: 'PREVIEW_PREVIOUS_MONTH'
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}, React__default.createElement(SvgChevronLeftStroke, null)), React__default.createElement(StyledHeaderLabel, {
|
|
50
|
+
isCompact: isCompact
|
|
51
|
+
}, headerLabelFormatter(state.previewDate)), React__default.createElement(StyledHeaderPaddle, {
|
|
52
|
+
isCompact: isCompact,
|
|
53
|
+
onClick: () => {
|
|
54
|
+
dispatch({
|
|
55
|
+
type: 'PREVIEW_NEXT_MONTH'
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}, React__default.createElement(SvgChevronRightStroke, null)));
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export { MonthSelector };
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Zendesk, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Use of this source code is governed under the Apache License, Version 2.0
|
|
5
|
+
* found at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
*/
|
|
7
|
+
import { addMonths } from 'date-fns/addMonths';
|
|
8
|
+
import { subMonths } from 'date-fns/subMonths';
|
|
9
|
+
import { isValid } from 'date-fns/isValid';
|
|
10
|
+
import { parse } from 'date-fns/parse';
|
|
11
|
+
import { isBefore } from 'date-fns/isBefore';
|
|
12
|
+
import { isSameDay } from 'date-fns/isSameDay';
|
|
13
|
+
|
|
14
|
+
function parseInputValue(_ref) {
|
|
15
|
+
let {
|
|
16
|
+
inputValue,
|
|
17
|
+
customParseDate
|
|
18
|
+
} = _ref;
|
|
19
|
+
if (customParseDate) {
|
|
20
|
+
return customParseDate(inputValue);
|
|
21
|
+
}
|
|
22
|
+
const MINIMUM_DATE = new Date(1001, 0, 0);
|
|
23
|
+
let tryParseDate = parse(inputValue, 'P', new Date());
|
|
24
|
+
if (isValid(tryParseDate) && !isBefore(tryParseDate, MINIMUM_DATE)) {
|
|
25
|
+
return tryParseDate;
|
|
26
|
+
}
|
|
27
|
+
tryParseDate = parse(inputValue, 'PP', new Date());
|
|
28
|
+
if (isValid(tryParseDate) && !isBefore(tryParseDate, MINIMUM_DATE)) {
|
|
29
|
+
return tryParseDate;
|
|
30
|
+
}
|
|
31
|
+
tryParseDate = parse(inputValue, 'PPP', new Date());
|
|
32
|
+
if (isValid(tryParseDate) && !isBefore(tryParseDate, MINIMUM_DATE)) {
|
|
33
|
+
return tryParseDate;
|
|
34
|
+
}
|
|
35
|
+
return new Date(NaN);
|
|
36
|
+
}
|
|
37
|
+
function formatInputValue(_ref2) {
|
|
38
|
+
let {
|
|
39
|
+
date,
|
|
40
|
+
locale,
|
|
41
|
+
formatDate
|
|
42
|
+
} = _ref2;
|
|
43
|
+
if (!date) {
|
|
44
|
+
return '';
|
|
45
|
+
}
|
|
46
|
+
if (formatDate) {
|
|
47
|
+
return formatDate(date);
|
|
48
|
+
}
|
|
49
|
+
return new Intl.DateTimeFormat(locale, {
|
|
50
|
+
month: 'long',
|
|
51
|
+
day: 'numeric',
|
|
52
|
+
year: 'numeric'
|
|
53
|
+
}).format(date);
|
|
54
|
+
}
|
|
55
|
+
const datepickerReducer = _ref3 => {
|
|
56
|
+
let {
|
|
57
|
+
value,
|
|
58
|
+
formatDate,
|
|
59
|
+
locale,
|
|
60
|
+
customParseDate,
|
|
61
|
+
onChange
|
|
62
|
+
} = _ref3;
|
|
63
|
+
return (state, action) => {
|
|
64
|
+
switch (action.type) {
|
|
65
|
+
case 'OPEN':
|
|
66
|
+
return {
|
|
67
|
+
...state,
|
|
68
|
+
isOpen: true,
|
|
69
|
+
previewDate: value || new Date()
|
|
70
|
+
};
|
|
71
|
+
case 'CLOSE':
|
|
72
|
+
{
|
|
73
|
+
const inputValue = formatInputValue({
|
|
74
|
+
date: value,
|
|
75
|
+
locale,
|
|
76
|
+
formatDate
|
|
77
|
+
});
|
|
78
|
+
return {
|
|
79
|
+
...state,
|
|
80
|
+
isOpen: false,
|
|
81
|
+
inputValue
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
case 'PREVIEW_NEXT_MONTH':
|
|
85
|
+
{
|
|
86
|
+
const previewDate = addMonths(state.previewDate, 1);
|
|
87
|
+
return {
|
|
88
|
+
...state,
|
|
89
|
+
previewDate
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
case 'PREVIEW_PREVIOUS_MONTH':
|
|
93
|
+
{
|
|
94
|
+
const previewDate = subMonths(state.previewDate, 1);
|
|
95
|
+
return {
|
|
96
|
+
...state,
|
|
97
|
+
previewDate
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
case 'MANUALLY_UPDATE_INPUT':
|
|
101
|
+
{
|
|
102
|
+
const inputValue = action.value;
|
|
103
|
+
const currentDate = parseInputValue({
|
|
104
|
+
inputValue,
|
|
105
|
+
customParseDate
|
|
106
|
+
});
|
|
107
|
+
if (onChange && currentDate && isValid(currentDate) && !isSameDay(value, currentDate)) {
|
|
108
|
+
onChange(currentDate);
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
...state,
|
|
112
|
+
isOpen: true,
|
|
113
|
+
inputValue
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
case 'CONTROLLED_VALUE_CHANGE':
|
|
117
|
+
{
|
|
118
|
+
const previewDate = action.value || new Date();
|
|
119
|
+
const inputValue = formatInputValue({
|
|
120
|
+
date: action.value,
|
|
121
|
+
locale,
|
|
122
|
+
formatDate
|
|
123
|
+
});
|
|
124
|
+
return {
|
|
125
|
+
...state,
|
|
126
|
+
previewDate,
|
|
127
|
+
inputValue
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
case 'CONTROLLED_LOCALE_CHANGE':
|
|
131
|
+
{
|
|
132
|
+
const inputValue = formatInputValue({
|
|
133
|
+
date: value,
|
|
134
|
+
locale,
|
|
135
|
+
formatDate
|
|
136
|
+
});
|
|
137
|
+
return {
|
|
138
|
+
...state,
|
|
139
|
+
inputValue
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
case 'SELECT_DATE':
|
|
143
|
+
{
|
|
144
|
+
const inputValue = formatInputValue({
|
|
145
|
+
date: action.value,
|
|
146
|
+
locale,
|
|
147
|
+
formatDate
|
|
148
|
+
});
|
|
149
|
+
if (onChange && action.value && isValid(action.value) && !isSameDay(value, action.value)) {
|
|
150
|
+
onChange(action.value);
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
...state,
|
|
154
|
+
isOpen: false,
|
|
155
|
+
inputValue
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
default:
|
|
159
|
+
throw new Error();
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
};
|
|
163
|
+
function retrieveInitialState(initialProps) {
|
|
164
|
+
let previewDate = initialProps.value;
|
|
165
|
+
if (previewDate === undefined || !isValid(previewDate)) {
|
|
166
|
+
previewDate = new Date();
|
|
167
|
+
}
|
|
168
|
+
let inputValue = '';
|
|
169
|
+
if (initialProps.value !== undefined) {
|
|
170
|
+
if (initialProps.formatDate) {
|
|
171
|
+
inputValue = initialProps.formatDate(initialProps.value);
|
|
172
|
+
} else {
|
|
173
|
+
inputValue = new Intl.DateTimeFormat(initialProps.locale, {
|
|
174
|
+
month: 'long',
|
|
175
|
+
day: 'numeric',
|
|
176
|
+
year: 'numeric'
|
|
177
|
+
}).format(previewDate);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
isOpen: false,
|
|
182
|
+
previewDate,
|
|
183
|
+
inputValue
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export { datepickerReducer, retrieveInitialState };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Zendesk, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Use of this source code is governed under the Apache License, Version 2.0
|
|
5
|
+
* found at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
*/
|
|
7
|
+
import { createContext, useContext } from 'react';
|
|
8
|
+
|
|
9
|
+
const DatePickerContext = createContext(undefined);
|
|
10
|
+
const useDatePickerContext = () => {
|
|
11
|
+
return useContext(DatePickerContext);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export { DatePickerContext, useDatePickerContext as default };
|