3 October 2026
Features
- feat: new
onEventsChangeprop, called once per user action with every stored row it touched:{ action, event, scope, added, updated, deleted }. A recurring edit touches several rows ("edit all" updates the series and deletes the occurrences that were moved one by one), andonEventAdd/onEventUpdate/onEventDeletereport them one call at a time;onEventsChangereports the action as one unit, so a backend can save it, or refuse it, in one transaction. FullCalendar reports an action once the same way (eventChangewithrelatedEvents). The per-row callbacks are unchanged.EventsChangeis exported, andRecurrenceEditScopefrom@ilamy/calendar/plugins/recurrence(#317) — Closes#309
Fixes
- fix: recurring events keep their local time across a daylight-saving change. With a
timezonethat differed from the browser's, every occurrence after a change ran an hour off: a daily 09:00 New York series showed at 10:00 from 9 March. Occurrences now follow RFC 5545: the same local time, a time skipped by the spring change moves forward by the gap, and one repeated by the autumn change takes its first occurrence. Exclusions and moved occurrences saved by earlier versions for an occurrence after a change, in such a calendar, hold the old shifted time and no longer match it (#312) — Closes#307 - fix: on the day the clocks change, timed events and the now-line sit beside their clock time. They were drawn an hour early on the spring day and an hour late on the autumn day, in the week, day and resource timeline views (
#313) — Closes#311 - fix: "delete this and following" also removes occurrences that were moved after the cut, and reports them to
onEventDelete. They used to stay on the grid (#316) — Closes#315 - fix: a resource whose id is
0no longer draws every resource's events, or a second dot on the now-line (#308) - fix: the header fits at every width, from phone to desktop. The navigation wraps instead of being cut off, and the single-row and segmented-switcher layouts now switch where they fit: at 576px and 896px of the calendar's own width (
#306) — Closes#298 - fix: the cell under a dragged event no longer takes the hover tint, so only the drop tint shows; hovering without a drag still tints. While an event is dragged, the calendar carries
data-draggingfor your own styles (#305) — Closes#299 - fix: the published type declarations reference valid
dayjsand React types, so a project type-checking withskipLibCheck: falsepasses (#304) — Closes#302
Performance
- perf: grid cells stay mounted when you navigate, in every view and orientation, and time-grid slots no longer mount a closed all-events dialog. A horizontal resource week with 30 rooms went from 1,229 ms to 728 ms per "next" in Chromium (
#301,#303) — Closes#300— Thanks @troioi-vn! - perf: a recurring series is expanded once per window rather than from its start for every column (200 series begun in 2015: 4,560 ms to 188 ms per week "next"); grid cells read a narrow context, so an event change no longer re-renders every time slot; event handlers keep one identity, so passing them inline no longer re-renders the grid; and drag hit-testing reads fewer cell edges (
#308)
Docs
- docs: the recurrence page's exclusions example used
Dateobjects, which exclude nothing; it now uses ISO strings, explains the time zone rule, and documents editing and deleting a series. The FAQ no longer tells you to remount the calendar whentimezoneorlocalechanges, and the performance tips no longer ask foruseCallbackaround event handlers (#318)
Internal
- refactor: the source follows Bulletproof React's structure (shared → features → app), and a Biome rule rejects a shared file importing a feature (
#319)