UNPKG

16.1 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.CalendarDayGridBase = void 0;
4var tslib_1 = require("tslib");
5var React = require("react");
6var utilities_1 = require("@fluentui/utilities");
7var FocusZone_1 = require("../../FocusZone");
8var date_time_utilities_1 = require("@fluentui/date-time-utilities");
9var react_hooks_1 = require("@fluentui/react-hooks");
10var CalendarMonthHeaderRow_1 = require("./CalendarMonthHeaderRow");
11var CalendarGridRow_1 = require("./CalendarGridRow");
12var getClassNames = utilities_1.classNamesFunction();
13function useDayRefs() {
14 var daysRef = React.useRef({});
15 var getSetRefCallback = function (dayKey) { return function (element) {
16 if (element === null) {
17 delete daysRef.current[dayKey];
18 }
19 else {
20 daysRef.current[dayKey] = element;
21 }
22 }; };
23 return [daysRef, getSetRefCallback];
24}
25function useWeeks(props, onSelectDate, getSetRefCallback) {
26 /**
27 * Initial parsing of the given props to generate IDayInfo two dimensional array, which contains a representation
28 * of every day in the grid. Convenient for helping with conversions between day refs and Date objects in callbacks.
29 */
30 var weeks = React.useMemo(function () {
31 var _a;
32 var weeksGrid = date_time_utilities_1.getDayGrid(props);
33 var firstVisibleDay = weeksGrid[1][0].originalDate;
34 var lastVisibleDay = weeksGrid[weeksGrid.length - 1][6].originalDate;
35 var markedDays = ((_a = props.getMarkedDays) === null || _a === void 0 ? void 0 : _a.call(props, firstVisibleDay, lastVisibleDay)) || [];
36 /**
37 * Weeks is a 2D array. Weeks[0] contains the last week of the prior range,
38 * Weeks[weeks.length - 1] contains first week of next range. These are for transition states.
39 *
40 * Weeks[1... weeks.length - 2] contains the actual visible data
41 */
42 var returnValue = [];
43 for (var weekIndex = 0; weekIndex < weeksGrid.length; weekIndex++) {
44 var week = [];
45 var _loop_1 = function (dayIndex) {
46 var day = weeksGrid[weekIndex][dayIndex];
47 var dayInfo = tslib_1.__assign(tslib_1.__assign({ onSelected: function () { return onSelectDate(day.originalDate); }, setRef: getSetRefCallback(day.key) }, day), { isMarked: day.isMarked || (markedDays === null || markedDays === void 0 ? void 0 : markedDays.some(function (markedDay) { return date_time_utilities_1.compareDates(day.originalDate, markedDay); })) });
48 week.push(dayInfo);
49 };
50 for (var dayIndex = 0; dayIndex < date_time_utilities_1.DAYS_IN_WEEK; dayIndex++) {
51 _loop_1(dayIndex);
52 }
53 returnValue.push(week);
54 }
55 return returnValue;
56 // TODO: this is missing deps on getSetRefCallback and onSelectDate (and depending on the entire
57 // props object may not be a good idea due to likely frequent mutation). It would be easy to
58 // fix getSetRefCallback to not mutate every render, but onSelectDate is passed down from
59 // Calendar and trying to fix it requires a huge cascade of changes.
60 // eslint-disable-next-line react-hooks/exhaustive-deps
61 }, [props]);
62 return weeks;
63}
64/**
65 * Hook to determine whether to animate the CalendarDayGrid forwards or backwards
66 * @returns true if the grid should animate backwards; false otherwise
67 */
68function useAnimateBackwards(weeks) {
69 var previousNavigatedDate = react_hooks_1.usePrevious(weeks[0][0].originalDate);
70 if (!previousNavigatedDate || previousNavigatedDate.getTime() === weeks[0][0].originalDate.getTime()) {
71 return undefined;
72 }
73 else if (previousNavigatedDate <= weeks[0][0].originalDate) {
74 return false;
75 }
76 else {
77 return true;
78 }
79}
80function useWeekCornerStyles(props) {
81 /**
82 *
83 * Section for setting the rounded corner styles on individual day cells. Individual day cells need different
84 * corners to be rounded depending on which date range type and where the cell is located in the current grid.
85 * If we just round all of the corners, there isn't a good overlap and we get gaps between contiguous day boxes
86 * in Edge browser.
87 *
88 */
89 var getWeekCornerStyles = function (classNames, initialWeeks) {
90 var weekCornersStyled = {};
91 /* need to handle setting all of the corners on arbitrarily shaped blobs
92 __
93 __|A |
94 |B |C |__
95 |D |E |F |
96
97 in this case, A needs top left rounded, top right rounded
98 B needs top left rounded
99 C doesn't need any rounding
100 D needs bottom left rounded
101 E doesn't need any rounding
102 F needs top right rounding
103 */
104 // cut off the animation transition weeks
105 var weeks = initialWeeks.slice(1, initialWeeks.length - 1);
106 // if there's an item above, lose both top corners. Item below, lose both bottom corners, etc.
107 weeks.forEach(function (week, weekIndex) {
108 week.forEach(function (day, dayIndex) {
109 var above = weeks[weekIndex - 1] &&
110 weeks[weekIndex - 1][dayIndex] &&
111 isInSameHoverRange(weeks[weekIndex - 1][dayIndex].originalDate, day.originalDate, weeks[weekIndex - 1][dayIndex].isSelected, day.isSelected);
112 var below = weeks[weekIndex + 1] &&
113 weeks[weekIndex + 1][dayIndex] &&
114 isInSameHoverRange(weeks[weekIndex + 1][dayIndex].originalDate, day.originalDate, weeks[weekIndex + 1][dayIndex].isSelected, day.isSelected);
115 var left = weeks[weekIndex][dayIndex - 1] &&
116 isInSameHoverRange(weeks[weekIndex][dayIndex - 1].originalDate, day.originalDate, weeks[weekIndex][dayIndex - 1].isSelected, day.isSelected);
117 var right = weeks[weekIndex][dayIndex + 1] &&
118 isInSameHoverRange(weeks[weekIndex][dayIndex + 1].originalDate, day.originalDate, weeks[weekIndex][dayIndex + 1].isSelected, day.isSelected);
119 var style = [];
120 style.push(calculateRoundedStyles(classNames, above, below, left, right));
121 style.push(calculateBorderStyles(classNames, above, below, left, right));
122 weekCornersStyled[weekIndex + '_' + dayIndex] = style.join(' ');
123 });
124 });
125 return weekCornersStyled;
126 };
127 var calculateRoundedStyles = function (classNames, above, below, left, right) {
128 var style = [];
129 var roundedTopLeft = !above && !left;
130 var roundedTopRight = !above && !right;
131 var roundedBottomLeft = !below && !left;
132 var roundedBottomRight = !below && !right;
133 if (roundedTopLeft) {
134 style.push(utilities_1.getRTL() ? classNames.topRightCornerDate : classNames.topLeftCornerDate);
135 }
136 if (roundedTopRight) {
137 style.push(utilities_1.getRTL() ? classNames.topLeftCornerDate : classNames.topRightCornerDate);
138 }
139 if (roundedBottomLeft) {
140 style.push(utilities_1.getRTL() ? classNames.bottomRightCornerDate : classNames.bottomLeftCornerDate);
141 }
142 if (roundedBottomRight) {
143 style.push(utilities_1.getRTL() ? classNames.bottomLeftCornerDate : classNames.bottomRightCornerDate);
144 }
145 return style.join(' ');
146 };
147 var calculateBorderStyles = function (classNames, above, below, left, right) {
148 var style = [];
149 if (!above) {
150 style.push(classNames.datesAbove);
151 }
152 if (!below) {
153 style.push(classNames.datesBelow);
154 }
155 if (!left) {
156 style.push(utilities_1.getRTL() ? classNames.datesRight : classNames.datesLeft);
157 }
158 if (!right) {
159 style.push(utilities_1.getRTL() ? classNames.datesLeft : classNames.datesRight);
160 }
161 return style.join(' ');
162 };
163 var isInSameHoverRange = function (date1, date2, date1Selected, date2Selected) {
164 var dateRangeType = props.dateRangeType, firstDayOfWeek = props.firstDayOfWeek, workWeekDays = props.workWeekDays;
165 // The hover state looks weird with non-contiguous days in work week view. In work week, show week hover state
166 var dateRangeHoverType = dateRangeType === date_time_utilities_1.DateRangeType.WorkWeek ? date_time_utilities_1.DateRangeType.Week : dateRangeType;
167 // we do not pass daysToSelectInDayView because we handle setting those styles dyanamically in onMouseOver
168 var dateRange = date_time_utilities_1.getDateRangeArray(date1, dateRangeHoverType, firstDayOfWeek, workWeekDays);
169 if (date1Selected !== date2Selected) {
170 // if one is selected and the other is not, they can't be in the same range
171 return false;
172 }
173 else if (date1Selected && date2Selected) {
174 // if they're both selected at the same time they must be in the same range
175 return true;
176 }
177 // otherwise, both must be unselected, so check the dateRange
178 return dateRange.filter(function (date) { return date.getTime() === date2.getTime(); }).length > 0;
179 };
180 return [getWeekCornerStyles, calculateRoundedStyles];
181}
182var CalendarDayGridBase = function (props) {
183 var navigatedDayRef = React.useRef(null);
184 var activeDescendantId = react_hooks_1.useId();
185 var onSelectDate = function (selectedDate) {
186 var _a, _b;
187 var firstDayOfWeek = props.firstDayOfWeek, minDate = props.minDate, maxDate = props.maxDate, workWeekDays = props.workWeekDays, daysToSelectInDayView = props.daysToSelectInDayView, restrictedDates = props.restrictedDates;
188 var restrictedDatesOptions = { minDate: minDate, maxDate: maxDate, restrictedDates: restrictedDates };
189 var dateRange = date_time_utilities_1.getDateRangeArray(selectedDate, dateRangeType, firstDayOfWeek, workWeekDays, daysToSelectInDayView);
190 dateRange = date_time_utilities_1.getBoundedDateRange(dateRange, minDate, maxDate);
191 dateRange = dateRange.filter(function (d) {
192 return !date_time_utilities_1.isRestrictedDate(d, restrictedDatesOptions);
193 });
194 (_a = props.onSelectDate) === null || _a === void 0 ? void 0 : _a.call(props, selectedDate, dateRange);
195 (_b = props.onNavigateDate) === null || _b === void 0 ? void 0 : _b.call(props, selectedDate, true);
196 };
197 var _a = useDayRefs(), daysRef = _a[0], getSetRefCallback = _a[1];
198 var weeks = useWeeks(props, onSelectDate, getSetRefCallback);
199 var animateBackwards = useAnimateBackwards(weeks);
200 var _b = useWeekCornerStyles(props), getWeekCornerStyles = _b[0], calculateRoundedStyles = _b[1];
201 React.useImperativeHandle(props.componentRef, function () { return ({
202 focus: function () {
203 var _a, _b;
204 (_b = (_a = navigatedDayRef.current) === null || _a === void 0 ? void 0 : _a.focus) === null || _b === void 0 ? void 0 : _b.call(_a);
205 },
206 }); }, []);
207 /**
208 *
209 * Section for setting hover/pressed styles. Because we want arbitrary blobs of days to be selectable, to support
210 * highlighting every day in the month for month view, css :hover style isn't enough, so we need mouse callbacks
211 * to set classnames on all relevant child refs to apply the styling
212 *
213 */
214 var getDayInfosInRangeOfDay = function (dayToCompare) {
215 // The hover state looks weird with non-contiguous days in work week view. In work week, show week hover state
216 var dateRangeHoverType = getDateRangeTypeToUse(props.dateRangeType, props.workWeekDays);
217 // gets all the dates for the given date range type that are in the same date range as the given day
218 var dateRange = date_time_utilities_1.getDateRangeArray(dayToCompare.originalDate, dateRangeHoverType, props.firstDayOfWeek, props.workWeekDays, props.daysToSelectInDayView).map(function (date) { return date.getTime(); });
219 // gets all the day refs for the given dates
220 var dayInfosInRange = weeks.reduce(function (accumulatedValue, currentWeek) {
221 return accumulatedValue.concat(currentWeek.filter(function (weekDay) { return dateRange.indexOf(weekDay.originalDate.getTime()) !== -1; }));
222 }, []);
223 return dayInfosInRange;
224 };
225 var getRefsFromDayInfos = function (dayInfosInRange) {
226 var dayRefs = [];
227 dayRefs = dayInfosInRange.map(function (dayInfo) { return daysRef.current[dayInfo.key]; });
228 return dayRefs;
229 };
230 var styles = props.styles, theme = props.theme, className = props.className, dateRangeType = props.dateRangeType, showWeekNumbers = props.showWeekNumbers, labelledBy = props.labelledBy, lightenDaysOutsideNavigatedMonth = props.lightenDaysOutsideNavigatedMonth, animationDirection = props.animationDirection;
231 var classNames = getClassNames(styles, {
232 theme: theme,
233 className: className,
234 dateRangeType: dateRangeType,
235 showWeekNumbers: showWeekNumbers,
236 lightenDaysOutsideNavigatedMonth: lightenDaysOutsideNavigatedMonth === undefined ? true : lightenDaysOutsideNavigatedMonth,
237 animationDirection: animationDirection,
238 animateBackwards: animateBackwards,
239 });
240 // When the month is highlighted get the corner dates so that styles can be added to them
241 var weekCorners = getWeekCornerStyles(classNames, weeks);
242 var partialWeekProps = {
243 weeks: weeks,
244 navigatedDayRef: navigatedDayRef,
245 calculateRoundedStyles: calculateRoundedStyles,
246 activeDescendantId: activeDescendantId,
247 classNames: classNames,
248 weekCorners: weekCorners,
249 getDayInfosInRangeOfDay: getDayInfosInRangeOfDay,
250 getRefsFromDayInfos: getRefsFromDayInfos,
251 };
252 return (React.createElement(FocusZone_1.FocusZone, { className: classNames.wrapper, preventDefaultWhenHandled: true },
253 React.createElement("table", { className: classNames.table, "aria-multiselectable": "false", "aria-labelledby": labelledBy, "aria-activedescendant": activeDescendantId, role: "grid" },
254 React.createElement("tbody", null,
255 React.createElement(CalendarMonthHeaderRow_1.CalendarMonthHeaderRow, tslib_1.__assign({}, props, { classNames: classNames, weeks: weeks })),
256 React.createElement(CalendarGridRow_1.CalendarGridRow, tslib_1.__assign({}, props, partialWeekProps, { week: weeks[0], weekIndex: -1, rowClassName: classNames.firstTransitionWeek, ariaRole: "presentation", ariaHidden: true })),
257 weeks.slice(1, weeks.length - 1).map(function (week, weekIndex) { return (React.createElement(CalendarGridRow_1.CalendarGridRow, tslib_1.__assign({}, props, partialWeekProps, { key: weekIndex, week: week, weekIndex: weekIndex, rowClassName: classNames.weekRow }))); }),
258 React.createElement(CalendarGridRow_1.CalendarGridRow, tslib_1.__assign({}, props, partialWeekProps, { week: weeks[weeks.length - 1], weekIndex: -2, rowClassName: classNames.lastTransitionWeek, ariaRole: "presentation", ariaHidden: true }))))));
259};
260exports.CalendarDayGridBase = CalendarDayGridBase;
261exports.CalendarDayGridBase.displayName = 'CalendarDayGridBase';
262/**
263 * When given work week, if the days are non-contiguous, the hover states look really weird. So for non-contiguous
264 * work weeks, we'll just show week view instead.
265 */
266function getDateRangeTypeToUse(dateRangeType, workWeekDays) {
267 if (workWeekDays && dateRangeType === date_time_utilities_1.DateRangeType.WorkWeek) {
268 var sortedWWDays = workWeekDays.slice().sort();
269 var isContiguous = true;
270 for (var i = 1; i < sortedWWDays.length; i++) {
271 if (sortedWWDays[i] !== sortedWWDays[i - 1] + 1) {
272 isContiguous = false;
273 break;
274 }
275 }
276 if (!isContiguous || workWeekDays.length === 0) {
277 return date_time_utilities_1.DateRangeType.Week;
278 }
279 }
280 return dateRangeType;
281}
282//# sourceMappingURL=CalendarDayGrid.base.js.map
\No newline at end of file