@primer/components 0.0.0-2021102224222 → 0.0.0-202110343939

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.
Files changed (140) hide show
  1. package/CHANGELOG.md +1 -29
  2. package/dist/browser.esm.js +50 -53
  3. package/dist/browser.esm.js.map +1 -1
  4. package/dist/browser.umd.js +48 -51
  5. package/dist/browser.umd.js.map +1 -1
  6. package/lib/ActionList/Header.js +1 -1
  7. package/lib/ActionList/Item.d.ts +0 -6
  8. package/lib/ActionList/Item.js +1 -5
  9. package/lib/AnchoredOverlay/AnchoredOverlay.d.ts +4 -2
  10. package/lib/AnchoredOverlay/AnchoredOverlay.js +6 -8
  11. package/lib/Autocomplete/Autocomplete.d.ts +8 -6
  12. package/lib/Autocomplete/AutocompleteInput.d.ts +8 -6
  13. package/lib/Button/Button.d.ts +5 -5
  14. package/lib/Button/ButtonBase.d.ts +1 -1
  15. package/lib/Button/ButtonClose.d.ts +3 -3
  16. package/lib/Button/ButtonDanger.d.ts +5 -5
  17. package/lib/Button/ButtonInvisible.d.ts +5 -5
  18. package/lib/Button/ButtonOutline.d.ts +5 -5
  19. package/lib/Button/ButtonPrimary.d.ts +5 -5
  20. package/lib/CircleBadge.d.ts +7 -6
  21. package/lib/CircleBadge.js +1 -1
  22. package/lib/CircleOcticon.d.ts +4 -4
  23. package/lib/DatePicker/DatePicker.d.ts +48 -0
  24. package/lib/DatePicker/DatePicker.js +109 -0
  25. package/lib/DatePicker/DatePickerAnchor.d.ts +5 -0
  26. package/lib/DatePicker/DatePickerAnchor.js +202 -0
  27. package/lib/DatePicker/DatePickerOverlay.d.ts +3 -0
  28. package/lib/DatePicker/DatePickerOverlay.js +53 -0
  29. package/lib/DatePicker/DatePickerPanel.d.ts +2 -0
  30. package/lib/DatePicker/DatePickerPanel.js +232 -0
  31. package/lib/DatePicker/Day.d.ts +15 -0
  32. package/lib/DatePicker/Day.js +197 -0
  33. package/lib/DatePicker/Month.d.ts +8 -0
  34. package/lib/DatePicker/Month.js +122 -0
  35. package/lib/DatePicker/dateParser.d.ts +12 -0
  36. package/lib/DatePicker/dateParser.js +192 -0
  37. package/lib/DatePicker/index.d.ts +2 -0
  38. package/lib/DatePicker/index.js +13 -0
  39. package/lib/DatePicker/useDatePicker.d.ts +107 -0
  40. package/lib/DatePicker/useDatePicker.js +685 -0
  41. package/lib/Dialog.d.ts +4 -4
  42. package/lib/Dropdown.d.ts +16 -16
  43. package/lib/DropdownMenu/DropdownButton.d.ts +6 -6
  44. package/lib/FilterList.d.ts +3 -3
  45. package/lib/Flash.d.ts +1 -1
  46. package/lib/Label.d.ts +1 -1
  47. package/lib/Position.d.ts +4 -4
  48. package/lib/ProgressBar.d.ts +1 -1
  49. package/lib/SelectMenu/SelectMenu.d.ts +28 -26
  50. package/lib/SelectMenu/SelectMenuItem.d.ts +1 -1
  51. package/lib/TextInputWithTokens.d.ts +8 -10
  52. package/lib/TextInputWithTokens.js +29 -102
  53. package/lib/Timeline.d.ts +4 -4
  54. package/lib/Token/AvatarToken.d.ts +1 -1
  55. package/lib/Token/IssueLabelToken.d.ts +1 -1
  56. package/lib/Token/Token.d.ts +1 -1
  57. package/lib/Token/Token.js +2 -13
  58. package/lib/Token/TokenBase.js +4 -0
  59. package/lib/Token/_RemoveTokenButton.js +2 -15
  60. package/lib/_TextInputWrapper.d.ts +1 -1
  61. package/lib/_TextInputWrapper.js +1 -1
  62. package/lib/hooks/useDebounce.d.ts +2 -0
  63. package/lib/hooks/useDebounce.js +24 -0
  64. package/lib/hooks/useResizeObserver.d.ts +1 -1
  65. package/lib/hooks/useResizeObserver.js +1 -1
  66. package/lib/sx.d.ts +2 -8
  67. package/lib/theme-preval.js +2 -2
  68. package/lib/theme.d.ts +0 -78
  69. package/lib/theme.js +1 -3
  70. package/lib/utils/testing.d.ts +1 -1
  71. package/lib-esm/ActionList/Header.js +1 -1
  72. package/lib-esm/ActionList/Item.d.ts +0 -6
  73. package/lib-esm/ActionList/Item.js +1 -5
  74. package/lib-esm/AnchoredOverlay/AnchoredOverlay.d.ts +4 -2
  75. package/lib-esm/AnchoredOverlay/AnchoredOverlay.js +6 -7
  76. package/lib-esm/Autocomplete/Autocomplete.d.ts +8 -6
  77. package/lib-esm/Autocomplete/AutocompleteInput.d.ts +8 -6
  78. package/lib-esm/Button/Button.d.ts +5 -5
  79. package/lib-esm/Button/ButtonBase.d.ts +1 -1
  80. package/lib-esm/Button/ButtonClose.d.ts +3 -3
  81. package/lib-esm/Button/ButtonDanger.d.ts +5 -5
  82. package/lib-esm/Button/ButtonInvisible.d.ts +5 -5
  83. package/lib-esm/Button/ButtonOutline.d.ts +5 -5
  84. package/lib-esm/Button/ButtonPrimary.d.ts +5 -5
  85. package/lib-esm/CircleBadge.d.ts +7 -6
  86. package/lib-esm/CircleBadge.js +2 -2
  87. package/lib-esm/CircleOcticon.d.ts +4 -4
  88. package/lib-esm/DatePicker/DatePicker.d.ts +48 -0
  89. package/lib-esm/DatePicker/DatePicker.js +92 -0
  90. package/lib-esm/DatePicker/DatePickerAnchor.d.ts +5 -0
  91. package/lib-esm/DatePicker/DatePickerAnchor.js +174 -0
  92. package/lib-esm/DatePicker/DatePickerOverlay.d.ts +3 -0
  93. package/lib-esm/DatePicker/DatePickerOverlay.js +38 -0
  94. package/lib-esm/DatePicker/DatePickerPanel.d.ts +2 -0
  95. package/lib-esm/DatePicker/DatePickerPanel.js +201 -0
  96. package/lib-esm/DatePicker/Day.d.ts +15 -0
  97. package/lib-esm/DatePicker/Day.js +174 -0
  98. package/lib-esm/DatePicker/Month.d.ts +8 -0
  99. package/lib-esm/DatePicker/Month.js +98 -0
  100. package/lib-esm/DatePicker/dateParser.d.ts +12 -0
  101. package/lib-esm/DatePicker/dateParser.js +178 -0
  102. package/lib-esm/DatePicker/index.d.ts +2 -0
  103. package/lib-esm/DatePicker/index.js +1 -0
  104. package/lib-esm/DatePicker/useDatePicker.d.ts +107 -0
  105. package/lib-esm/DatePicker/useDatePicker.js +650 -0
  106. package/lib-esm/Dialog.d.ts +4 -4
  107. package/lib-esm/Dropdown.d.ts +16 -16
  108. package/lib-esm/DropdownMenu/DropdownButton.d.ts +6 -6
  109. package/lib-esm/FilterList.d.ts +3 -3
  110. package/lib-esm/Flash.d.ts +1 -1
  111. package/lib-esm/Label.d.ts +1 -1
  112. package/lib-esm/Position.d.ts +4 -4
  113. package/lib-esm/ProgressBar.d.ts +1 -1
  114. package/lib-esm/SelectMenu/SelectMenu.d.ts +28 -26
  115. package/lib-esm/SelectMenu/SelectMenuItem.d.ts +1 -1
  116. package/lib-esm/TextInputWithTokens.d.ts +8 -10
  117. package/lib-esm/TextInputWithTokens.js +30 -101
  118. package/lib-esm/Timeline.d.ts +4 -4
  119. package/lib-esm/Token/AvatarToken.d.ts +1 -1
  120. package/lib-esm/Token/IssueLabelToken.d.ts +1 -1
  121. package/lib-esm/Token/Token.d.ts +1 -1
  122. package/lib-esm/Token/Token.js +2 -13
  123. package/lib-esm/Token/TokenBase.js +4 -0
  124. package/lib-esm/Token/_RemoveTokenButton.js +2 -11
  125. package/lib-esm/_TextInputWrapper.d.ts +1 -1
  126. package/lib-esm/_TextInputWrapper.js +1 -1
  127. package/lib-esm/hooks/useDebounce.d.ts +2 -0
  128. package/lib-esm/hooks/useDebounce.js +16 -0
  129. package/lib-esm/hooks/useResizeObserver.d.ts +1 -1
  130. package/lib-esm/hooks/useResizeObserver.js +1 -1
  131. package/lib-esm/sx.d.ts +2 -8
  132. package/lib-esm/theme-preval.js +2 -2
  133. package/lib-esm/theme.d.ts +0 -78
  134. package/lib-esm/theme.js +1 -2
  135. package/lib-esm/utils/testing.d.ts +1 -1
  136. package/package.json +14 -15
  137. package/lib/utils/types/KeyPaths.d.ts +0 -3
  138. package/lib/utils/types/KeyPaths.js +0 -1
  139. package/lib-esm/utils/types/KeyPaths.d.ts +0 -3
  140. package/lib-esm/utils/types/KeyPaths.js +0 -1
