UNPKG

@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

115 lines 6.74 kB
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 import React, { useEffect, useRef, useState } from 'react'; import clsx from 'clsx'; import { addMonths, addYears, isSameDay, isSameMonth, isSameYear } from 'date-fns'; import { useUniqueId } from '@awsui/component-toolkit/internal'; import { getBaseProps } from '../internal/base-component'; import { fireNonCancelableEvent } from '../internal/events/index.js'; import checkControlled from '../internal/hooks/check-controlled/index.js'; import { useDateCache } from '../internal/hooks/use-date-cache/index.js'; import { formatDate, parseDate } from '../internal/utils/date-time'; import { normalizeLocale } from '../internal/utils/locale'; import Grid from './grid'; import CalendarGridHeader from './grid/calendar-grid-header'; import useCalendarGridKeyboardNavigation from './grid/use-calendar-grid-keyboard-navigation'; import useCalendarGridRows from './grid/use-calendar-grid-rows'; import CalendarHeader from './header'; import useCalendarLabels from './use-calendar-labels'; import { getBaseDay } from './utils/navigation-day'; import { getBaseMonth } from './utils/navigation-month'; import styles from './styles.css.js'; export default function Calendar({ value, locale = '', startOfWeek, isDateEnabled = () => true, dateDisabledReason = () => '', ariaLabel, ariaLabelledby, ariaDescribedby, onChange, __internalRootRef, i18nStrings, granularity = 'day', previousMonthAriaLabel, nextMonthAriaLabel, todayAriaLabel, ...rest }) { checkControlled('Calendar', 'value', value, 'onChange', onChange); const baseProps = getBaseProps(rest); const normalizedLocale = normalizeLocale('Calendar', locale); const gridWrapperRef = useRef(null); const [focusedDate, setFocusedDate] = useState(null); const valueDateCache = useDateCache(); const focusedDateCache = useDateCache(); // Set displayed date to value if defined or to current date otherwise. const parsedValue = value && value.length >= 4 ? parseDate(value) : null; const memoizedValue = parsedValue && !isNaN(parsedValue.getDate()) ? valueDateCache(parsedValue) : null; const defaultDisplayedDate = memoizedValue !== null && memoizedValue !== void 0 ? memoizedValue : new Date(); const [displayedDate, setDisplayedDate] = useState(defaultDisplayedDate); const headingId = useUniqueId('calendar-heading'); const isMonthPicker = granularity === 'month'; const isDateFocusable = (date) => isDateEnabled(date) || (!isDateEnabled(date) && !!dateDisabledReason(date)); const baseDate = isMonthPicker ? getBaseMonth(displayedDate, isDateEnabled) : getBaseDay(displayedDate, isDateEnabled); const isSameDate = isMonthPicker ? isSameMonth : isSameDay; const isSamePage = isMonthPicker ? isSameYear : isSameMonth; const isCurrentPage = (date) => isMonthPicker || isSameMonth(date, baseDate); const { previousButtonLabel, nextButtonLabel, renderDate, renderDateAnnouncement, renderHeaderText } = useCalendarLabels({ granularity, i18nStrings, locale: normalizedLocale, previousMonthAriaLabel, nextMonthAriaLabel, todayAriaLabel, }); const gridRows = useCalendarGridRows({ baseDate, granularity, startOfWeek, locale: normalizedLocale }); // Update displayed date if value changes. useEffect(() => { if (memoizedValue) { setDisplayedDate(prev => (prev.getTime() !== memoizedValue.getTime() ? memoizedValue : prev)); } }, [memoizedValue]); const selectFocusedDate = (selected, baseDate) => { if (selected && isDateFocusable(selected) && isSamePage(selected, baseDate)) { return selected; } const today = new Date(); if (isDateFocusable(today) && isSamePage(today, baseDate)) { return today; } if (isDateFocusable(baseDate)) { return baseDate; } return null; }; const focusableDate = focusedDate || selectFocusedDate(memoizedValue, baseDate); const onHeaderChangePageHandler = (amount) => { const movePage = isMonthPicker ? addYears : addMonths; const newDate = movePage(baseDate, amount); onChangePageHandler(newDate); }; const onChangePageHandler = (newDate) => { setDisplayedDate(newDate); setFocusedDate(null); }; const onGridFocusDateHandler = (date) => { if (date) { setFocusedDate(date ? focusedDateCache(date) : null); } }; const onGridSelectDateHandler = (date) => { fireNonCancelableEvent(onChange, { value: formatDate(date, granularity) }); setFocusedDate(null); }; const onGridBlur = (event) => { var _a; const newFocusTargetIsInGrid = event.relatedTarget && ((_a = gridWrapperRef.current) === null || _a === void 0 ? void 0 : _a.contains(event.relatedTarget)); if (!newFocusTargetIsInGrid) { setFocusedDate(null); } }; const onGridKeyDownHandler = useCalendarGridKeyboardNavigation({ baseDate, focusableDate, granularity, isDateEnabled, isDateFocusable, onChangePage: onChangePageHandler, onFocusDate: onGridFocusDateHandler, onSelectDate: onGridSelectDateHandler, }); const headerText = renderHeaderText(baseDate); return (React.createElement("div", { ref: __internalRootRef, ...baseProps, role: "group", "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, "aria-describedby": ariaDescribedby, className: clsx(styles.root, styles.calendar, baseProps.className) }, React.createElement("div", { className: styles['calendar-inner'] }, React.createElement(CalendarHeader, { formattedDate: headerText, onChange: onHeaderChangePageHandler, previousLabel: previousButtonLabel, nextLabel: nextButtonLabel, headingId: headingId }), React.createElement("div", { onBlur: onGridBlur, ref: gridWrapperRef }, React.createElement(Grid, { isDateEnabled: isDateEnabled, dateDisabledReason: dateDisabledReason, focusedDate: focusedDate, focusableDate: focusableDate, onSelectDate: onGridSelectDateHandler, onFocusDate: onGridFocusDateHandler, onChangePage: onChangePageHandler, selectedDate: memoizedValue, ariaLabelledby: headingId, header: isMonthPicker ? null : React.createElement(CalendarGridHeader, { locale: normalizedLocale, rows: gridRows }), rows: gridRows, isCurrentPage: isCurrentPage, renderDate: renderDate, renderDateAnnouncement: renderDateAnnouncement, isSameDate: isSameDate, onGridKeyDownHandler: onGridKeyDownHandler }))))); } //# sourceMappingURL=internal.js.map