@primer/components 0.0.0-2021931194230 → 0.0.0-202193121134
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/CHANGELOG.md +1 -1
- package/lib/DatePicker/DatePicker.js +1 -0
- package/lib/DatePicker/DatePickerOverlay.js +7 -10
- package/lib/DatePicker/Day.d.ts +1 -0
- package/lib/DatePicker/Day.js +11 -6
- package/lib/DatePicker/useDatePicker.d.ts +9 -1
- package/lib/DatePicker/useDatePicker.js +117 -25
- package/lib-esm/DatePicker/DatePicker.js +1 -0
- package/lib-esm/DatePicker/DatePickerOverlay.js +7 -6
- package/lib-esm/DatePicker/Day.d.ts +1 -0
- package/lib-esm/DatePicker/Day.js +11 -6
- package/lib-esm/DatePicker/useDatePicker.d.ts +9 -1
- package/lib-esm/DatePicker/useDatePicker.js +117 -26
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
@@ -85,6 +85,7 @@ const DatePicker = ({
|
|
85
85
|
|
86
86
|
return /*#__PURE__*/_react.default.createElement(_useDatePicker.DatePickerProvider, {
|
87
87
|
configuration: datePickerConfiguration,
|
88
|
+
isOpen: isOpen,
|
88
89
|
value: value,
|
89
90
|
closePicker: () => setIsOpen(false)
|
90
91
|
}, /*#__PURE__*/_react.default.createElement(_DatePickerAnchor.DatePickerAnchor, {
|
@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
5
5
|
});
|
6
6
|
exports.DatePickerOverlay = void 0;
|
7
7
|
|
8
|
-
var _react =
|
8
|
+
var _react = _interopRequireDefault(require("react"));
|
9
9
|
|
10
10
|
var _useDatePicker = _interopRequireDefault(require("./useDatePicker"));
|
11
11
|
|
@@ -15,10 +15,6 @@ var _DatePickerPanel = require("./DatePickerPanel");
|
|
15
15
|
|
16
16
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
17
17
|
|
18
|
-
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
19
|
-
|
20
|
-
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
21
|
-
|
22
18
|
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
23
19
|
|
24
20
|
const DatePickerOverlay = ({
|
@@ -26,15 +22,16 @@ const DatePickerOverlay = ({
|
|
26
22
|
...rest
|
27
23
|
}) => {
|
28
24
|
const {
|
29
|
-
|
25
|
+
dialogOpen,
|
26
|
+
onClose: onDatePickerClose,
|
27
|
+
setDialogOpen
|
30
28
|
} = (0, _useDatePicker.default)();
|
31
|
-
const [suspendFocusTrap, setSuspendFocusTrap] = (0, _react.useState)(false);
|
32
29
|
|
33
30
|
const onOverlayClose = async gesture => {
|
34
|
-
if (!
|
35
|
-
|
31
|
+
if (!dialogOpen) {
|
32
|
+
setDialogOpen(true);
|
36
33
|
await onDatePickerClose();
|
37
|
-
|
34
|
+
setDialogOpen(false);
|
38
35
|
onClose === null || onClose === void 0 ? void 0 : onClose(gesture);
|
39
36
|
}
|
40
37
|
};
|
package/lib/DatePicker/Day.d.ts
CHANGED
@@ -6,6 +6,7 @@ import { DaySelection } from './useDatePicker';
|
|
6
6
|
export declare type DayProps = {
|
7
7
|
blocked?: boolean;
|
8
8
|
disabled?: boolean;
|
9
|
+
focused?: boolean;
|
9
10
|
onAction?: (date: Date, event?: React.MouseEvent<HTMLDivElement> | React.KeyboardEvent<HTMLDivElement>) => void;
|
10
11
|
selected?: DaySelection;
|
11
12
|
date: Date;
|
package/lib/DatePicker/Day.js
CHANGED
@@ -90,15 +90,12 @@ const getStateStyles = (props, prop, state) => {
|
|
90
90
|
const {
|
91
91
|
blocked,
|
92
92
|
disabled,
|
93
|
+
focused,
|
93
94
|
selected,
|
94
95
|
today
|
95
96
|
} = props;
|
96
97
|
|
97
|
-
if (
|
98
|
-
return states.blocked[prop];
|
99
|
-
} else if (disabled) {
|
100
|
-
return states.disabled[prop];
|
101
|
-
} else if (selected) {
|
98
|
+
if (selected) {
|
102
99
|
switch (selected) {
|
103
100
|
case 'start':
|
104
101
|
return today && prop === 'color' ? states.selected.start['todayColor'] : states.selected.start[prop];
|
@@ -112,6 +109,12 @@ const getStateStyles = (props, prop, state) => {
|
|
112
109
|
default:
|
113
110
|
return today && prop === 'color' ? states.selected.default['todayColor'] : states.selected.default[prop];
|
114
111
|
}
|
112
|
+
} else if (blocked) {
|
113
|
+
return states.blocked[prop];
|
114
|
+
} else if (disabled) {
|
115
|
+
return states.disabled[prop];
|
116
|
+
} else if (focused) {
|
117
|
+
return states.default.hover[prop];
|
115
118
|
} else {
|
116
119
|
return today && prop === 'color' ? states.default[state]['todayColor'] : states.default[state][prop];
|
117
120
|
}
|
@@ -128,7 +131,7 @@ const DayComponent = (0, _styledComponents.default)(DayBaseComponent).attrs(prop
|
|
128
131
|
})).withConfig({
|
129
132
|
displayName: "Day__DayComponent",
|
130
133
|
componentId: "sc-1japneh-1"
|
131
|
-
})(["background-color:", ";border-radius:", ";transition:0.1s background-color ease;& ", "{align-self:center;color:", ";display:flex;font-family:", ";font-size:", ";justify-self:center;user-select:none;transition:0.1s color ease;}&:hover{background-color:", ";cursor:pointer;transition:0.05s background-color ease;& ", "{color:", ";transition:0.1s color ease;}}&:active{background-color:", ";box-shadow:inset ", ";transition:0.1s background-color ease,0.1s box-shadow ease,0.1s color ease;& ", "{color:", ";transition:0.1s color ease;}}"], props => props.background, props => props.borderRadius, _Text.default, props => props.textColor, (0, _constants.get)('fonts.mono'), (0, _constants.get)('fontSizes.0'), props => props.backgroundHover, _Text.default, props => props.textColorHover, props => props.backgroundPressed, (0, _constants.get)('shadows.shadow.medium'), _Text.default, props => props.textColorPressed);
|
134
|
+
})(["background-color:", ";border-radius:", ";opacity:", ";transition:0.1s background-color ease;& ", "{align-self:center;color:", ";display:flex;font-family:", ";font-size:", ";justify-self:center;user-select:none;transition:0.1s color ease;}&:hover{background-color:", ";cursor:pointer;transition:0.05s background-color ease;& ", "{color:", ";transition:0.1s color ease;}}&:active{background-color:", ";box-shadow:inset ", ";transition:0.1s background-color ease,0.1s box-shadow ease,0.1s color ease;& ", "{color:", ";transition:0.1s color ease;}}"], props => props.background, props => props.borderRadius, props => props.disabled ? 0.5 : 1, _Text.default, props => props.textColor, (0, _constants.get)('fonts.mono'), (0, _constants.get)('fontSizes.0'), props => props.backgroundHover, _Text.default, props => props.textColorHover, props => props.backgroundPressed, (0, _constants.get)('shadows.shadow.medium'), _Text.default, props => props.textColorPressed);
|
132
135
|
|
133
136
|
const Day = ({
|
134
137
|
date,
|
@@ -139,6 +142,7 @@ const Day = ({
|
|
139
142
|
onSelection,
|
140
143
|
disabled,
|
141
144
|
blocked,
|
145
|
+
focused,
|
142
146
|
selected,
|
143
147
|
today
|
144
148
|
} = (0, _useDatePicker.default)(date);
|
@@ -172,6 +176,7 @@ const Day = ({
|
|
172
176
|
"aria-selected": selected !== false,
|
173
177
|
blocked: blocked,
|
174
178
|
disabled: disabled,
|
179
|
+
focused: focused,
|
175
180
|
selected: selected,
|
176
181
|
today: today,
|
177
182
|
onClick: clickHandler,
|
@@ -33,6 +33,8 @@ export interface DatePickerContext {
|
|
33
33
|
disabled?: boolean;
|
34
34
|
configuration: DatePickerConfiguration;
|
35
35
|
currentViewingDate: Date;
|
36
|
+
dialogOpen: boolean;
|
37
|
+
focusDate: Date;
|
36
38
|
goToMonth: (date: Date) => void;
|
37
39
|
hoverRange?: RangeSelection | null;
|
38
40
|
selection?: Selection;
|
@@ -47,6 +49,7 @@ export interface DatePickerContext {
|
|
47
49
|
previousMonth: () => void;
|
48
50
|
revertValue: () => void;
|
49
51
|
saveValue: (selection?: Selection) => void;
|
52
|
+
setDialogOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
50
53
|
}
|
51
54
|
export declare type Selection = Date | Array<Date> | RangeSelection | null;
|
52
55
|
export declare type StringSelection = string | Array<string> | {
|
@@ -56,11 +59,14 @@ export declare type StringSelection = string | Array<string> | {
|
|
56
59
|
export declare type DaySelection = boolean | 'start' | 'middle' | 'end';
|
57
60
|
declare const useDatePicker: (date?: Date | undefined) => {
|
58
61
|
blocked: boolean | undefined;
|
59
|
-
disabled: boolean;
|
62
|
+
disabled: boolean | undefined;
|
63
|
+
focused: boolean;
|
60
64
|
selected: DaySelection;
|
61
65
|
today: boolean;
|
62
66
|
configuration: DatePickerConfiguration;
|
63
67
|
currentViewingDate: Date;
|
68
|
+
dialogOpen: boolean;
|
69
|
+
focusDate: Date;
|
64
70
|
goToMonth: (date: Date) => void;
|
65
71
|
hoverRange?: RangeSelection | null | undefined;
|
66
72
|
selection?: Selection | undefined;
|
@@ -75,11 +81,13 @@ declare const useDatePicker: (date?: Date | undefined) => {
|
|
75
81
|
previousMonth: () => void;
|
76
82
|
revertValue: () => void;
|
77
83
|
saveValue: (selection?: Selection | undefined) => void;
|
84
|
+
setDialogOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
78
85
|
};
|
79
86
|
export default useDatePicker;
|
80
87
|
export interface DatePickerProviderProps {
|
81
88
|
closePicker?: () => void;
|
82
89
|
configuration?: DatePickerConfiguration;
|
90
|
+
isOpen?: boolean;
|
83
91
|
value?: Selection | StringSelection;
|
84
92
|
}
|
85
93
|
export declare function isSingleSelection(selection: Selection): selection is Date;
|
@@ -13,6 +13,8 @@ var _octiconsReact = require("@primer/octicons-react");
|
|
13
13
|
|
14
14
|
var _dateFns = require("date-fns");
|
15
15
|
|
16
|
+
var _esm = require("date-fns/esm");
|
17
|
+
|
16
18
|
var _deepmerge = _interopRequireDefault(require("deepmerge"));
|
17
19
|
|
18
20
|
var _react = _interopRequireWildcard(require("react"));
|
@@ -30,65 +32,69 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
30
32
|
const DatePickerContext = /*#__PURE__*/(0, _react.createContext)(null);
|
31
33
|
|
32
34
|
const useDatePicker = date => {
|
33
|
-
const
|
35
|
+
const dateCtx = (0, _react.useContext)(DatePickerContext);
|
34
36
|
const [selected, setSelected] = (0, _react.useState)(false);
|
35
37
|
const today = date ? (0, _dateFns.isToday)(date) : false;
|
36
38
|
|
37
|
-
if (!
|
39
|
+
if (!dateCtx) {
|
38
40
|
throw new Error('useDatePicker must be used inside a DatePickerProvider');
|
39
41
|
}
|
40
42
|
|
41
43
|
(0, _react.useEffect)(() => {
|
42
44
|
if (date) {
|
43
|
-
if (
|
44
|
-
if (isRangeSelection(
|
45
|
-
if ((0, _dateFns.isEqual)(date,
|
45
|
+
if (dateCtx.hoverRange) {
|
46
|
+
if (isRangeSelection(dateCtx.hoverRange)) {
|
47
|
+
if ((0, _dateFns.isEqual)(date, dateCtx.hoverRange.from)) {
|
46
48
|
setSelected('start');
|
47
|
-
} else if (
|
49
|
+
} else if (dateCtx.hoverRange.to && (0, _dateFns.isEqual)(date, dateCtx.hoverRange.to)) {
|
48
50
|
setSelected('end');
|
49
|
-
} else if ((0, _dateFns.isAfter)(date,
|
51
|
+
} else if ((0, _dateFns.isAfter)(date, dateCtx.hoverRange.from) && dateCtx.hoverRange.to && (0, _dateFns.isBefore)(date, dateCtx.hoverRange.to)) {
|
50
52
|
setSelected('middle');
|
51
53
|
} else {
|
52
54
|
setSelected(false);
|
53
55
|
}
|
54
56
|
}
|
55
|
-
} else if (
|
56
|
-
if (isMultiSelection(
|
57
|
-
setSelected(!!
|
58
|
-
} else if (isRangeSelection(
|
59
|
-
if ((0, _dateFns.isEqual)(date,
|
57
|
+
} else if (dateCtx.selection) {
|
58
|
+
if (isMultiSelection(dateCtx.selection)) {
|
59
|
+
setSelected(!!dateCtx.selection.find(d => (0, _dateFns.isEqual)(d, date)));
|
60
|
+
} else if (isRangeSelection(dateCtx.selection)) {
|
61
|
+
if ((0, _dateFns.isEqual)(date, dateCtx.selection.from)) {
|
60
62
|
setSelected('start');
|
61
|
-
} else if (
|
63
|
+
} else if (dateCtx.selection.to && (0, _dateFns.isEqual)(date, dateCtx.selection.to)) {
|
62
64
|
setSelected('end');
|
63
|
-
} else if ((0, _dateFns.isAfter)(date,
|
65
|
+
} else if ((0, _dateFns.isAfter)(date, dateCtx.selection.from) && dateCtx.selection.to && (0, _dateFns.isBefore)(date, dateCtx.selection.to)) {
|
64
66
|
setSelected('middle');
|
65
67
|
} else {
|
66
68
|
setSelected(false);
|
67
69
|
}
|
68
70
|
} else {
|
69
|
-
setSelected((0, _dateFns.isEqual)(date,
|
71
|
+
setSelected((0, _dateFns.isEqual)(date, dateCtx.selection));
|
70
72
|
}
|
71
73
|
}
|
72
74
|
}
|
73
|
-
}, [date,
|
75
|
+
}, [date, dateCtx.hoverRange, dateCtx.selection, today]);
|
74
76
|
let blocked,
|
75
|
-
disabled
|
77
|
+
disabled,
|
78
|
+
focused = false;
|
76
79
|
|
77
80
|
if (date) {
|
78
|
-
// Determine if date is
|
79
|
-
if (
|
80
|
-
|
81
|
+
// Determine if date is focused
|
82
|
+
if ((0, _dateFns.isEqual)(dateCtx.focusDate, date)) focused = true; // Determine if date is blocked out
|
83
|
+
|
84
|
+
if (dateCtx.configuration.blockedDates) {
|
85
|
+
blocked = !!dateCtx.configuration.blockedDates.find(d => (0, _dateFns.isEqual)(d, date));
|
81
86
|
} // Determine if date is disabled
|
82
87
|
|
83
88
|
|
84
|
-
if (
|
85
|
-
disabled = (
|
89
|
+
if (dateCtx.configuration.minDate || dateCtx.configuration.maxDate || dateCtx.configuration.disableWeekends) {
|
90
|
+
disabled = (dateCtx.configuration.minDate ? (0, _dateFns.isBefore)(date, dateCtx.configuration.minDate) : false) || (dateCtx.configuration.maxDate ? (0, _dateFns.isAfter)(date, dateCtx.configuration.maxDate) : false) || (dateCtx.configuration.disableWeekends ? (0, _dateFns.isWeekend)(date) : false);
|
86
91
|
}
|
87
92
|
}
|
88
93
|
|
89
|
-
return { ...
|
94
|
+
return { ...dateCtx,
|
90
95
|
blocked,
|
91
96
|
disabled,
|
97
|
+
focused,
|
92
98
|
selected,
|
93
99
|
today
|
94
100
|
};
|
@@ -167,6 +173,20 @@ function parseSelection(selection, variant) {
|
|
167
173
|
}
|
168
174
|
}
|
169
175
|
|
176
|
+
const getInitialFocusDate = selection => {
|
177
|
+
if (!selection) return new Date();
|
178
|
+
|
179
|
+
if (selection instanceof Date) {
|
180
|
+
return selection;
|
181
|
+
} else if (Array.isArray(selection)) {
|
182
|
+
return selection[0];
|
183
|
+
} else if (isRangeSelection(selection)) {
|
184
|
+
return selection.from;
|
185
|
+
} else {
|
186
|
+
return new Date();
|
187
|
+
}
|
188
|
+
};
|
189
|
+
|
170
190
|
const defaultConfiguration = {
|
171
191
|
anchorVariant: 'button',
|
172
192
|
confirmation: false,
|
@@ -184,6 +204,7 @@ const DatePickerProvider = ({
|
|
184
204
|
configuration: externalConfig = {},
|
185
205
|
children,
|
186
206
|
closePicker,
|
207
|
+
isOpen = false,
|
187
208
|
value
|
188
209
|
}) => {
|
189
210
|
const [configuration, setConfiguration] = (0, _react.useState)((0, _deepmerge.default)(defaultConfiguration, externalConfig));
|
@@ -193,6 +214,8 @@ const DatePickerProvider = ({
|
|
193
214
|
const [hoverRange, setHoverRange] = (0, _react.useState)(null);
|
194
215
|
const [currentViewingDate, setCurrentViewingDate] = (0, _react.useState)(new Date());
|
195
216
|
const confirm = (0, _.useConfirm)();
|
217
|
+
const [dialogOpen, setDialogOpen] = (0, _react.useState)(false);
|
218
|
+
const [focusDate, setFocusDate] = (0, _react.useState)(getInitialFocusDate(selection));
|
196
219
|
(0, _react.useEffect)(() => {
|
197
220
|
setConfiguration((0, _deepmerge.default)(defaultConfiguration, externalConfig));
|
198
221
|
setSelection(parseSelection(selection, configuration.variant)); // Don't want this to run every time selection gets updated
|
@@ -330,6 +353,67 @@ const DatePickerProvider = ({
|
|
330
353
|
}
|
331
354
|
}
|
332
355
|
}, [configuration]);
|
356
|
+
const handleKeyDown = (0, _react.useCallback)(async e => {
|
357
|
+
const key = e.key;
|
358
|
+
|
359
|
+
switch (key) {
|
360
|
+
case 'ArrowRight':
|
361
|
+
{
|
362
|
+
// Increase selection by 1 day
|
363
|
+
setFocusDate((0, _dateFns.addDays)(focusDate, 1));
|
364
|
+
break;
|
365
|
+
}
|
366
|
+
|
367
|
+
case 'ArrowLeft':
|
368
|
+
{
|
369
|
+
// Decrease selection by 1 day
|
370
|
+
setFocusDate((0, _dateFns.subDays)(focusDate, 1));
|
371
|
+
break;
|
372
|
+
}
|
373
|
+
|
374
|
+
case 'ArrowUp':
|
375
|
+
{
|
376
|
+
// Decrease selection by 1 week
|
377
|
+
setFocusDate((0, _dateFns.subWeeks)(focusDate, 1));
|
378
|
+
break;
|
379
|
+
}
|
380
|
+
|
381
|
+
case 'ArrowDown':
|
382
|
+
{
|
383
|
+
// Decrease selection by 1 week
|
384
|
+
setFocusDate((0, _dateFns.addWeeks)(focusDate, 1));
|
385
|
+
break;
|
386
|
+
}
|
387
|
+
|
388
|
+
case 'Enter':
|
389
|
+
{
|
390
|
+
// Start Selection
|
391
|
+
break;
|
392
|
+
}
|
393
|
+
|
394
|
+
case 'Esc':
|
395
|
+
{
|
396
|
+
// Cancel Selection if started, reset if not? or close
|
397
|
+
break;
|
398
|
+
}
|
399
|
+
|
400
|
+
default:
|
401
|
+
{
|
402
|
+
break;
|
403
|
+
}
|
404
|
+
}
|
405
|
+
}, [focusDate]);
|
406
|
+
(0, _react.useEffect)(() => {
|
407
|
+
if (isOpen) {
|
408
|
+
window.addEventListener('keydown', handleKeyDown);
|
409
|
+
} else {
|
410
|
+
window.removeEventListener('keydown', handleKeyDown);
|
411
|
+
}
|
412
|
+
|
413
|
+
return () => {
|
414
|
+
window.removeEventListener('keydown', handleKeyDown);
|
415
|
+
};
|
416
|
+
}, [handleKeyDown, isOpen]);
|
333
417
|
const selectionHandler = (0, _react.useCallback)(date => {
|
334
418
|
setIsDirty(true);
|
335
419
|
|
@@ -389,6 +473,7 @@ const DatePickerProvider = ({
|
|
389
473
|
minDate,
|
390
474
|
maxDate,
|
391
475
|
maxRangeSize,
|
476
|
+
disableWeekends,
|
392
477
|
variant
|
393
478
|
} = configuration;
|
394
479
|
|
@@ -401,6 +486,10 @@ const DatePickerProvider = ({
|
|
401
486
|
hoverDate = (0, _dateFns.isBefore)(hoverDate, selection.from) ? (0, _dateFns.subDays)(selection.from, configuration.maxRangeSize - 1) : (0, _dateFns.addDays)(selection.from, configuration.maxRangeSize - 1);
|
402
487
|
}
|
403
488
|
|
489
|
+
if (disableWeekends && (0, _dateFns.isWeekend)(hoverDate)) {
|
490
|
+
hoverDate = (0, _esm.previousFriday)(hoverDate);
|
491
|
+
}
|
492
|
+
|
404
493
|
setHoverRange((0, _dateFns.isBefore)(hoverDate, selection.from) ? {
|
405
494
|
from: hoverDate,
|
406
495
|
to: selection.from
|
@@ -415,9 +504,11 @@ const DatePickerProvider = ({
|
|
415
504
|
configuration,
|
416
505
|
currentViewingDate,
|
417
506
|
disabled: false,
|
507
|
+
focusDate,
|
418
508
|
formattedDate: getFormattedDate,
|
419
509
|
goToMonth,
|
420
510
|
hoverRange,
|
511
|
+
dialogOpen,
|
421
512
|
nextMonth,
|
422
513
|
onClose: handleClose,
|
423
514
|
onDateInput: inputHandler,
|
@@ -427,9 +518,10 @@ const DatePickerProvider = ({
|
|
427
518
|
revertValue,
|
428
519
|
saveValue,
|
429
520
|
selectionActive: false,
|
430
|
-
selection
|
521
|
+
selection,
|
522
|
+
setDialogOpen
|
431
523
|
};
|
432
|
-
}, [configuration, currentViewingDate, focusHnadler, getFormattedDate, goToMonth, handleClose, hoverRange, inputHandler, nextMonth, previousMonth, revertValue, saveValue, selection, selectionHandler]);
|
524
|
+
}, [configuration, currentViewingDate, dialogOpen, focusDate, focusHnadler, getFormattedDate, goToMonth, handleClose, hoverRange, inputHandler, nextMonth, previousMonth, revertValue, saveValue, selection, selectionHandler]);
|
433
525
|
return /*#__PURE__*/_react.default.createElement(DatePickerContext.Provider, {
|
434
526
|
value: datePickerCtx
|
435
527
|
}, children);
|
@@ -70,6 +70,7 @@ export const DatePicker = ({
|
|
70
70
|
|
71
71
|
return /*#__PURE__*/React.createElement(DatePickerProvider, {
|
72
72
|
configuration: datePickerConfiguration,
|
73
|
+
isOpen: isOpen,
|
73
74
|
value: value,
|
74
75
|
closePicker: () => setIsOpen(false)
|
75
76
|
}, /*#__PURE__*/React.createElement(DatePickerAnchor, {
|
@@ -1,6 +1,6 @@
|
|
1
1
|
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
2
2
|
|
3
|
-
import React
|
3
|
+
import React from 'react';
|
4
4
|
import useDatePicker from './useDatePicker';
|
5
5
|
import { AnchoredOverlay } from '../AnchoredOverlay';
|
6
6
|
import { DatePickerPanel } from './DatePickerPanel';
|
@@ -9,15 +9,16 @@ export const DatePickerOverlay = ({
|
|
9
9
|
...rest
|
10
10
|
}) => {
|
11
11
|
const {
|
12
|
-
|
12
|
+
dialogOpen,
|
13
|
+
onClose: onDatePickerClose,
|
14
|
+
setDialogOpen
|
13
15
|
} = useDatePicker();
|
14
|
-
const [suspendFocusTrap, setSuspendFocusTrap] = useState(false);
|
15
16
|
|
16
17
|
const onOverlayClose = async gesture => {
|
17
|
-
if (!
|
18
|
-
|
18
|
+
if (!dialogOpen) {
|
19
|
+
setDialogOpen(true);
|
19
20
|
await onDatePickerClose();
|
20
|
-
|
21
|
+
setDialogOpen(false);
|
21
22
|
onClose === null || onClose === void 0 ? void 0 : onClose(gesture);
|
22
23
|
}
|
23
24
|
};
|
@@ -6,6 +6,7 @@ import { DaySelection } from './useDatePicker';
|
|
6
6
|
export declare type DayProps = {
|
7
7
|
blocked?: boolean;
|
8
8
|
disabled?: boolean;
|
9
|
+
focused?: boolean;
|
9
10
|
onAction?: (date: Date, event?: React.MouseEvent<HTMLDivElement> | React.KeyboardEvent<HTMLDivElement>) => void;
|
10
11
|
selected?: DaySelection;
|
11
12
|
date: Date;
|
@@ -71,15 +71,12 @@ const getStateStyles = (props, prop, state) => {
|
|
71
71
|
const {
|
72
72
|
blocked,
|
73
73
|
disabled,
|
74
|
+
focused,
|
74
75
|
selected,
|
75
76
|
today
|
76
77
|
} = props;
|
77
78
|
|
78
|
-
if (
|
79
|
-
return states.blocked[prop];
|
80
|
-
} else if (disabled) {
|
81
|
-
return states.disabled[prop];
|
82
|
-
} else if (selected) {
|
79
|
+
if (selected) {
|
83
80
|
switch (selected) {
|
84
81
|
case 'start':
|
85
82
|
return today && prop === 'color' ? states.selected.start['todayColor'] : states.selected.start[prop];
|
@@ -93,6 +90,12 @@ const getStateStyles = (props, prop, state) => {
|
|
93
90
|
default:
|
94
91
|
return today && prop === 'color' ? states.selected.default['todayColor'] : states.selected.default[prop];
|
95
92
|
}
|
93
|
+
} else if (blocked) {
|
94
|
+
return states.blocked[prop];
|
95
|
+
} else if (disabled) {
|
96
|
+
return states.disabled[prop];
|
97
|
+
} else if (focused) {
|
98
|
+
return states.default.hover[prop];
|
96
99
|
} else {
|
97
100
|
return today && prop === 'color' ? states.default[state]['todayColor'] : states.default[state][prop];
|
98
101
|
}
|
@@ -109,7 +112,7 @@ const DayComponent = styled(DayBaseComponent).attrs(props => ({
|
|
109
112
|
})).withConfig({
|
110
113
|
displayName: "Day__DayComponent",
|
111
114
|
componentId: "sc-1japneh-1"
|
112
|
-
})(["background-color:", ";border-radius:", ";transition:0.1s background-color ease;& ", "{align-self:center;color:", ";display:flex;font-family:", ";font-size:", ";justify-self:center;user-select:none;transition:0.1s color ease;}&:hover{background-color:", ";cursor:pointer;transition:0.05s background-color ease;& ", "{color:", ";transition:0.1s color ease;}}&:active{background-color:", ";box-shadow:inset ", ";transition:0.1s background-color ease,0.1s box-shadow ease,0.1s color ease;& ", "{color:", ";transition:0.1s color ease;}}"], props => props.background, props => props.borderRadius, Text, props => props.textColor, get('fonts.mono'), get('fontSizes.0'), props => props.backgroundHover, Text, props => props.textColorHover, props => props.backgroundPressed, get('shadows.shadow.medium'), Text, props => props.textColorPressed);
|
115
|
+
})(["background-color:", ";border-radius:", ";opacity:", ";transition:0.1s background-color ease;& ", "{align-self:center;color:", ";display:flex;font-family:", ";font-size:", ";justify-self:center;user-select:none;transition:0.1s color ease;}&:hover{background-color:", ";cursor:pointer;transition:0.05s background-color ease;& ", "{color:", ";transition:0.1s color ease;}}&:active{background-color:", ";box-shadow:inset ", ";transition:0.1s background-color ease,0.1s box-shadow ease,0.1s color ease;& ", "{color:", ";transition:0.1s color ease;}}"], props => props.background, props => props.borderRadius, props => props.disabled ? 0.5 : 1, Text, props => props.textColor, get('fonts.mono'), get('fontSizes.0'), props => props.backgroundHover, Text, props => props.textColorHover, props => props.backgroundPressed, get('shadows.shadow.medium'), Text, props => props.textColorPressed);
|
113
116
|
export const Day = ({
|
114
117
|
date,
|
115
118
|
onAction
|
@@ -119,6 +122,7 @@ export const Day = ({
|
|
119
122
|
onSelection,
|
120
123
|
disabled,
|
121
124
|
blocked,
|
125
|
+
focused,
|
122
126
|
selected,
|
123
127
|
today
|
124
128
|
} = useDatePicker(date);
|
@@ -152,6 +156,7 @@ export const Day = ({
|
|
152
156
|
"aria-selected": selected !== false,
|
153
157
|
blocked: blocked,
|
154
158
|
disabled: disabled,
|
159
|
+
focused: focused,
|
155
160
|
selected: selected,
|
156
161
|
today: today,
|
157
162
|
onClick: clickHandler,
|
@@ -33,6 +33,8 @@ export interface DatePickerContext {
|
|
33
33
|
disabled?: boolean;
|
34
34
|
configuration: DatePickerConfiguration;
|
35
35
|
currentViewingDate: Date;
|
36
|
+
dialogOpen: boolean;
|
37
|
+
focusDate: Date;
|
36
38
|
goToMonth: (date: Date) => void;
|
37
39
|
hoverRange?: RangeSelection | null;
|
38
40
|
selection?: Selection;
|
@@ -47,6 +49,7 @@ export interface DatePickerContext {
|
|
47
49
|
previousMonth: () => void;
|
48
50
|
revertValue: () => void;
|
49
51
|
saveValue: (selection?: Selection) => void;
|
52
|
+
setDialogOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
50
53
|
}
|
51
54
|
export declare type Selection = Date | Array<Date> | RangeSelection | null;
|
52
55
|
export declare type StringSelection = string | Array<string> | {
|
@@ -56,11 +59,14 @@ export declare type StringSelection = string | Array<string> | {
|
|
56
59
|
export declare type DaySelection = boolean | 'start' | 'middle' | 'end';
|
57
60
|
declare const useDatePicker: (date?: Date | undefined) => {
|
58
61
|
blocked: boolean | undefined;
|
59
|
-
disabled: boolean;
|
62
|
+
disabled: boolean | undefined;
|
63
|
+
focused: boolean;
|
60
64
|
selected: DaySelection;
|
61
65
|
today: boolean;
|
62
66
|
configuration: DatePickerConfiguration;
|
63
67
|
currentViewingDate: Date;
|
68
|
+
dialogOpen: boolean;
|
69
|
+
focusDate: Date;
|
64
70
|
goToMonth: (date: Date) => void;
|
65
71
|
hoverRange?: RangeSelection | null | undefined;
|
66
72
|
selection?: Selection | undefined;
|
@@ -75,11 +81,13 @@ declare const useDatePicker: (date?: Date | undefined) => {
|
|
75
81
|
previousMonth: () => void;
|
76
82
|
revertValue: () => void;
|
77
83
|
saveValue: (selection?: Selection | undefined) => void;
|
84
|
+
setDialogOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
78
85
|
};
|
79
86
|
export default useDatePicker;
|
80
87
|
export interface DatePickerProviderProps {
|
81
88
|
closePicker?: () => void;
|
82
89
|
configuration?: DatePickerConfiguration;
|
90
|
+
isOpen?: boolean;
|
83
91
|
value?: Selection | StringSelection;
|
84
92
|
}
|
85
93
|
export declare function isSingleSelection(selection: Selection): selection is Date;
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import { CheckIcon, TrashIcon } from '@primer/octicons-react';
|
2
|
-
import { isEqual, isAfter, isBefore, addMonths, subMonths, isToday, isWeekend, differenceInDays, addDays, subDays } from 'date-fns';
|
2
|
+
import { isEqual, isAfter, isBefore, addMonths, subMonths, isToday, isWeekend, differenceInDays, addDays, subDays, addWeeks, subWeeks } from 'date-fns';
|
3
|
+
import { previousFriday } from 'date-fns/esm';
|
3
4
|
import deepmerge from 'deepmerge';
|
4
5
|
import React, { createContext, useCallback, useContext, useMemo, useEffect, useState } from 'react';
|
5
6
|
import { Text, useConfirm } from '..';
|
@@ -7,65 +8,69 @@ import { formatDate } from './dateParser';
|
|
7
8
|
const DatePickerContext = /*#__PURE__*/createContext(null);
|
8
9
|
|
9
10
|
const useDatePicker = date => {
|
10
|
-
const
|
11
|
+
const dateCtx = useContext(DatePickerContext);
|
11
12
|
const [selected, setSelected] = useState(false);
|
12
13
|
const today = date ? isToday(date) : false;
|
13
14
|
|
14
|
-
if (!
|
15
|
+
if (!dateCtx) {
|
15
16
|
throw new Error('useDatePicker must be used inside a DatePickerProvider');
|
16
17
|
}
|
17
18
|
|
18
19
|
useEffect(() => {
|
19
20
|
if (date) {
|
20
|
-
if (
|
21
|
-
if (isRangeSelection(
|
22
|
-
if (isEqual(date,
|
21
|
+
if (dateCtx.hoverRange) {
|
22
|
+
if (isRangeSelection(dateCtx.hoverRange)) {
|
23
|
+
if (isEqual(date, dateCtx.hoverRange.from)) {
|
23
24
|
setSelected('start');
|
24
|
-
} else if (
|
25
|
+
} else if (dateCtx.hoverRange.to && isEqual(date, dateCtx.hoverRange.to)) {
|
25
26
|
setSelected('end');
|
26
|
-
} else if (isAfter(date,
|
27
|
+
} else if (isAfter(date, dateCtx.hoverRange.from) && dateCtx.hoverRange.to && isBefore(date, dateCtx.hoverRange.to)) {
|
27
28
|
setSelected('middle');
|
28
29
|
} else {
|
29
30
|
setSelected(false);
|
30
31
|
}
|
31
32
|
}
|
32
|
-
} else if (
|
33
|
-
if (isMultiSelection(
|
34
|
-
setSelected(!!
|
35
|
-
} else if (isRangeSelection(
|
36
|
-
if (isEqual(date,
|
33
|
+
} else if (dateCtx.selection) {
|
34
|
+
if (isMultiSelection(dateCtx.selection)) {
|
35
|
+
setSelected(!!dateCtx.selection.find(d => isEqual(d, date)));
|
36
|
+
} else if (isRangeSelection(dateCtx.selection)) {
|
37
|
+
if (isEqual(date, dateCtx.selection.from)) {
|
37
38
|
setSelected('start');
|
38
|
-
} else if (
|
39
|
+
} else if (dateCtx.selection.to && isEqual(date, dateCtx.selection.to)) {
|
39
40
|
setSelected('end');
|
40
|
-
} else if (isAfter(date,
|
41
|
+
} else if (isAfter(date, dateCtx.selection.from) && dateCtx.selection.to && isBefore(date, dateCtx.selection.to)) {
|
41
42
|
setSelected('middle');
|
42
43
|
} else {
|
43
44
|
setSelected(false);
|
44
45
|
}
|
45
46
|
} else {
|
46
|
-
setSelected(isEqual(date,
|
47
|
+
setSelected(isEqual(date, dateCtx.selection));
|
47
48
|
}
|
48
49
|
}
|
49
50
|
}
|
50
|
-
}, [date,
|
51
|
+
}, [date, dateCtx.hoverRange, dateCtx.selection, today]);
|
51
52
|
let blocked,
|
52
|
-
disabled
|
53
|
+
disabled,
|
54
|
+
focused = false;
|
53
55
|
|
54
56
|
if (date) {
|
55
|
-
// Determine if date is
|
56
|
-
if (
|
57
|
-
|
57
|
+
// Determine if date is focused
|
58
|
+
if (isEqual(dateCtx.focusDate, date)) focused = true; // Determine if date is blocked out
|
59
|
+
|
60
|
+
if (dateCtx.configuration.blockedDates) {
|
61
|
+
blocked = !!dateCtx.configuration.blockedDates.find(d => isEqual(d, date));
|
58
62
|
} // Determine if date is disabled
|
59
63
|
|
60
64
|
|
61
|
-
if (
|
62
|
-
disabled = (
|
65
|
+
if (dateCtx.configuration.minDate || dateCtx.configuration.maxDate || dateCtx.configuration.disableWeekends) {
|
66
|
+
disabled = (dateCtx.configuration.minDate ? isBefore(date, dateCtx.configuration.minDate) : false) || (dateCtx.configuration.maxDate ? isAfter(date, dateCtx.configuration.maxDate) : false) || (dateCtx.configuration.disableWeekends ? isWeekend(date) : false);
|
63
67
|
}
|
64
68
|
}
|
65
69
|
|
66
|
-
return { ...
|
70
|
+
return { ...dateCtx,
|
67
71
|
blocked,
|
68
72
|
disabled,
|
73
|
+
focused,
|
69
74
|
selected,
|
70
75
|
today
|
71
76
|
};
|
@@ -139,6 +144,20 @@ function parseSelection(selection, variant) {
|
|
139
144
|
}
|
140
145
|
}
|
141
146
|
|
147
|
+
const getInitialFocusDate = selection => {
|
148
|
+
if (!selection) return new Date();
|
149
|
+
|
150
|
+
if (selection instanceof Date) {
|
151
|
+
return selection;
|
152
|
+
} else if (Array.isArray(selection)) {
|
153
|
+
return selection[0];
|
154
|
+
} else if (isRangeSelection(selection)) {
|
155
|
+
return selection.from;
|
156
|
+
} else {
|
157
|
+
return new Date();
|
158
|
+
}
|
159
|
+
};
|
160
|
+
|
142
161
|
const defaultConfiguration = {
|
143
162
|
anchorVariant: 'button',
|
144
163
|
confirmation: false,
|
@@ -155,6 +174,7 @@ export const DatePickerProvider = ({
|
|
155
174
|
configuration: externalConfig = {},
|
156
175
|
children,
|
157
176
|
closePicker,
|
177
|
+
isOpen = false,
|
158
178
|
value
|
159
179
|
}) => {
|
160
180
|
const [configuration, setConfiguration] = useState(deepmerge(defaultConfiguration, externalConfig));
|
@@ -164,6 +184,8 @@ export const DatePickerProvider = ({
|
|
164
184
|
const [hoverRange, setHoverRange] = useState(null);
|
165
185
|
const [currentViewingDate, setCurrentViewingDate] = useState(new Date());
|
166
186
|
const confirm = useConfirm();
|
187
|
+
const [dialogOpen, setDialogOpen] = useState(false);
|
188
|
+
const [focusDate, setFocusDate] = useState(getInitialFocusDate(selection));
|
167
189
|
useEffect(() => {
|
168
190
|
setConfiguration(deepmerge(defaultConfiguration, externalConfig));
|
169
191
|
setSelection(parseSelection(selection, configuration.variant)); // Don't want this to run every time selection gets updated
|
@@ -301,6 +323,67 @@ export const DatePickerProvider = ({
|
|
301
323
|
}
|
302
324
|
}
|
303
325
|
}, [configuration]);
|
326
|
+
const handleKeyDown = useCallback(async e => {
|
327
|
+
const key = e.key;
|
328
|
+
|
329
|
+
switch (key) {
|
330
|
+
case 'ArrowRight':
|
331
|
+
{
|
332
|
+
// Increase selection by 1 day
|
333
|
+
setFocusDate(addDays(focusDate, 1));
|
334
|
+
break;
|
335
|
+
}
|
336
|
+
|
337
|
+
case 'ArrowLeft':
|
338
|
+
{
|
339
|
+
// Decrease selection by 1 day
|
340
|
+
setFocusDate(subDays(focusDate, 1));
|
341
|
+
break;
|
342
|
+
}
|
343
|
+
|
344
|
+
case 'ArrowUp':
|
345
|
+
{
|
346
|
+
// Decrease selection by 1 week
|
347
|
+
setFocusDate(subWeeks(focusDate, 1));
|
348
|
+
break;
|
349
|
+
}
|
350
|
+
|
351
|
+
case 'ArrowDown':
|
352
|
+
{
|
353
|
+
// Decrease selection by 1 week
|
354
|
+
setFocusDate(addWeeks(focusDate, 1));
|
355
|
+
break;
|
356
|
+
}
|
357
|
+
|
358
|
+
case 'Enter':
|
359
|
+
{
|
360
|
+
// Start Selection
|
361
|
+
break;
|
362
|
+
}
|
363
|
+
|
364
|
+
case 'Esc':
|
365
|
+
{
|
366
|
+
// Cancel Selection if started, reset if not? or close
|
367
|
+
break;
|
368
|
+
}
|
369
|
+
|
370
|
+
default:
|
371
|
+
{
|
372
|
+
break;
|
373
|
+
}
|
374
|
+
}
|
375
|
+
}, [focusDate]);
|
376
|
+
useEffect(() => {
|
377
|
+
if (isOpen) {
|
378
|
+
window.addEventListener('keydown', handleKeyDown);
|
379
|
+
} else {
|
380
|
+
window.removeEventListener('keydown', handleKeyDown);
|
381
|
+
}
|
382
|
+
|
383
|
+
return () => {
|
384
|
+
window.removeEventListener('keydown', handleKeyDown);
|
385
|
+
};
|
386
|
+
}, [handleKeyDown, isOpen]);
|
304
387
|
const selectionHandler = useCallback(date => {
|
305
388
|
setIsDirty(true);
|
306
389
|
|
@@ -360,6 +443,7 @@ export const DatePickerProvider = ({
|
|
360
443
|
minDate,
|
361
444
|
maxDate,
|
362
445
|
maxRangeSize,
|
446
|
+
disableWeekends,
|
363
447
|
variant
|
364
448
|
} = configuration;
|
365
449
|
|
@@ -372,6 +456,10 @@ export const DatePickerProvider = ({
|
|
372
456
|
hoverDate = isBefore(hoverDate, selection.from) ? subDays(selection.from, configuration.maxRangeSize - 1) : addDays(selection.from, configuration.maxRangeSize - 1);
|
373
457
|
}
|
374
458
|
|
459
|
+
if (disableWeekends && isWeekend(hoverDate)) {
|
460
|
+
hoverDate = previousFriday(hoverDate);
|
461
|
+
}
|
462
|
+
|
375
463
|
setHoverRange(isBefore(hoverDate, selection.from) ? {
|
376
464
|
from: hoverDate,
|
377
465
|
to: selection.from
|
@@ -386,9 +474,11 @@ export const DatePickerProvider = ({
|
|
386
474
|
configuration,
|
387
475
|
currentViewingDate,
|
388
476
|
disabled: false,
|
477
|
+
focusDate,
|
389
478
|
formattedDate: getFormattedDate,
|
390
479
|
goToMonth,
|
391
480
|
hoverRange,
|
481
|
+
dialogOpen,
|
392
482
|
nextMonth,
|
393
483
|
onClose: handleClose,
|
394
484
|
onDateInput: inputHandler,
|
@@ -398,9 +488,10 @@ export const DatePickerProvider = ({
|
|
398
488
|
revertValue,
|
399
489
|
saveValue,
|
400
490
|
selectionActive: false,
|
401
|
-
selection
|
491
|
+
selection,
|
492
|
+
setDialogOpen
|
402
493
|
};
|
403
|
-
}, [configuration, currentViewingDate, focusHnadler, getFormattedDate, goToMonth, handleClose, hoverRange, inputHandler, nextMonth, previousMonth, revertValue, saveValue, selection, selectionHandler]);
|
494
|
+
}, [configuration, currentViewingDate, dialogOpen, focusDate, focusHnadler, getFormattedDate, goToMonth, handleClose, hoverRange, inputHandler, nextMonth, previousMonth, revertValue, saveValue, selection, selectionHandler]);
|
404
495
|
return /*#__PURE__*/React.createElement(DatePickerContext.Provider, {
|
405
496
|
value: datePickerCtx
|
406
497
|
}, children);
|