@@ -0,0 +1,650 @@
1
+ import { CheckIcon, TrashIcon } from '@primer/octicons-react';
2
+ import { isEqual, isAfter, isBefore, addMonths, subMonths, isToday, isWeekend, differenceInDays, addDays, subDays, addWeeks, subWeeks, isSaturday, isSunday, nextSaturday, previousFriday, previousSunday, subYears, addYears, differenceInBusinessDays, nextMonday, isMonday, previousMonday, isFriday, nextFriday } from 'date-fns';
3
+ import { addBusinessDays, subBusinessDays } from 'date-fns/esm';
4
+ import deepmerge from 'deepmerge';
5
+ import React, { createContext, useCallback, useContext, useMemo, useEffect, useState } from 'react';
6
+ import { Text, useConfirm } from '..';
7
+ import { useResizeObserver } from '../hooks/useResizeObserver';
8
+ import { formatDate } from './dateParser';
9
+ const DatePickerContext = /*#__PURE__*/createContext(null);
10
+
11
+ const useDatePicker = date => {
12
+ const dateCtx = useContext(DatePickerContext);
13
+ const [selected, setSelected] = useState(false);
14
+ const [focused, setFocused] = useState(false);
15
+ const today = date ? isToday(date) : false;
16
+
17
+ if (!dateCtx) {
18
+ throw new Error('useDatePicker must be used inside a DatePickerProvider');
19
+ }
20
+
21
+ useEffect(() => {
22
+ if (date) {
23
+ if (dateCtx.hoverRange) {
24
+ if (isRangeSelection(dateCtx.hoverRange)) {
25
+ if (isEqual(date, dateCtx.hoverRange.from)) {
26
+ setSelected('start');
27
+ } else if (dateCtx.hoverRange.to && isEqual(date, dateCtx.hoverRange.to)) {
28
+ setSelected('end');
29
+ } else if (isAfter(date, dateCtx.hoverRange.from) && dateCtx.hoverRange.to && isBefore(date, dateCtx.hoverRange.to)) {
30
+ setSelected('middle');
31
+ } else {
32
+ setSelected(false);
33
+ }
34
+ }
35
+ } else if (dateCtx.selection) {
36
+ if (isMultiSelection(dateCtx.selection)) {
37
+ setSelected(!!dateCtx.selection.find(d => isEqual(d, date)));
38
+ } else if (isRangeSelection(dateCtx.selection)) {
39
+ if (isEqual(date, dateCtx.selection.from)) {
40
+ setSelected('start');
41
+ } else if (dateCtx.selection.to && isEqual(date, dateCtx.selection.to)) {
42
+ setSelected('end');
43
+ } else if (isAfter(date, dateCtx.selection.from) && dateCtx.selection.to && isBefore(date, dateCtx.selection.to)) {
44
+ setSelected('middle');
45
+ } else {
46
+ setSelected(false);
47
+ }
48
+ } else {
49
+ setSelected(isEqual(date, dateCtx.selection));
50
+ }
51
+ }
52
+ }
53
+ }, [date, dateCtx.hoverRange, dateCtx.selection, today]);
54
+ useEffect(() => {
55
+ if (date) {
56
+ // Determine if date is focused
57
+ setFocused(isEqual(dateCtx.focusDate, date));
58
+ }
59
+ }, [date, dateCtx.focusDate]);
60
+ let blocked,
61
+ disabled = false;
62
+
63
+ if (date) {
64
+ // Determine if date is blocked out
65
+ if (dateCtx.configuration.blockedDates) {
66
+ blocked = !!dateCtx.configuration.blockedDates.find(d => isEqual(d, date));
67
+ } // Determine if date is disabled
68
+
69
+
70
+ if (dateCtx.configuration.minDate || dateCtx.configuration.maxDate || dateCtx.configuration.disableWeekends) {
71
+ 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);
72
+ }
73
+ }
74
+
75
+ return { ...dateCtx,
76
+ blocked,
77
+ disabled,
78
+ focused,
79
+ selected,
80
+ today
81
+ };
82
+ };
83
+
84
+ export default useDatePicker;
85
+ export function isSingleSelection(selection) {
86
+ return selection instanceof Date;
87
+ }
88
+ export function isMultiSelection(selection) {
89
+ return Array.isArray(selection);
90
+ }
91
+ export function isRangeSelection(selection) {
92
+ return !!selection.from;
93
+ }
94
+ export function isStringRangeSelection(selection) {
95
+ return !!selection.from;
96
+ }
97
+
98
+ function parseSelection(selection, variant) {
99
+ if (!selection) return;
100
+
101
+ if (variant === 'multi') {
102
+ if (isMultiSelection(selection)) {
103
+ const parsedSelection = [];
104
+
105
+ for (const d of selection) {
106
+ parsedSelection.push(normalizeDate(d));
107
+ }
108
+
109
+ return parsedSelection.sort((a, b) => a.getTime() - b.getTime());
110
+ } else if (selection instanceof Date) {
111
+ return [normalizeDate(selection)];
112
+ } else if (isRangeSelection(selection)) {
113
+ const parsedSelection = [];
114
+ parsedSelection.push(normalizeDate(selection.from));
115
+
116
+ if (selection.to) {
117
+ parsedSelection.push(normalizeDate(selection.to));
118
+ }
119
+
120
+ return parsedSelection.sort((a, b) => a.getTime() - b.getTime());
121
+ }
122
+ } else if (variant === 'range') {
123
+ if (isRangeSelection(selection)) {
124
+ return {
125
+ from: normalizeDate(selection.from),
126
+ to: selection.to ? normalizeDate(selection.to) : null
127
+ };
128
+ } else if (isMultiSelection(selection)) {
129
+ return {
130
+ from: normalizeDate(selection[0]),
131
+ to: selection[1] ? normalizeDate(selection[1]) : null
132
+ };
133
+ } else if (selection instanceof Date) {
134
+ return {
135
+ from: normalizeDate(selection),
136
+ to: null
137
+ };
138
+ }
139
+ } else {
140
+ if (selection instanceof Date) {
141
+ return normalizeDate(selection);
142
+ } else if (isMultiSelection(selection)) {
143
+ return normalizeDate(selection[0]);
144
+ } else if (isRangeSelection(selection)) {
145
+ return normalizeDate(selection.from);
146
+ } else {
147
+ return;
148
+ }
149
+ }
150
+ }
151
+
152
+ const getInitialFocusDate = selection => {
153
+ if (!selection) return normalizeDate(new Date());
154
+
155
+ if (selection instanceof Date) {
156
+ return normalizeDate(selection);
157
+ } else if (Array.isArray(selection)) {
158
+ return normalizeDate(selection[0]);
159
+ } else if (isRangeSelection(selection)) {
160
+ return normalizeDate(selection.from);
161
+ } else {
162
+ return normalizeDate(new Date());
163
+ }
164
+ };
165
+
166
+ export const normalizeDate = date => new Date(new Date(date).toDateString());
167
+ const defaultConfiguration = {
168
+ anchorVariant: 'button',
169
+ confirmation: false,
170
+ confirmUnsavedClose: false,
171
+ compressedHeader: false,
172
+ disableWeekends: false,
173
+ iconPlacement: 'start',
174
+ placeholder: 'Choose Date...',
175
+ showInputPrompt: false,
176
+ variant: 'single',
177
+ view: '2-month',
178
+ weekStartsOn: 'Sunday'
179
+ };
180
+ export const DatePickerProvider = ({
181
+ configuration: externalConfig = {},
182
+ children,
183
+ closePicker,
184
+ isOpen = false,
185
+ value
186
+ }) => {
187
+ const [configuration, setConfiguration] = useState(deepmerge(defaultConfiguration, externalConfig));
188
+ const initialSelection = parseSelection(value, configuration.variant);
189
+ const [previousSelection, setPreviousSelection] = useState(parseSelection(value, configuration.variant));
190
+ const [isDirty, setIsDirty] = useState(false);
191
+ const [selection, setSelection] = useState(initialSelection);
192
+ const [hoverRange, setHoverRange] = useState(null);
193
+ const [currentViewingDate, setCurrentViewingDate] = useState(new Date());
194
+ const [multiMonthSupport, setMultiMonthSupport] = useState(true);
195
+ const confirm = useConfirm();
196
+ const [dialogOpen, setDialogOpen] = useState(false);
197
+ const [focusDate, setFocusDate] = useState(getInitialFocusDate(initialSelection));
198
+ useEffect(() => {
199
+ setConfiguration(deepmerge(defaultConfiguration, externalConfig));
200
+ setSelection(parseSelection(selection, configuration.variant)); // Don't want this to run every time selection gets updated
201
+ // eslint-disable-next-line react-hooks/exhaustive-deps
202
+ }, [configuration.variant, externalConfig]);
203
+ const goToMonth = useCallback(date => {
204
+ let newDate = date;
205
+ const {
206
+ minDate,
207
+ maxDate
208
+ } = configuration;
209
+
210
+ if (minDate && isBefore(date, minDate)) {
211
+ newDate = minDate;
212
+ } else if (maxDate && isAfter(date, maxDate)) {
213
+ newDate = maxDate;
214
+ }
215
+
216
+ setFocusDate(normalizeDate(newDate));
217
+ setCurrentViewingDate(normalizeDate(newDate));
218
+ }, [configuration]);
219
+ const nextMonth = useCallback(() => {
220
+ const date = addMonths(currentViewingDate, 1);
221
+ setFocusDate(normalizeDate(date));
222
+ setCurrentViewingDate(date);
223
+ }, [currentViewingDate]);
224
+ const previousMonth = useCallback(() => {
225
+ const date = subMonths(currentViewingDate, 1);
226
+ setFocusDate(normalizeDate(date));
227
+ setCurrentViewingDate(date);
228
+ }, [currentViewingDate]);
229
+ const formattedDate = useMemo(() => {
230
+ const {
231
+ anchorVariant,
232
+ dateFormat,
233
+ placeholder,
234
+ variant
235
+ } = configuration;
236
+ return formatDate({
237
+ selection,
238
+ anchorVariant,
239
+ dateFormat,
240
+ placeholder,
241
+ rawFormat: false,
242
+ variant
243
+ });
244
+ }, [configuration, selection]);
245
+ const inputDate = useMemo(() => {
246
+ const {
247
+ dateFormat,
248
+ placeholder,
249
+ variant
250
+ } = configuration;
251
+ return formatDate({
252
+ selection,
253
+ dateFormat,
254
+ placeholder,
255
+ rawFormat: true,
256
+ variant
257
+ });
258
+ }, [configuration, selection]);
259
+ const saveValue = useCallback(updatedSelection => {
260
+ setPreviousSelection(updatedSelection !== null && updatedSelection !== void 0 ? updatedSelection : selection);
261
+ setIsDirty(false);
262
+ closePicker === null || closePicker === void 0 ? void 0 : closePicker();
263
+ }, [closePicker, selection]);
264
+ const revertValue = useCallback(() => {
265
+ setSelection(previousSelection);
266
+ setIsDirty(false);
267
+ }, [previousSelection]);
268
+ const handleClose = useCallback(async () => {
269
+ if (configuration.confirmUnsavedClose) {
270
+ if (isDirty) {
271
+ const result = await confirm({
272
+ title: 'Save Changes?',
273
+ content: 'You have unsaved changes, would you like to save them?',
274
+ confirmButtonContent: /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(CheckIcon, null), /*#__PURE__*/React.createElement(Text, {
275
+ sx: {
276
+ ml: 1
277
+ }
278
+ }, "Save")),
279
+ cancelButtonContent: /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(TrashIcon, null), /*#__PURE__*/React.createElement(Text, {
280
+ sx: {
281
+ ml: 1
282
+ }
283
+ }, "Discard"))
284
+ });
285
+
286
+ if (result) {
287
+ saveValue();
288
+ } else {
289
+ revertValue();
290
+ }
291
+ }
292
+ } else if (isDirty) revertValue();
293
+ }, [configuration.confirmUnsavedClose, confirm, isDirty, revertValue, saveValue]);
294
+ const inputHandler = useCallback(updatedSelection => {
295
+ if (!updatedSelection) return;
296
+ const {
297
+ maxDate,
298
+ minDate,
299
+ variant,
300
+ maxSelections,
301
+ maxRangeSize
302
+ } = configuration;
303
+
304
+ switch (variant) {
305
+ case 'single':
306
+ {
307
+ if (updatedSelection instanceof Date) {
308
+ if (maxDate && isAfter(updatedSelection, maxDate)) {
309
+ setSelection(maxDate);
310
+ } else if (minDate && isBefore(minDate, updatedSelection)) {
311
+ setSelection(minDate);
312
+ } else {
313
+ setSelection(updatedSelection);
314
+ }
315
+ }
316
+
317
+ break;
318
+ }
319
+
320
+ case 'multi':
321
+ {
322
+ if (Array.isArray(updatedSelection)) {
323
+ let validSelections = updatedSelection.filter(d => (maxDate ? isBefore(d, maxDate) : true) && (minDate ? isAfter(d, minDate) : true));
324
+
325
+ if (maxSelections) {
326
+ validSelections = validSelections.slice(0, maxSelections);
327
+ }
328
+
329
+ setSelection(validSelections);
330
+ }
331
+
332
+ break;
333
+ }
334
+
335
+ case 'range':
336
+ {
337
+ if (isRangeSelection(updatedSelection)) {
338
+ const validRange = updatedSelection;
339
+
340
+ if (minDate) {
341
+ validRange.from = isAfter(updatedSelection.from, minDate) ? updatedSelection.from : minDate;
342
+
343
+ if (updatedSelection.to) {
344
+ validRange.to = isAfter(updatedSelection.to, minDate) ? updatedSelection.to : minDate;
345
+ }
346
+ }
347
+
348
+ if (maxDate) {
349
+ validRange.from = isBefore(updatedSelection.from, maxDate) ? updatedSelection.from : maxDate;
350
+
351
+ if (updatedSelection.to) {
352
+ validRange.to = isBefore(updatedSelection.to, maxDate) ? updatedSelection.to : maxDate;
353
+ }
354
+ }
355
+
356
+ if (maxRangeSize && validRange.to && Math.abs(differenceInDays(validRange.from, validRange.to)) >= maxRangeSize) {
357
+ validRange.to = addDays(validRange.from, maxRangeSize - 1);
358
+ }
359
+
360
+ setSelection(updatedSelection);
361
+ }
362
+
363
+ break;
364
+ }
365
+ }
366
+ }, [configuration]);
367
+ useEffect(() => {
368
+ if (currentViewingDate.getMonth() !== focusDate.getMonth() || currentViewingDate.getFullYear() !== focusDate.getFullYear()) {
369
+ setCurrentViewingDate(focusDate);
370
+ }
371
+ }, [currentViewingDate, focusDate]);
372
+ const selectionHandler = useCallback(date => {
373
+ setIsDirty(true);
374
+
375
+ if (configuration.variant === 'multi') {
376
+ const selections = [...selection];
377
+ const existingIndex = selections.findIndex(s => isEqual(s, date));
378
+
379
+ if (existingIndex > -1) {
380
+ selections.splice(existingIndex, 1);
381
+ setSelection(selections.sort((a, b) => a.getTime() - b.getTime()));
382
+ } else {
383
+ if (configuration.maxSelections && selections.length + 1 > configuration.maxSelections) return;
384
+ setSelection([...selections, date].sort((a, b) => a.getTime() - b.getTime()));
385
+ }
386
+ } else if (configuration.variant === 'range') {
387
+ if (selection && isRangeSelection(selection) && !selection.to) {
388
+ let toDate = date;
389
+
390
+ if (configuration.maxRangeSize && Math.abs(differenceInDays(selection.from, date)) >= configuration.maxRangeSize) {
391
+ toDate = isBefore(date, selection.from) ? subDays(selection.from, configuration.maxRangeSize - 1) : addDays(selection.from, configuration.maxRangeSize - 1);
392
+ }
393
+
394
+ const updatedSelection = isBefore(toDate, selection.from) ? {
395
+ from: toDate,
396
+ to: selection.from
397
+ } : {
398
+ from: selection.from,
399
+ to: toDate
400
+ };
401
+ setSelection(updatedSelection);
402
+ setHoverRange(null);
403
+
404
+ if (!configuration.confirmation) {
405
+ saveValue(updatedSelection);
406
+ }
407
+ } else {
408
+ setHoverRange({
409
+ from: date,
410
+ to: date
411
+ });
412
+ setSelection({
413
+ from: date,
414
+ to: null
415
+ });
416
+ }
417
+ } else {
418
+ setSelection(date);
419
+
420
+ if (!configuration.confirmation) {
421
+ saveValue(date);
422
+ }
423
+ }
424
+ }, [configuration.confirmation, configuration.maxRangeSize, configuration.maxSelections, configuration.variant, saveValue, selection]);
425
+ const focusHandler = useCallback(date => {
426
+ if (!selection) return;
427
+ const {
428
+ minDate,
429
+ maxDate,
430
+ maxRangeSize,
431
+ disableWeekends,
432
+ variant
433
+ } = configuration;
434
+
435
+ if (variant === 'range' && isRangeSelection(selection) && hoverRange) {
436
+ let hoverDate = date;
437
+ if (minDate) hoverDate = isBefore(date, minDate) ? minDate : hoverDate;
438
+ if (maxDate) hoverDate = isAfter(date, maxDate) ? maxDate : hoverDate;
439
+ const daysInRange = disableWeekends ? Math.abs(differenceInBusinessDays(selection.from, hoverDate)) : Math.abs(differenceInDays(selection.from, hoverDate));
440
+
441
+ if (maxRangeSize && daysInRange >= maxRangeSize) {
442
+ if (disableWeekends) {
443
+ hoverDate = isBefore(hoverDate, selection.from) ? subBusinessDays(selection.from, configuration.maxRangeSize - 1) : addBusinessDays(selection.from, configuration.maxRangeSize - 1);
444
+ } else {
445
+ hoverDate = isBefore(hoverDate, selection.from) ? subDays(selection.from, configuration.maxRangeSize - 1) : addDays(selection.from, configuration.maxRangeSize - 1);
446
+ }
447
+ }
448
+
449
+ if (disableWeekends && isWeekend(hoverDate)) {
450
+ hoverDate = previousFriday(hoverDate);
451
+ }
452
+
453
+ setHoverRange(isBefore(hoverDate, selection.from) ? {
454
+ from: hoverDate,
455
+ to: selection.from
456
+ } : {
457
+ from: selection.from,
458
+ to: hoverDate
459
+ });
460
+ }
461
+ }, [configuration, hoverRange, selection]);
462
+ const handleKeyDown = useCallback(async e => {
463
+ const key = e.key;
464
+ const {
465
+ disableWeekends,
466
+ minDate,
467
+ maxDate
468
+ } = configuration;
469
+
470
+ switch (key) {
471
+ case 'ArrowRight':
472
+ {
473
+ // Increase selection by 1 day
474
+ let newDate = normalizeDate(addDays(focusDate, 1));
475
+ if (maxDate && isAfter(newDate, maxDate)) newDate = maxDate;
476
+
477
+ if (disableWeekends && isWeekend(newDate)) {
478
+ const monday = nextMonday(newDate);
479
+ newDate = maxDate && isAfter(monday, maxDate) ? maxDate : monday;
480
+ }
481
+
482
+ setFocusDate(newDate);
483
+ focusHandler(newDate);
484
+ break;
485
+ }
486
+
487
+ case 'ArrowLeft':
488
+ {
489
+ // Decrease selection by 1 day
490
+ let newDate = normalizeDate(subDays(focusDate, 1));
491
+ if (minDate && isBefore(newDate, minDate)) newDate = minDate;
492
+
493
+ if (disableWeekends && isWeekend(newDate)) {
494
+ const friday = previousFriday(newDate);
495
+ newDate = minDate && isBefore(friday, minDate) ? minDate : friday;
496
+ }
497
+
498
+ setFocusDate(newDate);
499
+ focusHandler(newDate);
500
+ break;
501
+ }
502
+
503
+ case 'ArrowUp':
504
+ {
505
+ // Decrease selection by 1 week
506
+ let newDate = normalizeDate(subWeeks(focusDate, 1));
507
+ if (minDate && isBefore(newDate, minDate)) newDate = minDate;
508
+ setFocusDate(newDate);
509
+ focusHandler(newDate);
510
+ break;
511
+ }
512
+
513
+ case 'ArrowDown':
514
+ {
515
+ // Increase selection by 1 week
516
+ let newDate = normalizeDate(addWeeks(focusDate, 1));
517
+ if (maxDate && isAfter(newDate, maxDate)) newDate = maxDate;
518
+ setFocusDate(newDate);
519
+ focusHandler(newDate);
520
+ break;
521
+ }
522
+
523
+ case 'Home':
524
+ {
525
+ let newDate = focusDate;
526
+
527
+ if (disableWeekends) {
528
+ newDate = normalizeDate(isMonday(focusDate) ? focusDate : previousMonday(focusDate));
529
+ } else {
530
+ newDate = normalizeDate(isSunday(focusDate) ? focusDate : previousSunday(focusDate));
531
+ }
532
+
533
+ if (minDate && isBefore(newDate, minDate)) newDate = minDate;
534
+ setFocusDate(newDate);
535
+ focusHandler(newDate);
536
+ break;
537
+ }
538
+
539
+ case 'End':
540
+ {
541
+ let newDate = focusDate;
542
+
543
+ if (disableWeekends) {
544
+ newDate = normalizeDate(isFriday(focusDate) ? focusDate : nextFriday(focusDate));
545
+ } else {
546
+ newDate = normalizeDate(isSaturday(focusDate) ? focusDate : nextSaturday(focusDate));
547
+ }
548
+
549
+ if (maxDate && isAfter(newDate, maxDate)) newDate = maxDate;
550
+ setFocusDate(newDate);
551
+ focusHandler(newDate);
552
+ break;
553
+ }
554
+
555
+ case 'PageUp':
556
+ {
557
+ let newDate = normalizeDate(e.shiftKey ? subYears(focusDate, 1) : subMonths(focusDate, 1));
558
+ if (minDate && isBefore(newDate, minDate)) newDate = minDate;
559
+ setFocusDate(newDate);
560
+ focusHandler(newDate);
561
+ break;
562
+ }
563
+
564
+ case 'PageDown':
565
+ {
566
+ let newDate = normalizeDate(e.shiftKey ? addYears(focusDate, 1) : addMonths(focusDate, 1));
567
+ if (maxDate && isAfter(newDate, maxDate)) newDate = maxDate;
568
+ setFocusDate(newDate);
569
+ focusHandler(newDate);
570
+ break;
571
+ }
572
+
573
+ case 'Enter':
574
+ case ' ':
575
+ {
576
+ // Start Selection
577
+ selectionHandler(focusDate);
578
+ break;
579
+ }
580
+
581
+ case 'Esc':
582
+ {
583
+ // Cancel Selection if started, reset if not? or close
584
+ if (hoverRange) {
585
+ setHoverRange(null);
586
+ }
587
+
588
+ break;
589
+ }
590
+
591
+ default:
592
+ {
593
+ break;
594
+ }
595
+ }
596
+ }, [configuration, focusDate, focusHandler, hoverRange, selectionHandler]);
597
+ useEffect(() => {
598
+ if (isOpen) {
599
+ window.addEventListener('keydown', handleKeyDown);
600
+ } else {
601
+ window.removeEventListener('keydown', handleKeyDown);
602
+ }
603
+
604
+ return () => {
605
+ window.removeEventListener('keydown', handleKeyDown);
606
+ };
607
+ }, [handleKeyDown, isOpen]);
608
+
609
+ const onResize = windowEntry => {
610
+ // Only care about the first element, we expect one element ot be watched
611
+ const {
612
+ width
613
+ } = windowEntry.contentRect; // 610 is the panel width with 2 months
614
+
615
+ setMultiMonthSupport(width > 610);
616
+ };
617
+
618
+ useResizeObserver(onResize);
619
+ const datePickerCtx = useMemo(() => {
620
+ return {
621
+ configuration,
622
+ currentViewingDate,
623
+ disabled: false,
624
+ focusDate,
625
+ formattedDate,
626
+ inputDate,
627
+ goToMonth,
628
+ hoverRange,
629
+ dialogOpen,
630
+ nextMonth,
631
+ onClose: handleClose,
632
+ onDateInput: inputHandler,
633
+ onDayFocus: focusHandler,
634
+ onSelection: selectionHandler,
635
+ previousMonth,
636
+ revertValue,
637
+ saveValue,
638
+ selectionActive: false,
639
+ setFocusDate,
640
+ setHoverRange,
641
+ selection,
642
+ setDialogOpen,
643
+ viewMode: configuration.view === '2-month' && multiMonthSupport ? '2-month' : '1-month'
644
+ };
645
+ }, [configuration, currentViewingDate, dialogOpen, focusDate, focusHandler, formattedDate, goToMonth, handleClose, hoverRange, inputDate, inputHandler, multiMonthSupport, nextMonth, previousMonth, revertValue, saveValue, selection, selectionHandler]);
646
+ return /*#__PURE__*/React.createElement(DatePickerContext.Provider, {
647
+ value: datePickerCtx
648
+ }, children);
649
+ };
650
+ DatePickerProvider.displayName = "DatePickerProvider";
@@ -15,7 +15,6 @@ declare namespace DialogHeader {
15
15
  };
