@awsui/components-react
Version:
On July 19th, 2022, we launched [Cloudscape Design System](https://cloudscape.design). Cloudscape is an evolution of AWS-UI. It consists of user interface guidelines, front-end components, design resources, and development tools for building intuitive, en
128 lines • 7.14 kB
JavaScript
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { addMonths, addYears, isAfter, isBefore, isSameMonth, isSameYear, max, min } from 'date-fns';
import { getBaseDay, moveNextDay, moveNextWeek, movePrevDay, movePrevWeek, } from '../../../calendar/utils/navigation-day';
import { getBaseMonth, moveMonthDown, moveMonthUp, moveNextMonth, movePrevMonth, } from '../../../calendar/utils/navigation-month';
import { useDateCache } from '../../../internal/hooks/use-date-cache';
import { KeyCode } from '../../../internal/keycode';
import handleKey from '../../../internal/utils/handle-key';
import { hasValue } from '../../../internal/utils/has-value';
import InternalSpaceBetween from '../../../space-between/internal';
import { findDateToFocus } from '../utils';
import { Grid } from './grid';
import testutilStyles from '../../test-classes/styles.css.js';
function isVisible(date, baseDate, isSingleGrid, granularity) {
const isSame = granularity === 'day' ? isSameMonth : isSameYear;
const add = granularity === 'day' ? addMonths : addYears;
if (isSingleGrid) {
return isSame(date, baseDate);
}
const previous = add(baseDate, -1);
return isSame(date, previous) || isSame(date, baseDate);
}
export const Grids = ({ baseDate, selectedStartDate, selectedEndDate, focusedDate, onFocusedDateChange, isDateEnabled, dateDisabledReason, isSingleGrid, onSelectDate, onPageChange, locale, todayAriaLabel, currentMonthAriaLabel, headingIdPrefix, startOfWeek = 0, granularity = 'day', }) => {
const containerRef = useRef(null);
const [gridHasFocus, setGridHasFocus] = useState(false);
const isMonthPicker = granularity === 'month';
const focusedDateRef = useRef(null);
const addPages = !isMonthPicker ? addMonths : addYears;
const getBase = !isMonthPicker ? getBaseDay : getBaseMonth;
const moveDown = isMonthPicker ? moveMonthDown : moveNextWeek;
const moveLeft = isMonthPicker ? movePrevMonth : movePrevDay;
const moveRight = isMonthPicker ? moveNextMonth : moveNextDay;
const moveUp = isMonthPicker ? moveMonthUp : movePrevWeek;
const dateCache = useDateCache();
baseDate = dateCache(baseDate);
focusedDate = focusedDate ? dateCache(focusedDate) : null;
const isDateFocusable = useCallback((date) => {
return isDateEnabled(date) || (!isDateEnabled(date) && !!dateDisabledReason(date));
}, [isDateEnabled, dateDisabledReason]);
useEffect(() => {
if (focusedDate && !isVisible(focusedDate, baseDate, isSingleGrid, granularity)) {
const direction = isAfter(focusedDate, baseDate) ? -1 : 1;
const newPage = !isSingleGrid && direction === -1 ? addPages(baseDate, -1) : baseDate;
const nearestBaseDate = getBase(newPage, isDateFocusable);
const newFocusedDate = findDateToFocus(focusedDate, nearestBaseDate, isDateFocusable);
onFocusedDateChange(newFocusedDate);
}
}, [baseDate, focusedDate, isSingleGrid, granularity, addPages, isDateFocusable, onFocusedDateChange, getBase]);
const onGridKeyDownHandler = (event) => {
let updatedFocusDate = null;
const keys = [KeyCode.up, KeyCode.down, KeyCode.left, KeyCode.right, KeyCode.space, KeyCode.enter];
if (focusedDate === null || keys.indexOf(event.keyCode) === -1) {
return;
}
event.preventDefault();
handleKey(event, {
onActivate: () => {
if (!focusedDate || !isDateEnabled(focusedDate)) {
return;
}
onSelectDate(focusedDate);
},
onBlockEnd: () => focusedDate && (updatedFocusDate = moveDown(focusedDate, isDateFocusable)),
onBlockStart: () => focusedDate && (updatedFocusDate = moveUp(focusedDate, isDateFocusable)),
onInlineStart: () => focusedDate && (updatedFocusDate = moveLeft(focusedDate, isDateFocusable)),
onInlineEnd: () => focusedDate && (updatedFocusDate = moveRight(focusedDate, isDateFocusable)),
});
if (!updatedFocusDate) {
return;
}
const updatedDateIsVisible = isVisible(updatedFocusDate, baseDate, isSingleGrid, granularity);
if (!updatedDateIsVisible) {
const newPageIsOnLeftSide = !isSingleGrid && isBefore(updatedFocusDate, baseDate);
onPageChange(newPageIsOnLeftSide ? addPages(updatedFocusDate, 1) : updatedFocusDate);
}
onFocusedDateChange(updatedFocusDate);
};
useEffect(() => {
// focus current date if the focus is already inside the calendar
if (focusedDate !== null && gridHasFocus) {
if (focusedDateRef.current && focusedDateRef.current !== document.activeElement) {
focusedDateRef.current.focus();
}
}
}, [focusedDate, gridHasFocus]);
const onGridBlur = (event) => {
var _a;
const newFocusTarget = event.relatedTarget || document.activeElement;
const newFocusTargetIsInGrid = (_a = containerRef.current) === null || _a === void 0 ? void 0 : _a.contains(newFocusTarget);
if (newFocusTarget && !newFocusTargetIsInGrid && gridHasFocus) {
setGridHasFocus(false);
}
};
const onGridFocus = () => {
if (!gridHasFocus) {
setGridHasFocus(true);
}
};
const isRangeVisible = (selectedStartDate && selectedEndDate) || gridHasFocus;
const rangeEnds = [selectedStartDate !== null && selectedStartDate !== void 0 ? selectedStartDate : focusedDate, selectedEndDate !== null && selectedEndDate !== void 0 ? selectedEndDate : focusedDate].filter(hasValue);
const rangeStartDate = min(rangeEnds);
const rangeEndDate = max(rangeEnds);
const pageUnit = isMonthPicker ? 'year' : 'month';
const sharedGridProps = {
selectedEndDate,
selectedStartDate,
focusedDate,
focusedDateRef,
rangeStartDate: isRangeVisible ? rangeStartDate : null,
rangeEndDate: isRangeVisible ? rangeEndDate : null,
isDateEnabled,
dateDisabledReason,
onSelectDate,
onGridKeyDownHandler,
onFocusedDateChange,
locale,
granularity,
currentMonthAriaLabel,
startOfWeek,
todayAriaLabel,
};
return (React.createElement("div", { ref: containerRef, onFocus: onGridFocus, onBlur: onGridBlur },
React.createElement(InternalSpaceBetween, { size: "xs", direction: "horizontal" },
!isSingleGrid && (React.createElement(Grid, Object.assign({}, sharedGridProps, { padDates: 'before', className: testutilStyles['first-grid'], baseDate: addPages(baseDate, -1), ariaLabelledby: `${headingIdPrefix}-prev${pageUnit}` }))),
React.createElement(Grid, Object.assign({}, sharedGridProps, { padDates: 'after', className: testutilStyles['second-grid'], baseDate: baseDate, ariaLabelledby: `${headingIdPrefix}-current${pageUnit}` })))));
};
//# sourceMappingURL=index.js.map