Collections & precedence
The most involved recipe: split a calendar into one collection per concern, load each into its own group, and let the engine handle precedence and provenance.
import { calendary, type Collection } from "calendaryjs";
// One collection per concern — each a portable, `.cdy`-shaped object.const publicHolidays: Collection = { collection: "public-holidays", priority: 100, // whole collection on top on busy days — no per-event stamping events: [{ type: "const", id: "newyear", month: 1, day: 1, title: "New Year" }],};const team: Collection = { collection: "team", priority: 50, events: [ { type: "const", id: "kickoff", month: 1, day: 1, title: "Team kickoff", metadata: { owner: "ops" }, // your domain object rides along on the event exceptions: { "2026-01-01": { skip: true } }, // cancelled this one year }, ],};
const cal = calendary().load(publicHolidays).load(team);Precedence on a busy day
Section titled “Precedence on a busy day”Every enabled collection’s events coexist, ordered by priority (higher first,
like CSS z-index; event-level overrides the collection’s):
cal.getDay("2027-01-01").events.map(e => `${e.title} (${e.priority})`);// → ["New Year (100)", "Team kickoff (50)"]Skipped & moved occurrences
Section titled “Skipped & moved occurrences”The 2026 kickoff is skipped — gone from the output, but getSkipped() lists it
(only real occurrences; a stale exception key is ignored). Each entry carries the
source event’s metadata, so you can render the ghost/struck-through chip from the
same domain object — no side id → event lookup. A rescheduled occurrence carries
movedFrom:
cal.getEventsInRange("2026-01-01", "2026-01-01").map(e => e.title); // → ["New Year"]cal.getSkipped({ from: "2026-01-01", to: "2026-12-31" });// → [{ date: "2026-01-01", sourceEventId: "kickoff", groupId: "team",// title: "Team kickoff", reason: "exception", metadata: { owner: "ops" } }]Manifest & toggling
Section titled “Manifest & toggling”cal.requiredPlugins(); // → [] — the minimal plugin manifest for everything loadedcal.setGroupEnabled("team", false); // hide a whole collection, like un-checking a calendarcal.getDay("2027-01-01").events.map(e => e.title); // → ["New Year"]One file, several collections
Section titled “One file, several collections”toBundle() exports every group as its own collection — id / priority / color
preserved — and load() expands the whole bundle in one call. So a single shareable
.cdy carries several named, independently-styled collections instead of flattening
to one.
const bundle = cal.toBundle({ version: "1.0.0" });// → { version, collections: [{ id: "public-holidays", priority: 100, events: [...] },// { id: "team", priority: 50, events: [...] }] }
const restored = calendary().load(bundle); // every collection back as its own groupFull reference: Collections & groups.