From 01e5bd9043cc9a634492f47b79e608e71fe1de70 Mon Sep 17 00:00:00 2001 From: Matt Stow Date: Thu, 19 Dec 2024 17:34:38 +1100 Subject: [PATCH] improve hover state logic, fix sticky bugs etc --- packages/react/src/date-picker/Calendar.tsx | 45 ++++++++++++- .../src/date-range-picker/DateRangePicker.tsx | 67 ++++++++++++++++--- 2 files changed, 101 insertions(+), 11 deletions(-) diff --git a/packages/react/src/date-picker/Calendar.tsx b/packages/react/src/date-picker/Calendar.tsx index 46a58fb554c9..2c63c31a5601 100644 --- a/packages/react/src/date-picker/Calendar.tsx +++ b/packages/react/src/date-picker/Calendar.tsx @@ -7,6 +7,7 @@ import { useCallback, useMemo, useRef, + // Profiler, } from 'react'; import FocusLock from 'react-focus-lock'; import { @@ -32,6 +33,7 @@ import { startOfWeek, type Locale, } from 'date-fns'; +import { DebouncedState } from 'use-debounce'; import { boxPalette, mapSpacing, tokens, useId } from '../core'; import { ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon } from '../icon'; import { Box } from '../box'; @@ -86,12 +88,14 @@ export type CalendarRangeProps = Omit< // returnFocusRef?: RefObject; inputMode?: 'from' | 'to'; onHover?: (date: Date) => void; + clearHoveredDay?: DebouncedState<() => void>; }; export function CalendarRange({ // returnFocusRef, inputMode, onHover, + clearHoveredDay, ...props }: CalendarRangeProps) { // console.log(`props`, props); @@ -160,10 +164,40 @@ export function CalendarRange({ // data-in-range={activeModifiers.qux} // data-day-after-from={props.date > selectedDays?.from} // data-day-before-to={props.date < selectedDays?.to} - onMouseEnter={onHover ? () => onHover(props.date) : undefined} > {/* Without this focusable span, left and right do not work in screen readers */} - {isHidden ? undefined : children} + { + // console.log(`props.date`, props.date); + // console.log(`e`, e); + !isHidden && clearHoveredDay?.(); + }} + onMouseEnter={ + onHover && !isHidden + ? () => { + clearHoveredDay?.cancel(); + onHover(props.date); + } + : undefined + } + css={{ + position: 'relative', + display: 'flex', + height: '3rem', + width: '3rem', + justifyContent: 'center', + alignItems: 'center', + '::before': { + content: '""', + position: 'absolute', + inset: 0, + // background: 'rgba(255,0,0,0.2)', + }, + }} + > + {isHidden ? undefined : children} + ); }, @@ -171,6 +205,12 @@ export function CalendarRange({ }; return ( + // { + // console.log(id, phase, duration); + // }} + // > { @@ -183,6 +223,7 @@ export function CalendarRange({ + // {/* */} ); } diff --git a/packages/react/src/date-range-picker/DateRangePicker.tsx b/packages/react/src/date-range-picker/DateRangePicker.tsx index ef92f386e93b..67aa18f79cf5 100644 --- a/packages/react/src/date-range-picker/DateRangePicker.tsx +++ b/packages/react/src/date-range-picker/DateRangePicker.tsx @@ -7,9 +7,11 @@ import { useState, useEffect, useMemo, + // Profiler, } from 'react'; import { SelectRangeEventHandler } from 'react-day-picker'; import { addDays, isAfter, isBefore } from 'date-fns'; +import { useDebouncedCallback } from 'use-debounce'; import { Box } from '../box'; import { Flex } from '../flex'; import { Stack } from '../stack'; @@ -243,6 +245,7 @@ export const DateRangePicker = ({ ); if ((range.from || fromInputValue) && (range.to || toInputValue)) { + setHoveredDay(undefined); closeCalendar(); return; } @@ -443,10 +446,13 @@ export const DateRangePicker = ({ ? getRange(valueAsDateOrUndefined.from, hoveredDay) : inputMode === 'from' ? getRange(hoveredDay, valueAsDateOrUndefined.from) - : [], + : {}, [hoveredDay, inputMode, valueAsDateOrUndefined] ); - // console.log(`range()`, range()); + + const clearHoveredDay = useDebouncedCallback(() => { + setHoveredDay(undefined); + }, 200); // These prop objects serve as a single source of truth for the duplicated Popovers and Calendars below // We duplicate the Popover + Calendar as a workaround for a bug that scrolls the page to the top on initial open of the calendar - https://github.com/gpbl/react-day-picker/discussions/2059 @@ -462,13 +468,25 @@ export const DateRangePicker = ({ returnFocusRef: inputMode === 'from' ? fromTriggerRef : toTriggerRef, selected: valueAsDateOrUndefined, modifiers: { + // fromRange: (day: Date) => { + // // console.log(`day`, day); + // return fromRange().some( + // (r) => r.toDateString() === day.toDateString() + // ); + // // return range().includes(day); + // }, fromRange: (day: Date) => { // console.log(`day`, day); - return fromRange().some( - (r) => r.toDateString() === day.toDateString() - ); + // console.log(`fromRange()`, fromRange()); + return fromRange()[day.toDateString()]; // return range().includes(day); }, + // fromRange: (day: Date) => { + // // console.log(`day`, day); + // // console.log(`fromRange()`, fromRange()); + // return fromRange().has(day.toDateString()); + // // return range().includes(day); + // }, // qux: range(), // foo: hoveredDay, }, @@ -477,10 +495,12 @@ export const DateRangePicker = ({ // foo: 'baz', }, onHover, + clearHoveredDay, }), [ defaultMonth, disabledCalendarDays, + clearHoveredDay, // hoveredDay, inputMode, numberOfMonths, @@ -492,6 +512,12 @@ export const DateRangePicker = ({ ); return ( + // { + // console.log(id, phase, duration); + // }} + // > {/* Legend needs to be the first element, so if none is supplied render a visually hidden element. */} @@ -584,6 +610,7 @@ export const DateRangePicker = ({ + // ); }; @@ -598,15 +625,37 @@ export function useDateRangePickerIds(idProp?: string) { } const getRange = (startDate?: Date, endDate?: Date) => { + // if (startDate && endDate) { + // const range = []; + // let current = addDays(startDate, 1); + // while (current < endDate) { + // // console.log(`current, hoverDate`, current, hoverDate); + // range.push(current); + // current = addDays(current, 1); + // } + // return range; + // } + // return []; + // const range = new Set(); + // if (startDate && endDate) { + // // const range = []; + // let current = addDays(startDate, 1); + // while (current < endDate) { + // // console.log(`current, hoverDate`, current, hoverDate); + // range.add(current.toDateString()); + // current = addDays(current, 1); + // } + // } + // return range; + const range: Record = {}; if (startDate && endDate) { - const range = []; let current = addDays(startDate, 1); while (current < endDate) { // console.log(`current, hoverDate`, current, hoverDate); - range.push(current); + range[current.toDateString()] = true; current = addDays(current, 1); } - return range; } - return []; + return range; + // return {}; };