@primer/components 0.0.0-2021103231920 → 0.0.0-20211040245

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 (70) hide show
  1. package/CHANGELOG.md +1 -5
  2. package/dist/browser.esm.js +5 -3
  3. package/dist/browser.esm.js.map +1 -1
  4. package/dist/browser.umd.js +30 -28
  5. package/dist/browser.umd.js.map +1 -1
  6. package/lib/AnchoredOverlay/AnchoredOverlay.d.ts +4 -2
  7. package/lib/Autocomplete/Autocomplete.d.ts +4 -2
  8. package/lib/Autocomplete/AutocompleteInput.d.ts +4 -2
  9. package/lib/DatePicker/DatePicker.d.ts +52 -0
  10. package/lib/DatePicker/DatePicker.js +109 -0
  11. package/lib/DatePicker/DatePickerAnchor.d.ts +5 -0
  12. package/lib/DatePicker/DatePickerAnchor.js +202 -0
  13. package/lib/DatePicker/DatePickerOverlay.d.ts +3 -0
  14. package/lib/DatePicker/DatePickerOverlay.js +55 -0
  15. package/lib/DatePicker/DatePickerPanel.d.ts +2 -0
  16. package/lib/DatePicker/DatePickerPanel.js +363 -0
  17. package/lib/DatePicker/Day.d.ts +15 -0
  18. package/lib/DatePicker/Day.js +206 -0
  19. package/lib/DatePicker/Month.d.ts +8 -0
  20. package/lib/DatePicker/Month.js +122 -0
  21. package/lib/DatePicker/dateParser.d.ts +12 -0
  22. package/lib/DatePicker/dateParser.js +192 -0
  23. package/lib/DatePicker/index.d.ts +2 -0
  24. package/lib/DatePicker/index.js +13 -0
  25. package/lib/DatePicker/useDatePicker.d.ts +107 -0
  26. package/lib/DatePicker/useDatePicker.js +558 -0
  27. package/lib/Link.d.ts +2 -1
  28. package/lib/Link.js +1 -1
  29. package/lib/SelectMenu/SelectMenu.d.ts +4 -2
  30. package/lib/SideNav.d.ts +2 -2
  31. package/lib/TextInputWithTokens.d.ts +4 -2
  32. package/lib/hooks/useDebounce.d.ts +2 -0
  33. package/lib/hooks/useDebounce.js +24 -0
  34. package/lib/hooks/useResizeObserver.d.ts +1 -1
  35. package/lib/hooks/useResizeObserver.js +1 -1
  36. package/lib/theme-preval.js +2 -2
  37. package/lib/utils/testing.d.ts +1 -1
  38. package/lib-esm/AnchoredOverlay/AnchoredOverlay.d.ts +4 -2
  39. package/lib-esm/Autocomplete/Autocomplete.d.ts +4 -2
  40. package/lib-esm/Autocomplete/AutocompleteInput.d.ts +4 -2
  41. package/lib-esm/DatePicker/DatePicker.d.ts +52 -0
  42. package/lib-esm/DatePicker/DatePicker.js +92 -0
  43. package/lib-esm/DatePicker/DatePickerAnchor.d.ts +5 -0
  44. package/lib-esm/DatePicker/DatePickerAnchor.js +174 -0
  45. package/lib-esm/DatePicker/DatePickerOverlay.d.ts +3 -0
  46. package/lib-esm/DatePicker/DatePickerOverlay.js +40 -0
  47. package/lib-esm/DatePicker/DatePickerPanel.d.ts +2 -0
  48. package/lib-esm/DatePicker/DatePickerPanel.js +332 -0
  49. package/lib-esm/DatePicker/Day.d.ts +15 -0
  50. package/lib-esm/DatePicker/Day.js +182 -0
  51. package/lib-esm/DatePicker/Month.d.ts +8 -0
  52. package/lib-esm/DatePicker/Month.js +98 -0
  53. package/lib-esm/DatePicker/dateParser.d.ts +12 -0
  54. package/lib-esm/DatePicker/dateParser.js +178 -0
  55. package/lib-esm/DatePicker/index.d.ts +2 -0
  56. package/lib-esm/DatePicker/index.js +1 -0
  57. package/lib-esm/DatePicker/useDatePicker.d.ts +107 -0
  58. package/lib-esm/DatePicker/useDatePicker.js +523 -0
  59. package/lib-esm/Link.d.ts +2 -1
  60. package/lib-esm/Link.js +2 -2
  61. package/lib-esm/SelectMenu/SelectMenu.d.ts +4 -2
  62. package/lib-esm/SideNav.d.ts +2 -2
  63. package/lib-esm/TextInputWithTokens.d.ts +4 -2
  64. package/lib-esm/hooks/useDebounce.d.ts +2 -0
  65. package/lib-esm/hooks/useDebounce.js +16 -0
  66. package/lib-esm/hooks/useResizeObserver.d.ts +1 -1
  67. package/lib-esm/hooks/useResizeObserver.js +1 -1
  68. package/lib-esm/theme-preval.js +2 -2
  69. package/lib-esm/utils/testing.d.ts +1 -1
  70. package/package.json +9 -8
