Skip to content

🐛(components) resolve the calendar hooks to a single react-aria copy - #304

Open
NathanVss wants to merge 1 commit into
mainfrom
fix/calendar-single-import
Open

🐛(components) resolve the calendar hooks to a single react-aria copy#304
NathanVss wants to merge 1 commit into
mainfrom
fix/calendar-single-import

Conversation

@NathanVss

@NathanVss NathanVss commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Problem

Calendar imports its three react-aria hooks through two different names:

CalendarCell.tsx   useCalendarCell    @react-aria/calendar
CalendarAux.tsx    useCalendar        @react-aria/calendar
CalendarGrid.tsx   useCalendarGrid    react-aria          ← the odd one out

They exchange per-render state through hookData, a WeakMap held in module scope.
That works only while every hook is the same module instance. In a consumer whose tree
carries two copies of @react-aria/calendar the grid writes to one map and the cell
reads the other, so opening a date picker throws:

TypeError: Cannot destructure property 'ariaLabel' of 'hookData.get(...)' as it is undefined.

This repository resolves a single copy of everything, which is why the split is
invisible here — typecheck, unit tests, component tests and Storybook all pass with the
bug present. No test could have caught it, so the guard has to be static.

Drive hit this on the date filter after upgrading to 1.1.1.

Changes

  • CalendarGrid.tsx imports useCalendarGrid from @react-aria/calendar, so all the
    calendar hooks resolve to one copy.
  • A no-restricted-imports rule blocks the calendar and date picker hooks from being
    imported through react-aria / react-stately. Type imports stay allowed, since
    types are erased and create no module instance.

The @react-aria/* pins are deliberately left exact. Relaxing them to ^ is worse, not
better: ^3.9.5 resolves to @react-aria/calendar 3.10.1, which is a re-export shim
requiring react-aria ^3.48.0, and that pulls a second umbrella in beside the pinned
3.47.0 — 41 nested copies in a scratch install.

Verification

Built this branch and installed the result into Drive's node_modules, leaving its
duplicated tree in place and removing the resolutions workaround it currently needs:

  • published 1.1.1 — opening the picker throws the error above
  • this branch — the calendar opens and a date is selected, no errors

Reverting the lint rule's target line reproduces the original import and fails eslint.

useCalendarGrid came from the react-aria umbrella while useCalendarCell
and useCalendar came from @react-aria/calendar. Those hooks exchange
per-render state through a WeakMap held in module scope, so a consumer
whose tree carries two copies of the package had the cell read a map
the grid never wrote to, and every click on a date threw on a failed
ariaLabel destructuring.

This repository resolves a single copy, so the split could not surface
here and no test could have caught it. A lint rule keeps the calendar
and date picker hooks on their scoped packages instead.
@NathanVss
NathanVss force-pushed the fix/calendar-single-import branch from 59237b2 to 642cb24 Compare September 4, 2026 16:00
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.

1 participant