@kubit-ui-web/react-components
Version:
Kubit React Components is a customizable, accessible library of React web components, designed to enhance your application's user experience
178 lines • 8.86 kB
JavaScript
import { jsx as _jsx } from "react/jsx-runtime";
import React from 'react';
import { ItemRove } from '../../../components/itemRove/itemRove';
import { useRoveFocus } from '../../../hooks/useRoveFocus/useRoveFocus';
import { useUtilsProvider } from '../../../provider/utils/provider';
import { NEUTRAL_DATE } from '../../../types/date/date';
import { ButtonType } from '../../button/types/type';
import { WEEK_DAYS } from '../constants/constants';
import { getAllDaysInMonth } from '../utils/getAllDaysInMonth';
import { getFirstDayOfMonth } from '../utils/getFirstDayOfMonth';
import { getStateDay } from '../utils/getState';
import { groupDaysByWeeks } from '../utils/groupDaysByWeeks';
import { getDaysAndEmptyDaysUntilMaxDate, getFirstEmptyAndDisabledDays, handleKeyDownMove, handleKeyLeftMove, handleKeyPageDownMove, handleKeyPageUpMove, handleKeyRightMove, handleKeyTabMove, handleKeyUpMove, } from '../utils/handleKeysmoves';
// styles
import { ElementEmptyStyled, ElementStyled, ItemRoveStyled, ListStyled, TableRowStyled, } from './list.styled';
import { ListDaysStateType } from './types/state';
export const List = ({ dataTestId = 'item', hasRange, selectedDate, disabledDates = [], ...props }) => {
const { formatDate, dateHelpers, transformDate } = useUtilsProvider();
const currentMonth = props.currentDate.getMonth() + 1;
const currentYear = props.currentDate.getFullYear();
const today = formatDate(new Date(), NEUTRAL_DATE);
const days = getAllDaysInMonth(currentMonth, currentYear);
const dayStarted = getFirstDayOfMonth(currentYear, currentMonth - 1) - (props.sundayFirst ? 0 : 1);
const dayList = [...new Array(dayStarted >= 0 ? dayStarted : 6), ...days];
const emptyDaysList = dayList.filter(day => day === undefined);
const [positionDateRange, setPositionDateRange] = React.useState(0);
const [ghostDateSelected, setGhostDateSelected] = React.useState(0);
const handleKeyMoveConfig = {
dayList,
maxDate: props.maxDate,
currentDate: props.currentDate,
minDate: props.minDate,
firstEmptyAndDisabledDays: getFirstEmptyAndDisabledDays(emptyDaysList, props.minDate, props.currentDate),
daysAndEmptyDaysUntilMaxDate: getDaysAndEmptyDaysUntilMaxDate(emptyDaysList, props.maxDate, props.currentDate),
};
const config = React.useMemo(() => ({
calendarBlankDaysSize: emptyDaysList.length,
size: dayList.length,
keyDownMove: handleKeyDownMove(handleKeyMoveConfig),
keyUpMove: handleKeyUpMove(handleKeyMoveConfig),
keyRightMove: handleKeyRightMove(handleKeyMoveConfig),
keyLeftMove: handleKeyLeftMove(handleKeyMoveConfig),
keyTabMove: handleKeyTabMove,
keyPageDownMove: handleKeyPageDownMove(handleKeyMoveConfig),
keyPageUpMove: handleKeyPageUpMove(handleKeyMoveConfig),
currentFocusSelected: (selectedDate[0] ? selectedDate[0].getDate() : new Date().getDate()) +
emptyDaysList.length -
1,
}), [emptyDaysList.length, dayList.length, props.currentDate, props.minDate, props.maxDate]);
const [focus, setFocus, listEl] = useRoveFocus(config);
const handleFocus = (index) => {
// when focus is on an empty date at the beginning
if (index) {
if (focus < emptyDaysList.length) {
setFocus(emptyDaysList.length);
}
// when focus is on an empty date at the end
if (focus > dayList.length) {
setFocus(dayList.length - 1);
}
}
return focus === index;
};
const onChangeSelectedDate = (newDate) => {
const [firstDate, secondDate] = selectedDate;
if (hasRange) {
if ((firstDate && secondDate) || (!firstDate && !secondDate)) {
props.setSelectedDate([newDate, 0]);
setPositionDateRange(1);
if (newDate instanceof Date) {
props.onDayClick?.(newDate.getDate().toString());
}
}
else {
props.setSelectedDate([firstDate, newDate]);
setPositionDateRange(0);
if (newDate instanceof Date) {
props.onDayClick?.(newDate.getDate().toString());
}
}
}
else {
props.setSelectedDate([newDate]);
if (newDate instanceof Date) {
props.onDayClick?.(newDate.getDate().toString());
}
}
};
const isGhostSelected = (dayFormatted) => {
if (ghostDateSelected) {
if (ghostDateSelected < selectedDate[0]) {
return dayFormatted > ghostDateSelected && dayFormatted < selectedDate[0];
}
else if (ghostDateSelected > selectedDate[0]) {
return dayFormatted < ghostDateSelected && dayFormatted > selectedDate[0];
}
}
else if (dayFormatted > selectedDate[0]) {
return dayFormatted < selectedDate[1];
}
else if (dayFormatted < selectedDate[0]) {
return dayFormatted > selectedDate[1];
}
return false;
};
const isSelectedToLeft = (dayFormatted) => {
if (!hasRange) {
return false;
}
const selectedIndex = selectedDate?.findIndex(date => date &&
dayFormatted &&
formatDate(date, NEUTRAL_DATE) === formatDate(dayFormatted, NEUTRAL_DATE));
if (selectedIndex === 0 && ghostDateSelected) {
return ghostDateSelected < dayFormatted;
}
else if (selectedIndex === 0) {
return dayFormatted > selectedDate[1];
}
else if (selectedIndex === 1) {
return dayFormatted > selectedDate[0];
}
return false;
};
const isSelectedToRight = (dayFormatted) => {
if (!hasRange) {
return false;
}
const selectedIndex = selectedDate?.findIndex(date => date &&
dayFormatted &&
formatDate(date, NEUTRAL_DATE) === formatDate(dayFormatted, NEUTRAL_DATE));
if (selectedIndex === 0 && ghostDateSelected) {
return ghostDateSelected > dayFormatted;
}
else if (selectedIndex === 0) {
return dayFormatted < selectedDate[1];
}
else if (selectedIndex === 1) {
return dayFormatted < selectedDate[0];
}
return false;
};
const buildDays = () => {
return groupDaysByWeeks(dayList).map((grupo, index) => (_jsx(TableRowStyled, { children: grupo.map((day, dayIndex) => {
const dayFormatted = day ? day : 0;
let isDisabled = day
? dateHelpers.isBefore(day, props.minDate) ||
dateHelpers.isAfter(day, transformDate(formatDate(props.maxDate, NEUTRAL_DATE), NEUTRAL_DATE))
: true;
if (!isDisabled) {
isDisabled = disabledDates.some(disabledDate => day && dateHelpers.isDatesEqual(day, disabledDate, false));
}
const stateDay = getStateDay({
dayFormatted,
isSelectedToLeft,
isSelectedToRight,
isGhostSelected,
selectedDate,
hasRange,
today,
formatDate,
});
return day ? (_jsx(ItemRoveStyled, { "$disabled": isDisabled, "aria-selected": stateDay === ListDaysStateType.SELECTED ? true : undefined, state: stateDay, styles: props.styles, children: _jsx(ItemRove, { ariaDisabled: isDisabled, ariaLabel: formatDate(day, {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric',
}), asElement: ElementStyled, dataTestId: `${dataTestId}-${dayIndex + WEEK_DAYS * index}`, focus: handleFocus(dayIndex + WEEK_DAYS * index), index: dayIndex + WEEK_DAYS * index, type: ButtonType.BUTTON, onMouseOver: () => {
if (positionDateRange === 1) {
setGhostDateSelected(dayFormatted);
}
}, onSelectItem: () => {
!isDisabled && onChangeSelectedDate(dayFormatted);
}, children: day.getDate() }) }, `day${dayIndex + WEEK_DAYS * index}${dayFormatted}`)) : (_jsx(ElementEmptyStyled, { "aria-hidden": true, "aria-label": "empty day" }, `day${dayIndex + WEEK_DAYS * index}${dayFormatted}`));
}) }, index)));
};
return (_jsx(ListStyled, { ref: listEl, styles: props.styles, children: buildDays() }));
};
//# sourceMappingURL=list.js.map