/* @oracle/oraclejet-preact: undefined */
import { jsx, jsxs } from 'preact/jsx-runtime';
import { g as getWeeksInMonth, a as getDaysOfWeekNames, b as getStartOfWeek, c as getDatesInWeek } from './dayUtils-3a0b2d66.js';
import { a as getFormatParse } from './getFormatParse-75ff7ef9.js';
import { w as warn } from './logger-c92f309c.js';
import { d as getIsoDateStr, t as toJSDate, b as checkNoCalendarExtension, f as formatFullCalendarDate, i as isDateOutOfRange } from './calendarDateUtils-ee408a52.js';
import { useMemo } from 'preact/hooks';
import { S as StyledDatePickerButton } from './StyledDatePickerButton-444aa824.js';
import { useCallback } from 'preact/compat';
import { u as useTranslationBundle } from './useTranslationBundle-09302c20.js';
import { u as useFocusableCell, a as useCellNavigation } from './useCellNavigation-bdb3248d.js';
import { dayCellStyles } from './PRIVATE_MonthView/themes/DayCellStyles.css.js';
import { u as useUser } from './useUser-1cd223a9.js';
import { G as Grid } from './Grid-421eb560.js';
import { MonthViewRedwoodTheme } from './PRIVATE_MonthView/themes/redwood/MonthViewTheme.js';
import { u as useComponentTheme } from './useComponentTheme-d2f9e47f.js';
import { monthViewScaleVars } from './PRIVATE_MonthView/themes/MonthViewContract.css.js';
import { weekNumberCellStyles, weekNumberStyles } from './PRIVATE_MonthView/themes/WeekNumberCellStyle.css.js';

/**
 * @license
 * Copyright (c) %FIRST_YEAR% %CURRENT_YEAR%, Oracle and/or its affiliates.
 * The Universal Permissive License (UPL), Version 1.0
 * as shown at https://oss.oracle.com/licenses/upl/
 * @ignore
 */
/**
 * The useDayCell hook returns properties for an individual DayCell. The properties returned should be spread on the StyledDatePickerButton.
 * These include the event handlers for keydown and click.
 */
const useDayCell = ({ date, dayFormatter = defaultDayFormatter, dateFormatter, isAdjacentMonth, isDisabled, isFocusable, isFocused, isHidden, isReadonly, isSelected, isToday, onAction, onNavigation }) => {
    // apply day formatting
    const { state } = dayFormatter(date);
    const isDisabledFormat = state === 'disabled';
    const isRestrictedFormat = state === 'restricted';
    // Focus the day cell with isFocused true when the state updates.
    const buttonProps = useFocusableCell({ isFocusable, isFocused });
    // Override onAction to not call it if disabled, readonly or restricted
    const handleAction = useCallback((payload) => {
        if (isDisabled || isReadonly || isDisabledFormat || isRestrictedFormat)
            return;
        onAction(payload);
    }, [isDisabled, isDisabledFormat, isReadonly, isRestrictedFormat, onAction]);
    const buttonEventHandlers = useCellNavigation({
        navigationMap: {
            ArrowLeft: { ltr: 'previousDay', rtl: 'nextDay' },
            ArrowRight: { ltr: 'nextDay', rtl: 'previousDay' },
            ArrowDown: 'nextWeek',
            ArrowUp: 'previousWeek',
            PageDown: 'nextMonth',
            PageUp: 'previousMonth',
            Home: 'firstDayOfMonth',
            End: 'lastDayOfMonth',
            ShiftPageDown: 'nextYear',
            ShiftPageUp: 'previousYear',
            CtrlAltT: 'today'
        },
        payload: { date },
        onAction: handleAction,
        onNavigation
    });
    // For accessibility, we want a full date.
    const translations = useTranslationBundle('@oracle/oraclejet-preact');
    const today = translations.datePicker_today();
    const selected = translations.datePicker_selected();
    const restricted = translations.datePicker_restricted();
    const dateIsoStr = getIsoDateStr(date.year, date.month, date.day);
    const formattedDate = dateFormatter(dateIsoStr);
    let ariaLabel = isToday ? `${today}, ${formattedDate}` : formattedDate;
    ariaLabel = isRestrictedFormat ? `${ariaLabel}, ${restricted}` : ariaLabel;
    ariaLabel = isSelected ? `${ariaLabel}, ${selected}` : ariaLabel;
    const dayOfMonth = toJSDate(date.year, date.month, date.day).getDate().toString();
    return {
        buttonProps: {
            'aria-label': ariaLabel,
            ...((isHidden || isDisabled || isDisabledFormat || isRestrictedFormat) && {
                'aria-disabled': true
            }),
            isActivable: !(isDisabled || isReadonly || isDisabledFormat || isRestrictedFormat),
            isAdjacentMonth,
            isDimmed: isDisabled || isDisabledFormat,
            isHidden,
            isHoverable: !(isDisabled || isReadonly || isDisabledFormat || isRestrictedFormat),
            isReadonly,
            isSelected,
            isRestricted: isRestrictedFormat,
            isToday,
            label: dayOfMonth,
            ...buttonProps,
            ...buttonEventHandlers
        }
    };
};
/**
 * A default day formatter that always formats as enabled state.
 */
