How it works
The packages, and how your events become a rendered view.
Packages
@moltenship/calendar what you import: everything below
├── @moltenship/calendar-react Root, components, hooks, state
├── @moltenship/calendar-dnd drag, resize, and create inside views
├── @moltenship/calendar-core adapters, validation, snapshots, queries, changes
└── @moltenship/calendar-temporal ranges, day boundaries, DST helperscalendar-react and calendar-dnd build on calendar-core, which builds on calendar-temporal. calendar-core and
calendar-temporal don't use React or the DOM, so they also run on a server or in a worker.
| Package | Use it when |
|---|---|
@moltenship/calendar | Almost always. It includes the packages below. |
@moltenship/calendar-core | You want to validate or query events in code that never loads React. |
@moltenship/calendar-temporal | You only need the date and time zone helpers. |
@moltenship/calendar-react | Rarely. @moltenship/calendar already includes everything in it. |
@moltenship/calendar has no "use client" directive of its own, so a Server Component can import
its core and Temporal helpers. The React parts and the pointer layer keep their client boundary.
Import from the package name only. Files inside a package, such as
@moltenship/calendar-core/src/events, aren't part of the API and can change at any time.
From events to the screen
- You pass
eventstoRoot. Rootruns each record through your adapter, validates it, and builds a snapshot: a frozen, indexed copy of your events.Rootasks the active view's strategy for the visible dates, then calls itsprojectfunction with the snapshot. The result is the view's projection: the events it needs, in the shape it needs.ActiveViewrenders the view'sRendererwith that projection.- Buttons and your own controls call actions such as
navigateNextorsetView. The calendar updates uncontrolled state itself and sends controlled changes to your handlers. A new date or view means a new range and a new projection.
Steps 2 and 3 only run again when their inputs change. A new array with the same records in the same
order reuses the snapshot, and records that are the same objects as before, or have an unchanged
getRevision value, reuse their earlier result.
Using the engine without React
Snapshots work anywhere. This finds the meetings in a time range using calendar-core and
calendar-temporal directly:
import { createEventSnapshotCache } from "@moltenship/calendar-core";
import { instantInterval } from "@moltenship/calendar-temporal";
const snapshots = createEventSnapshotCache(eventAdapter);
const snapshot = snapshots.getSnapshot(meetings);
const morning = snapshot.queryTimed(
instantInterval(
Temporal.Instant.from("2026-10-08T06:00:00Z"),
Temporal.Instant.from("2026-10-08T10:00:00Z"),
),
);
morning.map((meeting) => meeting.title); // ["Standup"]eventAdapter and meetings are the ones from the Quick start. The
snapshot reference lists every query.
Last updated on