Skip to content

Add isRangeSelected and isRangeHovered to Calendar render props#81

Open
Copilot wants to merge 10 commits intomainfrom
copilot/add-israngeselected-hovered-props
Open

Add isRangeSelected and isRangeHovered to Calendar render props#81
Copilot wants to merge 10 commits intomainfrom
copilot/add-israngeselected-hovered-props

Conversation

Copy link
Contributor

Copilot AI commented Mar 8, 2026

Computing range selection and hover state required boilerplate Temporal comparisons in every consumer. These are now computed internally and exposed via renderDay/dayProps.

API changes (Calendar.tsx)

  • renderDay and dayProps callbacks now receive isRangeSelected: boolean and isRangeHovered: boolean
  • isRangeHovered covers both directions (hover before or after the anchor date)

API changes (useTempocal.ts)

  • hoverValue (Temporal.PlainDate | undefined) is now managed as state inside useTempocal — no manual useState needed in consumer code
  • New onChangeHoverValue callback returned from the hook, to be attached to day onMouseOver handlers
  • calendarProps now includes hoverValue and rangeValue (the selected range, when in range mode), so spreading {...calendarProps} onto Calendar passes them automatically — no explicit props needed

New core utility (packages/core)

  • isDateWithinRange(date, rangeValue) added to packages/core/src/isDateWithinRange.ts and exported from the core package
  • Returns a single booleantrue if date falls within the closed interval defined by rangeValue (both start and end must be defined)
  • Supports both PlainDate and PlainDateTime range tuples; date-time values are automatically converted to plain dates for comparison
  • Calendar.tsx calls isDateWithinRange twice for the bidirectional hover case: isDateWithinRange(date, [rangeStart, hoverValue]) || isDateWithinRange(date, [hoverValue, rangeStart])
  • Tests in packages/core/test/isDateWithinRange.test.ts covering: no range, partial range, dates inside/on/outside a closed range, and bidirectional hover intervals
  • Documented at /core/isDateWithinRange in packages/www

Example (DateRangePicker.tsx)

Before:

const [hoverValue, setHoveredValue] = React.useState<Temporal.PlainDate>();

const { calendarProps, onChangeSelectedValue } = useTempocal({ ... });

<Calendar
  {...calendarProps}
  rangeValue={values}
  hoverValue={hoverValue}
  renderDay={({ date, disabled, plainDateLike }) => {
    const isRangeSelected = /* manual Temporal.PlainDate.compare calls */;
    const isRangeHovered = /* manual Temporal.PlainDate.compare calls */;
    return <button onMouseOver={() => setHoveredValue(date)} />;
  }}
/>

After:

const { calendarProps, onChangeHoverValue, onChangeSelectedValue } = useTempocal({ ... });

// calendarProps.hoverValue and isDateWithinRange are available for direct use outside Calendar
const { hoverValue } = calendarProps;
const previewEnd = values[1] ?? hoverValue;
const isForward = !values[0] || !previewEnd || isDateWithinRange(values[0], [values[0], previewEnd]);

<Calendar
  {...calendarProps}
  renderDay={({ date, disabled, isRangeSelected, isRangeHovered, plainDateLike }) => {
    // isRangeSelected and isRangeHovered ready to use
    return <button onMouseOver={() => onChangeHoverValue(date)} />;
  }}
/>

The DateRangePicker example also demonstrates using isDateWithinRange and calendarProps.hoverValue directly to render a live hover preview in the footer: when only the start date is selected, the footer shows the previewed range in correct chronological order (handling both forward and backward hover) using isDateWithinRange(start, [start, previewEnd]) to determine the display direction.

Original prompt

This section details on the original issue you should resolve

<issue_title>Add isRangeSelected and isRangeHovered to render props in daterange and datetimerange modes</issue_title>
<issue_description>They are tedious to compute manually and should be handled internally.

Look at the examples to understand how to calculate them and update the examples to use the new props.</issue_description>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

@vercel
Copy link

vercel bot commented Mar 8, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
tempocal Ready Ready Preview, Comment Mar 8, 2026 3:32pm