const defaultDayFormatter = () => ({ state: 'enabled' });

/**
 * The DayCell is the cell within the DatePicker's month view that contains the day in the month view.
 * This component will format the date for the aria-label.
 * The DayCell components uses the useDayCell hook to handle the user interactions with the day cell.
 */
const DayCell = (props) => {
    const { buttonProps } = useDayCell(props);
    // buttonProps, e.g., tabIndex, aria-label, onclick, onkeydown and visual states
    return (jsx("div", { role: "gridcell", class: dayCellStyles, children: jsx(StyledDatePickerButton, { ...buttonProps }) }));
};

/**
 * The ISO 8601 definition for week 01 is the week with the first Thursday of the Gregorian year (i.e. of January) in it.
 * https://en.wikipedia.org/wiki/ISO_week_date
 * @param date The first date of the week row to be used to calculate the week number.
 * The date must be a Saturday, Sunday, or Monday. We assume this because the week for
 * all the locales we support start on one of these days.
 * @returns the number of week in the year
 */
const calculateWeekNumber = (date) => {
    const checkDate = toJSDate(date.year, date.month, date.day);
    const dayNumber = checkDate.getUTCDay(); // 0 for Sunday, 1 for Monday, 2 for Tuesday, etc.
    if (dayNumber !== 0 && dayNumber !== 1 && dayNumber !== 6) {
        // This message is for internal JET developers. We should never see this message. In all locales the day of the
        // week starts on Sunday, Monday or Saturday.
        warn(`calculateWeekNumber's date property's getUTCDay() is assumed to be 0 (Sunday), 1 (Monday) or 6 (Saturday)
      since that is the first day of the week for the locale's JET supports.`);
    }
    // For ISO week, we set the start of the week to Monday
    if (dayNumber !== 1) {
        // If it is already Monday, do nothing.
        // If it is Sunday (0), add 1 to move it up to Monday.
        // If it is Saturday (6), move it up two days to Monday.
        checkDate.setUTCDate(checkDate.getUTCDate() + (dayNumber === 0 ? 1 : 2));
    }
    // Find Thursday (day value of 4) of this week. Since we know checkDate at this point is a Monday,
    // we move it up 3 days.
    checkDate.setUTCDate(checkDate.getUTCDate() + 3);
    // Create the start of the year date
    const janFirst = toJSDate(checkDate.getUTCFullYear(), 1, 1);
    return Math.floor(Math.round((checkDate.getTime() - janFirst.getTime()) / 86400000) / 7) + 1;
};
/**
 * The WeekNumberCell is the cell at the start of a week's row within the DatePicker's
 * month view that contains the week's number within the year. This displays when
 * the DatePicker's 'weekDisplay' prop is set to 'number'.
 * This component will format the week number for the aria-label.
 */
const WeekNumberCell = ({ startDateOfWeek }) => {
    const weekNumber = calculateWeekNumber(startDateOfWeek);
    const translations = useTranslationBundle('@oracle/oraclejet-preact');
    return (jsx("div", { "aria-label": translations.datePicker_weekNum({ NUM: String(weekNumber) }), class: weekNumberCellStyles, role: "rowheader", children: jsx("span", { class: weekNumberStyles, children: weekNumber }) }));
};

