From 44f949b368c1108b06624d7a0d375b558a243356 Mon Sep 17 00:00:00 2001 From: Gabriele Assentato Date: Fri, 1 Nov 2024 14:25:54 +0100 Subject: [PATCH] feature/now-prop: allows dev to specify the current date (example used for offsetting the timezone of a different user) --- packages/react-calendar/README.md | 1 + packages/react-calendar/src/Calendar.tsx | 9 +++++++++ packages/react-calendar/src/DecadeView/Years.tsx | 3 ++- packages/react-calendar/src/MonthView.tsx | 11 ++++++++++- packages/react-calendar/src/MonthView/Days.tsx | 2 ++ packages/react-calendar/src/MonthView/Weekdays.tsx | 10 +++++++++- packages/react-calendar/src/TileGroup.tsx | 3 +++ packages/react-calendar/src/YearView/Months.tsx | 3 ++- packages/react-calendar/src/shared/dates.ts | 5 +++-- packages/react-calendar/src/shared/utils.ts | 3 ++- test/Test.tsx | 6 +++++- 11 files changed, 48 insertions(+), 8 deletions(-) diff --git a/packages/react-calendar/README.md b/packages/react-calendar/README.md index b949eaff..71b03991 100644 --- a/packages/react-calendar/README.md +++ b/packages/react-calendar/README.md @@ -147,6 +147,7 @@ Displays a complete, interactive calendar. | tileDisabled | Pass a function to determine if a certain day should be displayed as disabled. | n/a | `({ activeStartDate, date, view }) => date.getDay() === 0` | | value | Calendar value. Can be either one value or an array of two values. If you wish to use react-calendar in an uncontrolled way, use `defaultValue` instead. | n/a | | | view | Determines which calendar view shall be opened. Does not disable navigation. Can be `"month"`, `"year"`, `"decade"` or `"century"`. If you wish to use react-calendar in an uncontrolled way, use `defaultView` instead. | The most detailed view allowed | `"year"` | +| now | Current date used as now, allows to display an offsetted time as today | `new Date()` | ### MonthView, YearView, DecadeView, CenturyView diff --git a/packages/react-calendar/src/Calendar.tsx b/packages/react-calendar/src/Calendar.tsx index a9aa6745..88de7a52 100644 --- a/packages/react-calendar/src/Calendar.tsx +++ b/packages/react-calendar/src/Calendar.tsx @@ -419,6 +419,13 @@ export type CalendarProps = { * @example 'year' */ view?: View; + /** + * Determines which date to show as the current date on the calendar + * + * @default new Date() + * @example 'year' + */ + now?: Date; }; function toDate(value: Date | string): Date { @@ -656,6 +663,7 @@ const Calendar: React.ForwardRefExoticComponent( @@ -1024,6 +1032,7 @@ const Calendar: React.ForwardRefExoticComponent, 'classes' | 'currentDecade' | 'date'>; export default function Years(props: YearsProps): React.ReactElement { - const { activeStartDate, hover, showNeighboringDecade, value, valueType, ...otherProps } = props; + const { activeStartDate, hover, showNeighboringDecade, value, valueType, now, ...otherProps } = props; const start = getBeginOfDecadeYear(activeStartDate); const end = start + (showNeighboringDecade ? 11 : 9); @@ -50,6 +50,7 @@ export default function Years(props: YearsProps): React.ReactElement { start={start} value={value} valueType={valueType} + now={now} /> ); } diff --git a/packages/react-calendar/src/MonthView.tsx b/packages/react-calendar/src/MonthView.tsx index d75fc796..69f9de49 100644 --- a/packages/react-calendar/src/MonthView.tsx +++ b/packages/react-calendar/src/MonthView.tsx @@ -34,6 +34,13 @@ type MonthViewProps = { * @example true */ showWeekNumbers?: boolean; + /** + * Determines which date to show as the current date on the calendar + * + * @default new Date() + * @example 'year' + */ + now?: Date; } & Omit< React.ComponentProps & React.ComponentProps & @@ -52,6 +59,7 @@ export default function MonthView(props: MonthViewProps): React.ReactElement { formatWeekday, onClickWeekNumber, showWeekNumbers, + now, ...childProps } = props; @@ -63,6 +71,7 @@ export default function MonthView(props: MonthViewProps): React.ReactElement { formatWeekday={formatWeekday} locale={locale} onMouseLeave={onMouseLeave} + now={now} /> ); } @@ -84,7 +93,7 @@ export default function MonthView(props: MonthViewProps): React.ReactElement { } function renderDays() { - return ; + return ; } const className = 'react-calendar__month-view'; diff --git a/packages/react-calendar/src/MonthView/Days.tsx b/packages/react-calendar/src/MonthView/Days.tsx index 7030b406..3e03439c 100644 --- a/packages/react-calendar/src/MonthView/Days.tsx +++ b/packages/react-calendar/src/MonthView/Days.tsx @@ -49,6 +49,7 @@ export default function Days(props: DaysProps): React.ReactElement { showNeighboringMonth, value, valueType, + now, ...otherProps } = props; @@ -118,6 +119,7 @@ export default function Days(props: DaysProps): React.ReactElement { start={start} value={value} valueType={valueType} + now={now} /> ); } diff --git a/packages/react-calendar/src/MonthView/Weekdays.tsx b/packages/react-calendar/src/MonthView/Weekdays.tsx index 1a911039..5a849698 100644 --- a/packages/react-calendar/src/MonthView/Weekdays.tsx +++ b/packages/react-calendar/src/MonthView/Weekdays.tsx @@ -40,6 +40,13 @@ type WeekdaysProps = { */ locale?: string; onMouseLeave?: () => void; + /** + * Determines which date to show as the current date on the calendar + * + * @default new Date() + * @example 'year' + */ + now?: Date; }; export default function Weekdays(props: WeekdaysProps): React.ReactElement { @@ -49,6 +56,7 @@ export default function Weekdays(props: WeekdaysProps): React.ReactElement { formatWeekday = defaultFormatWeekday, locale, onMouseLeave, + now, } = props; const anyDate = new Date(); @@ -72,7 +80,7 @@ export default function Weekdays(props: WeekdaysProps): React.ReactElement { key={weekday} className={clsx( weekdayClassName, - isCurrentDayOfWeek(weekdayDate) && `${weekdayClassName}--current`, + isCurrentDayOfWeek(weekdayDate, now) && `${weekdayClassName}--current`, isWeekend(weekdayDate, calendarType) && `${weekdayClassName}--weekend`, )} > diff --git a/packages/react-calendar/src/TileGroup.tsx b/packages/react-calendar/src/TileGroup.tsx index d5735f99..08efa7eb 100644 --- a/packages/react-calendar/src/TileGroup.tsx +++ b/packages/react-calendar/src/TileGroup.tsx @@ -17,6 +17,7 @@ type TileGroupProps = { step?: number; value?: Value; valueType: RangeType; + now?: Date; }; export default function TileGroup({ @@ -32,6 +33,7 @@ export default function TileGroup({ step = 1, value, valueType, + now, }: TileGroupProps): React.ReactElement { const tiles = []; for (let point = start; point <= end; point += step) { @@ -45,6 +47,7 @@ export default function TileGroup({ hover, value, valueType, + now, }), date, }), diff --git a/packages/react-calendar/src/YearView/Months.tsx b/packages/react-calendar/src/YearView/Months.tsx index 77d55509..f75a6125 100644 --- a/packages/react-calendar/src/YearView/Months.tsx +++ b/packages/react-calendar/src/YearView/Months.tsx @@ -17,7 +17,7 @@ type MonthsProps = { Omit, 'classes' | 'date'>; export default function Months(props: MonthsProps): React.ReactElement { - const { activeStartDate, hover, value, valueType, ...otherProps } = props; + const { activeStartDate, hover, value, valueType, now, ...otherProps } = props; const start = 0; const end = 11; const year = getYear(activeStartDate); @@ -45,6 +45,7 @@ export default function Months(props: MonthsProps): React.ReactElement { start={start} value={value} valueType={valueType} + now={now} /> ); } diff --git a/packages/react-calendar/src/shared/dates.ts b/packages/react-calendar/src/shared/dates.ts index 5e03be19..bfd670d5 100644 --- a/packages/react-calendar/src/shared/dates.ts +++ b/packages/react-calendar/src/shared/dates.ts @@ -393,10 +393,11 @@ export function getDecadeLabel( * Returns a boolean determining whether a given date is the current day of the week. * * @param {Date} date Date. + * @param {Date} now optional defaults to new Date() * @returns {boolean} Whether a given date is the current day of the week. */ -export function isCurrentDayOfWeek(date: Date): boolean { - return date.getDay() === new Date().getDay(); +export function isCurrentDayOfWeek(date: Date, now?: Date): boolean { + return date.getDay() === (now ?? new Date()).getDay(); } /** diff --git a/packages/react-calendar/src/shared/utils.ts b/packages/react-calendar/src/shared/utils.ts index 888f0418..2b6384ea 100644 --- a/packages/react-calendar/src/shared/utils.ts +++ b/packages/react-calendar/src/shared/utils.ts @@ -79,6 +79,7 @@ export function getTileClasses(args: { hover?: Date | null; value?: Value; valueType?: RangeType; + now?: Date; }): string[] { if (!args) { throw new Error('args is required'); @@ -93,7 +94,7 @@ export function getTileClasses(args: { return classes; } - const now = new Date(); + const now = args.now ?? new Date(); const dateRange = (() => { if (Array.isArray(date)) { return date; diff --git a/test/Test.tsx b/test/Test.tsx index 820ca6ed..149407e3 100644 --- a/test/Test.tsx +++ b/test/Test.tsx @@ -15,7 +15,10 @@ import './Test.css'; import type { LooseValue, Value, View } from './shared/types.js'; -const now = new Date(); +// Now can be changed to test the calendar in a different instant +// const now = new Date(); + +const now = new Date(2024, 7, 31); const tileClassName = ({ date, view }: { date: Date; view: View }) => { switch (view) { @@ -122,6 +125,7 @@ export default function Test() { className: 'myCustomCalendarClassName', locale, maxDate, + now, maxDetail, minDate, minDetail,