@@ -0,0 +1,332 @@
1
+ import { isAfter, isBefore, addMonths, subMonths, isWeekend, addDays, subDays, addWeeks, subWeeks, isSaturday, isSunday, nextSaturday, previousFriday, previousSunday, subYears, addYears, nextMonday, isMonday, previousMonday, isFriday, nextFriday, format } from 'date-fns';
2
+ import React, { useCallback, useMemo, useRef } from 'react';
3
+ import Box from '../Box';
4
+ import { Month } from './Month';
5
+ import styled from 'styled-components';
6
+ import { COMMON, get, TYPOGRAPHY } from '../constants';
7
+ import useDatePicker, { normalizeDate } from './useDatePicker';
8
+ import { ChevronLeftIcon, ChevronRightIcon } from '@primer/octicons-react';
9
+ import StyledOcticon from '../StyledOcticon';
10
+ import Button, { ButtonPrimary } from '../Button';
11
+ import sx from '../sx';
12
+ import { useFocusZone } from '../hooks/useFocusZone';
13
+ import { FocusKeys } from '../behaviors/focusZone';
14
+ const DatePickerPanelContainer = styled(Box).withConfig({
15
+ displayName: "DatePickerPanel__DatePickerPanelContainer",
16
+ componentId: "sc-19upxpo-0"
17
+ })(["align-items:stretch;display:flex;flex-direction:column;position:relative;"]);
18
+ const DatePickerTopNav = styled(Box).withConfig({
19
+ displayName: "DatePickerPanel__DatePickerTopNav",
20
+ componentId: "sc-19upxpo-1"
21
+ })(["display:flex;justify-content:space-between;position:absolute;top:0;left:0;right:0;padding:", ";z-index:10;"], get('space.3'));
22
+ const DatePickerPanelMonths = styled(Box).withConfig({
23
+ displayName: "DatePickerPanel__DatePickerPanelMonths",
24
+ componentId: "sc-19upxpo-2"
25
+ })(["align-items:flex-start;display:flex;flex-direction:row;gap:", ";margin-top:", ";padding:", ";position:relative;"], get('space.6'), get('space.1'), get('space.3'));
26
+ const DatePickerPanelFooter = styled(Box).withConfig({
27
+ displayName: "DatePickerPanel__DatePickerPanelFooter",
28
+ componentId: "sc-19upxpo-3"
29
+ })(["align-items:flex-start;border-top:1px solid;border-top-color:", ";display:flex;gap:", ";padding-top:12px;padding-bottom:12px;padding-left:", ";padding-right:", ";flex-direction:row;justify-content:space-between;position:relative;"], get('colors.border.default'), get('space.6'), get('space.3'), get('space.3'));
30
+ const ArrowButton = styled(Button).withConfig({
31
+ displayName: "DatePickerPanel__ArrowButton",
32
+ componentId: "sc-19upxpo-4"
33
+ })(["width:40px;height:28px;"]);
34
+ const Select = styled.select.withConfig({
35
+ displayName: "DatePickerPanel__Select",
36
+ componentId: "sc-19upxpo-5"
37
+ })(["background:", ";border:0;color:", ";font-weight:600;", ";", ";", ";"], get('colors.canvas.default'), get('colors.fg.default'), TYPOGRAPHY, COMMON, sx);
38
+ const Option = styled.option.withConfig({
39
+ displayName: "DatePickerPanel__Option",
40
+ componentId: "sc-19upxpo-6"
41
+ })(["background:", ";border:0;color:", ";font-weight:400;padding:", " ", ";", ";", ";", ";"], get('colors.canvas.default'), get('colors.fg.default'), get('space.2'), get('space.2'), TYPOGRAPHY, COMMON, sx);
42
+ export const DatePickerPanel = () => {
43
+ const {
44
+ configuration,
45
+ saveValue,
46
+ revertValue,
47
+ currentViewingDate,
48
+ goToMonth,
49
+ nextMonth,
50
+ previousMonth,
51
+ onDayFocus,
52
+ setFocusDate,
53
+ viewMode
54
+ } = useDatePicker();
55
+ const panelRef = useRef(null);
56
+ const headerRef = useRef(null);
57
+ const datePanelRef = useRef(null);
58
+ const footerRef = useRef(null);
59
+ useFocusZone({
60
+ containerRef: headerRef,
61
+ bindKeys: FocusKeys.Tab,
62
+ focusInStrategy: 'closest'
63
+ });
64
+ const getNextFocusable = useCallback((direction, from, event) => {
65
+ var _datePanelRef$current, _datePanelRef$current2;
66
+
67
+ const key = event.key;
68
+ const {
69
+ disableWeekends,
70
+ minDate,
71
+ maxDate
72
+ } = configuration;
73
+ const fromDate = from === null || from === void 0 ? void 0 : from.getAttribute('data-date');
74
+ const focusDate = fromDate ? new Date(fromDate) : new Date();
75
+ let newDate = normalizeDate(focusDate);
76
+
77
+ switch (key) {
78
+ case 'ArrowRight':
79
+ {
80
+ // Increase selection by 1 day
81
+ newDate = normalizeDate(addDays(focusDate, 1));
82
+ if (maxDate && isAfter(newDate, maxDate)) newDate = maxDate;
83
+
84
+ if (disableWeekends && isWeekend(newDate)) {
85
+ const monday = nextMonday(newDate);
86
+ newDate = maxDate && isAfter(monday, maxDate) ? maxDate : monday;
87
+ }
88
+
89
+ setFocusDate(newDate);
90
+ onDayFocus(newDate);
91
+ break;
92
+ }
93
+
94
+ case 'ArrowLeft':
95
+ {
96
+ // Decrease selection by 1 day
97
+ newDate = normalizeDate(subDays(focusDate, 1));
98
+ if (minDate && isBefore(newDate, minDate)) newDate = minDate;
99
+
100
+ if (disableWeekends && isWeekend(newDate)) {
101
+ const friday = previousFriday(newDate);
102
+ newDate = minDate && isBefore(friday, minDate) ? minDate : friday;
103
+ }
104
+
105
+ setFocusDate(newDate);
106
+ onDayFocus(newDate);
107
+ break;
108
+ }
109
+
110
+ case 'ArrowUp':
111
+ {
112
+ // Decrease selection by 1 week
113
+ newDate = normalizeDate(subWeeks(focusDate, 1));
114
+ if (minDate && isBefore(newDate, minDate)) newDate = minDate;
115
+ setFocusDate(newDate);
116
+ onDayFocus(newDate);
117
+ break;
118
+ }
119
+
120
+ case 'ArrowDown':
121
+ {
122
+ // Increase selection by 1 week
123
+ newDate = normalizeDate(addWeeks(focusDate, 1));
124
+ if (maxDate && isAfter(newDate, maxDate)) newDate = maxDate;
125
+ setFocusDate(newDate);
126
+ onDayFocus(newDate);
127
+ break;
128
+ }
129
+
130
+ case 'Home':
131
+ {
132
+ newDate = focusDate;
133
+
134
+ if (disableWeekends) {
135
+ newDate = normalizeDate(isMonday(focusDate) ? focusDate : previousMonday(focusDate));
136
+ } else {
137
+ newDate = normalizeDate(isSunday(focusDate) ? focusDate : previousSunday(focusDate));
138
+ }
139
+
140
+ if (minDate && isBefore(newDate, minDate)) newDate = minDate;
141
+ setFocusDate(newDate);
142
+ onDayFocus(newDate);
143
+ break;
144
+ }
145
+
146
+ case 'End':
147
+ {
148
+ newDate = focusDate;
149
+
150
+ if (disableWeekends) {
151
+ newDate = normalizeDate(isFriday(focusDate) ? focusDate : nextFriday(focusDate));
152
+ } else {
153
+ newDate = normalizeDate(isSaturday(focusDate) ? focusDate : nextSaturday(focusDate));
154
+ }
155
+
156
+ if (maxDate && isAfter(newDate, maxDate)) newDate = maxDate;
157
+ setFocusDate(newDate);
158
+ onDayFocus(newDate);
159
+ break;
160
+ }
161
+
162
+ case 'PageUp':
163
+ {
164
+ newDate = normalizeDate(event.shiftKey ? subYears(focusDate, 1) : subMonths(focusDate, 1));
165
+ if (minDate && isBefore(newDate, minDate)) newDate = minDate;
166
+ setFocusDate(newDate);
167
+ onDayFocus(newDate);
168
+ break;
169
+ }
170
+
171
+ case 'PageDown':
172
+ {
173
+ newDate = normalizeDate(event.shiftKey ? addYears(focusDate, 1) : addMonths(focusDate, 1));
174
+ if (maxDate && isAfter(newDate, maxDate)) newDate = maxDate;
175
+ setFocusDate(newDate);
176
+ onDayFocus(newDate);
177
+ break;
178
+ }
179
+
180
+ default:
181
+ {
182
+ break;
183
+ }
184
+ }
185
+
186
+ return (_datePanelRef$current = (_datePanelRef$current2 = datePanelRef.current) === null || _datePanelRef$current2 === void 0 ? void 0 : _datePanelRef$current2.querySelector(`[data-date="${format(newDate, 'MM/dd/yyyy')}"]`)) !== null && _datePanelRef$current !== void 0 ? _datePanelRef$current : undefined;
187
+ }, [configuration, onDayFocus, setFocusDate]);
188
+ useFocusZone({
189
+ containerRef: datePanelRef,
190
+ bindKeys: FocusKeys.ArrowAll | FocusKeys.HomeAndEnd | FocusKeys.PageUpDown,
191
+ focusInStrategy: 'previous',
192
+ getNextFocusable
193
+ }, [getNextFocusable]);
194
+ useFocusZone({
195
+ containerRef: footerRef,
196
+ bindKeys: FocusKeys.Tab,
197
+ focusInStrategy: 'closest'
198
+ });
199
+ const previousDisabled = useMemo(() => {
200
+ const {
201
+ minDate
202
+ } = configuration;
203
+ if (!minDate) return false;
204
+ const previous = subMonths(currentViewingDate, 1);
205
+
206
+ if (minDate.getFullYear() >= previous.getFullYear() && minDate.getMonth() > previous.getMonth()) {
207
+ return true;
208
+ }
209
+
210
+ return false;
211
+ }, [configuration, currentViewingDate]);
212
+ const nextDisabled = useMemo(() => {
213
+ const {
214
+ maxDate,
215
+ view
216
+ } = configuration;
217
+ if (!maxDate) return false;
218
+ const next = addMonths(currentViewingDate, view === '2-month' ? 2 : 1);
219
+
220
+ if (maxDate.getFullYear() <= next.getFullYear() && maxDate.getMonth() < next.getMonth()) {
221
+ return true;
222
+ }
223
+
224
+ return false;
225
+ }, [configuration, currentViewingDate]);
226
+ const currentMonth = useMemo(() => currentViewingDate.getMonth(), [currentViewingDate]);
227
+ const currentYear = useMemo(() => currentViewingDate.getFullYear(), [currentViewingDate]);
228
+ const headerSelectionHandler = useCallback(e => {
229
+ const selection = parseInt(e.currentTarget.value, 10);
230
+
231
+ if (e.currentTarget.id === 'picker-header-year') {
232
+ goToMonth(new Date(selection, currentMonth));
233
+ } else {
234
+ goToMonth(new Date(currentYear, selection));
235
+ }
236
+ }, [currentMonth, currentYear, goToMonth]);
237
+ const getMonthPicker = useMemo(() => {
238
+ const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
239
+ const monthElements = [];
240
+
241
+ for (let i = 0; i < months.length; i++) {
242
+ monthElements.push( /*#__PURE__*/React.createElement(Option, {
243
+ key: i,
244
+ value: i
245
+ }, months[i]));
246
+ }
247
+
248
+ return /*#__PURE__*/React.createElement(Select, {
249
+ id: "picker-header-month",
250
+ value: currentMonth,
251
+ sx: {
252
+ mr: '6px'
253
+ },
254
+ onChange: headerSelectionHandler
255
+ }, monthElements);
256
+ }, [currentMonth, headerSelectionHandler]);
257
+ const getYearPicker = useMemo(() => {
258
+ const years = [];
259
+ const minYear = currentYear - 200;
260
+ const maxYear = currentYear + 200;
261
+
262
+ for (let i = minYear; i <= maxYear; i++) {
263
+ years.push( /*#__PURE__*/React.createElement(Option, {
264
+ key: i,
265
+ value: i
266
+ }, i));
267
+ }
268
+
269
+ return /*#__PURE__*/React.createElement(Select, {
270
+ id: "picker-header-year",
271
+ value: currentYear,
272
+ onChange: headerSelectionHandler
273
+ }, years);
274
+ }, [currentYear, headerSelectionHandler]);
275
+ return /*#__PURE__*/React.createElement(DatePickerPanelContainer, {
276
+ ref: panelRef
277
+ }, /*#__PURE__*/React.createElement(DatePickerTopNav, {
278
+ ref: headerRef
279
+ }, configuration.compressedHeader && /*#__PURE__*/React.createElement(Box, {
280
+ sx: {
281
+ flex: 1
282
+ }
283
+ }, getMonthPicker, getYearPicker), /*#__PURE__*/React.createElement(ArrowButton, {
284
+ variant: "small",
285
+ sx: {
286
+ mr: 1
287
+ },
288
+ onClick: previousMonth,
289
+ disabled: previousDisabled,
290
+ "aria-label": "Previous Month",
291
+ "aria-live": "polite"
292
+ }, /*#__PURE__*/React.createElement(StyledOcticon, {
293
+ icon: ChevronLeftIcon,
294
+ color: "fg.muted"
295
+ })), /*#__PURE__*/React.createElement(ArrowButton, {
296
+ variant: "small",
297
+ onClick: nextMonth,
298
+ disabled: nextDisabled,
299
+ "aria-label": "Next Month",
300
+ "aria-live": "polite"
301
+ }, /*#__PURE__*/React.createElement(StyledOcticon, {
302
+ icon: ChevronRightIcon,
303
+ color: "fg.muted"
304
+ }))), /*#__PURE__*/React.createElement(DatePickerPanelMonths, {
305
+ ref: datePanelRef
306
+ }, /*#__PURE__*/React.createElement(Month, {
307
+ date: currentViewingDate
308
+ }), viewMode === '2-month' && /*#__PURE__*/React.createElement(Month, {
309
+ date: addMonths(currentViewingDate, 1)
310
+ })), /*#__PURE__*/React.createElement(DatePickerPanelFooter, {
311
+ ref: footerRef
312
+ }, /*#__PURE__*/React.createElement(Box, null, /*#__PURE__*/React.createElement(Button, {
313
+ variant: "small",
314
+ sx: {
315
+ mr: 1
316
+ },
317
+ onClick: () => revertValue(),
318
+ "aria-label": "Reset Selection",
319
+ "aria-live": "polite"
320
+ }, "Reset"), /*#__PURE__*/React.createElement(Button, {
321
+ variant: "small",
322
+ onClick: () => goToMonth(new Date()),
323
+ "aria-label": "Go to Today",
324
+ "aria-live": "polite"
325
+ }, "Today")), configuration.confirmation && /*#__PURE__*/React.createElement(ButtonPrimary, {
326
+ variant: "small",
327
+ onClick: () => saveValue(),
328
+ "aria-label": "Apply Selection",
329
+ "aria-live": "polite"
330
+ }, "Apply")));
331
+ };
332
+ DatePickerPanel.displayName = "DatePickerPanel";
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ import { FontSizeProps } from 'styled-system';
3
+ import { SystemCommonProps, SystemLayoutProps } from '../constants';
4
+ import { SxProp } from '../sx';
5
+ import { DaySelection } from './useDatePicker';
6
+ export declare type DayProps = {
7
+ blocked?: boolean;
8
+ disabled?: boolean;
9
+ focused?: boolean;
10
+ onAction?: (date: Date, event?: React.MouseEvent<HTMLDivElement> | React.KeyboardEvent<HTMLDivElement>) => void;
11
+ selected?: DaySelection;
12
+ date: Date;
13
+ } & FontSizeProps & SystemCommonProps & SxProp & SystemLayoutProps;
14
+ export declare const Day: React.FC<DayProps>;
15
+ export declare const BlankDay: import("styled-components").StyledComponent<"div", any, import("styled-system").SpaceProps<Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>, string | number | symbol> & import("styled-system").ColorProps<Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>, string | number | symbol> & import("styled-system").TypographyProps<Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>> & import("styled-system").LayoutProps<Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>> & import("styled-system").FlexboxProps<Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>> & import("styled-system").GridProps<Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>> & import("styled-system").BackgroundProps<Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>, import("csstype").Property.Background<import("styled-system").TLengthStyledSystem>> & import("styled-system").BorderProps<Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>, import("csstype").Property.Border<import("styled-system").TLengthStyledSystem>> & import("styled-system").PositionProps<Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>> & import("styled-system").ShadowProps<Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>> & SxProp, never>;
@@ -0,0 +1,182 @@
1
+ import React, { useCallback, useEffect, useMemo, useRef } from 'react';
2
+ import styled from 'styled-components';
3
+ import Box from '../Box';
4
+ import Text from '../Text';
5
+ import { get } from '../constants';
6
+ import useDatePicker from './useDatePicker';
7
+ import { format } from 'date-fns';
8
+ const DayBaseComponent = styled(Box).withConfig({
9
+ displayName: "Day__DayBaseComponent",
10
+ componentId: "sc-1japneh-0"
11
+ })(["align-content:center;display:flex;justify-content:center;min-width:38px;min-height:38px;padding:", ";"], get('space.1'));
12
+ const states = {
13
+ blocked: {
14
+ background: get('colors.neutral.subtle'),
15
+ borderRadius: get('radii.2'),
16
+ color: get('colors.fg.subtle')
17
+ },
18
+ disabled: {
19
+ background: get('colors.canvas.primary'),
20
+ borderRadius: get('radii.2'),
21
+ color: get('colors.fg.subtle')
22
+ },
23
+ selected: {
24
+ default: {
25
+ background: get('colors.accent.emphasis'),
26
+ borderRadius: get('radii.2'),
27
+ color: get('colors.fg.onEmphasis'),
28
+ todayColor: get('colors.fg.onEmphasis')
29
+ },
30
+ start: {
31
+ background: get('colors.accent.emphasis'),
32
+ borderRadius: '4px 0 0 4px',
33
+ color: get('colors.fg.onEmphasis'),
34
+ todayColor: get('colors.fg.onEmphasis')
35
+ },
36
+ middle: {
37
+ background: get('colors.accent.subtle'),
38
+ borderRadius: '0',
39
+ color: get('colors.fg.default'),
40
+ todayColor: get('colors.accent.fg')
41
+ },
42
+ end: {
43
+ background: get('colors.accent.emphasis'),
44
+ borderRadius: '0 4px 4px 0',
45
+ color: get('colors.fg.onEmphasis'),
46
+ todayColor: get('colors.fg.onEmphasis')
47
+ }
48
+ },
49
+ default: {
50
+ normal: {
51
+ background: get('colors.canvas.primary'),
52
+ borderRadius: get('radii.2'),
53
+ color: get('colors.fg.default'),
54
+ todayColor: get('colors.accent.fg')
55
+ },
56
+ hover: {
57
+ background: get('colors.neutral.muted'),
58
+ borderRadius: get('radii.2'),
59
+ color: get('colors.fg.default'),
60
+ todayColor: get('colors.accent.fg')
61
+ },
62
+ pressed: {
63
+ background: get('colors.neutral.emphasis'),
64
+ borderRadius: get('radii.2'),
65
+ color: get('colors.fg.onEmphasis'),
66
+ todayColor: get('colors.fg.onEmphasis')
67
+ }
68
+ }
69
+ };
70
+
71
+ const getStateStyles = (props, prop, state) => {
72
+ const {
73
+ blocked,
74
+ disabled,
75
+ selected,
76
+ today
77
+ } = props;
78
+
79
+ if (selected) {
80
+ switch (selected) {
81
+ case 'start':
82
+ return today && prop === 'color' ? states.selected.start['todayColor'] : states.selected.start[prop];
83
+
84
+ case 'middle':
85
+ return today && prop === 'color' ? states.selected.middle['todayColor'] : states.selected.middle[prop];
86
+
87
+ case 'end':
88
+ return today && prop === 'color' ? states.selected.end['todayColor'] : states.selected.end[prop];
89
+
90
+ default:
91
+ return today && prop === 'color' ? states.selected.default['todayColor'] : states.selected.default[prop];
92
+ }
93
+ } else if (blocked) {
94
+ return states.blocked[prop];
95
+ } else if (disabled) {
96
+ return states.disabled[prop];
97
+ } else {
98
+ return today && prop === 'color' ? states.default[state]['todayColor'] : states.default[state][prop];
99
+ }
100
+ };
101
+
102
+ const DayComponent = styled(DayBaseComponent).attrs(props => ({
103
+ background: getStateStyles(props, 'background', 'normal'),
104
+ borderRadius: getStateStyles(props, 'borderRadius', 'normal'),
105
+ textColor: getStateStyles(props, 'color', 'normal'),
106
+ backgroundHover: getStateStyles(props, 'background', 'hover'),
107
+ textColorHover: getStateStyles(props, 'color', 'hover'),
108
+ backgroundPressed: getStateStyles(props, 'background', 'pressed'),
109
+ textColorPressed: getStateStyles(props, 'color', 'pressed')
110
+ })).withConfig({
111
+ displayName: "Day__DayComponent",
112
+ componentId: "sc-1japneh-1"
113
+ })(["background-color:", ";border-radius:", ";opacity:", ";transition:0.1s background-color ease;& ", "{align-self:center;color:", ";display:flex;font-family:", ";font-size:", ";justify-content:center;justify-self:center;padding:4px 0;position:relative;transition:0.1s color ease;user-select:none;width:16px;&:after{content:'';display:", ";position:absolute;bottom:0;background:", ";width:100%;height:2px;border-radius:1px;}}&:hover,&:focus{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.today ? 'block' : 'none', props => props.selected && props.selected !== 'middle' ? get('colors.fg.onEmphasis')(props) : get('colors.accent.emphasis')(props), props => props.backgroundHover, Text, props => props.textColorHover, props => props.backgroundPressed, get('shadows.shadow.medium'), Text, props => props.textColorPressed);
114
+ export const Day = ({
115
+ date,
116
+ onAction
117
+ }) => {
118
+ const {
119
+ onDayFocus,
120
+ onSelection,
121
+ disabled,
122
+ blocked,
123
+ focused,
124
+ selected,
125
+ today
126
+ } = useDatePicker(date);
127
+ const dayRef = useRef(null);
128
+ useEffect(() => {
129
+ if (focused) {
130
+ setTimeout(() => {
131
+ var _dayRef$current;
132
+
133
+ return (_dayRef$current = dayRef.current) === null || _dayRef$current === void 0 ? void 0 : _dayRef$current.focus();
134
+ }, 0);
135
+ }
136
+ }, [focused]);
137
+ const keyPressHandler = useCallback(event => {
138
+ if (disabled) {
139
+ return;
140
+ }
141
+
142
+ if ([' ', 'Enter'].includes(event.key)) {
143
+ onSelection(date);
144
+ onAction === null || onAction === void 0 ? void 0 : onAction(date, event);
145
+ }
146
+ }, [disabled, onSelection, onAction, date]);
147
+ const clickHandler = useCallback(event => {
148
+ if (disabled) {
149
+ return;
150
+ }
151
+
152
+ onSelection(date);
153
+ onAction === null || onAction === void 0 ? void 0 : onAction(date, event);
154
+ }, [disabled, onSelection, date, onAction]);
155
+ const todayStyles = useMemo(() => today ? {
156
+ fontWeight: 'bold'
157
+ } : {}, [today]);
158
+ return /*#__PURE__*/React.createElement(DayComponent, {
159
+ ref: dayRef,
160
+ role: "gridcell",
161
+ "aria-disabled": disabled,
162
+ "aria-selected": selected !== false,
163
+ blocked: blocked,
164
+ disabled: disabled,
165
+ focused: focused,
166
+ selected: selected,
167
+ today: today,
168
+ onClick: clickHandler,
169
+ onMouseEnter: () => onDayFocus(date),
170
+ onFocus: () => onDayFocus(date),
171
+ onKeyPress: keyPressHandler,
172
+ tabIndex: -1,
173
+ "data-date": format(date, 'MM/dd/yyyy')
174
+ }, /*#__PURE__*/React.createElement(Text, {
175
+ sx: todayStyles
176
+ }, date.getDate()));
177
+ };
178
+ Day.displayName = "Day";
179
+ export const BlankDay = styled(DayBaseComponent).withConfig({
180
+ displayName: "Day__BlankDay",
181
+ componentId: "sc-1japneh-2"
182
+ })(["background-color:", ";"], get('colors.canvas.primary'));
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import { FontSizeProps } from 'styled-system';
3
+ import { SystemCommonProps, SystemLayoutProps } from '../constants';
4
+ import { SxProp } from '../sx';
5
+ export interface MonthProps extends FontSizeProps, SystemCommonProps, SxProp, SystemLayoutProps {
6
+ date: Date;
7
+ }
8
+ export declare const Month: React.FC<MonthProps>;
@@ -0,0 +1,98 @@
1
+ import { format, isEqual, lastDayOfMonth, getDaysInMonth, eachDayOfInterval, startOfWeek, endOfWeek } from 'date-fns';
2
+ import React, { useMemo, useState } from 'react';
3
+ import styled from 'styled-components';
4
+ import Box from '../Box';
5
+ import Text from '../Text';
6
+ import { get } from '../constants';
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
+ };
18
+ const MonthComponent = styled(Box).withConfig({
19
+ displayName: "Month__MonthComponent",
20
+ componentId: "l6j7o0-0"
21
+ })(["display:grid;grid-auto-rows:min-content;grid-template-columns:repeat(1fr,7);grid-template-rows:1fr;gap:0px 0px;grid-template-areas:'month month month month month month month' 'sunday monday tuesday wednesday thursday friday saturday';justify-items:stretch;align-items:stretch;"]);
22
+ const MonthTitle = styled(Text).withConfig({
23
+ displayName: "Month__MonthTitle",
24
+ componentId: "l6j7o0-1"
25
+ })(["font-size:", ";font-weight:", ";grid-area:month;height:", ";justify-self:center;"], get('fontSizes.1'), get('fontWeights.bold'), get('space.4'));
26
+ const WeekdayHeader = styled(Text).withConfig({
27
+ displayName: "Month__WeekdayHeader",
28
+ componentId: "l6j7o0-2"
29
+ })(["color:", ";font-family:", ";font-size:", ";justify-self:center;padding:", " 0 ", ";"], get('colors.fg.subtle'), get('fonts.mono'), get('fontSizes.0'), get('space.3'), get('space.2'));
30
+ export const Month = ({
31
+ date
32
+ }) => {
33
+ const {
34
+ configuration
35
+ } = useDatePicker();
36
+ const [selectedDay, setSelectedDay] = useState(null);
37
+ const getTitle = useMemo(() => `${format(new Date(date), 'MMMM yyyy')}`, [date]);
38
+ const weekdayHeaders = useMemo(() => {
39
+ var _configuration$weekSt;
40
+
41
+ const now = new Date(date);
42
+ const weekOptions = {
43
+ weekStartsOn: weekdayEnum[(_configuration$weekSt = configuration.weekStartsOn) !== null && _configuration$weekSt !== void 0 ? _configuration$weekSt : 'Sunday']
44
+ };
45
+ return eachDayOfInterval({
46
+ start: startOfWeek(now, weekOptions),
47
+ end: endOfWeek(now, weekOptions)
48
+ }).map(d => /*#__PURE__*/React.createElement(WeekdayHeader, {
49
+ key: `weekday-${d}-header`
50
+ }, format(d, 'EEEEEE')));
51
+ }, [configuration.weekStartsOn, date]);
52
+
53
+ const dayAction = day => {
54
+ setSelectedDay(day);
55
+ };
56
+
57
+ const dayComponents = useMemo(() => {
58
+ var _configuration$weekSt2, _configuration$weekSt3;
59
+
60
+ const components = [];
61
+ const firstDay = new Date(date.getFullYear(), date.getMonth(), 1);
62
+ const preBlanks = (firstDay.getDay() + (7 - weekdayEnum[(_configuration$weekSt2 = configuration.weekStartsOn) !== null && _configuration$weekSt2 !== void 0 ? _configuration$weekSt2 : 'Sunday'])) % 7;
63
+
64
+ for (let i = 0; i < preBlanks; i++) {
65
+ components.push( /*#__PURE__*/React.createElement(BlankDay, {
66
+ key: `month-pre-blank-${i}`
67
+ }));
68
+ }
69
+
70
+ for (let i = 1; i <= getDaysInMonth(firstDay); i++) {
71
+ const day = new Date(date.getFullYear(), date.getMonth(), i);
72
+ components.push( /*#__PURE__*/React.createElement(Day, {
73
+ key: `day-component-${day.toString()}`,
74
+ date: day,
75
+ selected: selectedDay ? isEqual(day, selectedDay) : false,
76
+ onAction: dayAction
77
+ }));
78
+ }
79
+
80
+ const lastDay = lastDayOfMonth(firstDay);
81
+ const postBlanks = (lastDay.getDay() + (7 - weekdayEnum[(_configuration$weekSt3 = configuration.weekStartsOn) !== null && _configuration$weekSt3 !== void 0 ? _configuration$weekSt3 : 'Sunday'])) % 7;
82
+
83
+ for (let i = 6; i > postBlanks; i--) {
84
+ components.push( /*#__PURE__*/React.createElement(BlankDay, {
85
+ key: `month-post-blank-${i}`
86
+ }));
87
+ }
88
+
89
+ return components;
90
+ }, [configuration.weekStartsOn, date, selectedDay]);
91
+ return /*#__PURE__*/React.createElement(MonthComponent, {
92
+ role: "grid",
93
+ "aria-labelledby": `${date.getMonth()} ${date.getFullYear()}`
94
+ }, /*#__PURE__*/React.createElement(MonthTitle, {
95
+ "aria-live": "polite"
96
+ }, !configuration.compressedHeader ? getTitle : ''), weekdayHeaders, dayComponents);
97
+ };
98
+ Month.displayName = "Month";
@@ -0,0 +1,12 @@
1
+ import { AnchorVariant, Selection, SelectionVariant } from './useDatePicker';
2
+ export declare const parseDate: (dateString: string, variant?: SelectionVariant) => Selection;
3
+ declare type FormatDateOptions = {
4
+ selection?: Selection;
5
+ anchorVariant?: AnchorVariant;
6
+ dateFormat?: string;
7
+ placeholder?: string;
8
+ rawFormat?: boolean;
9
+ variant?: SelectionVariant;
10
+ };
11
+ export declare const formatDate: ({ selection, dateFormat, placeholder, rawFormat, variant }: FormatDateOptions) => string;
12
+ export {};