/**
 * A MonthView is a month interface that allows users to select a single date. The MonthView is the week day header
 * abbreviations and the days of the month. A MonthView is used inside of a DatePicker
 * along with the DatePickerHeader and the MonthGridView and YearGridView.
 */
const MonthView = ({ dayFormatter, daysOutsideMonth = 'hidden', isReadonly = false, max, min, onAction, onNavigation, selectedDate, focusableDate, isFocused = false, testId, todaysDate, weekDisplay = 'none' }) => {
    const { locale } = useUser();
    const weeksInMonth = getWeeksInMonth(focusableDate.year, focusableDate.month, locale);
    const { baseTheme, styles } = useComponentTheme(MonthViewRedwoodTheme, {});
    const isWeekNumberDisplayed = weekDisplay === 'number';
    const gridTemplateColumns = `repeat(${isWeekNumberDisplayed ? 8 : 7}, 1fr)`;
    const dateFormatter = useMemo(() => {
        checkNoCalendarExtension(locale);
        const dateFormatOptions = {
            locale,
            dateStyle: 'full'
        };
        const { format } = getFormatParse(dateFormatOptions);
        return format;
    }, [locale]);
    const renderMonthViewHeaderRow = () => {
        const weekDays = getDaysOfWeekNames(locale, 'short');
        return (jsx("div", { class: styles.sticky, children: jsxs(Grid, { role: "row", "aria-hidden": "true", gridTemplateColumns: gridTemplateColumns, gap: monthViewScaleVars.columnGap, children: [isWeekNumberDisplayed && jsx("div", { role: "presentation" }), weekDays.map((day) => (jsx("div", { role: "columnheader", class: styles.dayOfTheWeek, children: jsx("span", { children: day }) })))] }) }));
    };
    const renderMonthView = () => {
        const calendarGrid = [];
        for (let weekIndex = 0; weekIndex < weeksInMonth; weekIndex++) {
            const startDateOfWeek = getStartOfWeek(focusableDate.year, focusableDate.month, 1, locale);
            const weekDates = getDatesInWeek(weekIndex, startDateOfWeek.year, startDateOfWeek.month, startDateOfWeek.day);
            const weekCells = weekDates.map((dayCellDate) => {
                // This figures out the visual state of the DayCell.
                const isDisabled = isDateOutOfRange(dayCellDate, min, max);
                // Even if the selected date is out of range, the UX design shows it as selected.
                const isSelected = selectedDate ? isSameDate(dayCellDate, selectedDate) : false;
                const isToday = isSameDate(dayCellDate, todaysDate);
                const isFocusable = isSameDate(dayCellDate, focusableDate);
                const isAdjacentMonth = isOutOfMonth(dayCellDate, focusableDate);
                const isHidden = isAdjacentMonth && daysOutsideMonth === 'hidden';
                return (jsx(DayCell, { date: dayCellDate, dateFormatter: dateFormatter, dayFormatter: dayFormatter, isAdjacentMonth: isAdjacentMonth, isDisabled: isDisabled, isFocusable: isFocusable, isFocused: isFocusable && isFocused, isHidden: isHidden, isReadonly: isReadonly, isSelected: isSelected, isToday: isToday, onAction: onAction, onNavigation: onNavigation }, `${dayCellDate.year}-${dayCellDate.month}-${dayCellDate.day}`));
            });
            calendarGrid.push(jsxs(Grid, { role: "row", gridTemplateColumns: gridTemplateColumns, gap: monthViewScaleVars.columnGap, children: [isWeekNumberDisplayed && jsx(WeekNumberCell, { startDateOfWeek: weekDates[0] }), weekCells] }, weekIndex));
        }
        return calendarGrid;
    };
    const monthViewAriaLabel = formatFullCalendarDate(locale, focusableDate, 'month');
    return (jsx("div", { class: baseTheme, children: jsxs(Grid, { gap: monthViewScaleVars.rowGap, "aria-label": monthViewAriaLabel, role: "grid", testId: testId, children: [renderMonthViewHeaderRow(), renderMonthView()] }) }));
};
function isSameDate(date1, date2) {
    return date1.year === date2.year && date1.month === date2.month && date1.day === date2.day;
}
function isOutOfMonth(date1, currentMonthDate) {
    return date1.month !== currentMonthDate.month;
}

export { MonthView as M };
//# sourceMappingURL=MonthView-21b2163a.js.map