Copilot AI and others added 2 commits March 8, 2026 12:27
Co-authored-by: Zertz <2636763+Zertz@users.noreply.github.com>
Co-authored-by: Zertz <2636763+Zertz@users.noreply.github.com>
Copilot AI changed the title [WIP] Add isRangeSelected and isRangeHovered to render props Add isRangeSelected and isRangeHovered to Calendar render props Mar 8, 2026
Copilot finished work on behalf of Zertz March 8, 2026 12:28
…feedback

Co-authored-by: Zertz <2636763+Zertz@users.noreply.github.com>
Copy link
Owner

@Zertz Zertz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update documentation in packages/www

Co-authored-by: Zertz <2636763+Zertz@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 8, 2026

Update documentation in packages/www

Done in c354d57. Updated packages/www/pages/react/useTempocal.tsx (added onChangeHoverValue to the destructuring example and Returns section; expanded calendarProps shape to include hoverValue and rangeValue) and packages/www/pages/react/Calendar.tsx (added isRangeHovered and isRangeSelected to both dayProps and renderDay signatures).

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds first-class range-selection/hover state to Tempocal’s React Calendar render props, and centralizes hover state management in useTempocal so examples/consumers no longer need to compute these booleans manually.

Changes:

  • Add isRangeSelected / isRangeHovered to Calendar’s dayProps and renderDay render-prop arguments (computed inside Day).
  • Move hoverValue state into useTempocal, and pass hoverValue + rangeValue through calendarProps (auto-spread onto Calendar).
  • Update docs and the DateRangePicker example; adjust useTempocal test expectations.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
packages/react/src/useTempocal.ts Adds internal hoverValue state; returns hoverValue/rangeValue in calendarProps and exposes onChangeHoverValue.
packages/react/src/Calendar.tsx Threads hoverValue/rangeValue into Month/Day and computes isRangeSelected/isRangeHovered for render props.
packages/react/test/useTempocal.test.ts Updates assertions for new useTempocal return shape.
packages/www/examples/DateRangePicker.tsx Uses new isRangeSelected/isRangeHovered props and onChangeHoverValue instead of local hover state.
packages/www/pages/react/useTempocal.tsx Documents onChangeHoverValue and updated calendarProps shape.
packages/www/pages/react/Calendar.tsx Documents updated dayProps/renderDay signatures including range booleans.
Comments suppressed due to low confidence (1)

packages/react/src/Calendar.tsx:64

  • dayProps is typed as returning ButtonHTMLAttributes<HTMLLIElement> but those props are spread onto a <li> in Day. This is both a typing mismatch (wrong attribute set for an <li>) and can encourage consumers to pass invalid DOM props like disabled. The return type should be based on <li> attributes (e.g., React.LiHTMLAttributes<HTMLLIElement> / React.HTMLAttributes<HTMLLIElement>) to match how it’s applied.
  }) => Omit<
    React.DetailedHTMLProps<
      React.ButtonHTMLAttributes<HTMLLIElement>,
      HTMLLIElement
    >,
    "style"
  >;

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 158 to 165
<CodeBlock>{`calendarProps: {
locale: Locale;
maxValue: Temporal.PlainDate;
minValue: Temporal.PlainDate;
value: Temporal.PlainDate;
hoverValue: Temporal.PlainDate | undefined;
rangeValue: DateRange | DateTimeRange | undefined;
}`}</CodeBlock>
Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the documented calendarProps shape, maxValue and minValue are shown as required Temporal.PlainDate, but useTempocal actually returns them as optional/possibly undefined. Updating this snippet to reflect the optionality would keep the docs aligned with the real API.

Copilot uses AI. Check for mistakes.
Co-authored-by: Zertz <2636763+Zertz@users.noreply.github.com>
Copy link
Owner

@Zertz Zertz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add isDateWithinRange to the docs

…ar entry

Co-authored-by: Zertz <2636763+Zertz@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 8, 2026

Add isDateWithinRange to the docs

Done in 5ad18fa. Added packages/www/pages/core/isDateWithinRange.tsx with the function signature and description, and added "isDateWithinRange" to the core section of the sidebar.

Co-authored-by: Zertz <2636763+Zertz@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add isRangeSelected and isRangeHovered to render props in daterange and datetimerange modes

3 participants