16
16
  var propTypes: {
17
17
  lineHeight?: React.Validator<import("styled-system").ResponsiveValue<string | number | symbol, Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>> | undefined> | undefined;
18
- border?: React.Validator<import("styled-system").ResponsiveValue<import("csstype").Property.Border<import("styled-system").TLengthStyledSystem>, Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>> | undefined> | undefined;
19
18
  alignContent?: React.Validator<import("styled-system").ResponsiveValue<import("csstype").Property.AlignContent, Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>> | undefined> | undefined;
20
19
  alignItems?: React.Validator<import("styled-system").ResponsiveValue<import("csstype").Property.AlignItems, Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>> | undefined> | undefined;
21
20
  alignSelf?: React.Validator<import("styled-system").ResponsiveValue<import("csstype").Property.AlignSelf, Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>> | undefined> | undefined;
@@ -91,6 +90,7 @@ declare namespace DialogHeader {
91
90
  zIndex?: React.Validator<import("styled-system").ResponsiveValue<import("csstype").Property.ZIndex, Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>> | undefined> | undefined;
92
91
  background?: React.Validator<import("styled-system").ResponsiveValue<import("csstype").Property.Background<import("styled-system").TLengthStyledSystem>, Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>> | undefined> | undefined;
93
92
  backgroundPosition?: React.Validator<import("styled-system").ResponsiveValue<import("csstype").Property.BackgroundPosition<import("styled-system").TLengthStyledSystem>, Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>> | undefined> | undefined;
93
+ border?: React.Validator<import("styled-system").ResponsiveValue<import("csstype").Property.Border<import("styled-system").TLengthStyledSystem>, Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>> | undefined> | undefined;
94
94
  borderBottom?: React.Validator<import("styled-system").ResponsiveValue<import("csstype").Property.BorderBottom<import("styled-system").TLengthStyledSystem>, Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>> | undefined> | undefined;
95
95
  borderColor?: React.Validator<import("styled-system").ResponsiveValue<string | number | symbol, Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>> | undefined> | undefined;
96
96
  borderLeft?: React.Validator<import("styled-system").ResponsiveValue<import("csstype").Property.BorderLeft<import("styled-system").TLengthStyledSystem>, Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>> | undefined> | undefined;
@@ -153,7 +153,7 @@ declare namespace DialogHeader {
153
153
  results?: React.Validator<number | null | undefined> | undefined;
154
154
  security?: React.Validator<string | null | undefined> | undefined;
155
155
  unselectable?: React.Validator<"on" | "off" | null | undefined> | undefined;
156
- inputMode?: React.Validator<"search" | "none" | "text" | "tel" | "url" | "email" | "numeric" | "decimal" | null | undefined> | undefined;
156
+ inputMode?: React.Validator<"none" | "text" | "search" | "tel" | "url" | "email" | "numeric" | "decimal" | null | undefined> | undefined;
157
157
  is?: React.Validator<string | null | undefined> | undefined;
158
158
  'aria-activedescendant'?: React.Validator<string | null | undefined> | undefined;
159
159
  'aria-atomic'?: React.Validator<boolean | "true" | "false" | null | undefined> | undefined;
@@ -168,7 +168,7 @@ declare namespace DialogHeader {
168
168
  'aria-describedby'?: React.Validator<string | null | undefined> | undefined;
169
169
  'aria-details'?: React.Validator<string | null | undefined> | undefined;
170
170
  'aria-disabled'?: React.Validator<boolean | "true" | "false" | null | undefined> | undefined;
171
- 'aria-dropeffect'?: React.Validator<"link" | "none" | "copy" | "execute" | "move" | "popup" | null | undefined> | undefined;
171
+ 'aria-dropeffect'?: React.Validator<"none" | "link" | "copy" | "execute" | "move" | "popup" | null | undefined> | undefined;
172
172
  'aria-errormessage'?: React.Validator<string | null | undefined> | undefined;
173
173
  'aria-expanded'?: React.Validator<boolean | "true" | "false" | null | undefined> | undefined;
174
174
  'aria-flowto'?: React.Validator<string | null | undefined> | undefined;
@@ -387,7 +387,7 @@ declare namespace DialogHeader {
387
387
  size?: React.Validator<import("styled-system").ResponsiveValue<import("csstype").Property.Height<import("styled-system").TLengthStyledSystem>, Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>> | undefined> | undefined;
388
388
  borderX?: React.Validator<import("styled-system").ResponsiveValue<import("csstype").Property.Border<import("styled-system").TLengthStyledSystem>, Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>> | undefined> | undefined;
389
389
  borderY?: React.Validator<import("styled-system").ResponsiveValue<import("csstype").Property.Border<import("styled-system").TLengthStyledSystem>, Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>> | undefined> | undefined;
390
- sx?: React.Validator<import("./sx").BetterSystemStyleObject | undefined> | undefined;
390
+ sx?: React.Validator<import("@styled-system/css").SystemStyleObject | undefined> | undefined;
391
391
  theme?: React.Validator<any> | undefined;
392
392
  };
393
393
  var displayName: string;