@primer/components 0.0.0-20219254849 → 0.0.0-202192633419
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 +6 -2
- package/lib/DatePicker/DatePickerAnchor.d.ts +1 -1
- package/lib/DatePicker/DatePickerAnchor.js +101 -9
- package/lib/DatePicker/Month.js +27 -6
- package/lib/DatePicker/useDatePicker.d.ts +6 -2
- package/lib/DatePicker/useDatePicker.js +13 -4
- package/lib/hooks/useDebounce.d.ts +2 -0
- package/lib/hooks/useDebounce.js +24 -0
- package/lib-esm/DatePicker/DatePicker.js +6 -2
- package/lib-esm/DatePicker/DatePickerAnchor.d.ts +1 -1
- package/lib-esm/DatePicker/DatePickerAnchor.js +100 -10
- package/lib-esm/DatePicker/Month.js +26 -6
- package/lib-esm/DatePicker/useDatePicker.d.ts +6 -2
- package/lib-esm/DatePicker/useDatePicker.js +13 -4
- package/lib-esm/hooks/useDebounce.d.ts +2 -0
- package/lib-esm/hooks/useDebounce.js +16 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
@@ -21,6 +21,7 @@ const DatePicker = ({
|
|
21
21
|
anchorVariant,
|
22
22
|
anchorRef: externalAnchorRef,
|
23
23
|
confirmation,
|
24
|
+
dateFormat,
|
24
25
|
focusTrapSettings,
|
25
26
|
focusZoneSettings,
|
26
27
|
maxDate,
|
@@ -32,17 +33,20 @@ const DatePicker = ({
|
|
32
33
|
renderAnchor,
|
33
34
|
selection,
|
34
35
|
value,
|
35
|
-
view
|
36
|
+
view,
|
37
|
+
weekStartsOn
|
36
38
|
}) => {
|
37
39
|
const buttonRef = (0, _react.useRef)(null);
|
38
40
|
const [isOpen, setIsOpen] = (0, _react.useState)(false);
|
39
41
|
const datePickerConfiguration = {
|
40
42
|
anchorVariant,
|
41
43
|
confirmation,
|
44
|
+
dateFormat,
|
42
45
|
maxDate,
|
43
46
|
minDate,
|
44
47
|
selection,
|
45
|
-
view
|
48
|
+
view,
|
49
|
+
weekStartsOn
|
46
50
|
};
|
47
51
|
|
48
52
|
const onOpen = gesture => {
|
@@ -2,4 +2,4 @@ import React from 'react';
|
|
2
2
|
export interface DatePickerAnchorProps {
|
3
3
|
onAction?: (event?: React.MouseEvent<HTMLDivElement> | React.KeyboardEvent<HTMLDivElement>) => void;
|
4
4
|
}
|
5
|
-
export declare const DatePickerAnchor: React.ForwardRefExoticComponent<DatePickerAnchorProps & React.RefAttributes<
|
5
|
+
export declare const DatePickerAnchor: React.ForwardRefExoticComponent<DatePickerAnchorProps & React.RefAttributes<HTMLDivElement>>;
|
@@ -11,7 +11,7 @@ var _styledComponents = _interopRequireDefault(require("styled-components"));
|
|
11
11
|
|
12
12
|
var _react = _interopRequireWildcard(require("react"));
|
13
13
|
|
14
|
-
var _Button =
|
14
|
+
var _Button = _interopRequireWildcard(require("../Button"));
|
15
15
|
|
16
16
|
var _Text = _interopRequireDefault(require("../Text"));
|
17
17
|
|
@@ -23,6 +23,10 @@ var _useDatePicker = _interopRequireDefault(require("./useDatePicker"));
|
|
23
23
|
|
24
24
|
var _TextInput = _interopRequireDefault(require("../TextInput"));
|
25
25
|
|
26
|
+
var _Box = _interopRequireDefault(require("../Box"));
|
27
|
+
|
28
|
+
var _dateFns = require("date-fns");
|
29
|
+
|
26
30
|
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); }
|
27
31
|
|
28
32
|
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; }
|
@@ -33,17 +37,22 @@ const DatePickerAnchorButton = (0, _styledComponents.default)(_Button.default).w
|
|
33
37
|
displayName: "DatePickerAnchor__DatePickerAnchorButton",
|
34
38
|
componentId: "sc-8gpb9d-0"
|
35
39
|
})(["align-items:center;display:flex;flex-direction:row;justify-content:space-between;max-width:350px;overflow:hidden;& ", "{margin-left:", ";}"], _Text.default, (0, _constants.get)('space.2'));
|
40
|
+
const INVALID_DATE = 'Invalid Date';
|
36
41
|
|
37
42
|
const DatePickerAnchor = /*#__PURE__*/_react.default.forwardRef(({
|
38
43
|
onAction
|
39
44
|
}, ref) => {
|
40
45
|
const {
|
41
46
|
configuration: {
|
42
|
-
anchorVariant
|
47
|
+
anchorVariant,
|
48
|
+
iconPlacement,
|
49
|
+
selection
|
43
50
|
},
|
44
51
|
disabled,
|
45
|
-
formattedDate
|
52
|
+
formattedDate,
|
53
|
+
onDateInput
|
46
54
|
} = (0, _useDatePicker.default)();
|
55
|
+
const [inputValue, setInputValue] = (0, _react.useState)(formattedDate);
|
47
56
|
const keyPressHandler = (0, _react.useCallback)(event => {
|
48
57
|
if (disabled) {
|
49
58
|
return;
|
@@ -60,15 +69,98 @@ const DatePickerAnchor = /*#__PURE__*/_react.default.forwardRef(({
|
|
60
69
|
|
61
70
|
onAction === null || onAction === void 0 ? void 0 : onAction(event);
|
62
71
|
}, [disabled, onAction]);
|
72
|
+
const onInputChangeHandler = (0, _react.useCallback)(e => {
|
73
|
+
const value = e.currentTarget.value;
|
74
|
+
if (!value) return;
|
75
|
+
|
76
|
+
if (selection === 'range') {
|
77
|
+
var _values$, _values$2, _values$3, _values$4, _values$5, _values$6;
|
78
|
+
|
79
|
+
const values = value.split(' - ');
|
80
|
+
const dates = (0, _dateFns.isBefore)(new Date((_values$ = values[0]) === null || _values$ === void 0 ? void 0 : _values$.trim()), new Date((_values$2 = values[1]) === null || _values$2 === void 0 ? void 0 : _values$2.trim())) ? {
|
81
|
+
from: new Date((_values$3 = values[0]) === null || _values$3 === void 0 ? void 0 : _values$3.trim()),
|
82
|
+
to: new Date((_values$4 = values[1]) === null || _values$4 === void 0 ? void 0 : _values$4.trim())
|
83
|
+
} : {
|
84
|
+
from: new Date((_values$5 = values[1]) === null || _values$5 === void 0 ? void 0 : _values$5.trim()),
|
85
|
+
to: new Date((_values$6 = values[0]) === null || _values$6 === void 0 ? void 0 : _values$6.trim())
|
86
|
+
};
|
87
|
+
setInputValue(value);
|
88
|
+
|
89
|
+
if (dates.from.toString() !== INVALID_DATE && dates.to.toString() !== INVALID_DATE) {
|
90
|
+
onDateInput(dates);
|
91
|
+
}
|
92
|
+
} else if (selection === 'multi') {
|
93
|
+
const values = value.split(',');
|
94
|
+
const dates = [];
|
95
|
+
|
96
|
+
for (const date of values) {
|
97
|
+
dates.push(new Date(date.trim()));
|
98
|
+
}
|
99
|
+
|
100
|
+
setInputValue(value);
|
101
|
+
|
102
|
+
if (dates.every(d => d.toString() !== INVALID_DATE)) {
|
103
|
+
onDateInput(dates);
|
104
|
+
}
|
105
|
+
} else {
|
106
|
+
const date = new Date(value);
|
107
|
+
setInputValue(value);
|
108
|
+
if (date.toString() !== INVALID_DATE) onDateInput(date);
|
109
|
+
}
|
110
|
+
}, [onDateInput, selection]);
|
111
|
+
|
112
|
+
const onBlurHandler = () => {
|
113
|
+
setInputValue(formattedDate);
|
114
|
+
};
|
63
115
|
|
64
116
|
if (anchorVariant === 'input') {
|
65
|
-
|
66
|
-
|
67
|
-
|
117
|
+
const calendarButton = side => /*#__PURE__*/_react.default.createElement(_Button.ButtonInvisible, {
|
118
|
+
onClick: clickHandler,
|
119
|
+
sx: {
|
120
|
+
width: '32px',
|
121
|
+
px: '6px',
|
122
|
+
position: 'absolute',
|
123
|
+
[side]: '1px',
|
124
|
+
top: '1px'
|
125
|
+
}
|
126
|
+
}, /*#__PURE__*/_react.default.createElement(_StyledOcticon.default, {
|
127
|
+
icon: _octiconsReact.CalendarIcon
|
128
|
+
}));
|
129
|
+
|
130
|
+
const inputSx = () => {
|
131
|
+
if (iconPlacement === 'start') {
|
132
|
+
return {
|
133
|
+
pl: 5,
|
134
|
+
pr: 2
|
135
|
+
};
|
136
|
+
} else if (iconPlacement === 'end') {
|
137
|
+
return {
|
138
|
+
pl: 2,
|
139
|
+
pr: 5
|
140
|
+
};
|
141
|
+
} else {
|
142
|
+
return {};
|
143
|
+
}
|
144
|
+
};
|
145
|
+
|
146
|
+
return /*#__PURE__*/_react.default.createElement(_Box.default, {
|
147
|
+
ref: ref,
|
148
|
+
sx: {
|
149
|
+
position: 'relative',
|
150
|
+
display: 'flex',
|
151
|
+
flex: 1
|
152
|
+
}
|
153
|
+
}, iconPlacement === 'start' && calendarButton('left'), /*#__PURE__*/_react.default.createElement(_TextInput.default, {
|
154
|
+
value: inputValue,
|
155
|
+
onChange: onInputChangeHandler,
|
156
|
+
sx: inputSx(),
|
157
|
+
onBlur: onBlurHandler
|
158
|
+
}), iconPlacement === 'end' && calendarButton('right'));
|
68
159
|
}
|
69
160
|
|
70
|
-
return /*#__PURE__*/_react.default.createElement(
|
71
|
-
ref: ref
|
161
|
+
return /*#__PURE__*/_react.default.createElement(_Box.default, {
|
162
|
+
ref: ref
|
163
|
+
}, /*#__PURE__*/_react.default.createElement(DatePickerAnchorButton, {
|
72
164
|
onClick: clickHandler,
|
73
165
|
onKeyPress: keyPressHandler
|
74
166
|
}, /*#__PURE__*/_react.default.createElement(_StyledOcticon.default, {
|
@@ -82,7 +174,7 @@ const DatePickerAnchor = /*#__PURE__*/_react.default.forwardRef(({
|
|
82
174
|
overflow: 'hidden',
|
83
175
|
textOverflow: 'ellipsis'
|
84
176
|
}
|
85
|
-
}, formattedDate));
|
177
|
+
}, formattedDate)));
|
86
178
|
});
|
87
179
|
|
88
180
|
exports.DatePickerAnchor = DatePickerAnchor;
|
package/lib/DatePicker/Month.js
CHANGED
@@ -19,12 +19,23 @@ var _constants = require("../constants");
|
|
19
19
|
|
20
20
|
var _Day = require("./Day");
|
21
21
|
|
22
|
+
var _useDatePicker = _interopRequireDefault(require("./useDatePicker"));
|
23
|
+
|
22
24
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
23
25
|
|
24
26
|
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); }
|
25
27
|
|
26
28
|
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; }
|
27
29
|
|
30
|
+
const weekdayEnum = {
|
31
|
+
Sunday: 0,
|
32
|
+
Monday: 1,
|
33
|
+
Tuesday: 2,
|
34
|
+
Wednesday: 3,
|
35
|
+
Thursday: 4,
|
36
|
+
Friday: 5,
|
37
|
+
Saturday: 6
|
38
|
+
};
|
28
39
|
const MonthComponent = (0, _styledComponents.default)(_Box.default).withConfig({
|
29
40
|
displayName: "Month__MonthComponent",
|
30
41
|
componentId: "l6j7o0-0"
|
@@ -42,17 +53,25 @@ const Month = ({
|
|
42
53
|
month,
|
43
54
|
year
|
44
55
|
}) => {
|
56
|
+
const {
|
57
|
+
configuration
|
58
|
+
} = (0, _useDatePicker.default)();
|
45
59
|
const [selectedDay, setSelectedDay] = (0, _react.useState)(null);
|
46
60
|
const getTitle = (0, _react.useMemo)(() => `${(0, _dateFns.format)(new Date(year, month), 'MMMM yyyy')}`, [month, year]);
|
47
61
|
const weekdayHeaders = (0, _react.useMemo)(() => {
|
62
|
+
var _configuration$weekSt;
|
63
|
+
|
48
64
|
const now = new Date(year, month);
|
65
|
+
const weekOptions = {
|
66
|
+
weekStartsOn: weekdayEnum[(_configuration$weekSt = configuration.weekStartsOn) !== null && _configuration$weekSt !== void 0 ? _configuration$weekSt : 'Sunday']
|
67
|
+
};
|
49
68
|
return (0, _dateFns.eachDayOfInterval)({
|
50
|
-
start: (0, _dateFns.startOfWeek)(now),
|
51
|
-
end: (0, _dateFns.endOfWeek)(now)
|
69
|
+
start: (0, _dateFns.startOfWeek)(now, weekOptions),
|
70
|
+
end: (0, _dateFns.endOfWeek)(now, weekOptions)
|
52
71
|
}).map(d => /*#__PURE__*/_react.default.createElement(WeekdayHeader, {
|
53
72
|
key: `weekday-${d}-header`
|
54
73
|
}, (0, _dateFns.format)(d, 'EEEEEE')));
|
55
|
-
}, [month, year]);
|
74
|
+
}, [configuration.weekStartsOn, month, year]);
|
56
75
|
|
57
76
|
const dayAction = date => {
|
58
77
|
setSelectedDay(date);
|
@@ -61,8 +80,9 @@ const Month = ({
|
|
61
80
|
const dayComponents = (0, _react.useMemo)(() => {
|
62
81
|
const components = [];
|
63
82
|
const firstDay = new Date(year, month, 1);
|
83
|
+
const preBlanks = configuration.weekStartsOn === 'Sunday' ? firstDay.getDay() : (firstDay.getDay() + 6) % 7;
|
64
84
|
|
65
|
-
for (let i = 0; i <
|
85
|
+
for (let i = 0; i < preBlanks; i++) {
|
66
86
|
components.push( /*#__PURE__*/_react.default.createElement(_Day.BlankDay, {
|
67
87
|
key: `month-pre-blank-${i}`
|
68
88
|
}));
|
@@ -79,15 +99,16 @@ const Month = ({
|
|
79
99
|
}
|
80
100
|
|
81
101
|
const lastDay = (0, _dateFns.lastDayOfMonth)(firstDay);
|
102
|
+
const postBlanks = configuration.weekStartsOn === 'Sunday' ? lastDay.getDay() : (lastDay.getDay() + 6) % 7;
|
82
103
|
|
83
|
-
for (let i = 6; i >
|
104
|
+
for (let i = 6; i > postBlanks; i--) {
|
84
105
|
components.push( /*#__PURE__*/_react.default.createElement(_Day.BlankDay, {
|
85
106
|
key: `month-post-blank-${i}`
|
86
107
|
}));
|
87
108
|
}
|
88
109
|
|
89
110
|
return components;
|
90
|
-
}, [month, selectedDay, year]);
|
111
|
+
}, [configuration.weekStartsOn, month, selectedDay, year]);
|
91
112
|
return /*#__PURE__*/_react.default.createElement(MonthComponent, {
|
92
113
|
role: "grid"
|
93
114
|
}, /*#__PURE__*/_react.default.createElement(MonthTitle, null, getTitle), weekdayHeaders, dayComponents);
|
@@ -9,12 +9,14 @@ export interface DatePickerConfiguration {
|
|
9
9
|
contiguousSelection?: boolean;
|
10
10
|
dateFormat?: DateFormat;
|
11
11
|
dimWeekends?: boolean;
|
12
|
+
iconPlacement?: 'start' | 'end' | 'none';
|
12
13
|
minDate?: Date;
|
13
14
|
maxDate?: Date;
|
14
15
|
placeholder?: string;
|
15
16
|
rangeIncrement?: number;
|
16
17
|
selection?: SelectionVariant;
|
17
18
|
view?: '1-month' | '2-month';
|
19
|
+
weekStartsOn?: 'Sunday' | 'Monday' | 'Tuesday' | 'Wednesday' | 'Thursday' | 'Friday' | 'Saturday';
|
18
20
|
}
|
19
21
|
export declare type RangeSelection = {
|
20
22
|
from: Date;
|
@@ -35,9 +37,10 @@ export interface DatePickerContext {
|
|
35
37
|
selectionActive?: boolean;
|
36
38
|
formattedDate: string;
|
37
39
|
nextMonth: () => void;
|
38
|
-
|
40
|
+
onDateInput: (updatedSelection: Selection) => void;
|
39
41
|
onDayFocus: (date: Date) => void;
|
40
42
|
onDayBlur: (date: Date) => void;
|
43
|
+
onSelection: (date: Date) => void;
|
41
44
|
previousMonth: () => void;
|
42
45
|
revertValue: () => void;
|
43
46
|
saveValue: (selection?: Selection) => void;
|
@@ -61,9 +64,10 @@ declare const useDatePicker: (date?: Date | undefined) => {
|
|
61
64
|
selectionActive?: boolean | undefined;
|
62
65
|
formattedDate: string;
|
63
66
|
nextMonth: () => void;
|
64
|
-
|
67
|
+
onDateInput: (updatedSelection: Selection) => void;
|
65
68
|
onDayFocus: (date: Date) => void;
|
66
69
|
onDayBlur: (date: Date) => void;
|
70
|
+
onSelection: (date: Date) => void;
|
67
71
|
previousMonth: () => void;
|
68
72
|
revertValue: () => void;
|
69
73
|
saveValue: (selection?: Selection | undefined) => void;
|
@@ -164,9 +164,11 @@ const defaultConfiguration = {
|
|
164
164
|
confirmation: false,
|
165
165
|
contiguousSelection: false,
|
166
166
|
dimWeekends: false,
|
167
|
+
iconPlacement: 'start',
|
167
168
|
placeholder: 'Select a Date...',
|
168
169
|
selection: 'single',
|
169
|
-
view: '2-month'
|
170
|
+
view: '2-month',
|
171
|
+
weekStartsOn: 'Sunday'
|
170
172
|
};
|
171
173
|
|
172
174
|
const DatePickerProvider = ({
|
@@ -201,7 +203,7 @@ const DatePickerProvider = ({
|
|
201
203
|
|
202
204
|
let template = 'MMM d';
|
203
205
|
|
204
|
-
if (configuration.dateFormat) {
|
206
|
+
if (configuration.anchorVariant !== 'input' && configuration.dateFormat) {
|
205
207
|
switch (configuration.dateFormat) {
|
206
208
|
case 'short':
|
207
209
|
template = 'MMM d';
|
@@ -215,6 +217,8 @@ const DatePickerProvider = ({
|
|
215
217
|
template = configuration.dateFormat;
|
216
218
|
break;
|
217
219
|
}
|
220
|
+
} else {
|
221
|
+
template = 'MM/dd/yyyy';
|
218
222
|
}
|
219
223
|
|
220
224
|
switch (configuration.selection) {
|
@@ -272,11 +276,15 @@ const DatePickerProvider = ({
|
|
272
276
|
return 'Invalid Configuration';
|
273
277
|
}
|
274
278
|
}
|
275
|
-
}, [configuration.dateFormat, configuration.placeholder, configuration.selection, selection]);
|
279
|
+
}, [configuration.anchorVariant, configuration.dateFormat, configuration.placeholder, configuration.selection, selection]);
|
276
280
|
const saveValue = (0, _react.useCallback)(updatedSelection => {
|
277
281
|
setPreviousSelection(updatedSelection !== null && updatedSelection !== void 0 ? updatedSelection : selection);
|
278
282
|
closePicker === null || closePicker === void 0 ? void 0 : closePicker();
|
279
283
|
}, [closePicker, selection]);
|
284
|
+
const inputHandler = (0, _react.useCallback)(updatedSelection => {
|
285
|
+
// validate date falls within range
|
286
|
+
setSelection(updatedSelection);
|
287
|
+
}, []);
|
280
288
|
const selectionHandler = (0, _react.useCallback)(date => {
|
281
289
|
if (configuration.selection === 'multi') {
|
282
290
|
const selections = [...selection];
|
@@ -352,6 +360,7 @@ const DatePickerProvider = ({
|
|
352
360
|
goToMonth,
|
353
361
|
hoverRange,
|
354
362
|
nextMonth,
|
363
|
+
onDateInput: inputHandler,
|
355
364
|
onDayBlur: blurHnadler,
|
356
365
|
onDayFocus: focusHnadler,
|
357
366
|
onSelection: selectionHandler,
|
@@ -361,7 +370,7 @@ const DatePickerProvider = ({
|
|
361
370
|
selectionActive: false,
|
362
371
|
selection
|
363
372
|
};
|
364
|
-
}, [blurHnadler, configuration, currentViewingDate, focusHnadler, getFormattedDate, goToMonth, hoverRange, nextMonth, previousMonth, revertValue, saveValue, selection, selectionHandler]);
|
373
|
+
}, [blurHnadler, configuration, currentViewingDate, focusHnadler, getFormattedDate, goToMonth, hoverRange, inputHandler, nextMonth, previousMonth, revertValue, saveValue, selection, selectionHandler]);
|
365
374
|
return /*#__PURE__*/_react.default.createElement(DatePickerContext.Provider, {
|
366
375
|
value: datePickerCtx
|
367
376
|
}, children);
|
@@ -0,0 +1,24 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
exports.default = void 0;
|
7
|
+
|
8
|
+
var _react = require("react");
|
9
|
+
|
10
|
+
function useDebounce(value, delay) {
|
11
|
+
const [debouncedValue, setDebouncedValue] = (0, _react.useState)(value);
|
12
|
+
(0, _react.useEffect)(() => {
|
13
|
+
const handler = setTimeout(() => {
|
14
|
+
setDebouncedValue(value);
|
15
|
+
}, delay);
|
16
|
+
return () => {
|
17
|
+
clearTimeout(handler);
|
18
|
+
};
|
19
|
+
}, [value, delay]);
|
20
|
+
return debouncedValue;
|
21
|
+
}
|
22
|
+
|
23
|
+
var _default = useDebounce;
|
24
|
+
exports.default = _default;
|
@@ -6,6 +6,7 @@ export const DatePicker = ({
|
|
6
6
|
anchorVariant,
|
7
7
|
anchorRef: externalAnchorRef,
|
8
8
|
confirmation,
|
9
|
+
dateFormat,
|
9
10
|
focusTrapSettings,
|
10
11
|
focusZoneSettings,
|
11
12
|
maxDate,
|
@@ -17,17 +18,20 @@ export const DatePicker = ({
|
|
17
18
|
renderAnchor,
|
18
19
|
selection,
|
19
20
|
value,
|
20
|
-
view
|
21
|
+
view,
|
22
|
+
weekStartsOn
|
21
23
|
}) => {
|
22
24
|
const buttonRef = useRef(null);
|
23
25
|
const [isOpen, setIsOpen] = useState(false);
|
24
26
|
const datePickerConfiguration = {
|
25
27
|
anchorVariant,
|
26
28
|
confirmation,
|
29
|
+
dateFormat,
|
27
30
|
maxDate,
|
28
31
|
minDate,
|
29
32
|
selection,
|
30
|
-
view
|
33
|
+
view,
|
34
|
+
weekStartsOn
|
31
35
|
};
|
32
36
|
|
33
37
|
const onOpen = gesture => {
|
@@ -2,4 +2,4 @@ import React from 'react';
|
|
2
2
|
export interface DatePickerAnchorProps {
|
3
3
|
onAction?: (event?: React.MouseEvent<HTMLDivElement> | React.KeyboardEvent<HTMLDivElement>) => void;
|
4
4
|
}
|
5
|
-
export declare const DatePickerAnchor: React.ForwardRefExoticComponent<DatePickerAnchorProps & React.RefAttributes<
|
5
|
+
export declare const DatePickerAnchor: React.ForwardRefExoticComponent<DatePickerAnchorProps & React.RefAttributes<HTMLDivElement>>;
|
@@ -1,26 +1,33 @@
|
|
1
1
|
import { CalendarIcon } from '@primer/octicons-react';
|
2
2
|
import styled from 'styled-components';
|
3
|
-
import React, { useCallback } from 'react';
|
4
|
-
import Button from '../Button';
|
3
|
+
import React, { useCallback, useState } from 'react';
|
4
|
+
import Button, { ButtonInvisible } from '../Button';
|
5
5
|
import Text from '../Text';
|
6
6
|
import { get } from '../constants';
|
7
7
|
import StyledOcticon from '../StyledOcticon';
|
8
8
|
import useDatePicker from './useDatePicker';
|
9
9
|
import TextInput from '../TextInput';
|
10
|
+
import Box from '../Box';
|
11
|
+
import { isBefore } from 'date-fns';
|
10
12
|
const DatePickerAnchorButton = styled(Button).withConfig({
|
11
13
|
displayName: "DatePickerAnchor__DatePickerAnchorButton",
|
12
14
|
componentId: "sc-8gpb9d-0"
|
13
15
|
})(["align-items:center;display:flex;flex-direction:row;justify-content:space-between;max-width:350px;overflow:hidden;& ", "{margin-left:", ";}"], Text, get('space.2'));
|
16
|
+
const INVALID_DATE = 'Invalid Date';
|
14
17
|
export const DatePickerAnchor = /*#__PURE__*/React.forwardRef(({
|
15
18
|
onAction
|
16
19
|
}, ref) => {
|
17
20
|
const {
|
18
21
|
configuration: {
|
19
|
-
anchorVariant
|
22
|
+
anchorVariant,
|
23
|
+
iconPlacement,
|
24
|
+
selection
|
20
25
|
},
|
21
26
|
disabled,
|
22
|
-
formattedDate
|
27
|
+
formattedDate,
|
28
|
+
onDateInput
|
23
29
|
} = useDatePicker();
|
30
|
+
const [inputValue, setInputValue] = useState(formattedDate);
|
24
31
|
const keyPressHandler = useCallback(event => {
|
25
32
|
if (disabled) {
|
26
33
|
return;
|
@@ -37,15 +44,98 @@ export const DatePickerAnchor = /*#__PURE__*/React.forwardRef(({
|
|
37
44
|
|
38
45
|
onAction === null || onAction === void 0 ? void 0 : onAction(event);
|
39
46
|
}, [disabled, onAction]);
|
47
|
+
const onInputChangeHandler = useCallback(e => {
|
48
|
+
const value = e.currentTarget.value;
|
49
|
+
if (!value) return;
|
50
|
+
|
51
|
+
if (selection === 'range') {
|
52
|
+
var _values$, _values$2, _values$3, _values$4, _values$5, _values$6;
|
53
|
+
|
54
|
+
const values = value.split(' - ');
|
55
|
+
const dates = isBefore(new Date((_values$ = values[0]) === null || _values$ === void 0 ? void 0 : _values$.trim()), new Date((_values$2 = values[1]) === null || _values$2 === void 0 ? void 0 : _values$2.trim())) ? {
|
56
|
+
from: new Date((_values$3 = values[0]) === null || _values$3 === void 0 ? void 0 : _values$3.trim()),
|
57
|
+
to: new Date((_values$4 = values[1]) === null || _values$4 === void 0 ? void 0 : _values$4.trim())
|
58
|
+
} : {
|
59
|
+
from: new Date((_values$5 = values[1]) === null || _values$5 === void 0 ? void 0 : _values$5.trim()),
|
60
|
+
to: new Date((_values$6 = values[0]) === null || _values$6 === void 0 ? void 0 : _values$6.trim())
|
61
|
+
};
|
62
|
+
setInputValue(value);
|
63
|
+
|
64
|
+
if (dates.from.toString() !== INVALID_DATE && dates.to.toString() !== INVALID_DATE) {
|
65
|
+
onDateInput(dates);
|
66
|
+
}
|
67
|
+
} else if (selection === 'multi') {
|
68
|
+
const values = value.split(',');
|
69
|
+
const dates = [];
|
70
|
+
|
71
|
+
for (const date of values) {
|
72
|
+
dates.push(new Date(date.trim()));
|
73
|
+
}
|
74
|
+
|
75
|
+
setInputValue(value);
|
76
|
+
|
77
|
+
if (dates.every(d => d.toString() !== INVALID_DATE)) {
|
78
|
+
onDateInput(dates);
|
79
|
+
}
|
80
|
+
} else {
|
81
|
+
const date = new Date(value);
|
82
|
+
setInputValue(value);
|
83
|
+
if (date.toString() !== INVALID_DATE) onDateInput(date);
|
84
|
+
}
|
85
|
+
}, [onDateInput, selection]);
|
86
|
+
|
87
|
+
const onBlurHandler = () => {
|
88
|
+
setInputValue(formattedDate);
|
89
|
+
};
|
40
90
|
|
41
91
|
if (anchorVariant === 'input') {
|
42
|
-
|
43
|
-
|
44
|
-
|
92
|
+
const calendarButton = side => /*#__PURE__*/React.createElement(ButtonInvisible, {
|
93
|
+
onClick: clickHandler,
|
94
|
+
sx: {
|
95
|
+
width: '32px',
|
96
|
+
px: '6px',
|
97
|
+
position: 'absolute',
|
98
|
+
[side]: '1px',
|
99
|
+
top: '1px'
|
100
|
+
}
|
101
|
+
}, /*#__PURE__*/React.createElement(StyledOcticon, {
|
102
|
+
icon: CalendarIcon
|
103
|
+
}));
|
104
|
+
|
105
|
+
const inputSx = () => {
|
106
|
+
if (iconPlacement === 'start') {
|
107
|
+
return {
|
108
|
+
pl: 5,
|
109
|
+
pr: 2
|
110
|
+
};
|
111
|
+
} else if (iconPlacement === 'end') {
|
112
|
+
return {
|
113
|
+
pl: 2,
|
114
|
+
pr: 5
|
115
|
+
};
|
116
|
+
} else {
|
117
|
+
return {};
|
118
|
+
}
|
119
|
+
};
|
120
|
+
|
121
|
+
return /*#__PURE__*/React.createElement(Box, {
|
122
|
+
ref: ref,
|
123
|
+
sx: {
|
124
|
+
position: 'relative',
|
125
|
+
display: 'flex',
|
126
|
+
flex: 1
|
127
|
+
}
|
128
|
+
}, iconPlacement === 'start' && calendarButton('left'), /*#__PURE__*/React.createElement(TextInput, {
|
129
|
+
value: inputValue,
|
130
|
+
onChange: onInputChangeHandler,
|
131
|
+
sx: inputSx(),
|
132
|
+
onBlur: onBlurHandler
|
133
|
+
}), iconPlacement === 'end' && calendarButton('right'));
|
45
134
|
}
|
46
135
|
|
47
|
-
return /*#__PURE__*/React.createElement(
|
48
|
-
ref: ref
|
136
|
+
return /*#__PURE__*/React.createElement(Box, {
|
137
|
+
ref: ref
|
138
|
+
}, /*#__PURE__*/React.createElement(DatePickerAnchorButton, {
|
49
139
|
onClick: clickHandler,
|
50
140
|
onKeyPress: keyPressHandler
|
51
141
|
}, /*#__PURE__*/React.createElement(StyledOcticon, {
|
@@ -59,5 +149,5 @@ export const DatePickerAnchor = /*#__PURE__*/React.forwardRef(({
|
|
59
149
|
overflow: 'hidden',
|
60
150
|
textOverflow: 'ellipsis'
|
61
151
|
}
|
62
|
-
}, formattedDate));
|
152
|
+
}, formattedDate)));
|
63
153
|
});
|
@@ -5,6 +5,16 @@ import Box from '../Box';
|
|
5
5
|
import Text from '../Text';
|
6
6
|
import { get } from '../constants';
|
7
7
|
import { BlankDay, Day } from './Day';
|
8
|
+
import useDatePicker from './useDatePicker';
|
9
|
+
const weekdayEnum = {
|
10
|
+
Sunday: 0,
|
11
|
+
Monday: 1,
|
12
|
+
Tuesday: 2,
|
13
|
+
Wednesday: 3,
|
14
|
+
Thursday: 4,
|
15
|
+
Friday: 5,
|
16
|
+
Saturday: 6
|
17
|
+
};
|
8
18
|
const MonthComponent = styled(Box).withConfig({
|
9
19
|
displayName: "Month__MonthComponent",
|
10
20
|
componentId: "l6j7o0-0"
|
@@ -21,17 +31,25 @@ export const Month = ({
|
|
21
31
|
month,
|
22
32
|
year
|
23
33
|
}) => {
|
34
|
+
const {
|
35
|
+
configuration
|
36
|
+
} = useDatePicker();
|
24
37
|
const [selectedDay, setSelectedDay] = useState(null);
|
25
38
|
const getTitle = useMemo(() => `${format(new Date(year, month), 'MMMM yyyy')}`, [month, year]);
|
26
39
|
const weekdayHeaders = useMemo(() => {
|
40
|
+
var _configuration$weekSt;
|
41
|
+
|
27
42
|
const now = new Date(year, month);
|
43
|
+
const weekOptions = {
|
44
|
+
weekStartsOn: weekdayEnum[(_configuration$weekSt = configuration.weekStartsOn) !== null && _configuration$weekSt !== void 0 ? _configuration$weekSt : 'Sunday']
|
45
|
+
};
|
28
46
|
return eachDayOfInterval({
|
29
|
-
start: startOfWeek(now),
|
30
|
-
end: endOfWeek(now)
|
47
|
+
start: startOfWeek(now, weekOptions),
|
48
|
+
end: endOfWeek(now, weekOptions)
|
31
49
|
}).map(d => /*#__PURE__*/React.createElement(WeekdayHeader, {
|
32
50
|
key: `weekday-${d}-header`
|
33
51
|
}, format(d, 'EEEEEE')));
|
34
|
-
}, [month, year]);
|
52
|
+
}, [configuration.weekStartsOn, month, year]);
|
35
53
|
|
36
54
|
const dayAction = date => {
|
37
55
|
setSelectedDay(date);
|
@@ -40,8 +58,9 @@ export const Month = ({
|
|
40
58
|
const dayComponents = useMemo(() => {
|
41
59
|
const components = [];
|
42
60
|
const firstDay = new Date(year, month, 1);
|
61
|
+
const preBlanks = configuration.weekStartsOn === 'Sunday' ? firstDay.getDay() : (firstDay.getDay() + 6) % 7;
|
43
62
|
|
44
|
-
for (let i = 0; i <
|
63
|
+
for (let i = 0; i < preBlanks; i++) {
|
45
64
|
components.push( /*#__PURE__*/React.createElement(BlankDay, {
|
46
65
|
key: `month-pre-blank-${i}`
|
47
66
|
}));
|
@@ -58,15 +77,16 @@ export const Month = ({
|
|
58
77
|
}
|
59
78
|
|
60
79
|
const lastDay = lastDayOfMonth(firstDay);
|
80
|
+
const postBlanks = configuration.weekStartsOn === 'Sunday' ? lastDay.getDay() : (lastDay.getDay() + 6) % 7;
|
61
81
|
|
62
|
-
for (let i = 6; i >
|
82
|
+
for (let i = 6; i > postBlanks; i--) {
|
63
83
|
components.push( /*#__PURE__*/React.createElement(BlankDay, {
|
64
84
|
key: `month-post-blank-${i}`
|
65
85
|
}));
|
66
86
|
}
|
67
87
|
|
68
88
|
return components;
|
69
|
-
}, [month, selectedDay, year]);
|
89
|
+
}, [configuration.weekStartsOn, month, selectedDay, year]);
|
70
90
|
return /*#__PURE__*/React.createElement(MonthComponent, {
|
71
91
|
role: "grid"
|
72
92
|
}, /*#__PURE__*/React.createElement(MonthTitle, null, getTitle), weekdayHeaders, dayComponents);
|
@@ -9,12 +9,14 @@ export interface DatePickerConfiguration {
|
|
9
9
|
contiguousSelection?: boolean;
|
10
10
|
dateFormat?: DateFormat;
|
11
11
|
dimWeekends?: boolean;
|
12
|
+
iconPlacement?: 'start' | 'end' | 'none';
|
12
13
|
minDate?: Date;
|
13
14
|
maxDate?: Date;
|
14
15
|
placeholder?: string;
|
15
16
|
rangeIncrement?: number;
|
16
17
|
selection?: SelectionVariant;
|
17
18
|
view?: '1-month' | '2-month';
|
19
|
+
weekStartsOn?: 'Sunday' | 'Monday' | 'Tuesday' | 'Wednesday' | 'Thursday' | 'Friday' | 'Saturday';
|
18
20
|
}
|
19
21
|
export declare type RangeSelection = {
|
20
22
|
from: Date;
|
@@ -35,9 +37,10 @@ export interface DatePickerContext {
|
|
35
37
|
selectionActive?: boolean;
|
36
38
|
formattedDate: string;
|
37
39
|
nextMonth: () => void;
|
38
|
-
|
40
|
+
onDateInput: (updatedSelection: Selection) => void;
|
39
41
|
onDayFocus: (date: Date) => void;
|
40
42
|
onDayBlur: (date: Date) => void;
|
43
|
+
onSelection: (date: Date) => void;
|
41
44
|
previousMonth: () => void;
|
42
45
|
revertValue: () => void;
|
43
46
|
saveValue: (selection?: Selection) => void;
|
@@ -61,9 +64,10 @@ declare const useDatePicker: (date?: Date | undefined) => {
|
|
61
64
|
selectionActive?: boolean | undefined;
|
62
65
|
formattedDate: string;
|
63
66
|
nextMonth: () => void;
|
64
|
-
|
67
|
+
onDateInput: (updatedSelection: Selection) => void;
|
65
68
|
onDayFocus: (date: Date) => void;
|
66
69
|
onDayBlur: (date: Date) => void;
|
70
|
+
onSelection: (date: Date) => void;
|
67
71
|
previousMonth: () => void;
|
68
72
|
revertValue: () => void;
|
69
73
|
saveValue: (selection?: Selection | undefined) => void;
|
@@ -139,9 +139,11 @@ const defaultConfiguration = {
|
|
139
139
|
confirmation: false,
|
140
140
|
contiguousSelection: false,
|
141
141
|
dimWeekends: false,
|
142
|
+
iconPlacement: 'start',
|
142
143
|
placeholder: 'Select a Date...',
|
143
144
|
selection: 'single',
|
144
|
-
view: '2-month'
|
145
|
+
view: '2-month',
|
146
|
+
weekStartsOn: 'Sunday'
|
145
147
|
};
|
146
148
|
export const DatePickerProvider = ({
|
147
149
|
configuration: externalConfig = {},
|
@@ -175,7 +177,7 @@ export const DatePickerProvider = ({
|
|
175
177
|
|
176
178
|
let template = 'MMM d';
|
177
179
|
|
178
|
-
if (configuration.dateFormat) {
|
180
|
+
if (configuration.anchorVariant !== 'input' && configuration.dateFormat) {
|
179
181
|
switch (configuration.dateFormat) {
|
180
182
|
case 'short':
|
181
183
|
template = 'MMM d';
|
@@ -189,6 +191,8 @@ export const DatePickerProvider = ({
|
|
189
191
|
template = configuration.dateFormat;
|
190
192
|
break;
|
191
193
|
}
|
194
|
+
} else {
|
195
|
+
template = 'MM/dd/yyyy';
|
192
196
|
}
|
193
197
|
|
194
198
|
switch (configuration.selection) {
|
@@ -246,11 +250,15 @@ export const DatePickerProvider = ({
|
|
246
250
|
return 'Invalid Configuration';
|
247
251
|
}
|
248
252
|
}
|
249
|
-
}, [configuration.dateFormat, configuration.placeholder, configuration.selection, selection]);
|
253
|
+
}, [configuration.anchorVariant, configuration.dateFormat, configuration.placeholder, configuration.selection, selection]);
|
250
254
|
const saveValue = useCallback(updatedSelection => {
|
251
255
|
setPreviousSelection(updatedSelection !== null && updatedSelection !== void 0 ? updatedSelection : selection);
|
252
256
|
closePicker === null || closePicker === void 0 ? void 0 : closePicker();
|
253
257
|
}, [closePicker, selection]);
|
258
|
+
const inputHandler = useCallback(updatedSelection => {
|
259
|
+
// validate date falls within range
|
260
|
+
setSelection(updatedSelection);
|
261
|
+
}, []);
|
254
262
|
const selectionHandler = useCallback(date => {
|
255
263
|
if (configuration.selection === 'multi') {
|
256
264
|
const selections = [...selection];
|
@@ -326,6 +334,7 @@ export const DatePickerProvider = ({
|
|
326
334
|
goToMonth,
|
327
335
|
hoverRange,
|
328
336
|
nextMonth,
|
337
|
+
onDateInput: inputHandler,
|
329
338
|
onDayBlur: blurHnadler,
|
330
339
|
onDayFocus: focusHnadler,
|
331
340
|
onSelection: selectionHandler,
|
@@ -335,7 +344,7 @@ export const DatePickerProvider = ({
|
|
335
344
|
selectionActive: false,
|
336
345
|
selection
|
337
346
|
};
|
338
|
-
}, [blurHnadler, configuration, currentViewingDate, focusHnadler, getFormattedDate, goToMonth, hoverRange, nextMonth, previousMonth, revertValue, saveValue, selection, selectionHandler]);
|
347
|
+
}, [blurHnadler, configuration, currentViewingDate, focusHnadler, getFormattedDate, goToMonth, hoverRange, inputHandler, nextMonth, previousMonth, revertValue, saveValue, selection, selectionHandler]);
|
339
348
|
return /*#__PURE__*/React.createElement(DatePickerContext.Provider, {
|
340
349
|
value: datePickerCtx
|
341
350
|
}, children);
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import { useEffect, useState } from 'react';
|
2
|
+
|
3
|
+
function useDebounce(value, delay) {
|
4
|
+
const [debouncedValue, setDebouncedValue] = useState(value);
|
5
|
+
useEffect(() => {
|
6
|
+
const handler = setTimeout(() => {
|
7
|
+
setDebouncedValue(value);
|
8
|
+
}, delay);
|
9
|
+
return () => {
|
10
|
+
clearTimeout(handler);
|
11
|
+
};
|
12
|
+
}, [value, delay]);
|
13
|
+
return debouncedValue;
|
14
|
+
}
|
15
|
+
|
16
|
+
export default useDebounce;
|