@renderlesskit/react
Version:
Collection of headless components/hooks that are accessible, composable, customizable from low level to build your own UI & Design System powered by Reakit
183 lines (158 loc) • 5.37 kB
JavaScript
/**
* All credit goes to [React Spectrum](https://github.com/adobe/react-spectrum)
* We improved the Calendar from Stately [useCalendarState](https://github.com/adobe/react-spectrum/tree/main/packages/%40react-stately/calendar)
* to work with Reakit System
*/
import * as React from "react";
import { unstable_useId as useId } from "reakit";
import { useUpdateEffect } from "@chakra-ui/hooks";
import { useDateFormatter } from "@react-aria/i18n";
import { addDays, addMonths, addWeeks, addYears, endOfMonth, getDaysInMonth, isSameMonth, startOfDay, startOfMonth, subDays, subMonths, subWeeks, subYears, toUTCString, useControllableState } from "../utils";
import { announce } from "../utils/LiveAnnouncer";
import { generateDaysInMonthArray, useWeekDays, useWeekStart } from "./helpers";
export function useCalendarState() {
var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var {
value: initialValue,
defaultValue = toUTCString(new Date()),
onChange,
minValue,
maxValue,
isDisabled = false,
isReadOnly = false,
autoFocus = false
} = props;
var [value, setValue] = useControllableState({
value: initialValue,
defaultValue,
onChange
});
var date = React.useMemo(() => new Date(value), [value]);
var minDateValue = React.useMemo(() => minValue ? new Date(minValue) : new Date(-864e13), [minValue]);
var maxDateValue = React.useMemo(() => maxValue ? new Date(maxValue) : new Date(864e13), [maxValue]);
var [currentMonth, setCurrentMonth] = React.useState(date);
var [focusedDate, setFocusedDate] = React.useState(date);
var [isFocused, setFocused] = React.useState(autoFocus);
var month = currentMonth.getMonth();
var year = currentMonth.getFullYear();
var weekStart = useWeekStart();
var weekDays = useWeekDays(weekStart);
var monthStartsAt = (startOfMonth(currentMonth).getDay() - weekStart) % 7;
if (monthStartsAt < 0) {
monthStartsAt += 7;
}
var days = getDaysInMonth(currentMonth);
var weeksInMonth = Math.ceil((monthStartsAt + days) / 7); // Get 2D Date arrays in 7 days a week format
var daysInMonth = React.useMemo(() => generateDaysInMonthArray(month, monthStartsAt, weeksInMonth, year), [month, monthStartsAt, weeksInMonth, year]);
function isInvalidDateRange(value) {
var min = new Date(minDateValue);
var max = new Date(maxDateValue);
return value < min || value > max;
} // Sets focus to a specific cell date
function focusCell(date) {
if (isInvalidDateRange(date)) return;
if (!isSameMonth(date, currentMonth)) {
setCurrentMonth(startOfMonth(date));
}
setFocusedDate(date);
}
var dateFormatter = useDateFormatter({
dateStyle: "full"
});
var announceSelectedDate = React.useCallback(value => {
if (!value) return;
announce("Selected Date: ".concat(dateFormatter.format(value)));
}, [dateFormatter]);
var setDate = React.useCallback(value => {
if (!isDisabled && !isReadOnly) {
setValue(toUTCString(value));
announceSelectedDate(value);
}
}, [announceSelectedDate, isDisabled, isReadOnly, setValue]); // TODO
// This runs only once when the component is mounted
// Controlled state doesn't change the claender position
// React.useEffect(() => {
// const clampedDate = clamp(date, {
// start: minDateValue,
// end: maxDateValue,
// });
// setDate(clampedDate);
// setCurrentMonth(clampedDate);
// setFocusedDate(clampedDate);
// }, [date, maxDateValue, minDateValue, setDate]);
var monthFormatter = useDateFormatter({
month: "long",
year: "numeric"
}); // Announce when the current month changes
useUpdateEffect(() => {
// announce the new month with a change from the Previous or Next button
if (!isFocused) {
announce(monthFormatter.format(currentMonth));
} // handle an update to the current month from the Previous or Next button
// rather than move focus, we announce the new month value
}, [currentMonth]);
var {
id: calendarId
} = useId({
id: props.id,
baseId: "calendar"
});
return {
dateValue: date,
setDateValue: setDate,
calendarId,
month,
year,
weekStart,
weekDays,
daysInMonth,
isDisabled,
isFocused,
isReadOnly,
setFocused,
currentMonth,
setCurrentMonth,
focusedDate,
focusCell,
setFocusedDate,
focusNextDay() {
focusCell(addDays(focusedDate, 1));
},
focusPreviousDay() {
focusCell(subDays(focusedDate, 1));
},
focusNextWeek() {
focusCell(addWeeks(focusedDate, 1));
},
focusPreviousWeek() {
focusCell(subWeeks(focusedDate, 1));
},
focusNextMonth() {
focusCell(addMonths(focusedDate, 1));
},
focusPreviousMonth() {
focusCell(subMonths(focusedDate, 1));
},
focusStartOfMonth() {
focusCell(startOfMonth(focusedDate));
},
focusEndOfMonth() {
focusCell(endOfMonth(startOfDay(focusedDate)));
},
focusNextYear() {
focusCell(addYears(focusedDate, 1));
},
focusPreviousYear() {
focusCell(subYears(focusedDate, 1));
},
selectFocusedDate() {
setDate(focusedDate);
},
selectDate(date) {
setDate(date);
},
isInvalidDateRange,
isRangeCalendar: false
};
}
//# sourceMappingURL=CalendarState.js.map