diff --git a/apps/vr-tests-react-components/package.json b/apps/vr-tests-react-components/package.json index d98e63caf1027d..5e2b6c76975d84 100644 --- a/apps/vr-tests-react-components/package.json +++ b/apps/vr-tests-react-components/package.json @@ -25,6 +25,7 @@ "@fluentui/react-badge": "*", "@fluentui/react-breadcrumb-preview": "*", "@fluentui/react-button": "*", + "@fluentui/react-calendar-compat": "*", "@fluentui/react-card": "*", "@fluentui/react-checkbox": "*", "@fluentui/react-combobox": "*", diff --git a/apps/vr-tests-react-components/src/stories/DatePickerCompat.stories.tsx b/apps/vr-tests-react-components/src/stories/DatePickerCompat.stories.tsx index d4e49f10299288..4b657e430a8191 100644 --- a/apps/vr-tests-react-components/src/stories/DatePickerCompat.stories.tsx +++ b/apps/vr-tests-react-components/src/stories/DatePickerCompat.stories.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { Steps, StoryWright } from 'storywright'; -import { DatePicker as DatePickerBase, DateRangeType } from '@fluentui/react-datepicker-compat'; +import { DatePicker as DatePickerBase } from '@fluentui/react-datepicker-compat'; +import { DateRangeType } from '@fluentui/react-calendar-compat'; import { Field } from '@fluentui/react-field'; import { storiesOf } from '@storybook/react'; import { TestWrapperDecorator } from '../utilities/TestWrapperDecorator'; diff --git a/change/@fluentui-react-datepicker-compat-881179ec-abf2-4f4f-8a61-1b88fd0220e5.json b/change/@fluentui-react-datepicker-compat-881179ec-abf2-4f4f-8a61-1b88fd0220e5.json new file mode 100644 index 00000000000000..070fa76e552328 --- /dev/null +++ b/change/@fluentui-react-datepicker-compat-881179ec-abf2-4f4f-8a61-1b88fd0220e5.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "BREAKING: Update Datepicker to use react-calendar-compat and remove Calendar related exports.", + "packageName": "@fluentui/react-datepicker-compat", + "email": "esteban.230@hotmail.com", + "dependentChangeType": "patch" +} diff --git a/packages/react-components/react-datepicker-compat/etc/react-datepicker-compat.api.md b/packages/react-components/react-datepicker-compat/etc/react-datepicker-compat.api.md index 7efe5bbd809d04..f9544aa22033eb 100644 --- a/packages/react-components/react-datepicker-compat/etc/react-datepicker-compat.api.md +++ b/packages/react-components/react-datepicker-compat/etc/react-datepicker-compat.api.md @@ -6,8 +6,13 @@ /// +import type { CalendarProps } from '@fluentui/react-calendar-compat'; +import type { CalendarStrings } from '@fluentui/react-calendar-compat'; import type { ComponentProps } from '@fluentui/react-utilities'; import type { ComponentState } from '@fluentui/react-utilities'; +import type { DateFormatting } from '@fluentui/react-calendar-compat'; +import { DayOfWeek } from '@fluentui/react-calendar-compat'; +import { FirstWeekOfYear } from '@fluentui/react-calendar-compat'; import type { ForwardRefComponent } from '@fluentui/react-utilities'; import { Input } from '@fluentui/react-input'; import type { PortalProps } from '@fluentui/react-portal'; @@ -16,137 +21,6 @@ import * as React_2 from 'react'; import type { Slot } from '@fluentui/react-utilities'; import type { SlotClassNames } from '@fluentui/react-utilities'; -// @public -export function addDays(date: Date, days: number): Date; - -// @public -export function addMonths(date: Date, months: number): Date; - -// @public -export function addWeeks(date: Date, weeks: number): Date; - -// @public -export function addYears(date: Date, years: number): Date; - -// @public (undocumented) -export enum AnimationDirection { - Horizontal = 0, - Vertical = 1 -} - -// @public (undocumented) -export interface CalendarDayProps extends CalendarDayGridProps { - allFocusable?: boolean; - className?: string; - componentRef?: React_2.RefObject; - dateTimeFormatter: DateFormatting; - maxDate?: Date; - minDate?: Date; - navigatedDate: Date; - onDismiss?: () => void; - onHeaderSelect?: () => void; - onNavigateDate: (date: Date, focusOnNavigatedDay: boolean) => void; - restrictedDates?: Date[]; - showCloseButton?: boolean; - showSixWeeksByDefault?: boolean; - showWeekNumbers?: boolean; - strings: CalendarStrings; -} - -// @public (undocumented) -export interface CalendarMonthProps { - allFocusable?: boolean; - animationDirection?: AnimationDirection; - className?: string; - componentRef?: React_2.RefObject; - dateTimeFormatter?: DateFormatting; - highlightCurrentMonth?: boolean; - highlightSelectedMonth?: boolean; - maxDate?: Date; - minDate?: Date; - navigatedDate: Date; - onHeaderSelect?: () => void; - onNavigateDate: (date: Date, focusOnNavigatedDay: boolean) => void; - onSelectDate?: (date: Date, selectedDateRangeArray?: Date[]) => void; - selectedDate: Date; - strings: CalendarStrings; - today?: Date; - yearPickerHidden?: boolean; -} - -// @public (undocumented) -export interface CalendarProps extends React_2.RefAttributes { - allFocusable?: boolean; - calendarDayProps?: Partial; - calendarMonthProps?: Partial; - className?: string; - componentRef?: React_2.RefObject; - dateRangeType?: DateRangeType; - dateTimeFormatter?: DateFormatting; - firstDayOfWeek?: DayOfWeek; - firstWeekOfYear?: FirstWeekOfYear; - highlightCurrentMonth?: boolean; - highlightSelectedMonth?: boolean; - id?: string; - isDayPickerVisible?: boolean; - isMonthPickerVisible?: boolean; - maxDate?: Date; - minDate?: Date; - onDismiss?: () => void; - onSelectDate?: (date: Date, selectedDateRangeArray?: Date[]) => void; - restrictedDates?: Date[]; - showCloseButton?: boolean; - showGoToToday?: boolean; - showMonthPickerAsOverlay?: boolean; - showSixWeeksByDefault?: boolean; - showWeekNumbers?: boolean; - strings?: CalendarStrings; - today?: Date; - value?: Date; - workWeekDays?: DayOfWeek[]; -} - -// @public (undocumented) -export interface CalendarStrings extends DateGridStrings { - closeButtonAriaLabel?: string; - dayMarkedAriaLabel?: string; - goToToday: string; - monthPickerHeaderAriaLabel?: string; - nextMonthAriaLabel?: string; - nextYearAriaLabel?: string; - nextYearRangeAriaLabel?: string; - prevMonthAriaLabel?: string; - prevYearAriaLabel?: string; - prevYearRangeAriaLabel?: string; - selectedDateFormatString?: string; - todayDateFormatString?: string; - weekNumberFormatString?: string; - yearPickerHeaderAriaLabel?: string; -} - -// @public -export function compareDatePart(date1: Date, date2: Date): Number; - -// @public -export function compareDates(date1: Date, date2: Date): boolean; - -// @public (undocumented) -export interface DateFormatting { - formatDay: (date: Date) => string; - formatMonth: (date: Date, strings: DateGridStrings) => string; - formatMonthDayYear: (date: Date, strings: DateGridStrings) => string; - formatMonthYear: (date: Date, strings: DateGridStrings) => string; - formatYear: (date: Date) => string; -} - -// @public (undocumented) -export interface DateGridStrings { - days: string[]; - months: string[]; - shortDays: string[]; - shortMonths: string[]; -} - // @public (undocumented) export const DatePicker: ForwardRefComponent; @@ -199,156 +73,15 @@ export type DatePickerValidationResultData = { error?: DatePickerErrorType; }; -// @public -export enum DateRangeType { - // (undocumented) - Day = 0, - // (undocumented) - Month = 2, - // (undocumented) - Week = 1, - // (undocumented) - WorkWeek = 3 -} - -// @public -export enum DayOfWeek { - // (undocumented) - Friday = 5, - // (undocumented) - Monday = 1, - // (undocumented) - Saturday = 6, - // (undocumented) - Sunday = 0, - // (undocumented) - Thursday = 4, - // (undocumented) - Tuesday = 2, - // (undocumented) - Wednesday = 3 -} - -// @public (undocumented) -export const DAYS_IN_WEEK = 7; - // @public (undocumented) export const defaultDatePickerErrorStrings: Record; // @public (undocumented) export const defaultDatePickerStrings: CalendarStrings; -// @public -export enum FirstWeekOfYear { - // (undocumented) - FirstDay = 0, - // (undocumented) - FirstFourDayWeek = 2, - // (undocumented) - FirstFullWeek = 1 -} - -// @public -export function getDatePartHashValue(date: Date): number; - -// @public -export function getDateRangeArray(date: Date, dateRangeType: DateRangeType, firstDayOfWeek: DayOfWeek, workWeekDays?: DayOfWeek[], daysToSelectInDayView?: number): Date[]; - -// @public -export function getEndDateOfWeek(date: Date, firstDayOfWeek: DayOfWeek): Date; - -// @public -export function getMonthEnd(date: Date): Date; - -// @public -export function getMonthStart(date: Date): Date; - -// @public -export function getStartDateOfWeek(date: Date, firstDayOfWeek: DayOfWeek): Date; - -// @public -export function getWeekNumber(date: Date, firstDayOfWeek: DayOfWeek, firstWeekOfYear: FirstWeekOfYear): number; - -// @public -export function getWeekNumbersInMonth(weeksInMonth: number, firstDayOfWeek: DayOfWeek, firstWeekOfYear: FirstWeekOfYear, navigatedDate: Date): number[]; - -// @public -export function getYearEnd(date: Date): Date; - -// @public -export function getYearStart(date: Date): Date; - -// @public (undocumented) -export interface ICalendar { - focus: () => void; -} - -// @public (undocumented) -export interface ICalendarDay { - // (undocumented) - focus(): void; -} - -// @public (undocumented) -export interface ICalendarMonth { - // (undocumented) - focus(): void; -} - -// @public -export function isInDateRangeArray(date: Date, dateRange: Date[]): boolean; - -// @public -export enum MonthOfYear { - // (undocumented) - April = 3, - // (undocumented) - August = 7, - // (undocumented) - December = 11, - // (undocumented) - February = 1, - // (undocumented) - January = 0, - // (undocumented) - July = 6, - // (undocumented) - June = 5, - // (undocumented) - March = 2, - // (undocumented) - May = 4, - // (undocumented) - November = 10, - // (undocumented) - October = 9, - // (undocumented) - September = 8 -} - // @public export const renderDatePicker_unstable: (state: DatePickerState) => JSX.Element; -// @public -export function setMonth(date: Date, month: number): Date; - -// @public (undocumented) -export const TimeConstants: { - MillisecondsInOneDay: number; - MillisecondsIn1Sec: number; - MillisecondsIn1Min: number; - MillisecondsIn30Mins: number; - MillisecondsIn1Hour: number; - MinutesInOneDay: number; - MinutesInOneHour: number; - DaysInOneWeek: number; - MonthInOneYear: number; - HoursInOneDay: number; - SecondsInOneMinute: number; - OffsetTo24HourFormat: number; - TimeFormatRegex: RegExp; -}; - // @public export const useDatePicker_unstable: (props: DatePickerProps, ref: React_2.Ref) => DatePickerState; diff --git a/packages/react-components/react-datepicker-compat/package.json b/packages/react-components/react-datepicker-compat/package.json index e3b736a1b2b6ae..27bd2f4f43d332 100644 --- a/packages/react-components/react-datepicker-compat/package.json +++ b/packages/react-components/react-datepicker-compat/package.json @@ -36,6 +36,7 @@ }, "dependencies": { "@fluentui/keyboard-keys": "^9.0.6", + "@fluentui/react-calendar-compat": "^0.0.1", "@fluentui/react-field": "^9.1.38", "@fluentui/react-icons": "^2.0.217", "@fluentui/react-input": "^9.4.48", diff --git a/packages/react-components/react-datepicker-compat/src/Calendar.ts b/packages/react-components/react-datepicker-compat/src/Calendar.ts deleted file mode 100644 index 44c674c047ffe5..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/Calendar.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './components/Calendar/index'; diff --git a/packages/react-components/react-datepicker-compat/src/CalendarDay.ts b/packages/react-components/react-datepicker-compat/src/CalendarDay.ts deleted file mode 100644 index 59f69692a93c58..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/CalendarDay.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './components/CalendarDay/index'; diff --git a/packages/react-components/react-datepicker-compat/src/CalendarDayGrid.ts b/packages/react-components/react-datepicker-compat/src/CalendarDayGrid.ts deleted file mode 100644 index 2beebf459bc992..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/CalendarDayGrid.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './components/CalendarDayGrid/index'; diff --git a/packages/react-components/react-datepicker-compat/src/CalendarMonth.ts b/packages/react-components/react-datepicker-compat/src/CalendarMonth.ts deleted file mode 100644 index 9f28941cc82d04..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/CalendarMonth.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './components/CalendarMonth/index'; diff --git a/packages/react-components/react-datepicker-compat/src/CalendarPicker.ts b/packages/react-components/react-datepicker-compat/src/CalendarPicker.ts deleted file mode 100644 index cb4cb2f81147ce..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/CalendarPicker.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './components/CalendarPicker/index'; diff --git a/packages/react-components/react-datepicker-compat/src/CalendarYear.ts b/packages/react-components/react-datepicker-compat/src/CalendarYear.ts deleted file mode 100644 index 4f0d02bcc054a7..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/CalendarYear.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './components/CalendarYear/index'; diff --git a/packages/react-components/react-datepicker-compat/src/components/Calendar/Calendar.test.tsx b/packages/react-components/react-datepicker-compat/src/components/Calendar/Calendar.test.tsx deleted file mode 100644 index aeedbf54a813df..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/Calendar/Calendar.test.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { Calendar } from './Calendar'; -import { isConformant } from '../../testing/isConformant'; - -describe('Calendar', () => { - isConformant({ - Component: Calendar, - displayName: 'Calendar', - disabledTests: [ - // compat components that are closer to their v8 counterparts do not adhere to this test - 'consistent-callback-args', - // Calendar is not exported at the top level since it's an internal component - 'exported-top-level', - // Calendar classnames are not exported since they are internal and are used differently compared to how v9 - // uses classnames - 'component-has-static-classnames-object', - ], - }); -}); diff --git a/packages/react-components/react-datepicker-compat/src/components/Calendar/Calendar.tsx b/packages/react-components/react-datepicker-compat/src/components/Calendar/Calendar.tsx deleted file mode 100644 index 0d3cc43404a39e..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/Calendar/Calendar.tsx +++ /dev/null @@ -1,407 +0,0 @@ -import * as React from 'react'; -import { Backspace, Enter, Escape, PageDown, PageUp, Space } from '@fluentui/keyboard-keys'; -import { useControllableState } from '@fluentui/react-utilities'; -import { - addMonths, - addYears, - DateRangeType, - DayOfWeek, - DEFAULT_CALENDAR_STRINGS, - DEFAULT_DATE_FORMATTING, - FirstWeekOfYear, - focusAsync, - getWindow, -} from '../../utils'; -import { CalendarDay } from '../CalendarDay/CalendarDay'; -import { CalendarMonth } from '../CalendarMonth/CalendarMonth'; -import { useCalendarStyles_unstable } from './useCalendarStyles.styles'; -import type { ICalendarDay } from '../CalendarDay/CalendarDay.types'; -import type { ICalendarMonth } from '../CalendarMonth/CalendarMonth.types'; -import type { CalendarProps } from './Calendar.types'; - -const MIN_SIZE_FORCE_OVERLAY = 440; - -const defaultWorkWeekDays: DayOfWeek[] = [ - DayOfWeek.Monday, - DayOfWeek.Tuesday, - DayOfWeek.Wednesday, - DayOfWeek.Thursday, - DayOfWeek.Friday, -]; - -function useDateState({ value, today = new Date(), onSelectDate }: CalendarProps) { - /** The currently selected date in the calendar */ - const [selectedDate, setSelectedDate] = useControllableState({ - defaultState: today, - initialState: today, - state: value, - }); - - /** The currently focused date in the day picker, but not necessarily selected */ - const [navigatedDay = today, setNavigatedDay] = React.useState(value); - - /** The currently focused date in the month picker, but not necessarily selected */ - const [navigatedMonth = today, setNavigatedMonth] = React.useState(value); - - /** If using a controlled value, when that value changes, navigate to that date */ - const [lastSelectedDate = today, setLastSelectedDate] = React.useState(value); - if (value && lastSelectedDate.valueOf() !== value.valueOf()) { - setNavigatedDay(value); - setNavigatedMonth(value); - setLastSelectedDate(value); - } - - const navigateMonth = (date: Date) => { - setNavigatedMonth(date); - }; - - const navigateDay = (date: Date) => { - setNavigatedMonth(date); - setNavigatedDay(date); - }; - - const onDateSelected = (date: Date, selectedDateRangeArray?: Date[]) => { - setNavigatedMonth(date); - setNavigatedDay(date); - setSelectedDate(date); - onSelectDate?.(date, selectedDateRangeArray); - }; - - return [selectedDate, navigatedDay, navigatedMonth, onDateSelected, navigateDay, navigateMonth] as const; -} - -function useVisibilityState({ - isDayPickerVisible: isDayPickerVisibleProp, - isMonthPickerVisible: isMonthPickerVisibleProp, - showMonthPickerAsOverlay, -}: CalendarProps) { - /** State used to show/hide month picker */ - const [isMonthPickerVisible, setIsMonthPickerVisible] = useControllableState({ - defaultState: false, - initialState: true, - state: getShowMonthPickerAsOverlay({ isDayPickerVisible: isDayPickerVisibleProp, showMonthPickerAsOverlay }) - ? undefined - : isMonthPickerVisibleProp, - }); - /** State used to show/hide day picker */ - const [isDayPickerVisible, setIsDayPickerVisible] = useControllableState({ - defaultState: true, - initialState: true, - state: getShowMonthPickerAsOverlay({ isDayPickerVisible: isDayPickerVisibleProp, showMonthPickerAsOverlay }) - ? undefined - : isDayPickerVisibleProp, - }); - - const toggleDayMonthPickerVisibility = () => { - setIsMonthPickerVisible(!isMonthPickerVisible); - setIsDayPickerVisible(!isDayPickerVisible); - }; - - return [isMonthPickerVisible, isDayPickerVisible, toggleDayMonthPickerVisibility] as const; -} - -function useFocusLogic({ componentRef }: CalendarProps, isDayPickerVisible: boolean, isMonthPickerVisible: boolean) { - const dayPicker = React.useRef(null); - const monthPicker = React.useRef(null); - const focusOnUpdate = React.useRef(false); - - const focus = React.useCallback(() => { - if (isDayPickerVisible && dayPicker.current) { - focusAsync(dayPicker.current); - } else if (isMonthPickerVisible && monthPicker.current) { - focusAsync(monthPicker.current); - } - }, [isDayPickerVisible, isMonthPickerVisible]); - - React.useImperativeHandle(componentRef, () => ({ focus }), [focus]); - - React.useEffect(() => { - if (focusOnUpdate.current) { - focus(); - focusOnUpdate.current = false; - } - }); - - const focusOnNextUpdate = () => { - focusOnUpdate.current = true; - }; - - return [dayPicker, monthPicker, focusOnNextUpdate] as const; -} - -/** - * @internal - */ -export const Calendar: React.FunctionComponent = React.forwardRef( - (props, forwardedRef) => { - const { - allFocusable = false, - calendarDayProps, - calendarMonthProps, - className, - componentRef, - dateRangeType = DateRangeType.Day, - dateTimeFormatter = DEFAULT_DATE_FORMATTING, - firstDayOfWeek = DayOfWeek.Sunday, - firstWeekOfYear = FirstWeekOfYear.FirstDay, - highlightCurrentMonth = false, - highlightSelectedMonth = false, - id, - isDayPickerVisible: isDayPickerVisibleProp = true, - isMonthPickerVisible: isMonthPickerVisibleProp = true, - maxDate, - minDate, - onDismiss, - onSelectDate, - restrictedDates, - showCloseButton = false, - showGoToToday = true, - showMonthPickerAsOverlay: showMonthPickerAsOverlayProp = false, - showSixWeeksByDefault = false, - showWeekNumbers = false, - strings = DEFAULT_CALENDAR_STRINGS, - today = new Date(), - value, - workWeekDays = defaultWorkWeekDays, - } = props; - - const [selectedDate, navigatedDay, navigatedMonth, onDateSelected, navigateDay, navigateMonth] = useDateState({ - onSelectDate, - value, - today, - }); - const [isMonthPickerVisible, isDayPickerVisible, toggleDayMonthPickerVisibility] = useVisibilityState({ - isDayPickerVisible: isDayPickerVisibleProp, - isMonthPickerVisible: isMonthPickerVisibleProp, - showMonthPickerAsOverlay: showMonthPickerAsOverlayProp, - }); - const [dayPicker, monthPicker, focusOnNextUpdate] = useFocusLogic( - { componentRef }, - isDayPickerVisible, - isMonthPickerVisible, - ); - - const renderGoToTodayButton = () => { - let goTodayEnabled = showGoToToday; - - if (goTodayEnabled && today) { - goTodayEnabled = - navigatedDay.getFullYear() !== today.getFullYear() || - navigatedDay.getMonth() !== today.getMonth() || - navigatedMonth.getFullYear() !== today.getFullYear() || - navigatedMonth.getMonth() !== today.getMonth(); - } - - return ( - showGoToToday && ( - - ) - ); - }; - - const onNavigateDayDate = (date: Date, focusOnNavigatedDay: boolean): void => { - navigateDay(date); - if (focusOnNavigatedDay) { - focusOnNextUpdate(); - } - }; - - const onNavigateMonthDate = (date: Date, focusOnNavigatedDay: boolean): void => { - if (focusOnNavigatedDay) { - focusOnNextUpdate(); - } - - if (!focusOnNavigatedDay) { - navigateMonth(date); - return; - } - - if (monthPickerOnly) { - onDateSelected(date); - } - - navigateDay(date); - }; - - const onHeaderSelect = getShowMonthPickerAsOverlay({ - isDayPickerVisible: isDayPickerVisibleProp, - showMonthPickerAsOverlay: showMonthPickerAsOverlayProp, - }) - ? (): void => { - toggleDayMonthPickerVisibility(); - - focusOnNextUpdate(); - } - : undefined; - - const onGotoToday = (): void => { - navigateDay(today!); - focusOnNextUpdate(); - }; - - const onButtonKeyDown = (callback: () => void): ((ev: React.KeyboardEvent) => void) => { - return (ev: React.KeyboardEvent) => { - switch (ev.key) { - case Enter: - case Space: - callback(); - break; - } - }; - }; - - const onDatePickerPopupKeyDown = (ev: React.KeyboardEvent): void => { - switch (ev.key) { - case Enter: - ev.preventDefault(); - break; - - case Backspace: - ev.preventDefault(); - break; - - case Escape: - ev.stopPropagation(); - onDismiss?.(); - break; - - case PageUp: - if (ev.ctrlKey) { - // go to next year - navigateDay(addYears(navigatedDay, 1)); - } else { - // go to next month - navigateDay(addMonths(navigatedDay, 1)); - } - ev.preventDefault(); - break; - case PageDown: - if (ev.ctrlKey) { - // go to previous year - navigateDay(addYears(navigatedDay, -1)); - } else { - // go to previous month - navigateDay(addMonths(navigatedDay, -1)); - } - ev.preventDefault(); - break; - default: - break; - } - }; - const showMonthPickerAsOverlay = getShowMonthPickerAsOverlay({ - isDayPickerVisible: isDayPickerVisibleProp, - showMonthPickerAsOverlay: showMonthPickerAsOverlayProp, - }); - - const monthPickerOnly = !showMonthPickerAsOverlay && !isDayPickerVisible; - - const classes = useCalendarStyles_unstable({ - className, - isDayPickerVisible, - isMonthPickerVisible, - showWeekNumbers, - }); - - let todayDateString: string = ''; - let selectedDateString: string = ''; - if (dateTimeFormatter && strings!.todayDateFormatString) { - todayDateString = strings!.todayDateFormatString.replace( - '{0}', - dateTimeFormatter.formatMonthDayYear(today, strings!), - ); - } - if (dateTimeFormatter && strings!.selectedDateFormatString) { - const dateStringFormatter = monthPickerOnly - ? dateTimeFormatter.formatMonthYear - : dateTimeFormatter.formatMonthDayYear; - selectedDateString = strings!.selectedDateFormatString.replace( - '{0}', - dateStringFormatter(selectedDate, strings!), - ); - } - const selectionAndTodayString = selectedDateString + ', ' + todayDateString; - - return ( -
-
- {selectedDateString} -
- {isDayPickerVisible && ( - - )} - {isDayPickerVisible && isMonthPickerVisible &&
} - {isMonthPickerVisible ? ( -
- - {renderGoToTodayButton()} -
- ) : ( - renderGoToTodayButton() - )} -
- ); - }, -); -Calendar.displayName = 'Calendar'; - -function getShowMonthPickerAsOverlay({ isDayPickerVisible, showMonthPickerAsOverlay }: CalendarProps) { - const win = getWindow(); - return showMonthPickerAsOverlay || (isDayPickerVisible && win && win.innerWidth <= MIN_SIZE_FORCE_OVERLAY); -} diff --git a/packages/react-components/react-datepicker-compat/src/components/Calendar/Calendar.types.ts b/packages/react-components/react-datepicker-compat/src/components/Calendar/Calendar.types.ts deleted file mode 100644 index a090d74c14a912..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/Calendar/Calendar.types.ts +++ /dev/null @@ -1,251 +0,0 @@ -import * as React from 'react'; -import type { CalendarStrings, DateFormatting, DateRangeType, DayOfWeek, FirstWeekOfYear } from '../../utils'; -import type { CalendarDayProps } from '../CalendarDay/CalendarDay.types'; -import type { CalendarMonthProps } from '../CalendarMonth/CalendarMonth.types'; - -// eslint-disable-next-line @typescript-eslint/naming-convention -export interface ICalendar { - /** Sets focus to the selected date. */ - focus: () => void; -} - -export interface CalendarProps extends React.RefAttributes { - /** - * Optional callback to access the ICalendar interface. Use this instead of ref for accessing - * the public methods and properties of the component. - */ - componentRef?: React.RefObject; - - /** - * Customized props for the calendar day - */ - calendarDayProps?: Partial; - - /** - * Customized props for the calendar month - */ - calendarMonthProps?: Partial; - - /** - * Optional class name to add to the root element. - */ - className?: string; - - /** - * Callback for when a date is selected - * @param date - The date the user selected - * @param selectedDateRangeArray - The resultant list of dates that are selected based on the date range type set - * for the component. - */ - onSelectDate?: (date: Date, selectedDateRangeArray?: Date[]) => void; - - /** - * Callback for when calendar is closed - */ - onDismiss?: () => void; - - /** - * ID for the calendar - */ - id?: string; - - /** - * Default value of the Calendar, if any - */ - value?: Date; - - /** - * Value of today. If unspecified, current time in client machine will be used. - */ - today?: Date; - - /** - * The date range type indicating how many days should be selected as the user - * selects days - * @default DateRangeType.Day - */ - dateRangeType?: DateRangeType; - - /** - * The first day of the week for your locale. - * @default DayOfWeek.Sunday - */ - firstDayOfWeek?: DayOfWeek; - - /** - * Defines when the first week of the year should start. - * @default FirstWeekOfYear.FirstDay - */ - firstWeekOfYear?: FirstWeekOfYear; - - /** - * Whether the month picker is shown beside the day picker or hidden. - * @default true - */ - isMonthPickerVisible?: boolean; - - /** - * Whether the day picker is shown beside the month picker or hidden. - * @default true - */ - isDayPickerVisible?: boolean; - - /** - * Show month picker on top of date picker when visible. - * @default false - */ - showMonthPickerAsOverlay?: boolean; - - /** - * Whether the "Go to today" link should be shown or not - */ - showGoToToday?: boolean; - - /** - * Whether the calendar should show the week number (weeks 1 to 53) before each week row - * @default false - */ - showWeekNumbers?: boolean; - - /** - * Localized strings to use in the Calendar - */ - strings?: CalendarStrings; - - /** - * Apply additional formatting to dates, for example localized date formatting. - */ - dateTimeFormatter?: DateFormatting; - - /** - * If set the Calendar will not allow navigation to or selection of a date earlier than this value. - */ - minDate?: Date; - - /** - * If set the Calendar will not allow navigation to or selection of a date later than this value. - */ - maxDate?: Date; - - /** - * If set the Calendar will not allow selection of dates in this array. - */ - restrictedDates?: Date[]; - - /** - * Whether the calendar should show 6 weeks by default. - * @default false - */ - showSixWeeksByDefault?: boolean; - - /** - * The days that are selectable when `dateRangeType` is `WorkWeek`. - * If `dateRangeType` is not `WorkWeek` this property does nothing. - * @default [Monday,Tuesday,Wednesday,Thursday,Friday] - */ - workWeekDays?: DayOfWeek[]; - - /** - * Whether the month picker should highlight the current month - * @default false - */ - highlightCurrentMonth?: boolean; - - /** - * Whether the month picker should highlight the selected month - * @default false - */ - highlightSelectedMonth?: boolean; - - /** - * Whether the close button should be shown or not - * @default false - */ - showCloseButton?: boolean; - - /** - * Allows all dates and buttons to be focused, including disabled ones - * @default false - */ - allFocusable?: boolean; -} - -/** - * @internal - */ -export interface CalendarStyleProps { - /** - * Custom CSS class for the calendar. - */ - className?: string; - - /** - * Whether the month picker is visible - */ - isMonthPickerVisible?: boolean; - - /** - * Whether the day picker is visible - */ - isDayPickerVisible?: boolean; - - /** - * Whether only month picker is shown - */ - monthPickerOnly?: boolean; - - /** - * Whether the month picker is overlaid on the day picker - */ - showMonthPickerAsOverlay?: boolean; - - /** - * @deprecated Use `overlaidWithButton` - */ - overlayedWithButton?: boolean; - - /** - * Whether the month and day picker are overlaid and the 'go to today' button is shown - */ - overlaidWithButton?: boolean; - - /** - * Whether the go to today button is shown - */ - showGoToToday?: boolean; - - /** - * Whether the week numbers are shown - */ - showWeekNumbers?: boolean; -} - -/** - * @internal - */ -export interface CalendarStyles { - /** - * Style for the root element. - */ - root: string; - - divider: string; - - goTodayButton: string; - - monthPickerWrapper: string; - - liveRegion: string; -} - -export enum AnimationDirection { - /** - * Grid will transition out and in horizontally - */ - Horizontal, - - /** - * Grid will transition out and in vertically - */ - Vertical, -} diff --git a/packages/react-components/react-datepicker-compat/src/components/Calendar/defaults.ts b/packages/react-components/react-datepicker-compat/src/components/Calendar/defaults.ts deleted file mode 100644 index 41c195df317311..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/Calendar/defaults.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { DEFAULT_CALENDAR_STRINGS } from '../../utils'; -import type { CalendarStrings } from '../../utils'; - -export const defaultCalendarStrings: CalendarStrings = DEFAULT_CALENDAR_STRINGS; diff --git a/packages/react-components/react-datepicker-compat/src/components/Calendar/index.ts b/packages/react-components/react-datepicker-compat/src/components/Calendar/index.ts deleted file mode 100644 index e03daab6f730fb..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/Calendar/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './Calendar'; -export * from './Calendar.types'; -export * from './useCalendarStyles.styles'; -export { defaultCalendarStrings } from './defaults'; diff --git a/packages/react-components/react-datepicker-compat/src/components/Calendar/useCalendarStyles.styles.ts b/packages/react-components/react-datepicker-compat/src/components/Calendar/useCalendarStyles.styles.ts deleted file mode 100644 index 430174a6bb679a..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/Calendar/useCalendarStyles.styles.ts +++ /dev/null @@ -1,142 +0,0 @@ -import { tokens } from '@fluentui/react-theme'; -import { makeStyles, mergeClasses, shorthands } from '@griffel/react'; -import type { SlotClassNames } from '@fluentui/react-utilities'; -import type { CalendarStyles, CalendarStyleProps } from './Calendar.types'; - -/** - * @internal - */ -export const calendarClassNames: SlotClassNames = { - root: 'fui-Calendar', - divider: 'fui-Calendar__divider', - goTodayButton: 'fui-Calendar__goTodayButton', - monthPickerWrapper: 'fui-Calendar__monthPickerWrapper', - liveRegion: 'fui-Calendar__liveRegion', -}; - -const useRootStyles = makeStyles({ - base: { - display: 'flex', - width: '220px', - }, - normalize: { - boxShadow: 'none', - boxSizing: 'border-box', - ...shorthands.margin(0), - ...shorthands.padding(0), - }, - monthPickerNotVisible: { - flexDirection: 'column', - }, - dayAndMonthPickersVisible: { - width: '440px', - }, - dayPickerVisibleAndWeekNumbersShown: { - width: '250px', - }, - dayAndMonthPickersVisibleAndWeekNumbersShown: { - width: '470px', - }, -}); - -const useDividerStyles = makeStyles({ - base: { - ...shorthands.borderColor(tokens.colorNeutralStroke2), - ...shorthands.borderRight('1px', 'solid'), - top: 0, - }, -}); - -const useMonthPickerWrapperStyles = makeStyles({ - base: { - display: 'flex', - flexDirection: 'column', - }, -}); - -const useGoTodayButtonStyles = makeStyles({ - base: { - alignSelf: 'flex-end', - backgroundColor: tokens.colorTransparentBackground, - ...shorthands.borderStyle('none'), - bottom: 0, - boxSizing: 'content-box', - color: tokens.colorNeutralForeground1, - fontFamily: 'inherit', - fontSize: tokens.fontSizeBase200, - height: '30px', - lineHeight: '30px', - marginRight: '16px', - marginTop: '3px', - ...shorthands.overflow('visible'), - ...shorthands.padding(0, '4px'), - - '& div': { - fontSize: tokens.fontSizeBase200, - }, - '&:hover': { - backgroundColor: tokens.colorTransparentBackground, - color: tokens.colorBrandForeground1, - cursor: 'pointer', - - '@media (forced-colors: active)': { - ...shorthands.outline(tokens.strokeWidthThin, 'solid', 'ButtonText'), - ...shorthands.borderRadius(tokens.borderRadiusSmall), - }, - }, - '&:hover:active': { - color: tokens.colorBrandForeground2, - }, - '&:disabled': { - color: tokens.colorNeutralForegroundDisabled, - pointerEvents: 'none', - }, - }, -}); - -const useLiveRegionStyles = makeStyles({ - base: { - ...shorthands.border(0), - height: '1px', - ...shorthands.margin('-1px'), - ...shorthands.overflow('hidden'), - ...shorthands.padding(0), - position: 'absolute', - width: '1px', - }, -}); - -/** - * @internal - * - * Apply styling to the Calendar slots based on the state - */ -export const useCalendarStyles_unstable = (props: CalendarStyleProps): CalendarStyles => { - const rootStyles = useRootStyles(); - const dividerStyles = useDividerStyles(); - const monthPickerWrapperStyles = useMonthPickerWrapperStyles(); - const goTodayButtonStyles = useGoTodayButtonStyles(); - const liveRegionStyles = useLiveRegionStyles(); - - const { className, isDayPickerVisible, isMonthPickerVisible, showWeekNumbers } = props; - - return { - root: mergeClasses( - calendarClassNames.root, - rootStyles.base, - rootStyles.normalize, - !isMonthPickerVisible && rootStyles.monthPickerNotVisible, - isDayPickerVisible && isMonthPickerVisible && !showWeekNumbers && rootStyles.dayAndMonthPickersVisible, - isDayPickerVisible && !isMonthPickerVisible && showWeekNumbers && rootStyles.dayPickerVisibleAndWeekNumbersShown, - isDayPickerVisible && - isMonthPickerVisible && - showWeekNumbers && - rootStyles.dayAndMonthPickersVisibleAndWeekNumbersShown, - className, - ), - divider: mergeClasses(calendarClassNames.divider, dividerStyles.base), - monthPickerWrapper: mergeClasses(calendarClassNames.monthPickerWrapper, monthPickerWrapperStyles.base), - goTodayButton: mergeClasses(calendarClassNames.goTodayButton, goTodayButtonStyles.base), - liveRegion: mergeClasses(calendarClassNames.liveRegion, liveRegionStyles.base), - }; -}; diff --git a/packages/react-components/react-datepicker-compat/src/components/CalendarDay/CalendarDay.tsx b/packages/react-components/react-datepicker-compat/src/components/CalendarDay/CalendarDay.tsx deleted file mode 100644 index 7d3ac925a13795..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/CalendarDay/CalendarDay.tsx +++ /dev/null @@ -1,183 +0,0 @@ -import * as React from 'react'; -import { Enter } from '@fluentui/keyboard-keys'; -import { ArrowDownRegular, ArrowUpRegular, DismissRegular } from '@fluentui/react-icons'; -import { useId } from '@fluentui/react-utilities'; -import { mergeClasses } from '@griffel/react'; -import { addMonths, compareDatePart, getMonthEnd, getMonthStart } from '../../utils'; -import { CalendarDayGrid } from '../CalendarDayGrid/CalendarDayGrid'; -import { useCalendarDayStyles_unstable } from './useCalendarDayStyles.styles'; -import type { ICalendarDayGrid } from '../CalendarDayGrid/CalendarDayGrid.types'; -import type { CalendarDayProps, CalendarDayStyles } from './CalendarDay.types'; - -/** - * @internal - */ -export const CalendarDay: React.FunctionComponent = props => { - const dayGrid = React.useRef(null); - - React.useImperativeHandle( - props.componentRef, - () => ({ - focus() { - dayGrid.current?.focus?.(); - }, - }), - [], - ); - - const { - strings, - navigatedDate, - dateTimeFormatter, - className, - onHeaderSelect, - showSixWeeksByDefault, - minDate, - maxDate, - restrictedDates, - onNavigateDate, - showWeekNumbers, - dateRangeType, - animationDirection, - } = props; - const monthAndYearId = useId(); - - const classNames = useCalendarDayStyles_unstable({ - className, - headerIsClickable: !!onHeaderSelect, - showWeekNumbers, - animationDirection, - }); - - const monthAndYear = dateTimeFormatter.formatMonthYear(navigatedDate, strings); - const HeaderButtonComponentType = onHeaderSelect ? 'button' : 'div'; - const headerAriaLabel = strings.yearPickerHeaderAriaLabel - ? strings.yearPickerHeaderAriaLabel.replace('{0}', monthAndYear) - : monthAndYear; - - const { ...propsWithoutStyles } = props; - - return ( -
-
- - - {monthAndYear} - - - -
- -
- ); -}; -CalendarDay.displayName = 'CalendarDay'; - -interface CalendarDayNavigationButtonsProps extends CalendarDayProps { - classNames: Record; -} - -const CalendarDayNavigationButtons = (props: CalendarDayNavigationButtonsProps): JSX.Element => { - const { - minDate, - maxDate, - navigatedDate, - allFocusable, - strings, - showCloseButton, - classNames, - onNavigateDate, - onDismiss, - } = props; - - const onSelectNextMonth = (): void => { - onNavigateDate(addMonths(navigatedDate, 1), false); - }; - - const onSelectPrevMonth = (): void => { - onNavigateDate(addMonths(navigatedDate, -1), false); - }; - - // determine if previous/next months are in bounds - const prevMonthInBounds = minDate ? compareDatePart(minDate, getMonthStart(navigatedDate)) < 0 : true; - const nextMonthInBounds = maxDate ? compareDatePart(getMonthEnd(navigatedDate), maxDate) < 0 : true; - - // use aria-disabled instead of disabled so focus is not lost - // when a prev/next button becomes disabled after being clicked - return ( -
- - - {showCloseButton && ( - - )} -
- ); -}; -CalendarDayNavigationButtons.displayName = 'CalendarDayNavigationButtons'; - -const onButtonKeyDown = - (callback?: () => void): ((ev: React.KeyboardEvent) => void) => - (ev: React.KeyboardEvent) => { - switch (ev.key) { - case Enter: - callback?.(); - break; - } - }; diff --git a/packages/react-components/react-datepicker-compat/src/components/CalendarDay/CalendarDay.types.ts b/packages/react-components/react-datepicker-compat/src/components/CalendarDay/CalendarDay.types.ts deleted file mode 100644 index e247c3cb108ec4..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/CalendarDay/CalendarDay.types.ts +++ /dev/null @@ -1,147 +0,0 @@ -import * as React from 'react'; -import type { CalendarStrings, DateFormatting } from '../../utils'; -import type { CalendarDayGridProps, CalendarDayGridStyleProps } from '../CalendarDayGrid/CalendarDayGrid.types'; - -// eslint-disable-next-line @typescript-eslint/naming-convention -export interface ICalendarDay { - focus(): void; -} - -export interface CalendarDayProps extends CalendarDayGridProps { - /** - * Optional callback to access the ICalendarDay interface. Use this instead of ref for accessing - * the public methods and properties of the component. - */ - componentRef?: React.RefObject; - - /** - * Additional CSS class(es) to apply to the CalendarDay. - */ - className?: string; - - /** - * Localized strings to use in the Calendar - */ - strings: CalendarStrings; - - /** - * The currently navigated date - */ - navigatedDate: Date; - - /** - * Callback issued when a date in the calendar is navigated - * @param date - The date that is navigated to - * @param focusOnNavigatedDay - Whether to set the focus to the navigated date. - */ - onNavigateDate: (date: Date, focusOnNavigatedDay: boolean) => void; - - /** - * Callback issued when calendar day is closed - */ - onDismiss?: () => void; - - /** - * Callback function when the header is selected - */ - onHeaderSelect?: () => void; - - /** - * Whether the calendar should show the week number (weeks 1 to 53) before each week row - * @default false - */ - showWeekNumbers?: boolean; - - /** - * Apply additional formatting to dates, for example localized date formatting. - */ - dateTimeFormatter: DateFormatting; - - /** - * Whether the calendar should show 6 weeks by default. - * @default false - */ - showSixWeeksByDefault?: boolean; - - /** - * If set the Calendar will not allow navigation to or selection of a date earlier than this value. - */ - minDate?: Date; - - /** - * If set the Calendar will not allow navigation to or selection of a date later than this value. - */ - maxDate?: Date; - - /** - * If set the Calendar will not allow selection of dates in this array. - */ - restrictedDates?: Date[]; - - /** - * Whether the close button should be shown or not - * @default false - */ - showCloseButton?: boolean; - - /** - * Allows all dates and buttons to be focused, including disabled ones - * @default false - */ - allFocusable?: boolean; -} - -/** - * @internal - */ -export interface CalendarDayStyleProps extends CalendarDayGridStyleProps { - /** - * Accept custom classNames - */ - className?: string; - - /** - * Whether the header is clickable - */ - headerIsClickable?: boolean; - - /** - * Whether week numbers are being shown - */ - showWeekNumbers?: boolean; -} - -/** - * @internal - */ -export interface CalendarDayStyles { - /** - * Style for the root element. - */ - root: string; - - /** - * The style for the header button and forward/back navigation button container - */ - header: string; - - /** - * The style for the title text inside the header - */ - monthAndYear: string; - - /** - * The style for the wrapper around forward/back/close buttons - */ - monthComponents: string; - - /** - * The style for the forward/back/close buttons - */ - headerIconButton: string; - - /** - * The style to apply for disabled elements - */ - disabledStyle: string; -} diff --git a/packages/react-components/react-datepicker-compat/src/components/CalendarDay/index.ts b/packages/react-components/react-datepicker-compat/src/components/CalendarDay/index.ts deleted file mode 100644 index e7be79824e0009..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/CalendarDay/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './CalendarDay'; -export * from './CalendarDay.types'; -export * from './useCalendarDayStyles.styles'; diff --git a/packages/react-components/react-datepicker-compat/src/components/CalendarDay/useCalendarDayStyles.styles.ts b/packages/react-components/react-datepicker-compat/src/components/CalendarDay/useCalendarDayStyles.styles.ts deleted file mode 100644 index 69f89afbb0e8f8..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/CalendarDay/useCalendarDayStyles.styles.ts +++ /dev/null @@ -1,163 +0,0 @@ -import { tokens } from '@fluentui/react-theme'; -import { makeStyles, mergeClasses, shorthands } from '@griffel/react'; -import { DURATION_2, EASING_FUNCTION_2, FADE_IN } from '../../utils/animations'; -import type { SlotClassNames } from '@fluentui/react-utilities'; -import type { CalendarDayStyles, CalendarDayStyleProps } from './CalendarDay.types'; - -/** - * @internal - */ -export const calendarDayClassNames: SlotClassNames = { - root: 'fui-CalendarDay', - header: 'fui-CalendarDay__header', - monthAndYear: 'fui-CalendarDay__monthAndYear', - monthComponents: 'fui-CalendarDay__monthComponents', - headerIconButton: 'fui-CalendarDay__headerIconButton', - disabledStyle: 'fui-CalendarDay__disabledStyle', -}; - -const useRootStyles = makeStyles({ - base: { - boxSizing: 'content-box', - ...shorthands.padding('12px'), - width: '196px', - }, - normalize: { - boxShadow: 'none', - boxSizing: 'border-box', - ...shorthands.margin(0), - ...shorthands.padding(0), - }, - showWeekNumbers: { - width: '226px', - }, -}); - -const useHeaderStyles = makeStyles({ - base: { - display: 'inline-flex', - height: '28px', - lineHeight: '44px', - position: 'relative', - width: '100%', - }, -}); - -const useMonthAndYearStyles = makeStyles({ - base: { - alignItems: 'center', - backgroundColor: tokens.colorTransparentBackground, - ...shorthands.borderStyle('none'), - ...shorthands.borderRadius('2px'), - color: tokens.colorNeutralForeground1, - display: 'inline-block', - flexGrow: 1, - fontFamily: 'inherit', - fontSize: tokens.fontSizeBase300, - fontWeight: tokens.fontWeightSemibold, - lineHeight: '28px', - ...shorthands.overflow('hidden'), - ...shorthands.padding(0, '4px', 0, '10px'), - textAlign: 'left', - textOverflow: 'ellipsis', - whiteSpace: 'nowrap', - }, - animation: { - animationDuration: DURATION_2, - animationFillMode: 'both', - animationName: FADE_IN, - animationTimingFunction: EASING_FUNCTION_2, - }, - headerIsClickable: { - '&:hover': { - backgroundColor: tokens.colorBrandBackground2, - color: tokens.colorNeutralForeground1Hover, - cursor: 'pointer', - }, - '&:hover:active': { - backgroundColor: tokens.colorBrandBackground2, - }, - }, -}); - -const useMonthComponentsStyles = makeStyles({ - base: { - alignSelf: 'flex-end', - display: 'inline-flex', - }, -}); - -const useHeaderIconButtonStyles = makeStyles({ - base: { - backgroundColor: tokens.colorTransparentBackground, - ...shorthands.borderStyle('none'), - ...shorthands.borderRadius('2px'), - color: tokens.colorNeutralForeground3, - display: 'block', - fontFamily: 'inherit', - fontSize: tokens.fontSizeBase200, - height: '28px', - lineHeight: '28px', - ...shorthands.overflow('visible'), - ...shorthands.padding(0), - position: 'relative', - textAlign: 'center', - width: '28px', - - '&:hover': { - backgroundColor: tokens.colorBrandBackgroundInvertedHover, - color: tokens.colorBrandForegroundOnLightHover, - cursor: 'pointer', - ...shorthands.outline('1px', 'solid', tokens.colorTransparentStroke), - }, - '&:hover:active': { - backgroundColor: tokens.colorBrandBackgroundInvertedPressed, - color: tokens.colorBrandForegroundOnLightPressed, - }, - }, -}); - -const useDisabledStyleStyles = makeStyles({ - base: { - '&, &:disabled, & button': { - color: tokens.colorNeutralForegroundDisabled, - pointerEvents: 'none', - }, - }, -}); - -/** - * @internal - * - * Apply styling to the CalendarDay slots based on the state - */ -export const useCalendarDayStyles_unstable = (props: CalendarDayStyleProps): CalendarDayStyles => { - const rootStyles = useRootStyles(); - const headerStyles = useHeaderStyles(); - const monthAndYearStyles = useMonthAndYearStyles(); - const monthComponentsStyles = useMonthComponentsStyles(); - const headerIconButtonStyles = useHeaderIconButtonStyles(); - const disabledStyleStyles = useDisabledStyleStyles(); - - const { className, headerIsClickable, showWeekNumbers } = props; - - return { - root: mergeClasses( - calendarDayClassNames.root, - rootStyles.normalize, - rootStyles.base, - showWeekNumbers && rootStyles.showWeekNumbers, - className, - ), - header: mergeClasses(calendarDayClassNames.header, headerStyles.base), - monthAndYear: mergeClasses( - calendarDayClassNames.monthAndYear, - monthAndYearStyles.base, - monthAndYearStyles.animation, - headerIsClickable && monthAndYearStyles.headerIsClickable, - ), - monthComponents: mergeClasses(calendarDayClassNames.monthComponents, monthComponentsStyles.base), - headerIconButton: mergeClasses(calendarDayClassNames.headerIconButton, headerIconButtonStyles.base), - disabledStyle: mergeClasses(calendarDayClassNames.disabledStyle, disabledStyleStyles.base), - }; -}; diff --git a/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/CalendarDayGrid.test.tsx b/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/CalendarDayGrid.test.tsx deleted file mode 100644 index 77e44d0a61d265..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/CalendarDayGrid.test.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { CalendarDayGrid } from './CalendarDayGrid'; -import { isConformant } from '../../testing/isConformant'; -import { DEFAULT_CALENDAR_STRINGS, DayOfWeek, DateRangeType, FirstWeekOfYear } from '../../utils'; - -describe('CalendarDayGrid', () => { - isConformant({ - Component: CalendarDayGrid, - displayName: 'CalendarDayGrid', - requiredProps: { - strings: DEFAULT_CALENDAR_STRINGS, - selectedDate: new Date('2020-09-18T21:06:52.856Z'), - navigatedDate: new Date('2020-09-18T21:06:52.856Z'), - dateRangeType: DateRangeType.Day, - firstDayOfWeek: DayOfWeek.Sunday, - firstWeekOfYear: FirstWeekOfYear.FirstFullWeek, - dateTimeFormatter: { - formatMonthDayYear: () => 'm/d/y', - formatMonthYear: () => 'm/y', - formatDay: () => 'd', - formatMonth: () => 'm', - formatYear: () => 'y', - }, - }, - disabledTests: [ - 'component-handles-classname', - 'exported-top-level', - 'has-top-level-file', - // This component is not currently intended to handle a ref - 'component-handles-ref', - 'component-has-root-ref', - // This test doesn't apply for compat components that are closer to their v8 counterpart - 'consistent-callback-args', - // Some classnames are applied conditionally - 'component-has-static-classnames-object', - ], - }); -}); diff --git a/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/CalendarDayGrid.tsx b/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/CalendarDayGrid.tsx deleted file mode 100644 index 4c3b7bc89d72ac..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/CalendarDayGrid.tsx +++ /dev/null @@ -1,214 +0,0 @@ -import * as React from 'react'; -import { useArrowNavigationGroup } from '@fluentui/react-tabster'; -import { useId } from '@fluentui/react-utilities'; -import { getBoundedDateRange, getDateRangeArray, isRestrictedDate, DateRangeType, DayOfWeek } from '../../utils'; -import { useCalendarDayGridStyles_unstable } from './useCalendarDayGridStyles.styles'; -import { CalendarMonthHeaderRow } from './CalendarMonthHeaderRow'; -import { CalendarGridRow } from './CalendarGridRow'; -import { useWeeks } from './useWeeks'; -import { useWeekCornerStyles, WeekCorners } from './useWeekCornerStyles.styles'; -import { mergeClasses } from '@griffel/react'; -import type { Day } from '../../utils'; -import type { CalendarDayGridProps } from './CalendarDayGrid.types'; - -export interface DayInfo extends Day { - onSelected: () => void; - setRef(element: HTMLElement | null): void; -} - -function useDayRefs() { - const daysRef = React.useRef>({}); - - const getSetRefCallback = (dayKey: string) => (element: HTMLElement | null) => { - if (element === null) { - delete daysRef.current[dayKey]; - } else { - daysRef.current[dayKey] = element; - } - }; - - return [daysRef, getSetRefCallback] as const; -} - -function useAnimateBackwards(weeks: DayInfo[][]): boolean | undefined { - const previousNavigatedDateRef = React.useRef(); - React.useEffect(() => { - previousNavigatedDateRef.current = weeks[0][0].originalDate; - }); - const previousNavigatedDate = previousNavigatedDateRef.current; - - if (!previousNavigatedDate || previousNavigatedDate.getTime() === weeks[0][0].originalDate.getTime()) { - return undefined; - } else if (previousNavigatedDate <= weeks[0][0].originalDate) { - return false; - } else { - return true; - } -} - -export const CalendarDayGrid: React.FunctionComponent = props => { - const navigatedDayRef = React.useRef(null) as React.MutableRefObject; - - const activeDescendantId = useId(); - - const onSelectDate = (selectedDate: Date): void => { - const { firstDayOfWeek, minDate, maxDate, workWeekDays, daysToSelectInDayView, restrictedDates } = props; - const restrictedDatesOptions = { minDate, maxDate, restrictedDates }; - - let dateRange = getDateRangeArray(selectedDate, dateRangeType, firstDayOfWeek, workWeekDays, daysToSelectInDayView); - dateRange = getBoundedDateRange(dateRange, minDate, maxDate); - - dateRange = dateRange.filter((d: Date) => { - return !isRestrictedDate(d, restrictedDatesOptions); - }); - - props.onSelectDate?.(selectedDate, dateRange); - props.onNavigateDate?.(selectedDate, true); - }; - - const [daysRef, getSetRefCallback] = useDayRefs(); - - const weeks = useWeeks(props, onSelectDate, getSetRefCallback); - const animateBackwards = useAnimateBackwards(weeks); - const [getWeekCornerStyles, calculateRoundedStyles] = useWeekCornerStyles(props); - - React.useImperativeHandle( - props.componentRef, - () => ({ - focus() { - navigatedDayRef.current?.focus?.(); - }, - }), - [], - ); - - /** - * - * Section for setting hover/pressed styles. Because we want arbitrary blobs of days to be selectable, to support - * highlighting every day in the month for month view, css :hover style isn't enough, so we need mouse callbacks - * to set classnames on all relevant child refs to apply the styling - * - */ - const getDayInfosInRangeOfDay = (dayToCompare: DayInfo): DayInfo[] => { - // The hover state looks weird with non-contiguous days in work week view. In work week, show week hover state - const dateRangeHoverType = getDateRangeTypeToUse(props.dateRangeType, props.workWeekDays); - - // gets all the dates for the given date range type that are in the same date range as the given day - const dateRange = getDateRangeArray( - dayToCompare.originalDate, - dateRangeHoverType, - props.firstDayOfWeek, - props.workWeekDays, - props.daysToSelectInDayView, - ).map((date: Date) => date.getTime()); - - // gets all the day refs for the given dates - const dayInfosInRange = weeks.reduce((accumulatedValue: DayInfo[], currentWeek: DayInfo[]) => { - return accumulatedValue.concat( - currentWeek.filter((weekDay: DayInfo) => dateRange.indexOf(weekDay.originalDate.getTime()) !== -1), - ); - }, []); - - return dayInfosInRange; - }; - - const getRefsFromDayInfos = (dayInfosInRange: DayInfo[]): (HTMLElement | null)[] => { - let dayRefs: (HTMLElement | null)[] = []; - dayRefs = dayInfosInRange.map((dayInfo: DayInfo) => daysRef.current[dayInfo.key]); - - return dayRefs; - }; - - const { dateRangeType, showWeekNumbers, labelledBy, lightenDaysOutsideNavigatedMonth, animationDirection } = props; - - const classNames = useCalendarDayGridStyles_unstable({ - animateBackwards, - animationDirection, - dateRangeType, - lightenDaysOutsideNavigatedMonth: - lightenDaysOutsideNavigatedMonth === undefined ? true : lightenDaysOutsideNavigatedMonth, - showWeekNumbers, - }); - - // When the month is highlighted get the corner dates so that styles can be added to them - const weekCorners: WeekCorners = getWeekCornerStyles(weeks!); - const partialWeekProps = { - weeks, - navigatedDayRef, - calculateRoundedStyles, - activeDescendantId, - classNames, - weekCorners, - getDayInfosInRangeOfDay, - getRefsFromDayInfos, - } as const; - - const arrowNavigationAttributes = useArrowNavigationGroup({ axis: 'grid' }); - - return ( - - - - - {weeks!.slice(1, weeks!.length - 1).map((week: DayInfo[], weekIndex: number) => ( - - ))} - - -
- ); -}; -CalendarDayGrid.displayName = 'CalendarDayGrid'; - -/** - * When given work week, if the days are non-contiguous, the hover states look really weird. So for non-contiguous - * work weeks, we'll just show week view instead. - */ -function getDateRangeTypeToUse(dateRangeType: DateRangeType, workWeekDays: DayOfWeek[] | undefined): DateRangeType { - if (workWeekDays && dateRangeType === DateRangeType.WorkWeek) { - const sortedWWDays = workWeekDays.slice().sort(); - let isContiguous = true; - for (let i = 1; i < sortedWWDays.length; i++) { - if (sortedWWDays[i] !== sortedWWDays[i - 1] + 1) { - isContiguous = false; - break; - } - } - - if (!isContiguous || workWeekDays.length === 0) { - return DateRangeType.Week; - } - } - - return dateRangeType; -} diff --git a/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/CalendarDayGrid.types.ts b/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/CalendarDayGrid.types.ts deleted file mode 100644 index a1ef13b5c6ce74..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/CalendarDayGrid.types.ts +++ /dev/null @@ -1,286 +0,0 @@ -import * as React from 'react'; -import { AnimationDirection } from '../Calendar/Calendar.types'; -import { DayOfWeek, FirstWeekOfYear, DateRangeType } from '../../utils'; -import type { CalendarStrings, DateFormatting, DayGridOptions } from '../../utils'; - -/** - * @internal - */ -// eslint-disable-next-line @typescript-eslint/naming-convention -export interface ICalendarDayGrid { - focus(): void; -} - -/** - * @internal - */ -export interface CalendarDayGridProps extends DayGridOptions { - /** - * Optional callback to access the ICalendarDayGrid interface. Use this instead of ref for accessing - * the public methods and properties of the component. - */ - componentRef?: React.RefObject; - - /** - * Additional CSS class(es) to apply to the CalendarDayGrid. - */ - className?: string; - - /** - * Localized strings to use in the CalendarDayGrid - */ - strings: CalendarStrings; - - /** - * The currently selected date - */ - selectedDate: Date; - - /** - * The currently navigated date - */ - navigatedDate: Date; - - /** - * Callback issued when a date is selected - * @param date - The date the user selected - * @param selectedDateRangeArray - The resultant list of dates that are selected based on the date range type set - * for the component. - */ - onSelectDate?: (date: Date, selectedDateRangeArray?: Date[]) => void; - - /** - * Callback issued when a date in the calendar is navigated - * @param date - The date that is navigated to - * @param focusOnNavigatedDay - Whether to set the focus to the navigated date. - */ - onNavigateDate: (date: Date, focusOnNavigatedDay: boolean) => void; - - /** - * Callback issued when calendar day is closed - */ - onDismiss?: () => void; - - /** - * The first day of the week for your locale. - * @default DayOfWeek.Sunday - */ - firstDayOfWeek: DayOfWeek; - - /** - * Defines when the first week of the year should start, FirstWeekOfYear.FirstDay, - * FirstWeekOfYear.FirstFullWeek or FirstWeekOfYear.FirstFourDayWeek are the possible values - * @default FirstWeekOfYear.FirstDay - */ - firstWeekOfYear: FirstWeekOfYear; - - /** - * The date range type indicating how many days should be selected as the user - * selects days - * @default DateRangeType.Day - */ - dateRangeType: DateRangeType; - - /** - * The number of days to select while dateRangeType === DateRangeType.Day. Used in order to have multi-day - * views. - * @default 1 - */ - daysToSelectInDayView?: number; - - /** - * Value of today. If unspecified, current time in client machine will be used. - */ - today?: Date; - - /** - * Whether the calendar should show the week number (weeks 1 to 53) before each week row - * @default false - */ - showWeekNumbers?: boolean; - - /** - * Apply additional formatting to dates, for example localized date formatting. - */ - dateTimeFormatter: DateFormatting; - - /** - * Ref callback for individual days. Allows for customization of the styling, properties, or listeners of the - * specific day. - */ - customDayCellRef?: (element: HTMLElement, date: Date, classNames: CalendarDayGridStyles) => void; - - /** - * How many weeks to show by default. If not provided, will show enough weeks to display the current - * month, between 4 and 6 depending - * @default undefined - */ - weeksToShow?: number; - - /** - * If set the Calendar will not allow navigation to or selection of a date earlier than this value. - */ - minDate?: Date; - - /** - * If set the Calendar will not allow navigation to or selection of a date later than this value. - */ - maxDate?: Date; - - /** - * If set the Calendar will not allow selection of dates in this array. - */ - restrictedDates?: Date[]; - - /** - * The days that are selectable when `dateRangeType` is WorkWeek. - * If `dateRangeType` is not WorkWeek this property does nothing. - * @default [Monday,Tuesday,Wednesday,Thursday,Friday] - */ - workWeekDays?: DayOfWeek[]; - - /** - * Whether the close button should be shown or not - * @default false - */ - showCloseButton?: boolean; - - /** - * Allows all dates and buttons to be focused, including disabled ones - * @default false - */ - allFocusable?: boolean; - - /** - * The ID of the control that labels this one - */ - labelledBy?: string; - - /** - * Whether to show days outside the selected month with lighter styles - * @default true - */ - lightenDaysOutsideNavigatedMonth?: boolean; - - /** - * The cardinal directions for animation to occur during transitions, either horizontal or veritcal - */ - animationDirection?: AnimationDirection; - - /** - * Optional callback function to mark specific days with a small symbol. Fires when the date range changes, - * gives the starting and ending displayed dates and expects the list of which days in between should be - * marked. - */ - getMarkedDays?: (startingDate: Date, endingDate: Date) => Date[]; -} - -/** - * @internal - */ -export interface CalendarDayGridStyleProps { - /** - * Accept custom classNames - */ - className?: string; - - /** - * The date range type - */ - dateRangeType?: DateRangeType; - - /** - * Whether week numbers are being shown - */ - showWeekNumbers?: boolean; - - /** - * Whether to show days outside the selected month with lighter styles - */ - lightenDaysOutsideNavigatedMonth?: boolean; - - /** - * Whether grid entering animation should be forwards or backwards - */ - animateBackwards?: boolean; - - /** - * The cardinal directions for animation to occur during transitions, either horizontal or vertical - */ - animationDirection?: AnimationDirection; -} - -/** - * @internal - */ -export interface CalendarDayGridStyles { - /** - * The style for the root div - */ - wrapper?: string; - - /** - * The style for the table containing the grid - */ - table?: string; - - /** - * The style to apply to the grid cells for days - */ - dayCell?: string; - - /** - * The style to apply to grid cells for days in the selected range - */ - daySelected?: string; - - /** - * The style to apply to row around weeks - */ - weekRow?: string; - - /** - * The style to apply to the column headers above the weeks - */ - weekDayLabelCell?: string; - - /** - * The style to apply to grid cells for week numbers - */ - weekNumberCell?: string; - - /** - * The style to apply to individual days that are outside the min/max date range - */ - dayOutsideBounds?: string; - - /** - * The style to apply to individual days that are outside the current month - */ - dayOutsideNavigatedMonth?: string; - - /** - * The style to apply to the button element within the day cells - */ - dayButton?: string; - - /** - * The style to apply to the individual button element that matches the "today" parameter - */ - dayIsToday?: string; - - /** - * The style applied to the first placeholder week used during transitions - */ - firstTransitionWeek?: string; - - /** - * The style applied to the last placeholder week used during transitions - */ - lastTransitionWeek?: string; - - /** - * The style applied to the marker on days to mark as important - */ - dayMarker?: string; -} diff --git a/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/CalendarGridDayCell.tsx b/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/CalendarGridDayCell.tsx deleted file mode 100644 index 843d53be01a8e6..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/CalendarGridDayCell.tsx +++ /dev/null @@ -1,255 +0,0 @@ -import * as React from 'react'; -import { ArrowDown, ArrowLeft, ArrowRight, ArrowUp, Enter } from '@fluentui/keyboard-keys'; -import { getRTLSafeKey } from '@fluentui/react-utilities'; -import { useFluent_unstable } from '@fluentui/react-shared-contexts'; -import { mergeClasses } from '@griffel/react'; -import { addDays, addWeeks, compareDates, findAvailableDate, DateRangeType } from '../../utils'; -import { weekCornersClassNames } from './useWeekCornerStyles.styles'; -import { extraCalendarDayGridClassNames } from './useCalendarDayGridStyles.styles'; -import type { AvailableDateOptions } from '../../utils'; -import type { DayInfo } from './CalendarDayGrid'; -import type { CalendarGridRowProps } from './CalendarGridRow'; - -/** - * @internal - */ -export interface CalendarGridDayCellProps extends CalendarGridRowProps { - day: DayInfo; - dayIndex: number; -} - -/** - * @internal - */ -export const CalendarGridDayCell: React.FunctionComponent = props => { - const { - navigatedDate, - dateTimeFormatter, - allFocusable, - strings, - activeDescendantId, - navigatedDayRef, - calculateRoundedStyles, - weeks, - classNames, - day, - dayIndex, - weekIndex, - weekCorners, - ariaHidden, - customDayCellRef, - dateRangeType, - daysToSelectInDayView, - onSelectDate, - restrictedDates, - minDate, - maxDate, - onNavigateDate, - getDayInfosInRangeOfDay, - getRefsFromDayInfos, - } = props; - const cornerStyle = weekCorners?.[weekIndex + '_' + dayIndex] ?? ''; - const isNavigatedDate = compareDates(navigatedDate, day.originalDate); - - const { dir } = useFluent_unstable(); - - const navigateMonthEdge = (ev: React.KeyboardEvent, date: Date): void => { - let targetDate: Date | undefined = undefined; - let direction = 1; // by default search forward - - if (ev.key === ArrowUp) { - targetDate = addWeeks(date, -1); - direction = -1; - } else if (ev.key === ArrowDown) { - targetDate = addWeeks(date, 1); - } else if (ev.key === getRTLSafeKey(ArrowLeft, dir)) { - targetDate = addDays(date, -1); - direction = -1; - } else if (ev.key === getRTLSafeKey(ArrowRight, dir)) { - targetDate = addDays(date, 1); - } - - if (!targetDate) { - // if we couldn't find a target date at all, do nothing - return; - } - - const findAvailableDateOptions: AvailableDateOptions = { - initialDate: date, - targetDate, - direction, - restrictedDates, - minDate, - maxDate, - }; - - // target date is restricted, search in whatever direction until finding the next possible date, - // stopping at boundaries - let nextDate = findAvailableDate(findAvailableDateOptions); - - if (!nextDate) { - // if no dates available in initial direction, try going backwards - findAvailableDateOptions.direction = -direction; - nextDate = findAvailableDate(findAvailableDateOptions); - } - - // if the nextDate is still inside the same focusZone area, let the focusZone handle setting the focus so we - // don't jump the view unnecessarily - const isInCurrentView = - weeks && - nextDate && - weeks.slice(1, weeks.length - 1).some((week: DayInfo[]) => { - return week.some((dayToCompare: DayInfo) => { - return compareDates(dayToCompare.originalDate, nextDate!); - }); - }); - if (isInCurrentView) { - return; - } - - // else, fire navigation on the date to change the view to show it - if (nextDate) { - onNavigateDate(nextDate, true); - ev.preventDefault(); - } - }; - - const onMouseOverDay = (ev: React.MouseEvent) => { - const dayInfos = getDayInfosInRangeOfDay(day); - const dayRefs = getRefsFromDayInfos(dayInfos); - - dayRefs.forEach((dayRef: HTMLElement | null, index: number) => { - if (dayRef) { - dayRef.classList.add(extraCalendarDayGridClassNames.hoverStyle); - if ( - !dayInfos[index].isSelected && - dateRangeType === DateRangeType.Day && - daysToSelectInDayView && - daysToSelectInDayView > 1 - ) { - // remove the static classes first to overwrite them - dayRef.classList.remove( - weekCornersClassNames.bottomLeftCornerDate!, - weekCornersClassNames.bottomRightCornerDate!, - weekCornersClassNames.topLeftCornerDate!, - weekCornersClassNames.topRightCornerDate!, - ); - - const classNamesToAdd = calculateRoundedStyles(false, false, index > 0, index < dayRefs.length - 1).trim(); - if (classNamesToAdd) { - dayRef.classList.add(...classNamesToAdd); - } - } - } - }); - }; - - const onMouseDownDay = (ev: React.MouseEvent) => { - const dayInfos = getDayInfosInRangeOfDay(day); - const dayRefs = getRefsFromDayInfos(dayInfos); - - dayRefs.forEach((dayRef: HTMLElement | null) => { - if (dayRef) { - dayRef.classList.add(extraCalendarDayGridClassNames.pressedStyle); - } - }); - }; - - const onMouseUpDay = (ev: React.MouseEvent) => { - const dayInfos = getDayInfosInRangeOfDay(day); - const dayRefs = getRefsFromDayInfos(dayInfos); - - dayRefs.forEach((dayRef: HTMLElement | null) => { - if (dayRef) { - dayRef.classList.remove(extraCalendarDayGridClassNames.pressedStyle); - } - }); - }; - - const onMouseOutDay = (ev: React.MouseEvent) => { - const dayInfos = getDayInfosInRangeOfDay(day); - const dayRefs = getRefsFromDayInfos(dayInfos); - - dayRefs.forEach((dayRef: HTMLElement | null, index: number) => { - if (dayRef) { - dayRef.classList.remove(extraCalendarDayGridClassNames.hoverStyle); - dayRef.classList.remove(extraCalendarDayGridClassNames.pressedStyle); - if ( - !dayInfos[index].isSelected && - dateRangeType === DateRangeType.Day && - daysToSelectInDayView && - daysToSelectInDayView > 1 - ) { - const classNamesToAdd = calculateRoundedStyles(false, false, index > 0, index < dayRefs.length - 1).trim(); - if (classNamesToAdd) { - dayRef.classList.remove(...classNamesToAdd); - } - } - } - }); - }; - - const onDayKeyDown = (ev: React.KeyboardEvent): void => { - if (ev.key === Enter) { - onSelectDate?.(day.originalDate); - } else { - navigateMonthEdge(ev, day.originalDate); - } - }; - - let ariaLabel = - day.originalDate.getDate() + - ', ' + - strings.months[day.originalDate.getMonth()] + - ', ' + - day.originalDate.getFullYear(); - - if (day.isMarked) { - ariaLabel = ariaLabel + ', ' + strings.dayMarkedAriaLabel; - } - - const isFocusable = !ariaHidden && (allFocusable || (day.isInBounds ? true : undefined)); - - return ( - { - customDayCellRef?.(element, day.originalDate, classNames); - day.setRef(element); - isNavigatedDate && (navigatedDayRef.current = element); - }} - aria-hidden={ariaHidden} - aria-disabled={!ariaHidden && !day.isInBounds} - onClick={day.isInBounds && !ariaHidden ? day.onSelected : undefined} - onMouseOver={!ariaHidden ? onMouseOverDay : undefined} - onMouseDown={!ariaHidden ? onMouseDownDay : undefined} - onMouseUp={!ariaHidden ? onMouseUpDay : undefined} - onMouseOut={!ariaHidden ? onMouseOutDay : undefined} - onKeyDown={!ariaHidden ? onDayKeyDown : undefined} - role="gridcell" - tabIndex={isNavigatedDate || isFocusable ? 0 : undefined} - aria-current={day.isToday ? 'date' : undefined} - aria-selected={day.isInBounds ? day.isSelected : undefined} - > - - - ); -}; diff --git a/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/CalendarGridRow.tsx b/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/CalendarGridRow.tsx deleted file mode 100644 index 0c6eb8e928addc..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/CalendarGridRow.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import * as React from 'react'; -import { getWeekNumbersInMonth } from '../../utils'; -import { CalendarGridDayCell } from './CalendarGridDayCell'; -import type { CalendarDayGridProps, CalendarDayGridStyles } from './CalendarDayGrid.types'; -import type { DayInfo } from './CalendarDayGrid'; -import type { WeekCorners } from './useWeekCornerStyles.styles'; - -/** - * @internal - */ -export interface CalendarGridRowProps extends CalendarDayGridProps { - classNames: CalendarDayGridStyles; - weeks: DayInfo[][]; - week: DayInfo[]; - weekIndex: number; - weekCorners?: WeekCorners; - ariaHidden?: boolean; - rowClassName?: string; - ariaRole?: string; - navigatedDayRef: React.MutableRefObject; - activeDescendantId: string; - calculateRoundedStyles(above: boolean, below: boolean, left: boolean, right: boolean): string; - getDayInfosInRangeOfDay(dayToCompare: DayInfo): DayInfo[]; - getRefsFromDayInfos(dayInfosInRange: DayInfo[]): (HTMLElement | null)[]; -} - -/** - * @internal - */ -export const CalendarGridRow: React.FunctionComponent = props => { - const { - classNames, - week, - weeks, - weekIndex, - rowClassName, - ariaRole, - showWeekNumbers, - firstDayOfWeek, - firstWeekOfYear, - navigatedDate, - strings, - } = props; - const weekNumbers = showWeekNumbers - ? getWeekNumbersInMonth(weeks!.length, firstDayOfWeek, firstWeekOfYear, navigatedDate) - : null; - - const titleString = weekNumbers - ? strings.weekNumberFormatString && strings.weekNumberFormatString.replace('{0}', `${weekNumbers[weekIndex]}`) - : ''; - - return ( - - {showWeekNumbers && weekNumbers && ( - - {weekNumbers[weekIndex]} - - )} - {week.map((day: DayInfo, dayIndex: number) => ( - - ))} - - ); -}; diff --git a/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/CalendarMonthHeaderRow.tsx b/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/CalendarMonthHeaderRow.tsx deleted file mode 100644 index fbe0a3cb479f6d..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/CalendarMonthHeaderRow.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import * as React from 'react'; -import { mergeClasses } from '@griffel/react'; -import { DAYS_IN_WEEK } from '../../utils'; -import type { CalendarDayGridProps, CalendarDayGridStyles } from './CalendarDayGrid.types'; -import type { DayInfo } from './CalendarDayGrid'; - -/** - * @internal - */ -export interface CalendarDayMonthHeaderRowProps extends CalendarDayGridProps { - weeks: DayInfo[][]; - classNames: CalendarDayGridStyles; -} - -/** - * @internal - */ -export const CalendarMonthHeaderRow: React.FunctionComponent = props => { - const { showWeekNumbers, strings, firstDayOfWeek, allFocusable, weeksToShow, weeks, classNames } = props; - const dayLabels = strings.shortDays.slice(); - - let firstOfMonthIndex = -1; - const firstWeekOfMonth = weeks![1]; - for (let i = 0; i < weeks![1].length; i++) { - if (firstWeekOfMonth[i].originalDate.getDate() === 1) { - firstOfMonthIndex = i; - break; - } - } - - if (weeksToShow === 1 && firstOfMonthIndex >= 0) { - // if we only show one week, replace the header with short month name - const firstOfMonthIndexOffset = (firstOfMonthIndex + firstDayOfWeek) % DAYS_IN_WEEK; - dayLabels[firstOfMonthIndexOffset] = strings.shortMonths[weeks![1][firstOfMonthIndex].originalDate.getMonth()]; - } - - return ( - - {showWeekNumbers && } - {dayLabels.map((val: string, index: number) => { - const i = (index + firstDayOfWeek) % DAYS_IN_WEEK; - const label = strings.days[i]; - return ( - - {dayLabels[i]} - - ); - })} - - ); -}; diff --git a/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/index.ts b/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/index.ts deleted file mode 100644 index 5b26ba8bc2f066..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './CalendarDayGrid'; -export * from './CalendarDayGrid.types'; -export * from './useCalendarDayGridStyles.styles'; -export { calendarDayGridClassNames, extraCalendarDayGridClassNames } from './useCalendarDayGridStyles.styles'; -export type { WeekCorners } from './useWeekCornerStyles.styles'; diff --git a/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/useCalendarDayGridStyles.styles.ts b/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/useCalendarDayGridStyles.styles.ts deleted file mode 100644 index a54ab99d1b4ff3..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/useCalendarDayGridStyles.styles.ts +++ /dev/null @@ -1,399 +0,0 @@ -import { tokens } from '@fluentui/react-theme'; -import { makeStyles, mergeClasses, shorthands } from '@griffel/react'; -import { - DURATION_2, - DURATION_3, - EASING_FUNCTION_1, - EASING_FUNCTION_2, - FADE_IN, - FADE_OUT, - SLIDE_DOWN_IN20, - SLIDE_DOWN_OUT20, - SLIDE_LEFT_IN20, - SLIDE_RIGHT_IN20, - SLIDE_UP_IN20, - SLIDE_UP_OUT20, - TRANSITION_ROW_DISAPPEARANCE, -} from '../../utils'; -import { AnimationDirection } from '../Calendar/Calendar.types'; -import { weekCornersClassNames } from './useWeekCornerStyles.styles'; -import type { SlotClassNames } from '@fluentui/react-utilities'; -import type { CalendarDayGridStyles, CalendarDayGridStyleProps } from './CalendarDayGrid.types'; - -/** - * @internal - */ -export const calendarDayGridClassNames: SlotClassNames = { - wrapper: 'fui-CalendarDayGrid__wrapper', - table: 'fui-CalendarDayGrid__table', - dayCell: 'fui-CalendarDayGrid__dayCell', - daySelected: 'fui-CalendarDayGrid__daySelected', - weekRow: 'fui-CalendarDayGrid__weekRow', - weekDayLabelCell: 'fui-CalendarDayGrid__weekDayLabelCell', - weekNumberCell: 'fui-CalendarDayGrid__weekNumberCell', - dayOutsideBounds: 'fui-CalendarDayGrid__dayOutsideBounds', - dayOutsideNavigatedMonth: 'fui-CalendarDayGrid__dayOutsideNavigatedMonth', - dayButton: 'fui-CalendarDayGrid__dayButton', - dayIsToday: 'fui-CalendarDayGrid__dayIsToday', - firstTransitionWeek: 'fui-CalendarDayGrid__firstTransitionWeek', - lastTransitionWeek: 'fui-CalendarDayGrid__lastTransitionWeek', - dayMarker: 'fui-CalendarDayGrid__dayMarker', -}; - -/** - * @internal - */ -export const extraCalendarDayGridClassNames = { - hoverStyle: 'fui-CalendarDayGrid__hoverStyle', - pressedStyle: 'fui-CalendarDayGrid__pressedStyle', -}; - -const useWrapperStyles = makeStyles({ - base: { - paddingBottom: '10px', - }, -}); - -const useTableStyles = makeStyles({ - base: { - borderCollapse: 'collapse', - borderSpacing: 0, - fontSize: 'inherit', - marginTop: '4px', - paddingBottom: '10px', - position: 'relative', - tableLayout: 'fixed', - textAlign: 'center', - width: '196px', - }, - showWeekNumbers: { - width: '226px', - }, -}); - -const useDayCellStyles = makeStyles({ - base: { - color: tokens.colorNeutralForeground1, - cursor: 'pointer', - fontSize: tokens.fontSizeBase200, - fontWeight: tokens.fontWeightRegular, - height: '28px', - lineHeight: '28px', - ...shorthands.margin(0), - ...shorthands.padding(0), - position: 'relative', - width: '28px', - '@media (forced-colors: active)': { - backgroundColor: 'Window', - color: 'WindowText', - }, - - [`&.${extraCalendarDayGridClassNames.hoverStyle}`]: { - color: tokens.colorNeutralForeground1Static, - backgroundColor: tokens.colorBrandBackgroundInvertedHover, - '@media (forced-colors: active)': { - backgroundColor: 'Window', - color: 'WindowText', - ...shorthands.outline('1px', 'solid', 'Highlight'), - zIndex: 3, - }, - }, - - [`&.${extraCalendarDayGridClassNames.pressedStyle}`]: { - color: tokens.colorNeutralForeground1Static, - backgroundColor: tokens.colorBrandBackgroundInvertedPressed, - '@media (forced-colors: active)': { - backgroundColor: 'Window', - ...shorthands.borderColor('Highlight'), - color: 'Highlight', - }, - }, - }, -}); - -const useDaySelectedStyles = makeStyles({ - base: { - backgroundColor: tokens.colorBrandBackgroundInvertedSelected, - color: tokens.colorNeutralForeground1Static, - - '@media (forced-colors: active)': { - backgroundColor: 'Highlight', - ...shorthands.borderColor('Highlight'), - color: 'HighlightText', - forcedColorAdjust: 'none', - }, - - [`&:hover, &.${extraCalendarDayGridClassNames.hoverStyle}, &.${extraCalendarDayGridClassNames.pressedStyle}`]: { - color: tokens.colorNeutralForeground1Static, - backgroundColor: tokens.colorBrandBackgroundInvertedSelected, - '@media (forced-colors: active)': { - backgroundColor: 'Highlight', - color: 'HighlightText', - }, - }, - - [`& > .${calendarDayGridClassNames.dayMarker}`]: { - '@media (forced-colors: active)': { - backgroundColor: 'Window', - }, - }, - }, -}); - -const useWeekRowStyles = makeStyles({ - base: { - animationDuration: DURATION_3, - animationFillMode: 'both', - animationTimingFunction: EASING_FUNCTION_1, - }, - horizontalBackward: { - animationName: [FADE_IN, SLIDE_RIGHT_IN20], - }, - horizontalForward: { - animationName: [FADE_IN, SLIDE_LEFT_IN20], - }, - verticalBackward: { - animationName: [FADE_IN, SLIDE_DOWN_IN20], - }, - verticalForward: { - animationName: [FADE_IN, SLIDE_UP_IN20], - }, -}); - -const useWeekDayLabelCellStyles = makeStyles({ - base: { - animationDuration: DURATION_2, - animationFillMode: 'both', - animationName: FADE_IN, - animationTimingFunction: EASING_FUNCTION_2, - }, -}); - -const useWeekNumberCellStyles = makeStyles({ - base: { - backgroundColor: tokens.colorTransparentBackground, - ...shorthands.borderColor(tokens.colorNeutralStroke2), - ...shorthands.borderRight('1px', 'solid'), - boxSizing: 'border-box', - color: tokens.colorNeutralForeground4, - fontSize: tokens.fontSizeBase200, - fontWeight: tokens.fontWeightRegular, - height: '28px', - ...shorthands.margin(0), - ...shorthands.padding(0), - width: '28px', - }, -}); - -const useDayOutsideBoundsStyles = makeStyles({ - base: { - [`&, &:disabled, & button, &.${extraCalendarDayGridClassNames.hoverStyle}` + - `, &.${extraCalendarDayGridClassNames.pressedStyle}`]: { - backgroundColor: tokens.colorTransparentBackground, - color: tokens.colorNeutralForegroundDisabled, - pointerEvents: 'none', - }, - '@media (forced-colors: active)': { - color: 'GrayText', - }, - }, -}); - -const useDayOutsideNavigatedMonthStyles = makeStyles({ - lightenDaysOutsideNavigatedMonth: { - color: tokens.colorNeutralForeground4, - fontWeight: tokens.fontWeightRegular, - - '@media (forced-colors: active)': { - color: 'GrayText', - }, - }, -}); - -const useDayButtonStyles = makeStyles({ - base: { - backgroundColor: tokens.colorTransparentBackground, - ...shorthands.borderRadius('2px'), - ...shorthands.borderStyle('none'), - color: 'inherit', - cursor: 'pointer', - fontSize: tokens.fontSizeBase200, - fontWeight: 'inherit', - height: '24px', - lineHeight: '24px', - ...shorthands.overflow('visible'), - ...shorthands.padding(0), - width: '24px', - - '&span': { - height: 'inherit', - lineHeight: 'inherit', - }, - }, -}); - -const useDayIsTodayStyles = makeStyles({ - base: { - backgroundColor: tokens.colorBrandBackground, - ...shorthands.borderRadius('100%'), - color: tokens.colorNeutralForegroundOnBrand, - fontWeight: tokens.fontWeightSemibold, - - '@media (forced-colors: active)': { - backgroundColor: 'WindowText', - ...shorthands.borderColor('WindowText'), - color: 'Window', - forcedColorAdjust: 'none', - }, - - [`& > .${calendarDayGridClassNames.dayMarker}`]: { - backgroundColor: tokens.colorNeutralForegroundOnBrand, - '@media (forced-colors: active)': { - backgroundColor: 'Window', - }, - }, - }, -}); - -const useFirstTransitionWeekStyles = makeStyles({ - base: { - height: 0, - opacity: 0, - ...shorthands.overflow('hidden'), - position: 'absolute', - width: 0, - }, - verticalForward: { - animationDuration: DURATION_3, - animationFillMode: 'both', - animationName: [FADE_OUT, SLIDE_UP_OUT20, TRANSITION_ROW_DISAPPEARANCE], - animationTimingFunction: EASING_FUNCTION_1, - }, -}); - -const useLastTransitionWeekStyles = makeStyles({ - base: { - height: 0, - marginTop: '-28px', - opacity: 0, - ...shorthands.overflow('hidden'), - position: 'absolute', - width: 0, - }, - verticalBackward: { - animationDuration: DURATION_3, - animationFillMode: 'both', - animationName: [FADE_OUT, SLIDE_DOWN_OUT20, TRANSITION_ROW_DISAPPEARANCE], - animationTimingFunction: EASING_FUNCTION_1, - }, -}); - -const useDayMarkerStyles = makeStyles({ - base: { - backgroundColor: tokens.colorBrandForeground2, - ...shorthands.borderRadius('100%'), - bottom: '1px', - height: '4px', - left: 0, - ...shorthands.margin('auto'), - position: 'absolute', - right: 0, - width: '4px', - - '@media (forced-colors: active)': { - backgroundColor: 'WindowText', - forcedColorAdjust: 'none', - }, - }, -}); - -const useCornerBorderAndRadiusStyles = makeStyles({ - corners: { - [`&.${weekCornersClassNames.topRightCornerDate}`]: { - borderTopRightRadius: '2px', - }, - [`&.${weekCornersClassNames.topLeftCornerDate}`]: { - borderTopLeftRadius: '2px', - }, - [`&.${weekCornersClassNames.bottomRightCornerDate}`]: { - borderBottomRightRadius: '2px', - }, - [`&.${weekCornersClassNames.bottomLeftCornerDate}`]: { - borderBottomLeftRadius: '2px', - }, - }, -}); - -/** - * @internal - * - * Apply styling to the CalendarDayGrid slots based on the state - */ -export const useCalendarDayGridStyles_unstable = (props: CalendarDayGridStyleProps): CalendarDayGridStyles => { - const wrapperStyles = useWrapperStyles(); - const tableStyles = useTableStyles(); - const dayCellStyles = useDayCellStyles(); - const daySelectedStyles = useDaySelectedStyles(); - const weekRowStyles = useWeekRowStyles(); - const weekDayLabelCellStyles = useWeekDayLabelCellStyles(); - const weekNumberCellStyles = useWeekNumberCellStyles(); - const dayOutsideBoundsStyles = useDayOutsideBoundsStyles(); - const dayOutsideNavigatedMonthStyles = useDayOutsideNavigatedMonthStyles(); - const dayButtonStyles = useDayButtonStyles(); - const dayIsTodayStyles = useDayIsTodayStyles(); - const firstTransitionWeekStyles = useFirstTransitionWeekStyles(); - const lastTransitionWeekStyles = useLastTransitionWeekStyles(); - const dayMarkerStyles = useDayMarkerStyles(); - const cornerBorderAndRadiusStyles = useCornerBorderAndRadiusStyles(); - - const { animateBackwards, animationDirection, lightenDaysOutsideNavigatedMonth, showWeekNumbers } = props; - - return { - wrapper: mergeClasses(calendarDayGridClassNames.wrapper, wrapperStyles.base), - table: mergeClasses( - calendarDayGridClassNames.table, - tableStyles.base, - showWeekNumbers && tableStyles.showWeekNumbers, - ), - dayCell: mergeClasses(calendarDayGridClassNames.dayCell, dayCellStyles.base, cornerBorderAndRadiusStyles.corners), - daySelected: mergeClasses(calendarDayGridClassNames.daySelected, daySelectedStyles.base), - weekRow: mergeClasses( - calendarDayGridClassNames.weekRow, - animateBackwards !== undefined && weekRowStyles.base, - animateBackwards !== undefined && - (animationDirection === AnimationDirection.Horizontal - ? animateBackwards - ? weekRowStyles.horizontalBackward - : weekRowStyles.horizontalForward - : animateBackwards - ? weekRowStyles.verticalBackward - : weekRowStyles.verticalForward), - ), - weekDayLabelCell: mergeClasses(calendarDayGridClassNames.weekDayLabelCell, weekDayLabelCellStyles.base), - weekNumberCell: mergeClasses(calendarDayGridClassNames.weekNumberCell, weekNumberCellStyles.base), - dayOutsideBounds: mergeClasses(calendarDayGridClassNames.dayOutsideBounds, dayOutsideBoundsStyles.base), - dayOutsideNavigatedMonth: mergeClasses( - calendarDayGridClassNames.dayOutsideNavigatedMonth, - lightenDaysOutsideNavigatedMonth && dayOutsideNavigatedMonthStyles.lightenDaysOutsideNavigatedMonth, - ), - dayButton: mergeClasses(calendarDayGridClassNames.dayButton, dayButtonStyles.base), - dayIsToday: mergeClasses(calendarDayGridClassNames.dayIsToday, dayIsTodayStyles.base), - firstTransitionWeek: mergeClasses( - calendarDayGridClassNames.firstTransitionWeek, - firstTransitionWeekStyles.base, - animateBackwards !== undefined && - animationDirection !== AnimationDirection.Horizontal && - !animateBackwards && - firstTransitionWeekStyles.verticalForward, - ), - lastTransitionWeek: mergeClasses( - calendarDayGridClassNames.lastTransitionWeek, - lastTransitionWeekStyles.base, - animateBackwards !== undefined && - animationDirection !== AnimationDirection.Horizontal && - animateBackwards && - lastTransitionWeekStyles.verticalBackward, - ), - dayMarker: mergeClasses(calendarDayGridClassNames.dayMarker, dayMarkerStyles.base), - }; -}; diff --git a/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/useWeekCornerStyles.styles.ts b/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/useWeekCornerStyles.styles.ts deleted file mode 100644 index caf8ab6f0a3888..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/useWeekCornerStyles.styles.ts +++ /dev/null @@ -1,152 +0,0 @@ -import { useFluent_unstable } from '@fluentui/react-shared-contexts'; -import { mergeClasses } from '@griffel/react'; -import { DateRangeType } from '../../utils/constants'; -import { getDateRangeArray } from '../../utils/index'; -import { DayInfo } from './CalendarDayGrid'; -import { CalendarDayGridProps } from './CalendarDayGrid.types'; - -/** - * @internal - */ -export const weekCornersClassNames = { - topRightCornerDate: 'fui-CalendarDayGrid__topRightCornerDate', - topLeftCornerDate: 'fui-CalendarDayGrid__topLeftCornerDate', - bottomRightCornerDate: 'fui-CalendarDayGrid__bottomRightCornerDate', - bottomLeftCornerDate: 'fui-CalendarDayGrid__bottomLeftCornerDate', -}; - -/** - * @internal - */ -export interface WeekCorners { - [key: string]: string; -} - -/** - * @internal - */ -export function useWeekCornerStyles(props: CalendarDayGridProps) { - const { dir } = useFluent_unstable(); - - /** - * - * Section for setting the rounded corner styles on individual day cells. Individual day cells need different - * corners to be rounded depending on which date range type and where the cell is located in the current grid. - * If we just round all of the corners, there isn't a good overlap and we get gaps between contiguous day boxes - * in Edge browser. - * - */ - const getWeekCornerStyles = (initialWeeks: DayInfo[][]): WeekCorners => { - const weekCornersStyled: { [key: string]: string } = {}; - /* need to handle setting all of the corners on arbitrarily shaped blobs - __ - __|A | - |B |C |__ - |D |E |F | - - in this case, A needs top left rounded, top right rounded - B needs top left rounded - C doesn't need any rounding - D needs bottom left rounded - E doesn't need any rounding - F needs top right rounding - */ - - // cut off the animation transition weeks - const weeks = initialWeeks.slice(1, initialWeeks.length - 1); - - // if there's an item above, lose both top corners. Item below, lose both bottom corners, etc. - weeks.forEach((week: DayInfo[], weekIndex: number) => { - week.forEach((day: DayInfo, dayIndex: number) => { - const above = - weeks[weekIndex - 1] && - weeks[weekIndex - 1][dayIndex] && - isInSameHoverRange( - weeks[weekIndex - 1][dayIndex].originalDate, - day.originalDate, - weeks[weekIndex - 1][dayIndex].isSelected, - day.isSelected, - ); - const below = - weeks[weekIndex + 1] && - weeks[weekIndex + 1][dayIndex] && - isInSameHoverRange( - weeks[weekIndex + 1][dayIndex].originalDate, - day.originalDate, - weeks[weekIndex + 1][dayIndex].isSelected, - day.isSelected, - ); - const left = - weeks[weekIndex][dayIndex - 1] && - isInSameHoverRange( - weeks[weekIndex][dayIndex - 1].originalDate, - day.originalDate, - weeks[weekIndex][dayIndex - 1].isSelected, - day.isSelected, - ); - const right = - weeks[weekIndex][dayIndex + 1] && - isInSameHoverRange( - weeks[weekIndex][dayIndex + 1].originalDate, - day.originalDate, - weeks[weekIndex][dayIndex + 1].isSelected, - day.isSelected, - ); - - weekCornersStyled[weekIndex + '_' + dayIndex] = calculateRoundedStyles(above, below, left, right); - }); - }); - - return weekCornersStyled; - }; - - const calculateRoundedStyles = (above: boolean, below: boolean, left: boolean, right: boolean): string => { - const style = []; - const roundedTopLeft = !above && !left; - const roundedTopRight = !above && !right; - const roundedBottomLeft = !below && !left; - const roundedBottomRight = !below && !right; - - if (roundedTopLeft) { - style.push(dir === 'rtl' ? weekCornersClassNames.topRightCornerDate : weekCornersClassNames.topLeftCornerDate); - } - if (roundedTopRight) { - style.push(dir === 'rtl' ? weekCornersClassNames.topLeftCornerDate : weekCornersClassNames.topRightCornerDate); - } - if (roundedBottomLeft) { - style.push( - dir === 'rtl' ? weekCornersClassNames.bottomRightCornerDate : weekCornersClassNames.bottomLeftCornerDate, - ); - } - if (roundedBottomRight) { - style.push( - dir === 'rtl' ? weekCornersClassNames.bottomLeftCornerDate : weekCornersClassNames.bottomRightCornerDate, - ); - } - - return mergeClasses(...style); - }; - - const isInSameHoverRange = (date1: Date, date2: Date, date1Selected: boolean, date2Selected: boolean): boolean => { - const { dateRangeType, firstDayOfWeek, workWeekDays } = props; - - // The hover state looks weird with non-contiguous days in work week view. In work week, show week hover state - const dateRangeHoverType = dateRangeType === DateRangeType.WorkWeek ? DateRangeType.Week : dateRangeType; - - // we do not pass daysToSelectInDayView because we handle setting those styles dyanamically in onMouseOver - const dateRange = getDateRangeArray(date1, dateRangeHoverType, firstDayOfWeek, workWeekDays); - - if (date1Selected !== date2Selected) { - // if one is selected and the other is not, they can't be in the same range - return false; - } else if (date1Selected && date2Selected) { - // if they're both selected at the same time they must be in the same range - return true; - } - - // otherwise, both must be unselected, so check the dateRange - return dateRange.filter((date: Date) => date.getTime() === date2.getTime()).length > 0; - }; - - return [getWeekCornerStyles, calculateRoundedStyles] as const; -} diff --git a/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/useWeeks.ts b/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/useWeeks.ts deleted file mode 100644 index ae1f370c27c0cb..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/CalendarDayGrid/useWeeks.ts +++ /dev/null @@ -1,58 +0,0 @@ -import * as React from 'react'; -import { compareDates, DAYS_IN_WEEK, getDayGrid } from '../../utils/index'; -import { DayInfo } from './CalendarDayGrid'; -import { CalendarDayGridProps } from './CalendarDayGrid.types'; - -/** - * @internal - */ -export function useWeeks( - props: CalendarDayGridProps, - onSelectDate: (date: Date) => void, - getSetRefCallback: (dayKey: string) => (element: HTMLElement | null) => void, -): DayInfo[][] { - /** - * Initial parsing of the given props to generate IDayInfo two dimensional array, which contains a representation - * of every day in the grid. Convenient for helping with conversions between day refs and Date objects in callbacks. - */ - const weeks = React.useMemo((): DayInfo[][] => { - const weeksGrid = getDayGrid(props); - - const firstVisibleDay = weeksGrid[1][0].originalDate; - const lastVisibleDay = weeksGrid[weeksGrid.length - 1][6].originalDate; - const markedDays = props.getMarkedDays?.(firstVisibleDay, lastVisibleDay) || []; - - /** - * Weeks is a 2D array. Weeks[0] contains the last week of the prior range, - * Weeks[weeks.length - 1] contains first week of next range. These are for transition states. - * - * Weeks[1... weeks.length - 2] contains the actual visible data - */ - const returnValue: DayInfo[][] = []; - - for (let weekIndex = 0; weekIndex < weeksGrid.length; weekIndex++) { - const week: DayInfo[] = []; - for (let dayIndex = 0; dayIndex < DAYS_IN_WEEK; dayIndex++) { - const day = weeksGrid[weekIndex][dayIndex]; - const dayInfo: DayInfo = { - onSelected: () => onSelectDate(day.originalDate), - setRef: getSetRefCallback(day.key), - ...day, - isMarked: day.isMarked || markedDays?.some(markedDay => compareDates(day.originalDate, markedDay)), - }; - - week.push(dayInfo); - } - returnValue.push(week); - } - - return returnValue; - // TODO: this is missing deps on getSetRefCallback and onSelectDate (and depending on the entire - // props object may not be a good idea due to likely frequent mutation). It would be easy to - // fix getSetRefCallback to not mutate every render, but onSelectDate is passed down from - // Calendar and trying to fix it requires a huge cascade of changes. - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [props]); - - return weeks; -} diff --git a/packages/react-components/react-datepicker-compat/src/components/CalendarMonth/CalendarMonth.tsx b/packages/react-components/react-datepicker-compat/src/components/CalendarMonth/CalendarMonth.tsx deleted file mode 100644 index a5be32bb5d6c96..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/CalendarMonth/CalendarMonth.tsx +++ /dev/null @@ -1,348 +0,0 @@ -import * as React from 'react'; -import { Enter } from '@fluentui/keyboard-keys'; -import { ArrowDownRegular, ArrowUpRegular } from '@fluentui/react-icons'; -import { useFluent_unstable } from '@fluentui/react-shared-contexts'; -import { useArrowNavigationGroup } from '@fluentui/react-tabster'; -import { mergeClasses } from '@griffel/react'; -import { - addYears, - compareDatePart, - getMonthEnd, - getMonthStart, - getYearEnd, - getYearStart, - setMonth, - DEFAULT_DATE_FORMATTING, -} from '../../utils'; -import { CalendarYear } from '../CalendarYear/CalendarYear'; -import { useCalendarMonthStyles_unstable } from './useCalendarMonthStyles'; -import type { CalendarMonthProps } from './CalendarMonth.types'; -import type { CalendarYearRange, ICalendarYear } from '../CalendarYear/CalendarYear.types'; - -const MONTHS_PER_ROW = 4; - -function useAnimateBackwards({ navigatedDate }: { navigatedDate: CalendarMonthProps['navigatedDate'] }) { - const currentYear = navigatedDate.getFullYear(); - - const previousYearRef = React.useRef(); - React.useEffect(() => { - previousYearRef.current = currentYear; - }); - const previousYear = previousYearRef.current; - - if (previousYear === undefined || previousYear === currentYear) { - return undefined; - } else { - return previousYear > currentYear; - } -} - -function useFocusLogic({ componentRef }: { componentRef: CalendarMonthProps['componentRef'] }) { - const navigatedMonthRef = React.useRef(null); - const calendarYearRef = React.useRef(null); - const focusOnUpdate = React.useRef(false); - - const focus = React.useCallback(() => { - if (calendarYearRef.current) { - calendarYearRef.current.focus(); - } else if (navigatedMonthRef.current) { - navigatedMonthRef.current.focus(); - } - }, []); - - React.useImperativeHandle(componentRef, () => ({ focus }), [focus]); - - React.useEffect(() => { - if (focusOnUpdate.current) { - focus(); - focusOnUpdate.current = false; - } - }); - - const focusOnNextUpdate = () => { - focusOnUpdate.current = true; - }; - - return [navigatedMonthRef, calendarYearRef, focusOnNextUpdate] as const; -} - -/** - * @internal - */ -export const CalendarMonth: React.FunctionComponent = props => { - const { - allFocusable, - animationDirection, - className, - componentRef, - dateTimeFormatter = DEFAULT_DATE_FORMATTING, - highlightCurrentMonth, - highlightSelectedMonth, - maxDate, - minDate, - navigatedDate, - onHeaderSelect: onUserHeaderSelect, - onNavigateDate, - selectedDate, - strings, - today = new Date(), - yearPickerHidden = false, - } = props; - - const [navigatedMonthRef, calendarYearRef, focusOnNextUpdate] = useFocusLogic({ componentRef }); - const [isYearPickerVisible, setIsYearPickerVisible] = React.useState(false); - - const animateBackwards = useAnimateBackwards({ navigatedDate }); - - const selectMonthCallback = (newMonth: number): (() => void) => { - return () => onSelectMonth(newMonth); - }; - - const onSelectNextYear = (): void => { - onNavigateDate(addYears(navigatedDate, 1), false); - }; - - const onSelectPrevYear = (): void => { - onNavigateDate(addYears(navigatedDate, -1), false); - }; - - const onSelectMonth = (newMonth: number): void => { - // If header is clickable the calendars are overlayed, switch back to day picker when month is clicked - onUserHeaderSelect?.(); - onNavigateDate(setMonth(navigatedDate, newMonth), true); - }; - - const onHeaderSelect = (): void => { - if (!yearPickerHidden) { - focusOnNextUpdate(); - setIsYearPickerVisible(true); - } else { - onUserHeaderSelect?.(); - } - }; - - const onSelectYear = (selectedYear: number) => { - focusOnNextUpdate(); - const navYear = navigatedDate.getFullYear(); - if (navYear !== selectedYear) { - let newNavigationDate = new Date(navigatedDate.getTime()); - newNavigationDate.setFullYear(selectedYear); - // for min and max dates, adjust the new navigation date - perhaps this should be - // checked on the master navigation date handler (i.e. in Calendar) - if (maxDate && newNavigationDate > maxDate) { - newNavigationDate = setMonth(newNavigationDate, maxDate.getMonth()); - } else if (minDate && newNavigationDate < minDate) { - newNavigationDate = setMonth(newNavigationDate, minDate.getMonth()); - } - onNavigateDate(newNavigationDate, true); - } - setIsYearPickerVisible(false); - }; - - const onYearPickerHeaderSelect = (focus: boolean): void => { - focusOnNextUpdate(); - setIsYearPickerVisible(false); - }; - - const dateFormatter = dateTimeFormatter!; - - // determine if previous/next years are in bounds - const isPrevYearInBounds = minDate ? compareDatePart(minDate, getYearStart(navigatedDate)) < 0 : true; - const isNextYearInBounds = maxDate ? compareDatePart(getYearEnd(navigatedDate), maxDate) < 0 : true; - - const classNames = useCalendarMonthStyles_unstable({ - className, - hasHeaderClickCallback: !!onUserHeaderSelect || !yearPickerHidden, - highlightCurrent: highlightCurrentMonth, - highlightSelected: highlightSelectedMonth, - animateBackwards, - animationDirection, - }); - - const { dir } = useFluent_unstable(); - const arrowNavigationAttributes = useArrowNavigationGroup({ axis: 'both' }); - - if (isYearPickerVisible) { - const [onRenderYear, yearStrings] = getYearStrings({ dateTimeFormatter, navigatedDate, strings }); - // use navigated date for the year picker - return ( - - ); - } - - const rowIndexes = []; - for (let i = 0; i < strings.shortMonths.length / MONTHS_PER_ROW; i++) { - rowIndexes.push(i); - } - - const yearString = dateFormatter.formatYear(navigatedDate); - const headerAriaLabel = strings.monthPickerHeaderAriaLabel - ? strings.monthPickerHeaderAriaLabel.replace('{0}', yearString) - : yearString; - - return ( -
-
- -
- - -
-
-
- {rowIndexes.map((rowNum: number) => { - const monthsForRow = strings!.shortMonths.slice(rowNum * MONTHS_PER_ROW, (rowNum + 1) * MONTHS_PER_ROW); - return ( -
- {monthsForRow.map((month: string, index: number) => { - const monthIndex = rowNum * MONTHS_PER_ROW + index; - const indexedMonth = setMonth(navigatedDate, monthIndex); - const isNavigatedMonth = navigatedDate.getMonth() === monthIndex; - const isSelectedMonth = selectedDate.getMonth() === monthIndex; - const isSelectedYear = selectedDate.getFullYear() === navigatedDate.getFullYear(); - const isInBounds = - (minDate ? compareDatePart(minDate, getMonthEnd(indexedMonth)) < 1 : true) && - (maxDate ? compareDatePart(getMonthStart(indexedMonth), maxDate) < 1 : true); - - return ( - - ); - })} -
- ); - })} -
-
- ); -}; -CalendarMonth.displayName = 'CalendarMonth'; - -function getYearStrings({ - dateTimeFormatter, - navigatedDate, - strings, -}: Pick) { - const yearToString = (year: number) => { - if (dateTimeFormatter) { - // create a date based on the current nav date - const yearFormattingDate = new Date(navigatedDate.getTime()); - yearFormattingDate.setFullYear(year); - return dateTimeFormatter.formatYear(yearFormattingDate); - } - return String(year); - }; - - const yearRangeToString = (yearRange: CalendarYearRange) => { - return `${yearToString(yearRange.fromYear)} - ${yearToString(yearRange.toYear)}`; - }; - - const yearRangeToNextDecadeLabel = (yearRange: CalendarYearRange) => { - return strings.nextYearRangeAriaLabel ? `${strings.nextYearRangeAriaLabel} ${yearRangeToString(yearRange)}` : ''; - }; - - const yearRangeToPrevDecadeLabel = (yearRange: CalendarYearRange) => { - return strings.prevYearRangeAriaLabel ? `${strings.prevYearRangeAriaLabel} ${yearRangeToString(yearRange)}` : ''; - }; - - return [ - yearToString, - { - rangeAriaLabel: yearRangeToString, - prevRangeAriaLabel: yearRangeToPrevDecadeLabel, - nextRangeAriaLabel: yearRangeToNextDecadeLabel, - headerAriaLabelFormatString: strings.yearPickerHeaderAriaLabel, - } as const, - ] as const; -} - -function isCurrentMonth(month: number, year: number, today: Date): boolean { - return today.getFullYear() === year && today.getMonth() === month; -} - -function onButtonKeyDown(callback: () => void): (ev: React.KeyboardEvent) => void { - return (ev: React.KeyboardEvent) => { - switch (ev.key) { - case Enter: - callback(); - break; - } - }; -} diff --git a/packages/react-components/react-datepicker-compat/src/components/CalendarMonth/CalendarMonth.types.ts b/packages/react-components/react-datepicker-compat/src/components/CalendarMonth/CalendarMonth.types.ts deleted file mode 100644 index 3e63e808b8e0e6..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/CalendarMonth/CalendarMonth.types.ts +++ /dev/null @@ -1,116 +0,0 @@ -import * as React from 'react'; -import { AnimationDirection } from '../Calendar/Calendar.types'; -import type { CalendarStrings, DateFormatting } from '../../utils'; -import type { CalendarPickerStyleProps, CalendarPickerStyles } from '../CalendarPicker/CalendarPicker.types'; - -// eslint-disable-next-line @typescript-eslint/naming-convention -export interface ICalendarMonth { - focus(): void; -} - -export interface CalendarMonthProps { - /** - * Optional callback to access the ICalendarMonth interface. Use this instead of ref for accessing - * the public methods and properties of the component. - */ - componentRef?: React.RefObject; - - /** - * Localized strings to use in the Calendar - */ - strings: CalendarStrings; - - /** - * The currently selected date - */ - selectedDate: Date; - - /** - * The currently navigated date - */ - navigatedDate: Date; - - /** - * Callback issued when a month is selected - * @param date - The date the user selected - * @param selectedDateRangeArray - The resultant list of dates that are selected based on the date range type set - * for the component. - */ - onSelectDate?: (date: Date, selectedDateRangeArray?: Date[]) => void; - - /** - * Callback issued when the year is navigated - * @param date - The date that is navigated to - * @param focusOnNavigatedDay - Whether to set the focus to the navigated date. - */ - onNavigateDate: (date: Date, focusOnNavigatedDay: boolean) => void; - - /** - * Value of today. If unspecified, current time in client machine will be used. - */ - today?: Date; - - /** - * Callback function when the header is selected - */ - onHeaderSelect?: () => void; - - /** - * Apply additional formatting to dates, for example localized date formatting. - */ - dateTimeFormatter?: DateFormatting; - - /** - * If set the Calendar will not allow navigation to or selection of a date earlier than this value. - */ - minDate?: Date; - - /** - * If set the Calendar will not allow navigation to or selection of a date later than this value. - */ - maxDate?: Date; - - /** - * Whether the month picker should highlight the current month - * @default false - */ - highlightCurrentMonth?: boolean; - - /** - * Whether the month picker should highlight the selected month - * @default false - */ - highlightSelectedMonth?: boolean; - - /** - * Allows all dates and buttons to be focused, including disabled ones - * @default false - */ - allFocusable?: boolean; - - /** - * Additional CSS class(es) to apply to the CalendarMonth. - */ - className?: string; - - /** - * Whether the year picker is hidden - * @default false - */ - yearPickerHidden?: boolean; - - /** - * The cardinal directions for animation to occur during transitions, either horizontal or veritcal - */ - animationDirection?: AnimationDirection; -} - -/** - * @internal - */ -export interface CalendarMonthStyleProps extends CalendarPickerStyleProps {} - -/** - * @internal - */ -export interface CalendarMonthStyles extends CalendarPickerStyles {} diff --git a/packages/react-components/react-datepicker-compat/src/components/CalendarMonth/index.ts b/packages/react-components/react-datepicker-compat/src/components/CalendarMonth/index.ts deleted file mode 100644 index dfa20f235aec36..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/CalendarMonth/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './CalendarMonth'; -export * from './CalendarMonth.types'; -export * from './useCalendarMonthStyles'; diff --git a/packages/react-components/react-datepicker-compat/src/components/CalendarMonth/useCalendarMonthStyles.ts b/packages/react-components/react-datepicker-compat/src/components/CalendarMonth/useCalendarMonthStyles.ts deleted file mode 100644 index 2127843467aac2..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/CalendarMonth/useCalendarMonthStyles.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { useCalendarPickerStyles_unstable } from '../CalendarPicker/useCalendarPickerStyles.styles'; -import type { CalendarMonthStyleProps, CalendarMonthStyles } from './CalendarMonth.types'; - -/** - * @internal - * - * Apply styling to the CalendarMonth slots based on the state - */ -export const useCalendarMonthStyles_unstable = (props: CalendarMonthStyleProps): CalendarMonthStyles => { - return useCalendarPickerStyles_unstable(props); -}; diff --git a/packages/react-components/react-datepicker-compat/src/components/CalendarPicker/CalendarPicker.types.ts b/packages/react-components/react-datepicker-compat/src/components/CalendarPicker/CalendarPicker.types.ts deleted file mode 100644 index de35513ce87635..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/CalendarPicker/CalendarPicker.types.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { AnimationDirection } from '../Calendar/Calendar.types'; - -/** - * @internal - */ -export interface CalendarPickerStyleProps { - /** - * Accept custom classNames - */ - className?: string; - - /** - * Whether the header can be clicked - */ - hasHeaderClickCallback?: boolean; - - /** - * Whether the picker should highlight the current item - */ - highlightCurrent?: boolean; - - /** - * Whether the picker should highlight the selected item - */ - highlightSelected?: boolean; - - /** - * The cardinal directions for animation to occur during transitions, either horizontal or veritcal - */ - animationDirection?: AnimationDirection; - - /** - * Whether grid entering animation should be forwards or backwards - */ - animateBackwards?: boolean; -} - -/** - * @internal - */ -export interface CalendarPickerStyles { - /** - * Style for the root element. - */ - root: string; - - headerContainer: string; - - currentItemButton: string; - - navigationButtonsContainer: string; - - navigationButton: string; - - gridContainer: string; - - buttonRow: string; - - itemButton: string; - - current: string; - - selected: string; - - disabled: string; -} diff --git a/packages/react-components/react-datepicker-compat/src/components/CalendarPicker/index.ts b/packages/react-components/react-datepicker-compat/src/components/CalendarPicker/index.ts deleted file mode 100644 index 45fa614ab928d6..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/CalendarPicker/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './CalendarPicker.types'; -export * from './useCalendarPickerStyles.styles'; diff --git a/packages/react-components/react-datepicker-compat/src/components/CalendarPicker/useCalendarPickerStyles.styles.ts b/packages/react-components/react-datepicker-compat/src/components/CalendarPicker/useCalendarPickerStyles.styles.ts deleted file mode 100644 index 24b67cfe32ebd4..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/CalendarPicker/useCalendarPickerStyles.styles.ts +++ /dev/null @@ -1,341 +0,0 @@ -import { tokens } from '@fluentui/react-theme'; -import { makeStyles, mergeClasses, shorthands } from '@griffel/react'; -import { - DURATION_2, - DURATION_3, - EASING_FUNCTION_1, - EASING_FUNCTION_2, - FADE_IN, - SLIDE_DOWN_IN20, - SLIDE_LEFT_IN20, - SLIDE_RIGHT_IN20, - SLIDE_UP_IN20, -} from '../../utils/animations'; -import { AnimationDirection } from '../Calendar/Calendar.types'; -import type { SlotClassNames } from '@fluentui/react-utilities'; -import type { CalendarPickerStyles, CalendarPickerStyleProps } from './CalendarPicker.types'; - -/** - * @internal - */ -export const calendarPickerClassNames: SlotClassNames = { - root: 'fui-CalendarPicker', - headerContainer: 'fui-CalendarPicker__headerContainer', - currentItemButton: 'fui-CalendarPicker__currentItemButton', - navigationButtonsContainer: 'fui-CalendarPicker__navigationButtonsContainer', - navigationButton: 'fui-CalendarPicker__navigationButton', - gridContainer: 'fui-CalendarPicker__gridContainer', - buttonRow: 'fui-CalendarPicker__buttonRow', - itemButton: 'fui-CalendarPicker__itemButton', - current: 'fui-CalendarPicker__current', - selected: 'fui-CalendarPicker__selected', - disabled: 'fui-CalendarPicker__disabled', -}; - -const useRootStyles = makeStyles({ - base: { - boxSizing: 'content-box', - ...shorthands.overflow('hidden'), - ...shorthands.padding('12px'), - width: '196px', - }, - normalize: { - boxShadow: 'none', - boxSizing: 'border-box', - ...shorthands.margin(0), - ...shorthands.padding(0), - }, -}); - -const useHeaderContainerStyles = makeStyles({ - base: { - display: 'flex', - }, -}); - -const useCurrentItemButtonStyles = makeStyles({ - base: { - backgroundColor: tokens.colorTransparentBackground, - ...shorthands.borderStyle('none'), - color: 'inherit', - flexGrow: 1, - fontFamily: 'inherit', - fontSize: tokens.fontSizeBase300, - fontWeight: tokens.fontWeightSemibold, - ...shorthands.overflow('visible'), - ...shorthands.padding(0, '4px', 0, '10px'), - textAlign: 'left', - }, - animation: { - animationDuration: DURATION_2, - animationFillMode: 'both', - animationName: FADE_IN, - animationTimingFunction: EASING_FUNCTION_2, - }, - hasHeaderClickCallback: { - '&:hover': { - backgroundColor: tokens.colorBrandBackgroundInvertedHover, - color: tokens.colorBrandForegroundOnLightHover, - cursor: 'pointer', - ...shorthands.outline('1px', 'solid', tokens.colorTransparentStroke), - }, - '&:hover:active': { - backgroundColor: tokens.colorBrandBackgroundInvertedPressed, - color: tokens.colorBrandForegroundOnLightPressed, - cursor: 'pointer', - ...shorthands.outline('1px', 'solid', tokens.colorTransparentStroke), - }, - }, -}); - -const useNavigationButtonsContainerStyles = makeStyles({ - base: { - alignItems: 'center', - display: 'flex', - }, -}); - -const useNavigationButtonStyles = makeStyles({ - base: { - backgroundColor: tokens.colorTransparentBackground, - ...shorthands.borderStyle('none'), - ...shorthands.borderRadius('2px'), - color: tokens.colorNeutralForeground1, - display: 'block', - fontFamily: 'inherit', - fontSize: tokens.fontSizeBase200, - height: '28px', - lineHeight: '28px', - minHeight: '28px', - minWidth: '28px', - ...shorthands.overflow('visible'), - ...shorthands.padding(0), - position: 'relative', - textAlign: 'center', - width: '28px', - - '&:hover': { - backgroundColor: tokens.colorBrandBackgroundInvertedHover, - color: tokens.colorBrandForegroundOnLightHover, - cursor: 'pointer', - ...shorthands.outline('1px', 'solid', tokens.colorTransparentStroke), - }, - - '&:hover:active': { - backgroundColor: tokens.colorBrandBackgroundInvertedPressed, - color: tokens.colorBrandForegroundOnLightPressed, - }, - }, -}); - -const useGridContainerStyles = makeStyles({ - base: { - marginTop: '4px', - }, -}); - -const useButtonRowStyles = makeStyles({ - base: { - marginBottom: '16px', - '&:last-of-type': { - marginBottom: 0, - }, - }, - animation: { - animationDuration: DURATION_3, - animationFillMode: 'both', - animationTimingFunction: EASING_FUNCTION_1, - }, - horizontalBackward: { - animationName: [FADE_IN, SLIDE_RIGHT_IN20], - }, - horizontalForward: { - animationName: [FADE_IN, SLIDE_LEFT_IN20], - }, - verticalBackward: { - animationName: [FADE_IN, SLIDE_DOWN_IN20], - }, - verticalForward: { - animationName: [FADE_IN, SLIDE_UP_IN20], - }, -}); - -const useItemButtonStyles = makeStyles({ - base: { - backgroundColor: tokens.colorTransparentBackground, - ...shorthands.borderStyle('none'), - ...shorthands.borderRadius('2px'), - color: tokens.colorNeutralForeground3, - fontFamily: 'inherit', - fontSize: tokens.fontSizeBase200, - height: '40px', - lineHeight: '40px', - minHeight: '40px', - minWidth: '40px', - ...shorthands.margin(0, '12px', 0, 0), - ...shorthands.overflow('visible'), - ...shorthands.padding(0), - width: '40px', - - '&:nth-child(4n + 4)': { - marginRight: 0, - }, - '&:nth-child(n + 9)': { - marginBottom: 0, - }, - '& div': { - fontWeight: tokens.fontWeightRegular, - }, - '&:hover': { - backgroundColor: tokens.colorBrandBackgroundInvertedHover, - color: tokens.colorNeutralForeground1Static, - cursor: 'pointer', - ...shorthands.outline('1px', 'solid', tokens.colorTransparentStroke), - - '@media (forced-colors: active)': { - backgroundColor: 'Window', - color: 'WindowText', - forcedColorAdjust: 'none', - ...shorthands.outline('1px', 'solid', 'Highlight'), - }, - }, - '&:hover:active': { - backgroundColor: tokens.colorBrandBackgroundInvertedPressed, - - '@media (forced-colors: active)': { - backgroundColor: 'Window', - color: 'Highlight', - forcedColorAdjust: 'none', - }, - }, - }, -}); - -const useCurrentStyles = makeStyles({ - highlightCurrent: { - backgroundColor: tokens.colorBrandBackground, - color: tokens.colorNeutralForegroundOnBrand, - fontWeight: tokens.fontWeightSemibold, - - '@media (forced-colors: active)': { - backgroundColor: 'WindowText', - color: 'Window', - forcedColorAdjust: 'none', - }, - '&:hover, &:hover:active': { - backgroundColor: tokens.colorBrandBackground, - color: tokens.colorNeutralForegroundOnBrand, - - '@media (forced-colors: active)': { - backgroundColor: 'WindowText', - color: 'Window', - forcedColorAdjust: 'none', - }, - }, - }, -}); - -const useSelectedStyles = makeStyles({ - highlightSelected: { - backgroundColor: tokens.colorBrandBackgroundInvertedSelected, - color: tokens.colorNeutralForeground1Static, - fontWeight: tokens.fontWeightSemibold, - - '@media (forced-colors: active)': { - backgroundColor: 'Highlight', - color: 'Window', - forcedColorAdjust: 'none', - }, - '& div': { - fontWeight: tokens.fontWeightSemibold, - }, - '&:hover': { - backgroundColor: tokens.colorBrandBackgroundInvertedSelected, - color: tokens.colorNeutralForeground1Static, - - '@media (forced-colors: active)': { - backgroundColor: 'Highlight', - color: 'Window', - forcedColorAdjust: 'none', - }, - }, - '&:hover:active': { - backgroundColor: tokens.colorBrandBackgroundInvertedPressed, - }, - }, -}); - -const useDisabledStyles = makeStyles({ - base: { - '&, &:disabled, & button': { - color: tokens.colorNeutralForegroundDisabled, - pointerEvents: 'none', - }, - '@media (forced-colors: active)': { - color: 'GrayText', - forcedColorAdjust: 'none', - }, - }, -}); - -/** - * @internal - * - * Apply styling to the CalendarPicker slots based on the state - */ -export const useCalendarPickerStyles_unstable = (props: CalendarPickerStyleProps): CalendarPickerStyles => { - const rootStyles = useRootStyles(); - const headerContainerStyles = useHeaderContainerStyles(); - const currentItemButtonStyles = useCurrentItemButtonStyles(); - const navigationButtonsContainerStyles = useNavigationButtonsContainerStyles(); - const navigationButtonStyles = useNavigationButtonStyles(); - const gridContainerStyles = useGridContainerStyles(); - const buttonRowStyles = useButtonRowStyles(); - const itemButtonStyles = useItemButtonStyles(); - const currentStyles = useCurrentStyles(); - const selectedStyles = useSelectedStyles(); - const disabledStyles = useDisabledStyles(); - - const { - animateBackwards, - animationDirection, - className, - hasHeaderClickCallback, - highlightCurrent, - highlightSelected, - } = props; - - return { - root: mergeClasses(calendarPickerClassNames.root, rootStyles.normalize, rootStyles.base, className), - headerContainer: mergeClasses(calendarPickerClassNames.headerContainer, headerContainerStyles.base), - currentItemButton: mergeClasses( - calendarPickerClassNames.currentItemButton, - currentItemButtonStyles.base, - animateBackwards !== undefined && currentItemButtonStyles.animation, - hasHeaderClickCallback && currentItemButtonStyles.hasHeaderClickCallback, - ), - navigationButtonsContainer: mergeClasses( - calendarPickerClassNames.navigationButtonsContainer, - navigationButtonsContainerStyles.base, - ), - navigationButton: mergeClasses(calendarPickerClassNames.navigationButton, navigationButtonStyles.base), - gridContainer: mergeClasses(calendarPickerClassNames.gridContainer, gridContainerStyles.base), - buttonRow: mergeClasses( - calendarPickerClassNames.buttonRow, - buttonRowStyles.base, - buttonRowStyles.animation, - animateBackwards !== undefined && - (animationDirection === AnimationDirection.Horizontal - ? animateBackwards - ? buttonRowStyles.horizontalBackward - : buttonRowStyles.horizontalForward - : animateBackwards - ? buttonRowStyles.verticalBackward - : buttonRowStyles.verticalForward), - ), - itemButton: mergeClasses(calendarPickerClassNames.itemButton, itemButtonStyles.base), - selected: mergeClasses(calendarPickerClassNames.selected, highlightSelected && selectedStyles.highlightSelected), - current: mergeClasses(calendarPickerClassNames.current, highlightCurrent && currentStyles.highlightCurrent), - disabled: mergeClasses(calendarPickerClassNames.disabled, disabledStyles.base), - }; -}; diff --git a/packages/react-components/react-datepicker-compat/src/components/CalendarYear/CalendarYear.tsx b/packages/react-components/react-datepicker-compat/src/components/CalendarYear/CalendarYear.tsx deleted file mode 100644 index c5f17973bf8c8a..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/CalendarYear/CalendarYear.tsx +++ /dev/null @@ -1,445 +0,0 @@ -import * as React from 'react'; -import { Enter, Space } from '@fluentui/keyboard-keys'; -import { ArrowDownRegular, ArrowUpRegular } from '@fluentui/react-icons'; -import { useFluent_unstable } from '@fluentui/react-shared-contexts'; -import { useArrowNavigationGroup } from '@fluentui/react-tabster'; -import { mergeClasses } from '@griffel/react'; -import { useCalendarYearStyles_unstable } from './useCalendarYearStyles.styles'; -import type { - CalendarYearStrings, - CalendarYearProps, - CalendarYearRange, - CalendarYearHeaderProps, -} from './CalendarYear.types'; - -const CELL_COUNT = 12; -const CELLS_PER_ROW = 4; - -const DefaultCalendarYearStrings: CalendarYearStrings = { - prevRangeAriaLabel: undefined, - nextRangeAriaLabel: undefined, -}; -interface CalendarYearGrid { - focus(): void; -} - -interface CalendarYearGridCellProps extends CalendarYearProps { - year: number; - current?: boolean; - selected?: boolean; - disabled?: boolean; - onSelectYear?: (year: number) => void; - onRenderYear?: (year: number) => React.ReactNode; -} - -interface CalendarYearGridProps extends CalendarYearProps, CalendarYearRange { - selectedYear?: number; - animateBackwards?: boolean; - componentRef?: React.RefObject; -} - -interface CalendarYearGridCell { - focus(): void; -} - -const CalendarYearGridCell: React.FunctionComponent = props => { - const { - className, - highlightCurrentYear, - highlightSelectedYear, - year, - selected, - disabled, - componentRef, - onSelectYear, - onRenderYear, - } = props; - - const buttonRef = React.useRef(null); - - React.useImperativeHandle( - componentRef, - () => ({ - focus() { - buttonRef.current?.focus?.(); - }, - }), - [], - ); - - const onClick = () => { - onSelectYear?.(year); - }; - - const onKeyDown = (ev: React.KeyboardEvent) => { - if (ev.key === Enter) { - onSelectYear?.(year); - } - }; - - const classNames = useCalendarYearStyles_unstable({ - className, - highlightCurrent: highlightCurrentYear, - highlightSelected: highlightSelectedYear, - }); - - return ( - - ); -}; -CalendarYearGridCell.displayName = 'CalendarYearGridCell'; - -const CalendarYearGrid: React.FunctionComponent = props => { - const { - className, - fromYear, - toYear, - animationDirection, - animateBackwards, - minYear, - maxYear, - onSelectYear, - selectedYear, - componentRef, - } = props; - - const selectedCellRef = React.useRef(null); - const currentCellRef = React.useRef(null); - - React.useImperativeHandle( - componentRef, - () => ({ - focus() { - (selectedCellRef.current || currentCellRef.current)?.focus?.(); - }, - }), - [], - ); - - const renderCell = (yearToRender: number): React.ReactNode => { - const selected = yearToRender === selectedYear; - const disabled = - (minYear !== undefined && yearToRender < minYear) || (maxYear !== undefined && yearToRender > maxYear); - const current = yearToRender === new Date().getFullYear(); - - return ( - - ); - }; - - const classNames = useCalendarYearStyles_unstable({ - className, - animateBackwards, - animationDirection, - }); - - const onRenderYear = (value: number) => { - return props.onRenderYear?.(value) ?? value; - }; - - const gridAriaLabel = `${onRenderYear(fromYear)} - ${onRenderYear(toYear)}`; - - let year = fromYear; - const cells: React.ReactNode[][] = []; - - for (let i = 0; i < (toYear - fromYear + 1) / CELLS_PER_ROW; i++) { - cells.push([]); - for (let j = 0; j < CELLS_PER_ROW; j++) { - cells[i].push(renderCell(year)); - year++; - } - } - - const arrowNavigationAttributes = useArrowNavigationGroup({ axis: 'both' }); - - return ( -
-
- {cells.map((cellRow: React.ReactNode[], index: number) => { - return ( -
- {cellRow} -
- ); - })} -
-
- ); -}; -CalendarYearGrid.displayName = 'CalendarYearGrid'; - -const CalendarYearNavDirection = { - Previous: 0 as const, - Next: 1 as const, -}; - -interface CalendarYearNavArrowProps extends CalendarYearHeaderProps { - direction: (typeof CalendarYearNavDirection)[keyof typeof CalendarYearNavDirection]; -} - -const CalendarYearNavArrow: React.FunctionComponent = props => { - const { - className, - strings = DefaultCalendarYearStrings, - direction, - onSelectPrev, - onSelectNext, - fromYear, - toYear, - maxYear, - minYear, - } = props; - - const classNames = useCalendarYearStyles_unstable({ - className, - }); - - const ariaLabel = - direction === CalendarYearNavDirection.Previous ? strings.prevRangeAriaLabel : strings.nextRangeAriaLabel; - const newRangeOffset = direction === CalendarYearNavDirection.Previous ? -CELL_COUNT : CELL_COUNT; - const newRange = { fromYear: fromYear + newRangeOffset, toYear: toYear + newRangeOffset }; - const ariaLabelString = ariaLabel ? (typeof ariaLabel === 'string' ? ariaLabel : ariaLabel(newRange)) : undefined; - const disabled = - direction === CalendarYearNavDirection.Previous - ? minYear !== undefined && fromYear < minYear - : maxYear !== undefined && props.fromYear + CELL_COUNT > maxYear; - - const onNavigate = () => { - direction === CalendarYearNavDirection.Previous ? onSelectPrev?.() : onSelectNext?.(); - }; - - const onKeyDown = (ev: React.KeyboardEvent) => { - if (ev.key === Enter) { - onNavigate(); - } - }; - - const { dir } = useFluent_unstable(); - - // can be condensed, but leaving verbose for clarity due to regressions - const isLeftNavigation = - dir === 'rtl' ? direction === CalendarYearNavDirection.Next : direction === CalendarYearNavDirection.Previous; - - return ( - - ); -}; -CalendarYearNavArrow.displayName = 'CalendarYearNavArrow'; - -const CalendarYearNav: React.FunctionComponent = props => { - const { className } = props; - - const classNames = useCalendarYearStyles_unstable({ - className, - }); - - return ( -
- - -
- ); -}; -CalendarYearNav.displayName = 'CalendarYearNav'; - -const CalendarYearTitle: React.FunctionComponent = props => { - const { - className, - fromYear, - toYear, - strings = DefaultCalendarYearStrings, - animateBackwards, - animationDirection, - } = props; - - const onHeaderSelect = () => { - props.onHeaderSelect?.(true); - }; - - const onHeaderKeyDown = (ev: React.KeyboardEvent) => { - if (ev.key === Enter || ev.key === Space) { - onHeaderSelect(); - } - }; - - const onRenderYear = (year: number) => { - return props.onRenderYear?.(year) ?? year; - }; - - const classNames = useCalendarYearStyles_unstable({ - className, - hasHeaderClickCallback: !!props.onHeaderSelect, - animateBackwards, - animationDirection, - }); - - if (props.onHeaderSelect) { - const rangeAriaLabel = strings.rangeAriaLabel; - const headerAriaLabelFormatString = strings.headerAriaLabelFormatString; - const currentDateRange = rangeAriaLabel - ? typeof rangeAriaLabel === 'string' - ? rangeAriaLabel - : rangeAriaLabel(props) - : undefined; - - const ariaLabel = headerAriaLabelFormatString - ? headerAriaLabelFormatString.replace('{0}', currentDateRange ?? '') - : currentDateRange; - - return ( - - ); - } - - return ( -
- {onRenderYear(fromYear)} - {onRenderYear(toYear)} -
- ); -}; -CalendarYearTitle.displayName = 'CalendarYearTitle'; - -const CalendarYearHeader: React.FunctionComponent = props => { - const { className, animateBackwards, animationDirection, onRenderTitle } = props; - - const classNames = useCalendarYearStyles_unstable({ - className, - hasHeaderClickCallback: !!props.onHeaderSelect, - animateBackwards, - animationDirection, - }); - - return ( -
- {onRenderTitle?.(props) ?? } - -
- ); -}; -CalendarYearHeader.displayName = 'CalendarYearHeader'; - -function useAnimateBackwards({ selectedYear, navigatedYear }: CalendarYearProps) { - const rangeYear = selectedYear || navigatedYear || new Date().getFullYear(); - const fromYear = Math.floor(rangeYear / 10) * 10; - - const previousFromYearRef = React.useRef(fromYear); - React.useRef(() => { - previousFromYearRef.current = fromYear; - }); - const previousFromYear = previousFromYearRef.current; - - if (!previousFromYear || previousFromYear === fromYear) { - return undefined; - } else if (previousFromYear > fromYear) { - return true; - } else { - return false; - } -} - -function useYearRangeState({ selectedYear, navigatedYear }: CalendarYearProps) { - const rangeYear = React.useMemo(() => { - return selectedYear || navigatedYear || Math.floor(new Date().getFullYear() / 10) * 10; - }, [navigatedYear, selectedYear]); - - const [fromYear, setFromYear] = React.useState(rangeYear); - - const onNavNext = () => { - setFromYear(year => year + CELL_COUNT); - }; - - const onNavPrevious = () => { - setFromYear(year => year - CELL_COUNT); - }; - - React.useEffect(() => { - setFromYear(rangeYear); - }, [rangeYear]); - - const toYear = fromYear + CELL_COUNT - 1; - - return [fromYear, toYear, onNavNext, onNavPrevious] as const; -} - -/** - * @internal - */ -export const CalendarYear: React.FunctionComponent = props => { - const animateBackwards = useAnimateBackwards(props); - const [fromYear, toYear, onNavNext, onNavPrevious] = useYearRangeState(props); - - const gridRef = React.useRef(null); - - React.useImperativeHandle(props.componentRef, () => ({ - focus() { - gridRef.current?.focus?.(); - }, - })); - - const { className } = props; - - const classNames = useCalendarYearStyles_unstable({ - className, - }); - - return ( -
- - -
- ); -}; -CalendarYear.displayName = 'CalendarYear'; diff --git a/packages/react-components/react-datepicker-compat/src/components/CalendarYear/CalendarYear.types.ts b/packages/react-components/react-datepicker-compat/src/components/CalendarYear/CalendarYear.types.ts deleted file mode 100644 index b0df727b09c3aa..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/CalendarYear/CalendarYear.types.ts +++ /dev/null @@ -1,145 +0,0 @@ -import * as React from 'react'; -import { AnimationDirection } from '../Calendar/Calendar.types'; -import type { CalendarPickerStyleProps, CalendarPickerStyles } from '../CalendarPicker/CalendarPicker.types'; - -/** - * @internal - */ -// eslint-disable-next-line @typescript-eslint/naming-convention -export interface ICalendarYear { - focus(): void; -} - -/** - * @internal - */ -export interface CalendarYearRange { - fromYear: number; - toYear: number; -} - -/** - * @internal - */ -export interface CalendarYearRangeToString { - (range: CalendarYearRange): string; -} - -/** - * @internal - */ -export interface CalendarYearStrings { - rangeAriaLabel?: string | CalendarYearRangeToString; - prevRangeAriaLabel?: string | CalendarYearRangeToString; - nextRangeAriaLabel?: string | CalendarYearRangeToString; - headerAriaLabelFormatString?: string; -} - -/** - * @internal - */ -export interface CalendarYearProps { - /** - * Optional callback to access the ICalendarYear interface. Use this instead of ref for accessing - * the public methods and properties of the component. - */ - componentRef?: React.RefObject; - - /** - * Localized strings to use in the Calendar - */ - strings?: CalendarYearStrings; - - /** - * The currently selected year - */ - selectedYear?: number; - - /** - * The currently navigated year - */ - navigatedYear?: number; - - /** - * Callback action when a year is selected - * @param year - The year the user selected - */ - onSelectYear?: (year: number) => void; - - /** - * Callback action when the header is selected - */ - onHeaderSelect?: (focus: boolean) => void; - - /** - * If set the Calendar will not allow navigation to or selection of a year earlier than this value. - */ - minYear?: number; - - /** - * If set the Calendar will not allow navigation to or selection of a year later than this value. - */ - maxYear?: number; - - /** - * Whether the year picker should highlight the current year - * @default false - */ - highlightCurrentYear?: boolean; - - /** - * Whether the year picker should highlight the selected year - * @default false - */ - highlightSelectedYear?: boolean; - - /** - * Accept custom classNames - */ - className?: string; - - /** - * Custom renderer for the title - */ - onRenderTitle?: (props: CalendarYearHeaderProps) => React.ReactNode; - - /** - * Custom renderer for the year - */ - onRenderYear?: (year: number) => React.ReactNode; - - /** - * The cardinal directions for animation to occur during transitions, either horizontal or veritcal - */ - animationDirection?: AnimationDirection; -} - -/** - * @internal - */ -export interface CalendarYearStyleProps extends CalendarPickerStyleProps {} - -/** - * @internal - */ -export interface CalendarYearStyles extends CalendarPickerStyles {} - -/** - * @internal - */ -export interface CalendarYearHeaderProps extends CalendarYearProps, CalendarYearRange { - /** - * Callback action when the 'previous' navigation button is selected - */ - onSelectPrev?: () => void; - - /** - * Callback action when the 'next' navigation button is selected - */ - onSelectNext?: () => void; - - /** - * Whether title entering animation should be forwards or backwards - */ - animateBackwards?: boolean; -} diff --git a/packages/react-components/react-datepicker-compat/src/components/CalendarYear/index.ts b/packages/react-components/react-datepicker-compat/src/components/CalendarYear/index.ts deleted file mode 100644 index d03d1a5c9d2fe0..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/CalendarYear/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './CalendarYear'; -export * from './CalendarYear.types'; -export * from './useCalendarYearStyles.styles'; diff --git a/packages/react-components/react-datepicker-compat/src/components/CalendarYear/useCalendarYearStyles.styles.ts b/packages/react-components/react-datepicker-compat/src/components/CalendarYear/useCalendarYearStyles.styles.ts deleted file mode 100644 index e81f0c58cc0f97..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/components/CalendarYear/useCalendarYearStyles.styles.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { useCalendarPickerStyles_unstable } from '../CalendarPicker/useCalendarPickerStyles.styles'; -import type { CalendarYearStyleProps, CalendarYearStyles } from './CalendarYear.types'; - -/** - * @internal - * - * Apply styling to the CalendarYear slots based on the state - */ -export const useCalendarYearStyles_unstable = (props: CalendarYearStyleProps): CalendarYearStyles => { - return useCalendarPickerStyles_unstable(props); -}; diff --git a/packages/react-components/react-datepicker-compat/src/components/DatePicker/DatePicker.types.ts b/packages/react-components/react-datepicker-compat/src/components/DatePicker/DatePicker.types.ts index 7cc83a55b85c1a..bffab2aa1118c0 100644 --- a/packages/react-components/react-datepicker-compat/src/components/DatePicker/DatePicker.types.ts +++ b/packages/react-components/react-datepicker-compat/src/components/DatePicker/DatePicker.types.ts @@ -1,8 +1,7 @@ -import { DayOfWeek, FirstWeekOfYear } from '../../utils'; +import { DayOfWeek, FirstWeekOfYear } from '@fluentui/react-calendar-compat'; import { Input } from '@fluentui/react-input'; import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities'; -import type { CalendarProps } from '../Calendar/Calendar.types'; -import type { CalendarStrings, DateFormatting } from '../../utils'; +import type { CalendarProps, CalendarStrings, DateFormatting } from '@fluentui/react-calendar-compat'; import type { PortalProps } from '@fluentui/react-portal'; import type { PositioningProps } from '@fluentui/react-positioning'; diff --git a/packages/react-components/react-datepicker-compat/src/components/DatePicker/defaults.ts b/packages/react-components/react-datepicker-compat/src/components/DatePicker/defaults.ts index d1b88828b935e7..6dac4e273923c2 100644 --- a/packages/react-components/react-datepicker-compat/src/components/DatePicker/defaults.ts +++ b/packages/react-components/react-datepicker-compat/src/components/DatePicker/defaults.ts @@ -1,5 +1,5 @@ -import { defaultCalendarStrings } from '../Calendar/defaults'; -import type { CalendarStrings } from '../../utils/index'; +import { defaultCalendarStrings } from '@fluentui/react-calendar-compat'; +import type { CalendarStrings } from '@fluentui/react-calendar-compat'; import type { DatePickerErrorType } from './DatePicker.types'; export const defaultDatePickerStrings: CalendarStrings = { diff --git a/packages/react-components/react-datepicker-compat/src/components/DatePicker/useDatePicker.tsx b/packages/react-components/react-datepicker-compat/src/components/DatePicker/useDatePicker.tsx index 95b31d8e8f3f93..6454e752a10b71 100644 --- a/packages/react-components/react-datepicker-compat/src/components/DatePicker/useDatePicker.tsx +++ b/packages/react-components/react-datepicker-compat/src/components/DatePicker/useDatePicker.tsx @@ -1,8 +1,7 @@ import * as React from 'react'; import { ArrowDown, Enter, Escape } from '@fluentui/keyboard-keys'; -import { Calendar } from '../Calendar/Calendar'; +import { Calendar, compareDatePart, DayOfWeek, FirstWeekOfYear } from '@fluentui/react-calendar-compat'; import { CalendarMonthRegular } from '@fluentui/react-icons'; -import { compareDatePart, DayOfWeek, FirstWeekOfYear } from '../../utils'; import { defaultDatePickerStrings } from './defaults'; import { Input } from '@fluentui/react-input'; import { @@ -19,7 +18,7 @@ import { useFieldContext_unstable as useFieldContext } from '@fluentui/react-fie import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts'; import { useModalAttributes } from '@fluentui/react-tabster'; import { usePopupPositioning } from '../../utils/usePopupPositioning'; -import type { CalendarProps, ICalendar } from '../Calendar/Calendar.types'; +import type { CalendarProps, ICalendar } from '@fluentui/react-calendar-compat'; import type { DatePickerProps, DatePickerState, DatePickerValidationResultData } from './DatePicker.types'; import type { InputProps, InputOnChangeData } from '@fluentui/react-input'; diff --git a/packages/react-components/react-datepicker-compat/src/index.ts b/packages/react-components/react-datepicker-compat/src/index.ts index a98fd72dd71daa..0373063bc7da9d 100644 --- a/packages/react-components/react-datepicker-compat/src/index.ts +++ b/packages/react-components/react-datepicker-compat/src/index.ts @@ -1,10 +1,3 @@ -export { AnimationDirection } from './Calendar'; -export type { CalendarProps, ICalendar } from './Calendar'; - -export type { CalendarDayProps, ICalendarDay } from './CalendarDay'; - -export type { CalendarMonthProps, ICalendarMonth } from './CalendarMonth'; - export { DatePicker, datePickerClassNames, @@ -15,31 +8,3 @@ export { useDatePickerStyles_unstable, } from './DatePicker'; export type { DatePickerErrorType, DatePickerProps, DatePickerValidationResultData } from './DatePicker'; - -export { - DAYS_IN_WEEK, - DateRangeType, - DayOfWeek, - FirstWeekOfYear, - MonthOfYear, - TimeConstants, - addDays, - addMonths, - addWeeks, - addYears, - compareDatePart, - compareDates, - getDatePartHashValue, - getDateRangeArray, - getEndDateOfWeek, - getMonthEnd, - getMonthStart, - getStartDateOfWeek, - getWeekNumber, - getWeekNumbersInMonth, - getYearEnd, - getYearStart, - isInDateRangeArray, - setMonth, -} from './utils'; -export type { CalendarStrings, DateFormatting, DateGridStrings } from './utils'; diff --git a/packages/react-components/react-datepicker-compat/src/utils/animations.ts b/packages/react-components/react-datepicker-compat/src/utils/animations.ts deleted file mode 100644 index b561146beb0a98..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/utils/animations.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { shorthands } from '@griffel/react'; - -export const EASING_FUNCTION_1 = 'cubic-bezier(.1,.9,.2,1)'; -export const EASING_FUNCTION_2 = 'cubic-bezier(.1,.25,.75,.9)'; -export const DURATION_1 = '0.167s'; -export const DURATION_2 = '0.267s'; -export const DURATION_3 = '0.367s'; -export const DURATION_4 = '0.467s'; - -export const FADE_IN = { - from: { - opacity: 0, - }, - to: { - opacity: 1, - }, -}; -export const FADE_OUT = { - from: { - opacity: 1, - }, - to: { - opacity: 0, - visibility: 'hidden' as const, - }, -}; -export const SLIDE_DOWN_IN20 = { - from: { - pointerEvents: 'none' as const, - transform: 'translate3d(0, -20px, 0)', - }, - to: { - pointerEvents: 'auto' as const, - transform: 'translate3d(0, 0, 0)', - }, -}; -export const SLIDE_LEFT_IN20 = { - from: { - pointerEvents: 'none' as const, - transform: 'translate3d(20px, 0, 0)', - }, - to: { - pointerEvents: 'auto' as const, - transform: 'translate3d(0, 0, 0)', - }, -}; -export const SLIDE_RIGHT_IN20 = { - from: { - pointerEvents: 'none' as const, - transform: 'translate3d(-20px, 0, 0)', - }, - to: { - pointerEvents: 'auto' as const, - transform: 'translate3d(0, 0, 0)', - }, -}; -export const SLIDE_UP_IN20 = { - from: { - pointerEvents: 'none' as const, - transform: 'translate3d(0, 20px, 0)', - }, - to: { - pointerEvents: 'auto' as const, - transform: 'translate3d(0, 0, 0)', - }, -}; -export const SLIDE_DOWN_OUT20 = { - from: { - transform: 'translate3d(0, 0, 0)', - }, - to: { - transform: 'translate3d(0, 20px, 0)', - }, -}; -export const SLIDE_UP_OUT20 = { - from: { - transform: 'translate3d(0, 0, 0)', - }, - to: { - transform: 'translate3d(0, -20px, 0)', - }, -}; -export const TRANSITION_ROW_DISAPPEARANCE = { - '100%': { - height: '0px', - ...shorthands.overflow('hidden'), - width: '0px', - }, - '99.9%': { - height: '28px', - ...shorthands.overflow('visible'), - width: '100%', - }, - '0%': { - height: '28px', - ...shorthands.overflow('visible'), - width: '100%', - }, -}; diff --git a/packages/react-components/react-datepicker-compat/src/utils/constants.ts b/packages/react-components/react-datepicker-compat/src/utils/constants.ts deleted file mode 100644 index 79266fabef021e..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/utils/constants.ts +++ /dev/null @@ -1,74 +0,0 @@ -/** - * The days of the week - */ -export enum DayOfWeek { - Sunday = 0, - Monday = 1, - Tuesday = 2, - Wednesday = 3, - Thursday = 4, - Friday = 5, - Saturday = 6, -} - -/** - * The months - */ -export enum MonthOfYear { - January = 0, - February = 1, - March = 2, - April = 3, - May = 4, - June = 5, - July = 6, - August = 7, - September = 8, - October = 9, - November = 10, - December = 11, -} - -/** - * First week of the year settings types - */ -export enum FirstWeekOfYear { - FirstDay = 0, - FirstFullWeek = 1, - FirstFourDayWeek = 2, -} - -/** - * The supported date range types - */ -export enum DateRangeType { - Day = 0, - Week = 1, - Month = 2, - WorkWeek = 3, -} - -export const DAYS_IN_WEEK = 7; - -export const TimeConstants = { - MillisecondsInOneDay: 86400000, - MillisecondsIn1Sec: 1000, - MillisecondsIn1Min: 60000, - MillisecondsIn30Mins: 1800000, - MillisecondsIn1Hour: 3600000, - MinutesInOneDay: 1440, - MinutesInOneHour: 60, - DaysInOneWeek: 7, - MonthInOneYear: 12, - HoursInOneDay: 24, - SecondsInOneMinute: 60, - OffsetTo24HourFormat: 12, - /** - * Matches a time string. Groups: - * 1. hours (with or without leading 0) - * 2. minutes - * 3. seconds (optional) - * 4. meridiem (am/pm, case-insensitive, optional) - */ - TimeFormatRegex: /^(\d\d?):(\d\d):?(\d\d)? ?([ap]m)?/i, -}; diff --git a/packages/react-components/react-datepicker-compat/src/utils/dateFormatting/dateFormatting.defaults.ts b/packages/react-components/react-datepicker-compat/src/utils/dateFormatting/dateFormatting.defaults.ts deleted file mode 100644 index 49e98c2d6c20b1..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/utils/dateFormatting/dateFormatting.defaults.ts +++ /dev/null @@ -1,83 +0,0 @@ -import type { CalendarStrings, DateFormatting, DateGridStrings } from './dateFormatting.types'; - -/** - * Format date to a day string representation - * @param date - input date to format - */ -export const formatDay = (date: Date) => date.getDate().toString(); - -/** - * Format date to a month-day-year string - * @param date - input date to format - * @param strings - localized strings - */ -export const formatMonthDayYear = (date: Date, strings: DateGridStrings) => - strings.months[date.getMonth()] + ' ' + date.getDate() + ', ' + date.getFullYear(); - -/** - * Format date to a month-year string - * @param date - input date to format - * @param strings - localized strings - */ -export const formatMonthYear = (date: Date, strings: DateGridStrings) => - strings.months[date.getMonth()] + ' ' + date.getFullYear(); - -/** - * Format date to a month string - * @param date - input date to format - * @param strings - localized strings - */ -export const formatMonth = (date: Date, strings: DateGridStrings) => strings.months[date.getMonth()]; - -/** - * Format date to a year string representation - * @param date - input date to format - */ -export const formatYear = (date: Date) => date.getFullYear().toString(); - -export const DEFAULT_DATE_GRID_STRINGS: DateGridStrings = { - months: [ - 'January', - 'February', - 'March', - 'April', - 'May', - 'June', - 'July', - 'August', - 'September', - 'October', - 'November', - 'December', - ], - shortMonths: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], - days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], - shortDays: ['S', 'M', 'T', 'W', 'T', 'F', 'S'], -}; - -export const DEFAULT_DATE_FORMATTING: DateFormatting = { - formatDay, - formatMonth, - formatYear, - formatMonthDayYear, - formatMonthYear, -}; - -export const DEFAULT_CALENDAR_STRINGS: CalendarStrings = { - ...DEFAULT_DATE_GRID_STRINGS, - - goToToday: 'Go to today', - weekNumberFormatString: 'Week number {0}', - prevMonthAriaLabel: 'Previous month', - nextMonthAriaLabel: 'Next month', - prevYearAriaLabel: 'Previous year', - nextYearAriaLabel: 'Next year', - prevYearRangeAriaLabel: 'Previous year range', - nextYearRangeAriaLabel: 'Next year range', - closeButtonAriaLabel: 'Close', - selectedDateFormatString: 'Selected date {0}', - todayDateFormatString: "Today's date {0}", - monthPickerHeaderAriaLabel: '{0}, change year', - yearPickerHeaderAriaLabel: '{0}, change month', - dayMarkedAriaLabel: 'marked', -}; diff --git a/packages/react-components/react-datepicker-compat/src/utils/dateFormatting/dateFormatting.test.ts b/packages/react-components/react-datepicker-compat/src/utils/dateFormatting/dateFormatting.test.ts deleted file mode 100644 index 1ed8ebc5cccfa1..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/utils/dateFormatting/dateFormatting.test.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { MonthOfYear } from '../constants'; -import { - formatDay, - formatMonth, - formatMonthDayYear, - formatMonthYear, - formatYear, - DEFAULT_DATE_GRID_STRINGS, -} from './dateFormatting.defaults'; - -const date = new Date(2016, MonthOfYear.April, 1); - -describe('formatDay', () => { - it('returns default format', () => { - const result = formatDay(date); - expect(result).toBe('1'); - }); -}); - -describe('formatMonth', () => { - it('returns default format', () => { - const result = formatMonth(date, DEFAULT_DATE_GRID_STRINGS); - expect(result).toBe('April'); - }); -}); - -describe('formatMonthDayYear', () => { - it('returns default format', () => { - const result = formatMonthDayYear(date, DEFAULT_DATE_GRID_STRINGS); - expect(result).toBe('April 1, 2016'); - }); -}); - -describe('formatMonthYear', () => { - it('returns default format', () => { - const result = formatMonthYear(date, DEFAULT_DATE_GRID_STRINGS); - expect(result).toBe('April 2016'); - }); -}); - -describe('formatYear', () => { - it('returns default format', () => { - const result = formatYear(date); - expect(result).toBe('2016'); - }); -}); diff --git a/packages/react-components/react-datepicker-compat/src/utils/dateFormatting/dateFormatting.types.ts b/packages/react-components/react-datepicker-compat/src/utils/dateFormatting/dateFormatting.types.ts deleted file mode 100644 index 1af630d1daf0a4..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/utils/dateFormatting/dateFormatting.types.ts +++ /dev/null @@ -1,127 +0,0 @@ -export interface DateGridStrings { - /** - * An array of strings for the full names of months. - * The array is 0-based, so months[0] should be the full name of January. - */ - months: string[]; - - /** - * An array of strings for the short names of months. - * The array is 0-based, so shortMonths[0] should be the short name of January. - */ - shortMonths: string[]; - - /** - * An array of strings for the full names of days of the week. - * The array is 0-based, so days[0] should be the full name of Sunday. - */ - days: string[]; - - /** - * An array of strings for the initials of the days of the week. - * The array is 0-based, so days[0] should be the initial of Sunday. - */ - shortDays: string[]; -} - -export interface DateFormatting { - /** - * Get a localized string for a day. - */ - formatDay: (date: Date) => string; - - /** - * Get a localized string for a month. - */ - formatMonth: (date: Date, strings: DateGridStrings) => string; - - /** - * Get a localized string for a year. - */ - formatYear: (date: Date) => string; - - /** - * Get a localized string for a month, day, and year. - */ - formatMonthDayYear: (date: Date, strings: DateGridStrings) => string; - - /** - * Get a localized string for a month and year. - */ - formatMonthYear: (date: Date, strings: DateGridStrings) => string; -} - -export interface CalendarStrings extends DateGridStrings { - /** - * String to render for button to direct the user to today's date. - */ - goToToday: string; - - /** - * Aria-label for the "previous month" button in day picker. - */ - prevMonthAriaLabel?: string; - - /** - * Aria-label for the "next month" button in day picker. - */ - nextMonthAriaLabel?: string; - - /** - * Aria-label for the "previous year" button in month picker. - */ - prevYearAriaLabel?: string; - - /** - * Aria-label for the "next year" button in month picker. - */ - nextYearAriaLabel?: string; - - /** - * Aria-label for the "previous year range" button in year picker. - */ - prevYearRangeAriaLabel?: string; - - /** - * Aria-label for the "next year range" button in year picker. - */ - nextYearRangeAriaLabel?: string; - - /** - * Aria-label format string for the header button in the month picker. Should have 1 string param, e.g. "`{0}`, - * select to change the year". This aria-label will only be applied if the year picker is enabled; otherwise - * the label will default to the header string, e.g. "2019". - */ - monthPickerHeaderAriaLabel?: string; - - /** - * Aria-label format string for the header button in the year picker. - * Should have 1 string param, e.g. "`{0}`, select to change the month" - */ - yearPickerHeaderAriaLabel?: string; - - /** - * Aria-label for the "close" button. - */ - closeButtonAriaLabel?: string; - - /** - * Aria-label format string for the week number header. Should have 1 string param, e.g. "week number `{0}`" - */ - weekNumberFormatString?: string; - - /** - * Aria-label format string for the currently selected date. Should have 1 string param, e.g. "Selected date `{0}`" - */ - selectedDateFormatString?: string; - - /** - * Aria-label format string for today's date. Should have 1 string param, e.g. "Today's date `{0}`" - */ - todayDateFormatString?: string; - - /** - * Aria-label for when a date is marked - */ - dayMarkedAriaLabel?: string; -} diff --git a/packages/react-components/react-datepicker-compat/src/utils/dateFormatting/index.ts b/packages/react-components/react-datepicker-compat/src/utils/dateFormatting/index.ts deleted file mode 100644 index 76cf3f30a0f1c6..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/utils/dateFormatting/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './dateFormatting.defaults'; -export * from './dateFormatting.types'; diff --git a/packages/react-components/react-datepicker-compat/src/utils/dateGrid/dateGrid.types.ts b/packages/react-components/react-datepicker-compat/src/utils/dateGrid/dateGrid.types.ts deleted file mode 100644 index ae06d8a9bdb130..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/utils/dateGrid/dateGrid.types.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { DayOfWeek, DateRangeType, FirstWeekOfYear } from '../constants'; - -export interface Day { - /** `Date.toString()` value of current date */ - key: string; - /** `Date.getDate()` value of current date */ - date: string; - /** `Date` object of current date */ - originalDate: Date; - /** Is current date is in the same month as "today" date */ - isInMonth: boolean; - /** Is current date is "today" date */ - isToday: boolean; - /** Is current date is selected */ - isSelected: boolean; - /** Is current date within restriction boundaries */ - isInBounds: boolean; - /** Is current date marked */ - isMarked: boolean; -} - -export interface AvailableDateOptions extends RestrictedDatesOptions { - /** Date from which we start the search */ - initialDate: Date; - /** Ideal available date */ - targetDate: Date; - /** Direction of search (`1` - search in future / `-1` search in past) */ - direction: number; -} - -export interface RestrictedDatesOptions { - /** - * If set the Calendar will not allow navigation to or selection of a date earlier than this value. - */ - minDate?: Date; - - /** - * If set the Calendar will not allow navigation to or selection of a date later than this value. - */ - maxDate?: Date; - - /** - * If set the Calendar will not allow selection of dates in this array. - */ - restrictedDates?: Date[]; -} - -export interface DayGridOptions extends RestrictedDatesOptions { - /** - * The first day of the week for your locale. - */ - firstDayOfWeek: DayOfWeek; - - /** - * Defines when the first week of the year should start, FirstWeekOfYear.FirstDay, - * FirstWeekOfYear.FirstFullWeek or FirstWeekOfYear.FirstFourDayWeek are the possible values - */ - firstWeekOfYear: FirstWeekOfYear; - - /** - * The date range type indicating how many days should be selected as the user - * selects days - */ - dateRangeType: DateRangeType; - - /** - * The number of days to select while dateRangeType === DateRangeType.Day. Used in order to have multi-day - * views. - */ - daysToSelectInDayView?: number; - - /** - * Value of today. If unspecified, current time in client machine will be used. - */ - today?: Date; - - /** - * Whether the calendar should show the week number (weeks 1 to 53) before each week row - */ - showWeekNumbers?: boolean; - - /** - * The days that are selectable when `dateRangeType` is WorkWeek. - * If `dateRangeType` is not WorkWeek this property does nothing. - */ - workWeekDays?: DayOfWeek[]; - - /** - * Which days in the generated grid should be marked. - */ - markedDays?: Date[]; - - /** - * The currently selected date - */ - selectedDate: Date; - - /** - * The currently navigated date - */ - navigatedDate: Date; - - /** - * How many weeks to show by default. If not provided, will show enough weeks to display the current - * month, between 4 and 6 depending - */ - weeksToShow?: number; -} diff --git a/packages/react-components/react-datepicker-compat/src/utils/dateGrid/findAvailableDate.ts b/packages/react-components/react-datepicker-compat/src/utils/dateGrid/findAvailableDate.ts deleted file mode 100644 index 291826faec642a..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/utils/dateGrid/findAvailableDate.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { AvailableDateOptions } from './dateGrid.types'; - -import { isRestrictedDate } from './isRestrictedDate'; - -import { isAfterMaxDate } from './isAfterMaxDate'; - -import { isBeforeMinDate } from './isBeforeMinDate'; -import { compareDatePart, addDays } from '../dateMath/dateMath'; - -/** - * Returns closest available date given the restriction `options`, or undefined otherwise - * @param options - list of search options - */ -export const findAvailableDate = (options: AvailableDateOptions): Date | undefined => { - const { targetDate, initialDate, direction, ...restrictedDateOptions } = options; - let availableDate = targetDate; - // if the target date is available, return it immediately - if (!isRestrictedDate(targetDate, restrictedDateOptions)) { - return targetDate; - } - - while ( - compareDatePart(initialDate, availableDate) !== 0 && - isRestrictedDate(availableDate, restrictedDateOptions) && - !isAfterMaxDate(availableDate, restrictedDateOptions) && - !isBeforeMinDate(availableDate, restrictedDateOptions) - ) { - availableDate = addDays(availableDate, direction); - } - - if (compareDatePart(initialDate, availableDate) !== 0 && !isRestrictedDate(availableDate, restrictedDateOptions)) { - return availableDate; - } - - return undefined; -}; diff --git a/packages/react-components/react-datepicker-compat/src/utils/dateGrid/getBoundedDateRange.ts b/packages/react-components/react-datepicker-compat/src/utils/dateGrid/getBoundedDateRange.ts deleted file mode 100644 index a49dfbe56df076..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/utils/dateGrid/getBoundedDateRange.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { compareDatePart } from '../dateMath/dateMath'; - -/** - * Generates a list of dates, bounded by min and max dates - * @param dateRange - input date range - * @param minDate - min date to limit the range - * @param maxDate - max date to limit the range - */ -export const getBoundedDateRange = (dateRange: Date[], minDate?: Date, maxDate?: Date): Date[] => { - let boundedDateRange = [...dateRange]; - if (minDate) { - boundedDateRange = boundedDateRange.filter((date: Date) => compareDatePart(date, minDate as Date) >= 0); - } - if (maxDate) { - boundedDateRange = boundedDateRange.filter((date: Date) => compareDatePart(date, maxDate as Date) <= 0); - } - return boundedDateRange; -}; diff --git a/packages/react-components/react-datepicker-compat/src/utils/dateGrid/getDateRangeTypeToUse.ts b/packages/react-components/react-datepicker-compat/src/utils/dateGrid/getDateRangeTypeToUse.ts deleted file mode 100644 index f01e9759b3ca5b..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/utils/dateGrid/getDateRangeTypeToUse.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { DateRangeType, DayOfWeek } from '../constants'; -import { isContiguous } from './isContiguous'; -/** - * Return corrected date range type, given `dateRangeType` and list of working days. - * For non-contiguous working days and working week range type, returns general week range type. - * For other cases returns input date range type. - * @param dateRangeType - input type of range - * @param workWeekDays - list of working days in a week - */ -export const getDateRangeTypeToUse = ( - dateRangeType: DateRangeType, - workWeekDays: DayOfWeek[] | undefined, - firstDayOfWeek: DayOfWeek, -): DateRangeType => { - if (workWeekDays && dateRangeType === DateRangeType.WorkWeek) { - if (!isContiguous(workWeekDays, true, firstDayOfWeek) || workWeekDays.length === 0) { - return DateRangeType.Week; - } - } - - return dateRangeType; -}; diff --git a/packages/react-components/react-datepicker-compat/src/utils/dateGrid/getDayGrid.ts b/packages/react-components/react-datepicker-compat/src/utils/dateGrid/getDayGrid.ts deleted file mode 100644 index c234b41d799d0b..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/utils/dateGrid/getDayGrid.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { addDays, compareDates, getDateRangeArray, isInDateRangeArray } from '../dateMath/dateMath'; -import { DAYS_IN_WEEK } from '../constants'; -import { Day, DayGridOptions } from './dateGrid.types'; -import { getDateRangeTypeToUse } from './getDateRangeTypeToUse'; -import { getBoundedDateRange } from './getBoundedDateRange'; -import { isRestrictedDate } from './isRestrictedDate'; - -/** - * Generates a grid of days, given the `options`. - * Returns one additional week at the begining from the previous range - * and one at the end from the future range - * @param options - parameters to specify date related restrictions for the resulting grid - */ -export const getDayGrid = (options: DayGridOptions): Day[][] => { - const { - selectedDate, - dateRangeType, - firstDayOfWeek, - today, - minDate, - maxDate, - weeksToShow, - workWeekDays, - daysToSelectInDayView, - restrictedDates, - markedDays, - } = options; - const restrictedDateOptions = { minDate, maxDate, restrictedDates }; - - const todaysDate = today || new Date(); - - const navigatedDate = options.navigatedDate ? options.navigatedDate : todaysDate; - - let date; - if (weeksToShow && weeksToShow <= 4) { - // if showing less than a full month, just use date == navigatedDate - date = new Date(navigatedDate.getFullYear(), navigatedDate.getMonth(), navigatedDate.getDate()); - } else { - date = new Date(navigatedDate.getFullYear(), navigatedDate.getMonth(), 1); - } - const weeks: Day[][] = []; - - // Cycle the date backwards to get to the first day of the week. - while (date.getDay() !== firstDayOfWeek) { - date.setDate(date.getDate() - 1); - } - - // add the transition week as last week of previous range - date = addDays(date, -DAYS_IN_WEEK); - - // a flag to indicate whether all days of the week are outside the month - let isAllDaysOfWeekOutOfMonth = false; - - // in work week view if the days aren't contiguous we use week view instead - const selectedDateRangeType = getDateRangeTypeToUse(dateRangeType, workWeekDays, firstDayOfWeek); - - let selectedDates: Date[] = []; - - if (selectedDate) { - selectedDates = getDateRangeArray( - selectedDate, - selectedDateRangeType, - firstDayOfWeek, - workWeekDays, - daysToSelectInDayView, - ); - selectedDates = getBoundedDateRange(selectedDates, minDate, maxDate); - } - - let shouldGetWeeks = true; - - for (let weekIndex = 0; shouldGetWeeks; weekIndex++) { - const week: Day[] = []; - - isAllDaysOfWeekOutOfMonth = true; - - for (let dayIndex = 0; dayIndex < DAYS_IN_WEEK; dayIndex++) { - const originalDate = new Date(date.getTime()); - const dayInfo: Day = { - key: date.toString(), - date: date.getDate().toString(), - originalDate, - isInMonth: date.getMonth() === navigatedDate.getMonth(), - isToday: compareDates(todaysDate, date), - isSelected: isInDateRangeArray(date, selectedDates), - isInBounds: !isRestrictedDate(date, restrictedDateOptions), - isMarked: markedDays?.some((markedDay: Date) => compareDates(originalDate, markedDay)) || false, - }; - - week.push(dayInfo); - - if (dayInfo.isInMonth) { - isAllDaysOfWeekOutOfMonth = false; - } - - date.setDate(date.getDate() + 1); - } - - // We append the condition of the loop depending upon the showSixWeeksByDefault prop. - shouldGetWeeks = weeksToShow ? weekIndex < weeksToShow + 1 : !isAllDaysOfWeekOutOfMonth || weekIndex === 0; - - // we don't check shouldGetWeeks before pushing because we want to add one extra week for transition state - weeks.push(week); - } - - return weeks; -}; diff --git a/packages/react-components/react-datepicker-compat/src/utils/dateGrid/index.ts b/packages/react-components/react-datepicker-compat/src/utils/dateGrid/index.ts deleted file mode 100644 index 015f680c01e9c3..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/utils/dateGrid/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './dateGrid.types'; -export * from './findAvailableDate'; -export * from './getBoundedDateRange'; -export * from './getDayGrid'; -export * from './isRestrictedDate'; diff --git a/packages/react-components/react-datepicker-compat/src/utils/dateGrid/isAfterMaxDate.ts b/packages/react-components/react-datepicker-compat/src/utils/dateGrid/isAfterMaxDate.ts deleted file mode 100644 index 8c3bcab9e6e126..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/utils/dateGrid/isAfterMaxDate.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { RestrictedDatesOptions } from './dateGrid.types'; -import { compareDatePart } from '../dateMath/dateMath'; - -/** - * Checks if `date` happens later than max date - * @param date - date to check - * @param options - object with max date to check against - */ -export const isAfterMaxDate = (date: Date, options: RestrictedDatesOptions): boolean => { - const { maxDate } = options; - return maxDate ? compareDatePart(date, maxDate) >= 1 : false; -}; diff --git a/packages/react-components/react-datepicker-compat/src/utils/dateGrid/isBeforeMinDate.ts b/packages/react-components/react-datepicker-compat/src/utils/dateGrid/isBeforeMinDate.ts deleted file mode 100644 index 74be1f648da7b6..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/utils/dateGrid/isBeforeMinDate.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { RestrictedDatesOptions } from './dateGrid.types'; -import { compareDatePart } from '../dateMath/dateMath'; - -/** - * Checks if `date` happens earlier than min date - * @param date - date to check - * @param options - object with min date to check against - */ -export const isBeforeMinDate = (date: Date, options: RestrictedDatesOptions): boolean => { - const { minDate } = options; - return minDate ? compareDatePart(minDate, date) >= 1 : false; -}; diff --git a/packages/react-components/react-datepicker-compat/src/utils/dateGrid/isContiguous.ts b/packages/react-components/react-datepicker-compat/src/utils/dateGrid/isContiguous.ts deleted file mode 100644 index a69a0a286af2c6..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/utils/dateGrid/isContiguous.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { DayOfWeek } from '../constants'; - -/** - * Returns whether provided week days are contiguous. - * @param days - list of days in a week - * @param isSingleWeek - decides whether the contiguous logic applies across week boundaries or not - * @param firstDayOfWeek - decides which day of week is the first one in the order. - */ -export const isContiguous = (days: DayOfWeek[], isSingleWeek: boolean, firstDayOfWeek: DayOfWeek): boolean => { - const daySet = new Set(days); - let amountOfNoNeighbors = 0; - for (const day of days) { - const nextDay = (day + 1) % 7; - if (!(daySet.has(nextDay) && (!isSingleWeek || firstDayOfWeek !== nextDay))) { - amountOfNoNeighbors++; - } - } - - // In case the full week is provided, then each day has a neighbor - //, otherwise the last day does not have a neighbor. - return amountOfNoNeighbors < 2; -}; diff --git a/packages/react-components/react-datepicker-compat/src/utils/dateGrid/isRestrictedDate.ts b/packages/react-components/react-datepicker-compat/src/utils/dateGrid/isRestrictedDate.ts deleted file mode 100644 index 611344dd4d0625..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/utils/dateGrid/isRestrictedDate.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { RestrictedDatesOptions } from './dateGrid.types'; -import { compareDates } from '../dateMath/dateMath'; -import { isBeforeMinDate } from './isBeforeMinDate'; -import { isAfterMaxDate } from './isAfterMaxDate'; - -/** - * Checks if `date` falls into the restricted `options` - * @param date - date to check - * @param options - restriction options (min date, max date and list of restricted dates) - */ -export const isRestrictedDate = (date: Date, options: RestrictedDatesOptions): boolean => { - const { restrictedDates, minDate, maxDate } = options; - if (!restrictedDates && !minDate && !maxDate) { - return false; - } - const inRestrictedDates = restrictedDates && restrictedDates.some((rd: Date) => compareDates(rd, date)); - return inRestrictedDates || isBeforeMinDate(date, options) || isAfterMaxDate(date, options); -}; diff --git a/packages/react-components/react-datepicker-compat/src/utils/dateMath/dateMath.test.ts b/packages/react-components/react-datepicker-compat/src/utils/dateMath/dateMath.test.ts deleted file mode 100644 index 5556a328ef77fe..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/utils/dateMath/dateMath.test.ts +++ /dev/null @@ -1,495 +0,0 @@ -import { DateRangeType, DayOfWeek } from '../constants'; -import * as DateMath from './dateMath'; - -enum Months { - Jan = 0, - Feb = 1, - Mar = 2, - Apr = 3, - May = 4, - Jun = 5, - Jul = 6, - Aug = 7, - Sep = 8, - Oct = 9, - Nov = 10, - Dec = 11, -} -describe('DateMath', () => { - it('can add days', () => { - const startDate = new Date(2016, Months.Apr, 1); - const result = DateMath.addDays(startDate, 5); - const expected = new Date(2016, Months.Apr, 6); - - expect(result.getTime()).toEqual(expected.getTime()); - }); - - it('can add days across a month boundary', () => { - const startDate = new Date(2016, Months.Mar, 30); - const result = DateMath.addDays(startDate, 5); - const expected = new Date(2016, Months.Apr, 4); - - expect(result.getTime()).toEqual(expected.getTime()); - }); - - it('can add days across multiple month boundaries', () => { - const startDate = new Date(2016, Months.Mar, 31); - const result = DateMath.addDays(startDate, 65); - const expected = new Date(2016, Months.Jun, 4); - - expect(result.getTime()).toEqual(expected.getTime()); - }); - - it('can add days across leap day boundaries', () => { - const startDate = new Date(2016, Months.Feb, 28); - const result = DateMath.addDays(startDate, 2); - const expected = new Date(2016, Months.Mar, 1); - - expect(result.getTime()).toEqual(expected.getTime()); - }); - - it('can add months', () => { - const startDate = new Date(2015, Months.Dec, 31); - - let result = DateMath.addMonths(startDate, 1); - let expected = new Date(2016, Months.Jan, 31); - expect(result.getTime()).toEqual(expected.getTime()); - - result = DateMath.addMonths(startDate, 2); - expected = new Date(2016, Months.Feb, 29); - expect(result.getTime()).toEqual(expected.getTime()); - - result = DateMath.addMonths(startDate, 3); - expected = new Date(2016, Months.Mar, 31); - expect(result.getTime()).toEqual(expected.getTime()); - - result = DateMath.addMonths(startDate, 4); - expected = new Date(2016, Months.Apr, 30); - expect(result.getTime()).toEqual(expected.getTime()); - - result = DateMath.addMonths(startDate, 5); - expected = new Date(2016, Months.May, 31); - expect(result.getTime()).toEqual(expected.getTime()); - - result = DateMath.addMonths(startDate, 6); - expected = new Date(2016, Months.Jun, 30); - expect(result.getTime()).toEqual(expected.getTime()); - - result = DateMath.addMonths(startDate, 7); - expected = new Date(2016, Months.Jul, 31); - expect(result.getTime()).toEqual(expected.getTime()); - - result = DateMath.addMonths(startDate, 8); - expected = new Date(2016, Months.Aug, 31); - expect(result.getTime()).toEqual(expected.getTime()); - - result = DateMath.addMonths(startDate, 9); - expected = new Date(2016, Months.Sep, 30); - expect(result.getTime()).toEqual(expected.getTime()); - - result = DateMath.addMonths(startDate, 10); - expected = new Date(2016, Months.Oct, 31); - expect(result.getTime()).toEqual(expected.getTime()); - - result = DateMath.addMonths(startDate, 11); - expected = new Date(2016, Months.Nov, 30); - expect(result.getTime()).toEqual(expected.getTime()); - - result = DateMath.addMonths(startDate, 12); - expected = new Date(2016, Months.Dec, 31); - expect(result.getTime()).toEqual(expected.getTime()); - - result = DateMath.addMonths(startDate, 14); - expected = new Date(2017, Months.Feb, 28); - expect(result.getTime()).toEqual(expected.getTime()); - }); - - it('can add years', () => { - let startDate = new Date(2016, Months.Feb, 29); - let result = DateMath.addYears(startDate, 1); - let expected = new Date(2017, Months.Feb, 28); - - expect(result.getTime()).toEqual(expected.getTime()); - - startDate = new Date(2016, Months.Feb, 29); - result = DateMath.addYears(startDate, 4); - expected = new Date(2020, Months.Feb, 29); - - expect(result.getTime()).toEqual(expected.getTime()); - - startDate = new Date(2016, Months.Jan, 1); - result = DateMath.addYears(startDate, 1); - expected = new Date(2017, Months.Jan, 1); - - expect(result.getTime()).toEqual(expected.getTime()); - }); - - it('can subtract days', () => { - const startDate = new Date(2016, Months.Apr, 30); - const result = DateMath.addDays(startDate, -5); - const expected = new Date(2016, Months.Apr, 25); - - expect(result.getTime()).toEqual(expected.getTime()); - }); - - it('can subtract days across a month boundry', () => { - const startDate = new Date(2016, Months.Apr, 1); - const result = DateMath.addDays(startDate, -5); - const expected = new Date(2016, Months.Mar, 27); - - expect(result.getTime()).toEqual(expected.getTime()); - }); - - it('can subtract days across multiple month boundaries', () => { - const startDate = new Date(2016, Months.Jul, 4); - const result = DateMath.addDays(startDate, -65); - const expected = new Date(2016, Months.Apr, 30); - - expect(result.getTime()).toEqual(expected.getTime()); - }); - - it('can subtract days across leap day boundaries', () => { - const startDate = new Date(2016, Months.Mar, 1); - const result = DateMath.addDays(startDate, -2); - const expected = new Date(2016, Months.Feb, 28); - - expect(result.getTime()).toEqual(expected.getTime()); - }); - - it('can subtract months', () => { - const startDate = new Date(2016, Months.Dec, 31); - - let result = DateMath.addMonths(startDate, -12); - let expected = new Date(2015, Months.Dec, 31); - expect(result.getTime()).toEqual(expected.getTime()); - - result = DateMath.addMonths(startDate, -11); - expected = new Date(2016, Months.Jan, 31); - expect(result.getTime()).toEqual(expected.getTime()); - - result = DateMath.addMonths(startDate, -10); - expected = new Date(2016, Months.Feb, 29); - expect(result.getTime()).toEqual(expected.getTime()); - - result = DateMath.addMonths(startDate, -9); - expected = new Date(2016, Months.Mar, 31); - expect(result.getTime()).toEqual(expected.getTime()); - - result = DateMath.addMonths(startDate, -8); - expected = new Date(2016, Months.Apr, 30); - expect(result.getTime()).toEqual(expected.getTime()); - - result = DateMath.addMonths(startDate, -7); - expected = new Date(2016, Months.May, 31); - expect(result.getTime()).toEqual(expected.getTime()); - - result = DateMath.addMonths(startDate, -6); - expected = new Date(2016, Months.Jun, 30); - expect(result.getTime()).toEqual(expected.getTime()); - - result = DateMath.addMonths(startDate, -5); - expected = new Date(2016, Months.Jul, 31); - expect(result.getTime()).toEqual(expected.getTime()); - - result = DateMath.addMonths(startDate, -4); - expected = new Date(2016, Months.Aug, 31); - expect(result.getTime()).toEqual(expected.getTime()); - - result = DateMath.addMonths(startDate, -3); - expected = new Date(2016, Months.Sep, 30); - expect(result.getTime()).toEqual(expected.getTime()); - - result = DateMath.addMonths(startDate, -2); - expected = new Date(2016, Months.Oct, 31); - expect(result.getTime()).toEqual(expected.getTime()); - - result = DateMath.addMonths(startDate, -1); - expected = new Date(2016, Months.Nov, 30); - expect(result.getTime()).toEqual(expected.getTime()); - - result = DateMath.addMonths(startDate, -22); - expected = new Date(2015, Months.Feb, 28); - expect(result.getTime()).toEqual(expected.getTime()); - }); - - it('can subtract years', () => { - let startDate = new Date(2016, Months.Feb, 29); - let result = DateMath.addYears(startDate, -1); - let expected = new Date(2015, Months.Feb, 28); - - expect(result.getTime()).toEqual(expected.getTime()); - - startDate = new Date(2016, Months.Feb, 29); - result = DateMath.addYears(startDate, -4); - expected = new Date(2012, Months.Feb, 29); - - expect(result.getTime()).toEqual(expected.getTime()); - - startDate = new Date(2016, Months.Jan, 1); - result = DateMath.addYears(startDate, -1); - expected = new Date(2015, Months.Jan, 1); - - expect(result.getTime()).toEqual(expected.getTime()); - }); - - it('can set the month', () => { - let startDate = new Date(2016, Months.Jan, 31); - let result = DateMath.setMonth(startDate, Months.Feb); - let expected = new Date(2016, Months.Feb, 29); - expect(result.getTime()).toEqual(expected.getTime()); - - startDate = new Date(2016, Months.Jun, 1); - result = DateMath.setMonth(startDate, Months.Feb); - expected = new Date(2016, Months.Feb, 1); - expect(result.getTime()).toEqual(expected.getTime()); - }); - - it('can compare dates', () => { - let date1 = new Date(2016, 4, 1); - let date2 = new Date(2016, 4, 1); - expect(DateMath.compareDates(date1, date2)).toBe(true); - - date1 = new Date(2016, 4, 1, 12, 30, 0); - date2 = new Date(2016, 4, 1, 10, 0, 0); - expect(DateMath.compareDates(date1, date2)).toBe(true); - - date1 = new Date(2016, 4, 1); - date2 = new Date(2016, 4, 2); - expect(DateMath.compareDates(date1, date2)).toBe(false); - - date1 = new Date(2016, 4, 1); - date2 = new Date(2016, 5, 1); - expect(DateMath.compareDates(date1, date2)).toBe(false); - - date1 = new Date(2016, 4, 1); - date2 = new Date(2017, 4, 1); - expect(DateMath.compareDates(date1, date2)).toBe(false); - }); - - it('can get date range array', () => { - const date = new Date(2017, 2, 16); - - // Date range: day - let dateRangeArray = DateMath.getDateRangeArray(date, DateRangeType.Day, DayOfWeek.Sunday); - expect(dateRangeArray.length).toEqual(1); - expect(DateMath.compareDates(dateRangeArray[0], date)).toBe(true); - - // Date range: week - let expectedDates = Array(7).map((val: undefined, i: number) => new Date(2017, 2, 12 + i)); - dateRangeArray = DateMath.getDateRangeArray(date, DateRangeType.Week, DayOfWeek.Sunday); - Array(7).forEach((val: undefined, i: number) => - expect(DateMath.compareDates(dateRangeArray[i], expectedDates[i])).toBe(true), - ); - - // Date range: work week - const workWeekDays = [DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Thursday, DayOfWeek.Friday]; - expectedDates = [new Date(2017, 2, 13), new Date(2017, 2, 14), new Date(2017, 2, 16), new Date(2017, 2, 17)]; - dateRangeArray = DateMath.getDateRangeArray(date, DateRangeType.Week, DayOfWeek.Sunday, workWeekDays); - Array(4).forEach((val: undefined, i: number) => - expect(DateMath.compareDates(dateRangeArray[i], expectedDates[i])).toBe(true), - ); - - // work week defaults - expectedDates = [ - new Date(2017, 2, 13), - new Date(2017, 2, 14), - new Date(2017, 2, 15), - new Date(2017, 2, 16), - new Date(2017, 2, 17), - ]; - dateRangeArray = DateMath.getDateRangeArray(date, DateRangeType.Week, DayOfWeek.Sunday); - Array(4).forEach((val: undefined, i: number) => - expect(DateMath.compareDates(dateRangeArray[i], expectedDates[i])).toBe(true), - ); - - // Date range: month - expectedDates = Array(31).map((val: undefined, i: number) => new Date(2017, 2, 1 + i)); - dateRangeArray = DateMath.getDateRangeArray(date, DateRangeType.Month, DayOfWeek.Sunday); - Array(31).forEach((val: undefined, i: number) => - expect(DateMath.compareDates(dateRangeArray[i], expectedDates[i])).toBe(true), - ); - - // First day of week: Tuesday - expectedDates = Array(7).map((val: undefined, i: number) => new Date(2017, 2, 14 + i)); - dateRangeArray = DateMath.getDateRangeArray(date, DateRangeType.Week, DayOfWeek.Tuesday); - Array(7).forEach((val: undefined, i: number) => expect(DateMath.compareDates(dateRangeArray[i], date)).toBe(true)); - }); - - // Generating week numbers array per month - it('can calculate week numbers from selected date', () => { - // firstDayOfWeek is Monday, firstWeekOfYear is firstFullWeek - let date = new Date(2017, 0, 4); - let result = DateMath.getWeekNumbersInMonth(6, 1, 1, date); - let expected = 52; - expect(result[0]).toEqual(expected); - - // firstDayOfWeek is Sunday, firstWeekOfYear is firstFullWeek - date = new Date(2000, 11, 31); - result = DateMath.getWeekNumbersInMonth(6, 0, 1, date); - expected = 53; - expect(result[5]).toEqual(expected); - - // firstDayOfWeek is Sunday, firstWeekOfYear is firstFullWeek - date = new Date(2010, 0, 1); - result = DateMath.getWeekNumbersInMonth(6, 0, 1, date); - expected = 52; - expect(result[0]).toEqual(expected); - - // firstDayOfWeek is Sunday, firstWeekOfYear is firstFourDayWeek - date = new Date(2018, 11, 31); - result = DateMath.getWeekNumbersInMonth(6, 0, 2, date); - expected = 1; - expect(result[5]).toEqual(expected); - }); - - // First week of year set to FirstWeekOfYear.FirstDay - it('can calculate week numbers - option 0', () => { - // firstDayOfWeek is Sunday - let date1 = new Date(2018, 0, 1); - let result = DateMath.getWeekNumber(date1, 0, 0); - let expected = 1; - expect(result).toEqual(expected); - - // firstDayOfWeek is Sunday - date1 = new Date(2010, 0, 1); - result = DateMath.getWeekNumber(date1, 0, 0); - expected = 1; - expect(result).toEqual(expected); - - // firstDayOfWeek is Sunday - date1 = new Date(2019, 0, 1); - result = DateMath.getWeekNumber(date1, 0, 0); - expected = 1; - expect(result).toEqual(expected); - - // firstDayOfWeek is Monday - date1 = new Date(2010, 11, 31); - result = DateMath.getWeekNumber(date1, 1, 0); - expected = 53; - expect(result).toEqual(expected); - }); - - // First week of year set to FirstWeekOfYear.FirstFullWeek - it('can calculate week numbers - option 1', () => { - // firstDayOfWeek is Sunday - let date1 = new Date(2018, 0, 1); - let result = DateMath.getWeekNumber(date1, 0, 1); - let expected = 53; - expect(result).toEqual(expected); - - // firstDayOfWeek is Sunday - date1 = new Date(2017, 11, 31); - result = DateMath.getWeekNumber(date1, 0, 1); - expected = 53; - expect(result).toEqual(expected); - - // firstDayOfWeek is Sunday - date1 = new Date(2010, 11, 31); - result = DateMath.getWeekNumber(date1, 0, 1); - expected = 52; - expect(result).toEqual(expected); - - // firstDayOfWeek is Monday - date1 = new Date(2011, 0, 1); - result = DateMath.getWeekNumber(date1, 1, 1); - expected = 52; - expect(result).toEqual(expected); - - // firstDayOfWeek is Sunday - date1 = new Date(2021, 0, 1); - result = DateMath.getWeekNumber(date1, 0, 1); - expected = 52; - expect(result).toEqual(expected); - - // firstDayOfWeek is Monday - date1 = new Date(2021, 0, 1); - result = DateMath.getWeekNumber(date1, 1, 1); - expected = 52; - expect(result).toEqual(expected); - }); - - // First week of year set to FirstWeekOfYear.FirstFourDayWeek - it('can calculate week numbers - option 2', () => { - // firstDayOfWeek is Sunday - let date1 = new Date(2019, 0, 5); - let result = DateMath.getWeekNumber(date1, 0, 2); - let expected = 1; - expect(result).toEqual(expected); - - // firstDayOfWeek is Sunday - date1 = new Date(2018, 0, 6); - result = DateMath.getWeekNumber(date1, 0, 2); - expected = 1; - expect(result).toEqual(expected); - - // firstDayOfWeek is Sunday - date1 = new Date(2014, 11, 31); - result = DateMath.getWeekNumber(date1, 0, 2); - expected = 53; - expect(result).toEqual(expected); - - // firstDayOfWeek is Sunday - date1 = new Date(2015, 0, 1); - result = DateMath.getWeekNumber(date1, 0, 2); - expected = 53; - expect(result).toEqual(expected); - - // firstDayOfWeek is Sunday - date1 = new Date(2010, 11, 31); - result = DateMath.getWeekNumber(date1, 0, 2); - expected = 52; - expect(result).toEqual(expected); - - // firstDayOfWeek is Monday - date1 = new Date(2011, 0, 1); - result = DateMath.getWeekNumber(date1, 1, 2); - expected = 52; - expect(result).toEqual(expected); - - // firstDayOfWeek is Sunday - date1 = new Date(2021, 0, 1); - result = DateMath.getWeekNumber(date1, 0, 2); - expected = 53; - expect(result).toEqual(expected); - - // firstDayOfWeek is Monday - date1 = new Date(2021, 0, 1); - result = DateMath.getWeekNumber(date1, 1, 2); - expected = 53; - expect(result).toEqual(expected); - }); - - it('can get the month start and end', () => { - const date = new Date('Dec 15 2017'); - - // First day of month - expect(DateMath.compareDates(new Date('Dec 1 2017'), DateMath.getMonthStart(date))).toBe(true); - - // Last day of month - expect(DateMath.compareDates(new Date('Dec 31 2017'), DateMath.getMonthEnd(date))).toBe(true); - }); - - it('can get the year start and end', () => { - const date = new Date('Dec 15 2017'); - - // First day of year - expect(DateMath.compareDates(new Date('Jan 1 2017'), DateMath.getYearStart(date))).toBe(true); - - // Last day of year - expect(DateMath.compareDates(new Date('Dec 31 2017'), DateMath.getYearEnd(date))).toBe(true); - }); - - it('can get start date of week', () => { - const date = new Date('Aug 2 2020'); - expect(DateMath.compareDates(new Date('Jul 28 2020'), DateMath.getStartDateOfWeek(date, DayOfWeek.Tuesday))).toBe( - true, - ); - }); - - it('can get end date of week', () => { - const date = new Date('Sep 29 2020'); - expect(DateMath.compareDates(new Date('Oct 5 2020'), DateMath.getEndDateOfWeek(date, DayOfWeek.Tuesday))).toBe( - true, - ); - }); -}); diff --git a/packages/react-components/react-datepicker-compat/src/utils/dateMath/dateMath.ts b/packages/react-components/react-datepicker-compat/src/utils/dateMath/dateMath.ts deleted file mode 100644 index 384912af339661..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/utils/dateMath/dateMath.ts +++ /dev/null @@ -1,431 +0,0 @@ -import { DateRangeType, DayOfWeek, FirstWeekOfYear, MonthOfYear, TimeConstants } from '../constants'; - -/** - * Returns a date offset from the given date by the specified number of days. - * @param date - The origin date - * @param days - The number of days to offset. 'days' can be negative. - * @returns A new Date object offset from the origin date by the given number of days - */ -export function addDays(date: Date, days: number): Date { - const result = new Date(date.getTime()); - result.setDate(result.getDate() + days); - return result; -} - -/** - * Returns a date offset from the given date by the specified number of weeks. - * @param date - The origin date - * @param weeks - The number of weeks to offset. 'weeks' can be negative. - * @returns A new Date object offset from the origin date by the given number of weeks - */ -export function addWeeks(date: Date, weeks: number): Date { - return addDays(date, weeks * TimeConstants.DaysInOneWeek); -} - -/** - * Returns a date offset from the given date by the specified number of months. - * The method tries to preserve the day-of-month; however, if the new month does not have enough days - * to contain the original day-of-month, we'll use the last day of the new month. - * @param date - The origin date - * @param months - The number of months to offset. 'months' can be negative. - * @returns A new Date object offset from the origin date by the given number of months - */ -export function addMonths(date: Date, months: number): Date { - let result = new Date(date.getTime()); - const newMonth = result.getMonth() + months; - result.setMonth(newMonth); - - // We want to maintain the same day-of-month, but that may not be possible if the new month doesn't have enough days. - // Loop until we back up to a day the new month has. - // (Weird modulo math is due to Javascript's treatment of negative numbers in modulo) - if ( - result.getMonth() !== - ((newMonth % TimeConstants.MonthInOneYear) + TimeConstants.MonthInOneYear) % TimeConstants.MonthInOneYear - ) { - result = addDays(result, -result.getDate()); - } - return result; -} - -/** - * Returns a date offset from the given date by the specified number of years. - * The method tries to preserve the day-of-month; however, if the new month does not have enough days - * to contain the original day-of-month, we'll use the last day of the new month. - * @param date - The origin date - * @param years - The number of years to offset. 'years' can be negative. - * @returns A new Date object offset from the origin date by the given number of years - */ -export function addYears(date: Date, years: number): Date { - let result = new Date(date.getTime()); - result.setFullYear(date.getFullYear() + years); - - // We want to maintain the same day-of-month, but that may not be possible if the new month doesn't have enough days. - // Loop until we back up to a day the new month has. - // (Weird modulo math is due to Javascript's treatment of negative numbers in modulo) - if ( - result.getMonth() !== - ((date.getMonth() % TimeConstants.MonthInOneYear) + TimeConstants.MonthInOneYear) % TimeConstants.MonthInOneYear - ) { - result = addDays(result, -result.getDate()); - } - return result; -} - -/** - * Returns a date that is the first day of the month of the provided date. - * @param date - The origin date - * @returns A new Date object with the day set to the first day of the month. - */ -export function getMonthStart(date: Date): Date { - return new Date(date.getFullYear(), date.getMonth(), 1, 0, 0, 0, 0); -} - -/** - * Returns a date that is the last day of the month of the provided date. - * @param date - The origin date - * @returns A new Date object with the day set to the last day of the month. - */ -export function getMonthEnd(date: Date): Date { - return new Date(date.getFullYear(), date.getMonth() + 1, 0, 0, 0, 0, 0); -} - -/** - * Returns a date that is the first day of the year of the provided date. - * @param date - The origin date - * @returns A new Date object with the day set to the first day of the year. - */ -export function getYearStart(date: Date): Date { - return new Date(date.getFullYear(), 0, 1, 0, 0, 0, 0); -} - -/** - * Returns a date that is the last day of the year of the provided date. - * @param date - The origin date - * @returns A new Date object with the day set to the last day of the year. - */ -export function getYearEnd(date: Date): Date { - return new Date(date.getFullYear() + 1, 0, 0, 0, 0, 0, 0); -} - -/** - * Returns a date that is a copy of the given date, aside from the month changing to the given month. - * The method tries to preserve the day-of-month; however, if the new month does not have enough days - * to contain the original day-of-month, we'll use the last day of the new month. - * @param date - The origin date - * @param month - The 0-based index of the month to set on the date. - * @returns A new Date object with the given month set. - */ -export function setMonth(date: Date, month: number): Date { - return addMonths(date, month - date.getMonth()); -} - -/** - * Compares two dates, and returns true if the two dates (not accounting for time-of-day) are equal. - * @returns True if the two dates represent the same date (regardless of time-of-day), false otherwise. - */ -export function compareDates(date1: Date, date2: Date): boolean { - if (!date1 && !date2) { - return true; - } else if (!date1 || !date2) { - return false; - } else { - return ( - date1.getFullYear() === date2.getFullYear() && - date1.getMonth() === date2.getMonth() && - date1.getDate() === date2.getDate() - ); - } -} - -/** - * Compare the date parts of two dates - * @param date1 - The first date to compare - * @param date2 - The second date to compare - * @returns A negative value if date1 is earlier than date2, 0 if the dates are equal, or a positive value - * if date1 is later than date2. - */ -export function compareDatePart(date1: Date, date2: Date): Number { - return getDatePartHashValue(date1) - getDatePartHashValue(date2); -} - -/** - * Gets the date range array including the specified date. The date range array is calculated as the list - * of dates accounting for the specified first day of the week and date range type. - * @param date - The input date - * @param dateRangeType - The desired date range type, i.e., day, week, month, etc. - * @param firstDayOfWeek - The first day of the week. - * @param workWeekDays - The allowed days in work week. If not provided, assumes all days are allowed. - * @param daysToSelectInDayView - The number of days to include when using dateRangeType === DateRangeType.Day - * for multiday view. Defaults to 1 - * @returns An array of dates representing the date range containing the specified date. - */ -export function getDateRangeArray( - date: Date, - dateRangeType: DateRangeType, - firstDayOfWeek: DayOfWeek, - workWeekDays?: DayOfWeek[], - daysToSelectInDayView: number = 1, -): Date[] { - const datesArray: Date[] = []; - let startDate: Date; - let endDate = null; - - if (!workWeekDays) { - workWeekDays = [DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday]; - } - - daysToSelectInDayView = Math.max(daysToSelectInDayView, 1); - - switch (dateRangeType) { - case DateRangeType.Day: - startDate = getDatePart(date); - endDate = addDays(startDate, daysToSelectInDayView); - break; - - case DateRangeType.Week: - case DateRangeType.WorkWeek: - startDate = getStartDateOfWeek(getDatePart(date), firstDayOfWeek); - endDate = addDays(startDate, TimeConstants.DaysInOneWeek); - break; - - case DateRangeType.Month: - startDate = new Date(date.getFullYear(), date.getMonth(), 1); - endDate = addMonths(startDate, 1); - break; - - default: - throw new Error('Unexpected object: ' + dateRangeType); - } - - // Populate the dates array with the dates in range - let nextDate = startDate; - - do { - if (dateRangeType !== DateRangeType.WorkWeek) { - // push all days not in work week view - datesArray.push(nextDate); - } else if (workWeekDays.indexOf(nextDate.getDay()) !== -1) { - datesArray.push(nextDate); - } - nextDate = addDays(nextDate, 1); - } while (!compareDates(nextDate, endDate)); - - return datesArray; -} - -/** - * Checks whether the specified date is in the given date range. - * @param date - The origin date - * @param dateRange - An array of dates to do the lookup on - * @returns True if the date matches one of the dates in the specified array, false otherwise. - */ -export function isInDateRangeArray(date: Date, dateRange: Date[]): boolean { - for (const dateInRange of dateRange) { - if (compareDates(date, dateInRange)) { - return true; - } - } - return false; -} - -/** - * Returns the week number for a date. - * Week numbers are 1 - 52 (53) in a year - * @param navigatedDate - A date to find the week number for. - * @param firstDayOfWeek - The first day of the week (0-6, Sunday = 0) - * @param firstWeekOfYear - The first week of the year (1-2) - * @returns The weeks number array for the current month. - */ -export function getWeekNumbersInMonth( - weeksInMonth: number, - firstDayOfWeek: DayOfWeek, - firstWeekOfYear: FirstWeekOfYear, - navigatedDate: Date, -): number[] { - const selectedYear = navigatedDate.getFullYear(); - const selectedMonth = navigatedDate.getMonth(); - let dayOfMonth = 1; - const fistDayOfMonth = new Date(selectedYear, selectedMonth, dayOfMonth); - const endOfFirstWeek = - dayOfMonth + - (firstDayOfWeek + TimeConstants.DaysInOneWeek - 1) - - adjustWeekDay(firstDayOfWeek, fistDayOfMonth.getDay()); - let endOfWeekRange = new Date(selectedYear, selectedMonth, endOfFirstWeek); - dayOfMonth = endOfWeekRange.getDate(); - - const weeksArray = []; - for (let i = 0; i < weeksInMonth; i++) { - // Get week number for end of week - weeksArray.push(getWeekNumber(endOfWeekRange, firstDayOfWeek, firstWeekOfYear)); - dayOfMonth += TimeConstants.DaysInOneWeek; - endOfWeekRange = new Date(selectedYear, selectedMonth, dayOfMonth); - } - return weeksArray; -} - -/** - * Returns the week number for a date. - * Week numbers are 1 - 52 (53) in a year - * @param date - A date to find the week number for. - * @param firstDayOfWeek - The first day of the week (0-6, Sunday = 0) - * @param firstWeekOfYear - The first week of the year (1-2) - * @returns The week's number in the year. - */ -export function getWeekNumber(date: Date, firstDayOfWeek: DayOfWeek, firstWeekOfYear: FirstWeekOfYear): number { - // First four-day week of the year - minumum days count - const fourDayWeek = 4; - - switch (firstWeekOfYear) { - case FirstWeekOfYear.FirstFullWeek: - return getWeekOfYearFullDays(date, firstDayOfWeek, TimeConstants.DaysInOneWeek); - - case FirstWeekOfYear.FirstFourDayWeek: - return getWeekOfYearFullDays(date, firstDayOfWeek, fourDayWeek); - - default: - return getFirstDayWeekOfYear(date, firstDayOfWeek); - } -} - -/** - * Gets the date for the first day of the week based on the given date assuming - * the specified first day of the week. - * @param date - The date to find the beginning of the week date for. - * @returns A new date object representing the first day of the week containing the input date. - */ -export function getStartDateOfWeek(date: Date, firstDayOfWeek: DayOfWeek): Date { - let daysOffset = firstDayOfWeek - date.getDay(); - if (daysOffset > 0) { - // If first day of week is > date, go 1 week back, to ensure resulting date is in the past. - daysOffset -= TimeConstants.DaysInOneWeek; - } - return addDays(date, daysOffset); -} - -/** - * Gets the date for the last day of the week based on the given date assuming - * the specified first day of the week. - * @param date - The date to find the beginning of the week date for. - * @returns A new date object representing the first day of the week containing the input date. - */ -export function getEndDateOfWeek(date: Date, firstDayOfWeek: DayOfWeek): Date { - const lastDayOfWeek = firstDayOfWeek - 1 >= 0 ? firstDayOfWeek - 1 : TimeConstants.DaysInOneWeek - 1; - let daysOffset = lastDayOfWeek - date.getDay(); - if (daysOffset < 0) { - // If last day of week is < date, go 1 week forward, to ensure resulting date is in the future. - daysOffset += TimeConstants.DaysInOneWeek; - } - return addDays(date, daysOffset); -} - -/** - * Gets a new date with the time portion zeroed out, i.e., set to midnight - * @param date - The origin date - * @returns A new date with the time set to midnight - */ -function getDatePart(date: Date): Date { - return new Date(date.getFullYear(), date.getMonth(), date.getDate()); -} - -/** - * Helper function to assist in date comparisons - */ -export function getDatePartHashValue(date: Date): number { - // Generate date hash value created as sum of Date (up to 31 = 5 bits), Month (up to 11 = 4 bits) and Year. - // eslint-disable-next-line no-bitwise - return date.getDate() + (date.getMonth() << 5) + (date.getFullYear() << 9); -} - -/** - * Helper function for `getWeekNumber`. - * Returns week number for a date. - * @param date - current selected date. - * @param firstDayOfWeek - The first day of week (0-6, Sunday = 0) - * @param numberOfFullDays - week settings. - * @returns The week's number in the year. - */ -function getWeekOfYearFullDays(date: Date, firstDayOfWeek: DayOfWeek, numberOfFullDays: number): number { - const dayOfYear = getDayOfYear(date) - 1; - let num = date.getDay() - (dayOfYear % TimeConstants.DaysInOneWeek); - - const lastDayOfPrevYear = new Date(date.getFullYear() - 1, MonthOfYear.December, 31); - const daysInYear = getDayOfYear(lastDayOfPrevYear) - 1; - - let num2 = (firstDayOfWeek - num + 2 * TimeConstants.DaysInOneWeek) % TimeConstants.DaysInOneWeek; - if (num2 !== 0 && num2 >= numberOfFullDays) { - num2 -= TimeConstants.DaysInOneWeek; - } - - let num3 = dayOfYear - num2; - if (num3 < 0) { - num -= daysInYear % TimeConstants.DaysInOneWeek; - num2 = (firstDayOfWeek - num + 2 * TimeConstants.DaysInOneWeek) % TimeConstants.DaysInOneWeek; - if (num2 !== 0 && num2 + 1 >= numberOfFullDays) { - num2 -= TimeConstants.DaysInOneWeek; - } - - num3 = daysInYear - num2; - } - - return Math.floor(num3 / TimeConstants.DaysInOneWeek + 1); -} - -/** - * Helper function for `getWeekNumber`. - * Returns week number for a date. - * @param date - current selected date. - * @param firstDayOfWeek - The first day of week (0-6, Sunday = 0) - * @returns The week's number in the year. - */ -function getFirstDayWeekOfYear(date: Date, firstDayOfWeek: number): number { - const num = getDayOfYear(date) - 1; - const num2 = date.getDay() - (num % TimeConstants.DaysInOneWeek); - const num3 = (num2 - firstDayOfWeek + 2 * TimeConstants.DaysInOneWeek) % TimeConstants.DaysInOneWeek; - - return Math.floor((num + num3) / TimeConstants.DaysInOneWeek + 1); -} - -/** - * Helper function for `getWeekNumber`. - * Returns adjusted week day number when `firstDayOfWeek` is other than Sunday. - * For Week Day Number comparison checks - * @param firstDayOfWeek - The first day of week (0-6, Sunday = 0) - * @param dateWeekDay - shifts number forward to 1 week in case passed as true - * @returns The day of week adjusted to `firstDayOfWeek`; e.g. when `firstDayOfWeek` is Monday (1), - * Sunday becomes 7. - */ -function adjustWeekDay(firstDayOfWeek: DayOfWeek, dateWeekDay: DayOfWeek): number { - return firstDayOfWeek !== DayOfWeek.Sunday && dateWeekDay < firstDayOfWeek - ? dateWeekDay + TimeConstants.DaysInOneWeek - : dateWeekDay; -} - -/** - * Returns the day number for a date in a year: - * the number of days since January 1st in the particular year. - * @param date - A date to find the day number for. - * @returns The day's number in the year. - */ -function getDayOfYear(date: Date): number { - const month = date.getMonth(); - const year = date.getFullYear(); - let daysUntilDate = 0; - - for (let i = 0; i < month; i++) { - daysUntilDate += daysInMonth(i + 1, year); - } - - daysUntilDate += date.getDate(); - - return daysUntilDate; -} - -/** - * Returns the number of days in the month - * @param month - The month number to target (months 1-12). - * @param year - The year to target. - * @returns The number of days in the month. - */ -function daysInMonth(month: number, year: number): number { - return new Date(year, month, 0).getDate(); -} diff --git a/packages/react-components/react-datepicker-compat/src/utils/dateMath/index.ts b/packages/react-components/react-datepicker-compat/src/utils/dateMath/index.ts deleted file mode 100644 index 162dde38c42c49..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/utils/dateMath/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './dateMath'; diff --git a/packages/react-components/react-datepicker-compat/src/utils/dom.ts b/packages/react-components/react-datepicker-compat/src/utils/dom.ts deleted file mode 100644 index 4ce45e2fa22b1f..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/utils/dom.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { canUseDOM } from '@fluentui/react-utilities'; - -export function getWindow(targetElement?: Element | null): Window | undefined { - if (!canUseDOM() || typeof window === 'undefined') { - return undefined; - } - - const el = targetElement as Element; - - return el && el.ownerDocument && el.ownerDocument.defaultView ? el.ownerDocument.defaultView : window; -} diff --git a/packages/react-components/react-datepicker-compat/src/utils/focus.ts b/packages/react-components/react-datepicker-compat/src/utils/focus.ts deleted file mode 100644 index 97bc5ddb7bfa8b..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/utils/focus.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { getWindow } from './dom'; - -let targetToFocusOnNextRepaint: HTMLElement | { focus: () => void } | null | undefined = undefined; - -/** - * Sets focus to an element asynchronously. The focus will be set at the next browser repaint, - * meaning it won't cause any extra recalculations. If more than one focusAsync is called during one frame, - * only the latest called focusAsync element will actually be focused - * @param element - The element to focus - */ -export function focusAsync(element: HTMLElement | { focus: () => void } | undefined | null): void { - if (element) { - // An element was already queued to be focused, so replace that one with the new element - if (targetToFocusOnNextRepaint) { - targetToFocusOnNextRepaint = element; - return; - } - - targetToFocusOnNextRepaint = element; - - const win = getWindow(element as Element); - - if (win) { - // element.focus() is a no-op if the element is no longer in the DOM, meaning this is always safe - win.requestAnimationFrame(() => { - targetToFocusOnNextRepaint && targetToFocusOnNextRepaint.focus(); - - // We are done focusing for this frame, so reset the queued focus element - targetToFocusOnNextRepaint = undefined; - }); - } - } -} diff --git a/packages/react-components/react-datepicker-compat/src/utils/index.ts b/packages/react-components/react-datepicker-compat/src/utils/index.ts deleted file mode 100644 index 488020805bb61c..00000000000000 --- a/packages/react-components/react-datepicker-compat/src/utils/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export * from './animations'; -export * from './constants'; -export * from './dateFormatting'; -export * from './dateGrid'; -export * from './dateMath'; -export * from './dom'; -export * from './focus'; diff --git a/packages/react-components/react-datepicker-compat/stories/DatePicker/DatePickerControlled.stories.tsx b/packages/react-components/react-datepicker-compat/stories/DatePicker/DatePickerControlled.stories.tsx index 31062666a944ef..be839c3aa6cd5b 100644 --- a/packages/react-components/react-datepicker-compat/stories/DatePicker/DatePickerControlled.stories.tsx +++ b/packages/react-components/react-datepicker-compat/stories/DatePicker/DatePickerControlled.stories.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; -import { addDays, DatePicker } from '@fluentui/react-datepicker-compat'; +import { addDays } from '@fluentui/react-calendar-compat'; +import { DatePicker } from '@fluentui/react-datepicker-compat'; import { Button, Field, makeStyles } from '@fluentui/react-components'; const useStyles = makeStyles({ diff --git a/packages/react-components/react-datepicker-compat/stories/DatePicker/DatePickerDateBoundaries.stories.tsx b/packages/react-components/react-datepicker-compat/stories/DatePicker/DatePickerDateBoundaries.stories.tsx index 1debb658c2ba7c..10877192660624 100644 --- a/packages/react-components/react-datepicker-compat/stories/DatePicker/DatePickerDateBoundaries.stories.tsx +++ b/packages/react-components/react-datepicker-compat/stories/DatePicker/DatePickerDateBoundaries.stories.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; -import { addMonths, addYears, DatePicker } from '@fluentui/react-datepicker-compat'; +import { addMonths, addYears } from '@fluentui/react-calendar-compat'; +import { DatePicker } from '@fluentui/react-datepicker-compat'; import { Field, makeStyles } from '@fluentui/react-components'; const useStyles = makeStyles({ diff --git a/packages/react-components/react-datepicker-compat/stories/DatePicker/DatePickerDateRange.stories.tsx b/packages/react-components/react-datepicker-compat/stories/DatePicker/DatePickerDateRange.stories.tsx index 1770ff822a032d..c4396e5c3e1e18 100644 --- a/packages/react-components/react-datepicker-compat/stories/DatePicker/DatePickerDateRange.stories.tsx +++ b/packages/react-components/react-datepicker-compat/stories/DatePicker/DatePickerDateRange.stories.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { Field, Label, makeStyles, Select } from '@fluentui/react-components'; -import { DatePicker, DateRangeType } from '@fluentui/react-datepicker-compat'; +import { DateRangeType } from '@fluentui/react-calendar-compat'; +import { DatePicker } from '@fluentui/react-datepicker-compat'; const useStyles = makeStyles({ container: { diff --git a/packages/react-components/react-datepicker-compat/stories/DatePicker/DatePickerErrorHandling.stories.tsx b/packages/react-components/react-datepicker-compat/stories/DatePicker/DatePickerErrorHandling.stories.tsx index 046c85d6c7eaa0..8ee8b60dc240a3 100644 --- a/packages/react-components/react-datepicker-compat/stories/DatePicker/DatePickerErrorHandling.stories.tsx +++ b/packages/react-components/react-datepicker-compat/stories/DatePicker/DatePickerErrorHandling.stories.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; -import { addMonths, addYears, DatePicker, defaultDatePickerErrorStrings } from '@fluentui/react-datepicker-compat'; +import { addMonths, addYears } from '@fluentui/react-calendar-compat'; +import { DatePicker, defaultDatePickerErrorStrings } from '@fluentui/react-datepicker-compat'; import { Field, makeStyles } from '@fluentui/react-components'; import type { DatePickerValidationResultData } from '@fluentui/react-datepicker-compat'; diff --git a/packages/react-components/react-datepicker-compat/stories/DatePicker/DatePickerFirstDayOfTheWeek.stories.tsx b/packages/react-components/react-datepicker-compat/stories/DatePicker/DatePickerFirstDayOfTheWeek.stories.tsx index e3c90b7fdd8e5b..a87a1d72c1cfb0 100644 --- a/packages/react-components/react-datepicker-compat/stories/DatePicker/DatePickerFirstDayOfTheWeek.stories.tsx +++ b/packages/react-components/react-datepicker-compat/stories/DatePicker/DatePickerFirstDayOfTheWeek.stories.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; -import { DatePicker, DayOfWeek } from '@fluentui/react-datepicker-compat'; +import { DayOfWeek } from '@fluentui/react-calendar-compat'; +import { DatePicker } from '@fluentui/react-datepicker-compat'; import { Dropdown, Field, makeStyles, Option, useId } from '@fluentui/react-components'; const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];