@bimetal/calendar-headless
Der kanonische, framework-agnostische Kalender-Controller. createCalendarController besitzt die gesamte Interaktionssemantik: Navigation, Dialog-Routing (inkl. Recurrence-Instanzen), Drag & Drop, Selection, Kategorie-/Ressourcen-Filter, Undo, Rule-Fehler und Tastatur. Die UI-Stacks (React, Vue, Svelte, Angular, Vanilla) sind reine Bindings.
Die Schnittlinie ist scharf: DOM-Messung & Listener-Registrierung = Framework. Jedes if = Controller. Damit ist Cross-Framework-Drift strukturell ausgeschlossen statt eine Frage der Disziplin. Das Paket kennt kein React/Vue/Svelte/Angular und kein DOM jenseits struktureller Drag-Typen — es läuft in Tests ohne Browser, in Workers und in Node.
Installation
npm install @bimetal/calendar-headless @bimetal/calendar-data
createCalendarController
import { createCalendarController } from '@bimetal/calendar-headless';
import { createCalendarStore } from '@bimetal/calendar-data';
const controller = createCalendarController({
store: createCalendarStore(),
config: { core: { timezone: 'Europe/Berlin' } },
rules: [],
customViews: [],
});
Signatur (gekürzt):
function createCalendarController(opts: CalendarControllerOptions): CalendarController;
interface CalendarControllerOptions {
store: CalendarStore;
config?: CalendarConfigInput;
rules?: readonly CalendarRule[];
customViews?: readonly CustomViewSpec[];
eventDialogKind?: 'builtin' | 'none' | 'custom';
}
Snapshot / subscribe-Vertrag
Der Controller folgt dem useSyncExternalStore-Kontrakt:
getSnapshot() liefert eine identitäts-stabile, immutable Sicht aller Interaktions-State-Felder (currentDate, currentView, events, dialog, selection, dragPreview, canUndo/canRedo, hiddenCategories, …). Dieselbe Referenz wird zurückgegeben, bis ein Intent tatsächlich etwas ändert.
subscribe(listener) registriert einen Listener und gibt eine Unsubscribe-Funktion zurück.
destroy() räumt Store-Subscriptions und Listener ab.
Reaktive Option-Updates ohne Neuerzeugung: setConfig, setRules, setCustomViews. Intents sind direkte Methoden — prev/next/today/setView, openEdit/openCreate/saveDialog/deleteDialog, dropAllDay/dropTimed/dropResource/dropTimeline, selectEvent, toggleCategory/toggleResource, undo, handleKeydown.
Architektur
Vertiefung: doc/02-architecture/06-headless.md.