diff --git a/change/@fluentui-react-calendar-compat-51c1ee36-d9f0-4d16-9a35-8e1fda9424e3.json b/change/@fluentui-react-calendar-compat-51c1ee36-d9f0-4d16-9a35-8e1fda9424e3.json new file mode 100644 index 00000000000000..dec3716fecb3f9 --- /dev/null +++ b/change/@fluentui-react-calendar-compat-51c1ee36-d9f0-4d16-9a35-8e1fda9424e3.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "refactor(react-calendar): migrate to motion components", + "packageName": "@fluentui/react-calendar-compat", + "email": "robertpenner@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/packages/react-components/react-calendar-compat/library/package.json b/packages/react-components/react-calendar-compat/library/package.json index 3d91899efe4ca1..560980418e24b9 100644 --- a/packages/react-components/react-calendar-compat/library/package.json +++ b/packages/react-components/react-calendar-compat/library/package.json @@ -15,6 +15,8 @@ "@fluentui/keyboard-keys": "^9.0.8", "@fluentui/react-icons": "^2.0.245", "@fluentui/react-jsx-runtime": "^9.4.1", + "@fluentui/react-motion": "^9.11.5", + "@fluentui/react-motion-components-preview": "^0.15.2", "@fluentui/react-shared-contexts": "^9.26.2", "@fluentui/react-tabster": "^9.26.13", "@fluentui/react-theme": "^9.2.1", diff --git a/packages/react-components/react-calendar-compat/library/src/components/CalendarDay/CalendarDay.tsx b/packages/react-components/react-calendar-compat/library/src/components/CalendarDay/CalendarDay.tsx index 2e52f1b2f45207..cce90fc28e6f72 100644 --- a/packages/react-components/react-calendar-compat/library/src/components/CalendarDay/CalendarDay.tsx +++ b/packages/react-components/react-calendar-compat/library/src/components/CalendarDay/CalendarDay.tsx @@ -9,6 +9,7 @@ import { useCalendarDayStyles_unstable } from './useCalendarDayStyles.styles'; import type { ICalendarDayGrid } from '../CalendarDayGrid/CalendarDayGrid.types'; import type { CalendarDayProps, CalendarDayStyles } from './CalendarDay.types'; import type { JSXElement } from '@fluentui/react-utilities'; +import { AnimationDirection } from '../../Calendar'; /** * @internal @@ -40,7 +41,7 @@ export const CalendarDay: React.FunctionComponent = props => { onNavigateDate, showWeekNumbers, dateRangeType, - animationDirection, + animationDirection = AnimationDirection.Vertical, } = props; const classNames = useCalendarDayStyles_unstable({ diff --git a/packages/react-components/react-calendar-compat/library/src/components/CalendarDay/useCalendarDayStyles.styles.ts b/packages/react-components/react-calendar-compat/library/src/components/CalendarDay/useCalendarDayStyles.styles.ts index 5c89a0db904251..62682c31ba561f 100644 --- a/packages/react-components/react-calendar-compat/library/src/components/CalendarDay/useCalendarDayStyles.styles.ts +++ b/packages/react-components/react-calendar-compat/library/src/components/CalendarDay/useCalendarDayStyles.styles.ts @@ -2,7 +2,6 @@ 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'; @@ -64,12 +63,6 @@ const useMonthAndYearStyles = makeStyles({ textOverflow: 'ellipsis', whiteSpace: 'nowrap', }, - animation: { - animationDuration: DURATION_2, - animationFillMode: 'both', - animationName: FADE_IN, - animationTimingFunction: EASING_FUNCTION_2, - }, headerIsClickable: { '&:hover': { backgroundColor: tokens.colorBrandBackgroundInvertedHover, @@ -166,7 +159,6 @@ export const useCalendarDayStyles_unstable = (props: CalendarDayStyleProps): Cal monthAndYear: mergeClasses( calendarDayClassNames.monthAndYear, monthAndYearStyles.base, - monthAndYearStyles.animation, headerIsClickable && monthAndYearStyles.headerIsClickable, ), monthComponents: mergeClasses(calendarDayClassNames.monthComponents, monthComponentsStyles.base), diff --git a/packages/react-components/react-calendar-compat/library/src/components/CalendarDayGrid/CalendarDayGrid.tsx b/packages/react-components/react-calendar-compat/library/src/components/CalendarDayGrid/CalendarDayGrid.tsx index 9fe504b3cedff8..541e29c051ac8f 100644 --- a/packages/react-components/react-calendar-compat/library/src/components/CalendarDayGrid/CalendarDayGrid.tsx +++ b/packages/react-components/react-calendar-compat/library/src/components/CalendarDayGrid/CalendarDayGrid.tsx @@ -12,6 +12,8 @@ import { useWeekCornerStyles, WeekCorners } from './useWeekCornerStyles.styles'; import { mergeClasses } from '@griffel/react'; import type { Day } from '../../utils'; import type { CalendarDayGridProps } from './CalendarDayGrid.types'; +import { DirectionalSlide } from '../../utils/calendarMotions'; +import { AnimationDirection } from '../../Calendar'; export interface DayInfo extends Day { onSelected: () => void; @@ -75,6 +77,7 @@ export const CalendarDayGrid: React.FunctionComponent = pr const weeks = useWeeks(props, onSelectDate, getSetRefCallback); const animateBackwards = useAnimateBackwards(weeks); + const [getWeekCornerStyles, calculateRoundedStyles] = useWeekCornerStyles(props); React.useImperativeHandle( @@ -130,7 +133,7 @@ export const CalendarDayGrid: React.FunctionComponent = pr showWeekNumbers, labelledBy, lightenDaysOutsideNavigatedMonth, - animationDirection, + animationDirection = AnimationDirection.Vertical, } = props; const classNames = useCalendarDayGridStyles_unstable({ @@ -156,6 +159,8 @@ export const CalendarDayGrid: React.FunctionComponent = pr } as const; const arrowNavigationAttributes = useArrowNavigationGroup({ axis: 'grid-linear' }); + const firstWeek = weeks[0]; + const finalWeek = weeks![weeks!.length - 1]; return ( = pr > - - {weeks!.slice(1, weeks!.length - 1).map((week: DayInfo[], weekIndex: number) => ( + + + {weeks!.slice(1, weeks!.length - 1).map((week: DayInfo[], weekIndex: number) => ( + + + ))} - + + +
); diff --git a/packages/react-components/react-calendar-compat/library/src/components/CalendarDayGrid/CalendarGridRow.tsx b/packages/react-components/react-calendar-compat/library/src/components/CalendarDayGrid/CalendarGridRow.tsx index 19094c629041c6..3f4daba5f849f4 100644 --- a/packages/react-components/react-calendar-compat/library/src/components/CalendarDayGrid/CalendarGridRow.tsx +++ b/packages/react-components/react-calendar-compat/library/src/components/CalendarDayGrid/CalendarGridRow.tsx @@ -1,3 +1,5 @@ +'use client'; + import * as React from 'react'; import { getWeekNumbersInMonth } from '../../utils'; import { CalendarGridDayCell } from './CalendarGridDayCell'; @@ -28,7 +30,7 @@ export interface CalendarGridRowProps extends CalendarDayGridProps { /** * @internal */ -export const CalendarGridRow: React.FunctionComponent = props => { +export const CalendarGridRow = React.forwardRef((props, ref) => { const { ariaHidden, classNames, @@ -52,7 +54,7 @@ export const CalendarGridRow: React.FunctionComponent = pr : ''; return ( - + {showWeekNumbers && weekNumbers && ( = pr ))} ); -}; +}); + +CalendarGridRow.displayName = 'CalendarGridRow'; diff --git a/packages/react-components/react-calendar-compat/library/src/components/CalendarDayGrid/CalendarMonthHeaderRow.tsx b/packages/react-components/react-calendar-compat/library/src/components/CalendarDayGrid/CalendarMonthHeaderRow.tsx index fbe0a3cb479f6d..157fd9fd596512 100644 --- a/packages/react-components/react-calendar-compat/library/src/components/CalendarDayGrid/CalendarMonthHeaderRow.tsx +++ b/packages/react-components/react-calendar-compat/library/src/components/CalendarDayGrid/CalendarMonthHeaderRow.tsx @@ -1,5 +1,7 @@ import * as React from 'react'; import { mergeClasses } from '@griffel/react'; +import { motionTokens } from '@fluentui/react-motion'; +import { Fade } from '@fluentui/react-motion-components-preview'; import { DAYS_IN_WEEK } from '../../utils'; import type { CalendarDayGridProps, CalendarDayGridStyles } from './CalendarDayGrid.types'; import type { DayInfo } from './CalendarDayGrid'; @@ -41,16 +43,17 @@ export const CalendarMonthHeaderRow: React.FunctionComponent - {dayLabels[i]} - + + + {dayLabels[i]} + + ); })} diff --git a/packages/react-components/react-calendar-compat/library/src/components/CalendarDayGrid/useCalendarDayGridStyles.styles.ts b/packages/react-components/react-calendar-compat/library/src/components/CalendarDayGrid/useCalendarDayGridStyles.styles.ts index 751067413d4b25..a96df5f6681abf 100644 --- a/packages/react-components/react-calendar-compat/library/src/components/CalendarDayGrid/useCalendarDayGridStyles.styles.ts +++ b/packages/react-components/react-calendar-compat/library/src/components/CalendarDayGrid/useCalendarDayGridStyles.styles.ts @@ -2,22 +2,6 @@ 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 { createFocusOutlineStyle } from '@fluentui/react-tabster'; import type { SlotClassNames } from '@fluentui/react-utilities'; @@ -180,32 +164,11 @@ const useWeekRowStyles = makeStyles({ zIndex: 1, }, }, - 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 useWeekDayLabelCellStyles = makeStyles({ base: { userSelect: 'none', - animationDuration: DURATION_2, - animationFillMode: 'both', - animationName: FADE_IN, - animationTimingFunction: EASING_FUNCTION_2, }, }); @@ -318,16 +281,9 @@ const useFirstTransitionWeekStyles = makeStyles({ height: 0, opacity: 0, 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({ @@ -339,12 +295,6 @@ const useLastTransitionWeekStyles = makeStyles({ 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({ @@ -410,7 +360,7 @@ export const useCalendarDayGridStyles_unstable = (props: CalendarDayGridStylePro const cornerBorderAndRadiusStyles = useCornerBorderAndRadiusStyles(); const dayTodayMarkerStyles = useDayTodayMarkerStyles(); - const { animateBackwards, animationDirection, lightenDaysOutsideNavigatedMonth, showWeekNumbers } = props; + const { lightenDaysOutsideNavigatedMonth, showWeekNumbers } = props; return { wrapper: mergeClasses(calendarDayGridClassNames.wrapper, wrapperStyles.base), @@ -427,19 +377,7 @@ export const useCalendarDayGridStyles_unstable = (props: CalendarDayGridStylePro ), daySelected: mergeClasses(calendarDayGridClassNames.daySelected, daySelectedStyles.base), daySingleSelected: mergeClasses(calendarDayGridClassNames.daySingleSelected, daySingleSelectedStyles.base), - weekRow: mergeClasses( - calendarDayGridClassNames.weekRow, - weekRowStyles.base, - animateBackwards !== undefined && weekRowStyles.animation, - animateBackwards !== undefined && - (animationDirection === AnimationDirection.Horizontal - ? animateBackwards - ? weekRowStyles.horizontalBackward - : weekRowStyles.horizontalForward - : animateBackwards - ? weekRowStyles.verticalBackward - : weekRowStyles.verticalForward), - ), + weekRow: mergeClasses(calendarDayGridClassNames.weekRow, weekRowStyles.base), weekDayLabelCell: mergeClasses(calendarDayGridClassNames.weekDayLabelCell, weekDayLabelCellStyles.base), weekNumberCell: mergeClasses(calendarDayGridClassNames.weekNumberCell, weekNumberCellStyles.base), dayOutsideBounds: mergeClasses(calendarDayGridClassNames.dayOutsideBounds, dayOutsideBoundsStyles.base), @@ -449,22 +387,8 @@ export const useCalendarDayGridStyles_unstable = (props: CalendarDayGridStylePro ), 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, - ), + firstTransitionWeek: mergeClasses(calendarDayGridClassNames.firstTransitionWeek, firstTransitionWeekStyles.base), + lastTransitionWeek: mergeClasses(calendarDayGridClassNames.lastTransitionWeek, lastTransitionWeekStyles.base), dayMarker: mergeClasses(calendarDayGridClassNames.dayMarker, dayMarkerStyles.base), dayTodayMarker: mergeClasses(calendarDayGridClassNames.dayTodayMarker, dayTodayMarkerStyles.base), }; diff --git a/packages/react-components/react-calendar-compat/library/src/components/CalendarMonth/CalendarMonth.tsx b/packages/react-components/react-calendar-compat/library/src/components/CalendarMonth/CalendarMonth.tsx index 96b7382655f3b4..0b70bbdaf39285 100644 --- a/packages/react-components/react-calendar-compat/library/src/components/CalendarMonth/CalendarMonth.tsx +++ b/packages/react-components/react-calendar-compat/library/src/components/CalendarMonth/CalendarMonth.tsx @@ -18,6 +18,8 @@ import { CalendarYear } from '../CalendarYear/CalendarYear'; import { useCalendarMonthStyles_unstable } from './useCalendarMonthStyles.styles'; import type { CalendarMonthProps } from './CalendarMonth.types'; import type { CalendarYearRange, ICalendarYear } from '../CalendarYear/CalendarYear.types'; +import { DirectionalSlide } from '../../utils/calendarMotions'; +import { AnimationDirection } from '../../Calendar'; const MONTHS_PER_ROW = 4; @@ -72,7 +74,7 @@ function useFocusLogic({ componentRef }: { componentRef: CalendarMonthProps['com export const CalendarMonth: React.FunctionComponent = props => { const { allFocusable, - animationDirection, + animationDirection = AnimationDirection.Vertical, className, componentRef, dateTimeFormatter = DEFAULT_DATE_FORMATTING, @@ -250,44 +252,47 @@ export const CalendarMonth: React.FunctionComponent = props
{rowIndexes.map((rowNum: number) => { const monthsForRow = strings!.shortMonths.slice(rowNum * MONTHS_PER_ROW, (rowNum + 1) * MONTHS_PER_ROW); + const rowKey = 'monthRow_' + rowNum + navigatedDate.getFullYear(); 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 ( - - ); - })} -
+ +
+ {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 ( + + ); + })} +
+
); })}
diff --git a/packages/react-components/react-calendar-compat/library/src/components/CalendarPicker/useCalendarPickerStyles.styles.ts b/packages/react-components/react-calendar-compat/library/src/components/CalendarPicker/useCalendarPickerStyles.styles.ts index 3d9de89c1ed179..2d77d1cf1774ab 100644 --- a/packages/react-components/react-calendar-compat/library/src/components/CalendarPicker/useCalendarPickerStyles.styles.ts +++ b/packages/react-components/react-calendar-compat/library/src/components/CalendarPicker/useCalendarPickerStyles.styles.ts @@ -2,18 +2,6 @@ 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'; @@ -69,12 +57,6 @@ const useCurrentItemButtonStyles = makeStyles({ padding: '0 4px 0 10px', textAlign: 'left', }, - animation: { - animationDuration: DURATION_2, - animationFillMode: 'both', - animationName: FADE_IN, - animationTimingFunction: EASING_FUNCTION_2, - }, hasHeaderClickCallback: { // If this is updated, make sure to update headerIsClickable in useCalendarDayStyles as well '&:hover': { @@ -145,23 +127,6 @@ const useButtonRowStyles = makeStyles({ 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({ @@ -302,14 +267,7 @@ export const useCalendarPickerStyles_unstable = (props: CalendarPickerStyleProps const selectedStyles = useSelectedStyles(); const disabledStyles = useDisabledStyles(); - const { - animateBackwards, - animationDirection, - className, - hasHeaderClickCallback, - highlightCurrent, - highlightSelected, - } = props; + const { className, hasHeaderClickCallback, highlightCurrent, highlightSelected } = props; return { root: mergeClasses(calendarPickerClassNames.root, rootStyles.normalize, rootStyles.base, className), @@ -317,7 +275,6 @@ export const useCalendarPickerStyles_unstable = (props: CalendarPickerStyleProps currentItemButton: mergeClasses( calendarPickerClassNames.currentItemButton, currentItemButtonStyles.base, - animateBackwards !== undefined && currentItemButtonStyles.animation, hasHeaderClickCallback && currentItemButtonStyles.hasHeaderClickCallback, ), navigationButtonsContainer: mergeClasses( @@ -326,19 +283,7 @@ export const useCalendarPickerStyles_unstable = (props: CalendarPickerStyleProps ), 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), - ), + buttonRow: mergeClasses(calendarPickerClassNames.buttonRow, buttonRowStyles.base), itemButton: mergeClasses(calendarPickerClassNames.itemButton, itemButtonStyles.base), selected: mergeClasses(calendarPickerClassNames.selected, highlightSelected && selectedStyles.highlightSelected), current: mergeClasses(calendarPickerClassNames.current, highlightCurrent && currentStyles.highlightCurrent), diff --git a/packages/react-components/react-calendar-compat/library/src/components/CalendarYear/CalendarYear.tsx b/packages/react-components/react-calendar-compat/library/src/components/CalendarYear/CalendarYear.tsx index 8c0190f04fd6c2..96e102e2d8d09f 100644 --- a/packages/react-components/react-calendar-compat/library/src/components/CalendarYear/CalendarYear.tsx +++ b/packages/react-components/react-calendar-compat/library/src/components/CalendarYear/CalendarYear.tsx @@ -5,6 +5,7 @@ import { Enter, Space } from '@fluentui/keyboard-keys'; import { useArrowNavigationGroup } from '@fluentui/react-tabster'; import { mergeClasses } from '@griffel/react'; import { useCalendarYearStyles_unstable } from './useCalendarYearStyles.styles'; +import { DirectionalSlide } from '../../utils/calendarMotions'; import type { CalendarYearStrings, CalendarYearProps, @@ -176,10 +177,13 @@ const CalendarYearGrid: React.FunctionComponent = props = return (
{cells.map((cellRow: React.ReactNode[], index: number) => { + const rowKey = 'yearPickerRow_' + index + '_' + fromYear; return ( -
- {cellRow} -
+ +
+ {cellRow} +
+
); })}
@@ -327,7 +331,9 @@ const CalendarYearTitle: React.FunctionComponent = prop return (
- {onRenderYear(fromYear)} - {onRenderYear(toYear)} + + {onRenderYear(fromYear)} - {onRenderYear(toYear)} +
); }; diff --git a/packages/react-components/react-calendar-compat/library/src/utils/animations.ts b/packages/react-components/react-calendar-compat/library/src/utils/animations.ts index 6a45c738aa1d89..52f9ea73fd5a98 100644 --- a/packages/react-components/react-calendar-compat/library/src/utils/animations.ts +++ b/packages/react-components/react-calendar-compat/library/src/utils/animations.ts @@ -1,10 +1,30 @@ -export const EASING_FUNCTION_1 = 'cubic-bezier(.1,.9,.2,1)'; +import { motionTokens } from '@fluentui/react-motion'; + +// === EASING FUNCTIONS === + +/** @deprecated Slide animations now use motion components. Use motionTokens.curveDecelerateMax instead. */ +export const EASING_FUNCTION_1 = motionTokens.curveDecelerateMax; + +/** @deprecated Fade animations now use Fade.In motion component. No exact motion token equivalent. */ 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'; +// === DURATIONS === + +/** @deprecated No longer used internally. */ +export const DURATION_1 = `${motionTokens.durationFast}ms`; + +/** @deprecated Fade animations now use Fade.In motion component with motionTokens.durationGentle. */ +export const DURATION_2 = `${motionTokens.durationGentle}ms`; + +/** @deprecated Slide animations now use motion components with motionTokens.durationSlower. */ +export const DURATION_3 = `${motionTokens.durationSlower}ms`; + +/** @deprecated No longer used internally. */ +export const DURATION_4 = `${motionTokens.durationUltraSlow}ms`; + +// === FADE ANIMATIONS === + +/** @deprecated Fade animations now use Fade.In motion component. */ export const FADE_IN = { from: { opacity: 0, @@ -13,6 +33,8 @@ export const FADE_IN = { opacity: 1, }, }; + +/** @deprecated Slide animations now use motion components. */ export const FADE_OUT = { from: { opacity: 1, @@ -22,6 +44,10 @@ export const FADE_OUT = { visibility: 'hidden' as const, }, }; + +// === SLIDE ANIMATIONS === + +/** @deprecated Slide animations now use DirectionalSlide motion component. */ export const SLIDE_DOWN_IN20 = { from: { pointerEvents: 'none' as const, @@ -32,36 +58,44 @@ export const SLIDE_DOWN_IN20 = { transform: 'translate3d(0, 0, 0)', }, }; -export const SLIDE_LEFT_IN20 = { + +/** @deprecated Slide animations now use DirectionalSlide motion component. */ +export const SLIDE_UP_IN20 = { from: { pointerEvents: 'none' as const, - transform: 'translate3d(20px, 0, 0)', + transform: 'translate3d(0, 20px, 0)', }, to: { pointerEvents: 'auto' as const, transform: 'translate3d(0, 0, 0)', }, }; -export const SLIDE_RIGHT_IN20 = { + +/** @deprecated Slide animations now use DirectionalSlide motion component. */ +export const SLIDE_LEFT_IN20 = { from: { pointerEvents: 'none' as const, - transform: 'translate3d(-20px, 0, 0)', + transform: 'translate3d(20px, 0, 0)', }, to: { pointerEvents: 'auto' as const, transform: 'translate3d(0, 0, 0)', }, }; -export const SLIDE_UP_IN20 = { + +/** @deprecated Slide animations now use DirectionalSlide motion component. */ +export const SLIDE_RIGHT_IN20 = { from: { pointerEvents: 'none' as const, - transform: 'translate3d(0, 20px, 0)', + transform: 'translate3d(-20px, 0, 0)', }, to: { pointerEvents: 'auto' as const, transform: 'translate3d(0, 0, 0)', }, }; + +/** @deprecated Slide animations now use DirectionalSlide motion component. */ export const SLIDE_DOWN_OUT20 = { from: { transform: 'translate3d(0, 0, 0)', @@ -70,6 +104,8 @@ export const SLIDE_DOWN_OUT20 = { transform: 'translate3d(0, 20px, 0)', }, }; + +/** @deprecated Slide animations now use DirectionalSlide motion component. */ export const SLIDE_UP_OUT20 = { from: { transform: 'translate3d(0, 0, 0)', @@ -79,11 +115,13 @@ export const SLIDE_UP_OUT20 = { }, }; +// === OTHER TRANSITIONS === + +/** @deprecated No longer used internally. */ export const TRANSITION_ROW_DISAPPEARANCE = { '100%': { height: '0px', overflow: 'hidden', - width: '0px', }, '99.9%': { diff --git a/packages/react-components/react-calendar-compat/library/src/utils/calendarMotions.tsx b/packages/react-components/react-calendar-compat/library/src/utils/calendarMotions.tsx new file mode 100644 index 00000000000000..aaf372dcbbe91f --- /dev/null +++ b/packages/react-components/react-calendar-compat/library/src/utils/calendarMotions.tsx @@ -0,0 +1,35 @@ +import { motionTokens } from '@fluentui/react-motion'; +import { Slide } from '@fluentui/react-motion-components-preview'; +import * as React from 'react'; +import { AnimationDirection } from '../Calendar'; +import { JSXElement } from '@fluentui/react-utilities'; + +export const DirectionalSlide: React.FC<{ + duration?: number; + easing?: string; + animationDirection?: AnimationDirection; + animateBackwards?: boolean; + children: JSXElement; +}> = ({ + // Using durationSlower (400ms) as the closest token to the original 367ms + duration = motionTokens.durationSlower, + easing = motionTokens.curveDecelerateMax, + animationDirection = AnimationDirection.Vertical, + animateBackwards = false, + children, +}) => { + let outX = '0px'; + let outY = '0px'; + const distance = animateBackwards ? '-20px' : '20px'; + if (animationDirection === AnimationDirection.Horizontal) { + outX = distance; + } else { + // default to vertical + outY = distance; + } + return ( + + {children} + + ); +}; diff --git a/packages/react-components/react-calendar-compat/library/src/utils/index.ts b/packages/react-components/react-calendar-compat/library/src/utils/index.ts index 2cdf76e5e0414c..d021332767de7e 100644 --- a/packages/react-components/react-calendar-compat/library/src/utils/index.ts +++ b/packages/react-components/react-calendar-compat/library/src/utils/index.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-deprecated -- Re-exporting deprecated animations for backwards compatibility */ export { DURATION_1, DURATION_2, @@ -15,6 +16,7 @@ export { SLIDE_UP_OUT20, TRANSITION_ROW_DISAPPEARANCE, } from './animations'; +/* eslint-enable @typescript-eslint/no-deprecated */ export { DAYS_IN_WEEK, DateRangeType, DayOfWeek, FirstWeekOfYear, MonthOfYear, TimeConstants } from './constants'; export type { CalendarStrings, DateFormatting, DateGridStrings } from './dateFormatting'; export {