Skip to content

feat: initial release — framework-agnostic calendar engine with React, Vue, Angular, Lit, and Svelte adapters#1

Merged
bigcalendar merged 194 commits into
mainfrom
feat/initial
Jul 1, 2026
Merged

feat: initial release — framework-agnostic calendar engine with React, Vue, Angular, Lit, and Svelte adapters#1
bigcalendar merged 194 commits into
mainfrom
feat/initial

Conversation

@cutterbl

@cutterbl cutterbl commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

This is the initial release of Big Calendar — a ground-up rewrite of react-big-calendar as a framework-agnostic Nx monorepo. The same calendar engine powers five independent framework adapters, all built from a shared core with no duplicated logic.

Packages shipping in this release

Package Purpose
@big-calendar/core Framework-agnostic engine: calendar store, view models, layout algorithms, slot-selection FSM, DnD state
@big-calendar/localizer Base localizer contract + Intl ponyfills
@big-calendar/localizer-temporal Recommended localizer — built on the browser Temporal API
@big-calendar/localizer-luxon Localizer for teams already using Luxon
@big-calendar/styles Design tokens, layout, and component CSS
@big-calendar/dnd Optional drag-to-move and drag-to-resize
@big-calendar/react React 18 adapter
@big-calendar/vue Vue 3 adapter
@big-calendar/angular Angular 21+ adapter
@big-calendar/lit Lit 3 adapter (standard web components)
@big-calendar/svelte Svelte 5 adapter
@big-calendar/codemods CLI migration tool from react-big-calendar
@big-calendar/mcp MCP server — gives AI coding assistants direct knowledge of the Big Calendar API

What's in the engine

  • Month, week, work-week, day, and agenda views
  • Event layout with multi-day spanning, overlap detection, and per-day overflow (+N more)
  • Slot selection (click and drag to create events) with keyboard support
  • Drag-to-move and drag-to-resize with live preview
  • Drop-from-outside support
  • RTL layout support
  • Localizer abstraction — ISO string boundaries everywhere, no raw Date objects
  • Headless composables in every adapter for full layout control

What's in the adapters

All five adapters ship:

  • Full view components wired to the engine
  • Default slot components (toolbar, event, date cell, show-more, popover, tooltip)
  • Complete customization surface via components prop
  • Drag-and-drop integration
  • Storybook with canonical stories and MDX documentation
  • MCP recipe resource
  • Unit test suite
  • Playwright cross-framework visual comparison spec

Tooling and CI

  • Nx 23 monorepo with affected-based CI
  • PR validation: lint, typecheck, test, build (affected)
  • Release: Nx Release with conventional commits, GitHub release, npm publish with provenance
  • Storybook composition site deployed to GitHub Pages on every merge
  • CodeQL security scanning on PRs and weekly schedule

Test plan

  • All packages pass nx run-many -t lint typecheck test build (verified locally before this PR)
  • PR validation CI passes (lint + typecheck + test + build, affected)
  • CodeQL scan passes
  • Merge triggers release workflow: version bump, changelog, GitHub release, npm publish
  • Merge triggers docs workflow: Storybook composition site deploys to GitHub Pages

Stephen Blades added 30 commits June 1, 2026 20:01
Nx (Cloud off) + pnpm workspace with eight package scaffolds (core,
localizer, localizer-temporal, localizer-luxon, styles, dnd, react,
codemods). Adds TS (ES2024/ESM) base config, Vite library builds with
.d.ts emit, Vitest (per-file 85/95 coverage bar), flat ESLint with
@nx/enforce-module-boundaries scope-tag graph + Appendix A naming rules,
Prettier, commitlint + Husky hooks, Vitest workspace, four CI/CD
workflows (PR validation, CodeQL, release, docs deploy), and memory/
checkpoint files.

All targets green: typecheck, lint, test, build across 8 projects.
Implements @big-calendar/localizer Phase 1 Task 1a:
- LocalizerContract / LocalizerOptions / DateParts types (string-in/string-out)
- abstract Localizer<T> template class with the full ~40-method contract built
  on a small protected-abstract engine primitive set
- getWeekInfo ponyfill (native Intl.Locale week API + CLDR region fallback)
- formatDuration ponyfill (native Intl.DurationFormat + NumberFormat/ListFormat fallback)
- DEFAULT_FORMATS named Intl option sets
- 44 contract tests via a UTC fixture localizer; 95.78% branch / 100% function
…k 1b plan

Pauses Phase 1 mid-Task-1b for a VS Code restart. Adds the lazy-loaded
temporal-polyfill@0.3.2 runtime dependency and records the full, probe-verified
localizer-temporal implementation design in memory/PROGRESS.md so the next
session can implement without re-investigation.
…oral API

Implements @big-calendar/localizer-temporal Phase 1 Task 1b:
- loadTemporal(): lazy, feature-detected polyfill loader (native globalThis.Temporal
  preferred; temporal-polyfill dynamically imported otherwise; cached)
- TemporalLocalizer: all engine primitives over Temporal.ZonedDateTime — DST-aware
  startOf/endOf, offset via offsetNanoseconds, RFC 3339 vs RFC 9557 serialization,
  date-only (PlainDate) parsing, normalized to the localizer timezone
- createTemporalLocalizer() async factory
- 17 tests incl. real EST/EDT DST, bracket round-trip, loader native+cached branches
Task 1c: desk-review spike (Jan-2026 platform-knowledge cutoff) of Subgrid,
Popover API, CSS Anchor Positioning, and :dir(). Outcome — adopt subgrid +
Popover + :dir() (Baseline); anchor positioning is non-Baseline so floating-ui
stays the default positioning engine. Records the fallback matrix and defers
empirical Playwright verification to Phase 3. Closes Phase 1.
Phase 2a foundation: Views/Navigate constants (values matched to v1 for
parity), ViewKey/EventId/ResourceId types, and the accessor module
(accessor/wrapAccessor/resolveAccessors) with v1-parity default field
names. 100% coverage.
Phase 2b: isolated store (createCalendarStore) over @preact/signals-core
holding date/view/selected/events/backgroundEvents/resources signals plus
actions (navigate/setView/setDate/select/setEvents/setBackgroundEvents/
setResources/destroy). Basic navigateDate (TODAY/DATE/PREV/NEXT, per-view
step; agenda by length) built on LocalizerContract. Drilldown and
visible-range derivation deferred to 2c. 100% branch/function coverage.
Pure, fraction-based ports of the v1 day-event layout algorithms:
overlap packs shared-time events into grown container/row/leaf columns;
no-overlap packs them into non-overlapping even columns. Both take
pre-positioned events (top/height as 0..1 fractions) and compute the
horizontal left/width plus a paint-order zIndex. Adds a default-algorithm
registry and resolver (key or custom fn). Removes the scaffold smoke test.
Pure monthViewModel: splits the padded day grid into weeks, clamps each
overlapping event into 1-based day-column segments (one per week it spans),
and stacks them into non-overlapping levels with a per-week limit that spills
overflow into each week's extra (the +N more list). Ports v1's eventSegments
/ eventLevels math against the LocalizerContract, dropping the legacy
segmentOffset tz hack (the Temporal localizer already works in-zone).
Adds createSlotMetrics (ports v1 getSlotMetrics to 0..1 fractions over the
LocalizerContract; DST-safe via getSlotDate/getDstOffset) and timeGridViewModel
for the day/week/work_week views: splits events into an all-day header row vs
timed events (v1's allDay/date-only/multi-day rule), builds one time column per
visible day, positions timed events with slot metrics, and packs them with the
chosen day-layout algorithm (overlap default, key or custom fn). Extracts the
month segmentation into a shared views/segments module (datedEvents, eventSegments,
stackIntoLevels, sortRowEvents, rowSegments) now reused by both the month grid
and the time-grid all-day row; month view model rewritten to consume it.
agendaViewModel walks the visible days and lists, per day with events, every
event touching it sorted by start (empty days omitted — v1 parity).
groupEventsByResource buckets events under their resource(s) in resource order
(single null group when there are no resources; multi-id events land in each
matching group; unmatched events are dropped) — a pure port of v1's
Resources.groupEvents, reusable across the resource-aware views.
createSelection is a pure signals FSM over slot indices (§8.2): start/to/
complete drive a drag (pointer or keyboard Shift+Arrow), click commits a
single slot, cancel aborts. onSelecting fires on every range change and may
veto by returning false; onSelect fires on commit. A normalized range signal
drives the live highlight overlay. Date translation, long-press timing and
event hit-testing stay in the adapters.
DEFAULT_MESSAGES holds the built-in English strings (v1 parity, including the
work_week key and the showMore(total) formatter); resolveMessages merges caller
overrides over the defaults for i18n without mutating the defaults.
Adds buildViewModel (dispatches view → month / time-grid / agenda model,
tagged by kind/view) and a store-level viewModel computed signal that rebuilds
from view + range + events + config. Adds the parity time-grid config options
(step, timeslots, min, max, dayLayoutAlgorithm, allDayMaxRows, showMultiDayTimes,
showAllEvents, selectable); the store resolves min/max to a minutes window and
folds showAllEvents into the all-day row limit. Completes the §4.2 store shape's
derived view model.
Stephen Blades added 21 commits June 26, 2026 12:07
…torybook alias configs

Moves the per-package @big-calendar/* source alias map into a shared
packages/aliases.ts helper. All vitest configs and storybook viteFinal
hooks now call packageAliases(pkgs) instead of maintaining their own
copies of the same list. Eliminates drift risk when new packages are added.
…in decorator

Toolbar globals (locale, timeZone, localizer type) now reach embedded ref
iframes in Storybook composition mode. The hub preview.ts relays UPDATE_GLOBALS
via postMessage; the decorator's new message listener picks them up and rebuilds
the localizer. manager.ts handles hard-reload at a ref story URL by injecting a
hidden iframe to prime SET_GLOBALS from the hub.

withLocalizerDecorator now wraps each story in
<div dir={localizer.direction} lang={localizer.language}> so RTL stories flip
automatically when the locale toolbar global changes. Switched to a synchronous
Luxon default to avoid top-level-await unhandledrejection on cold load.
floatingPosition: add isRTL platform method so @floating-ui/core interprets
start/end placement suffixes correctly in RTL layouts.

useFloatingAnchor: switch from logical inset-inline/block to physical left/top
— @floating-ui/core always returns physical viewport offsets, so logical
properties misplace panels in RTL.

DefaultToolbar: replace glyph characters with messages.previous / messages.today
/ messages.next so toolbar labels honour the configured locale.
Two stories demonstrating the i18n layers working together:
ArabicRTL — Arabic locale, full messages override, dir/lang set from
localizer.direction/language, whole layout flips via CSS logical properties.
SpanishMessages — Spanish locale with complete messages translation including
the screen-reader instruction strings.
tokens.css: event border now derives from event-bg (not AccentColor) so it
stays coherent with custom --bc-color-event-bg overrides.
event.css + toolbar.css: switch border properties to use --bc-color-event-border.
month.css: date numbers anchor to physical right in RTL via :dir(rtl) override.
timegrid.css: add missing inline-start border on the time grid container.
Vue's MonthView was missing the ResizeObserver-based row measurement
that React has via useMonthRowMeasure. Without it, store.measuredWeekLimit
stayed at Infinity and the month view showed all events regardless of
available row height — no +N more indicators ever appeared.

Adds useMonthRowMeasure.ts (Vue watchEffect equivalent of the React hook)
and calls it from useMonthView, watching roving.containerRef which is
already set to the month grid DOM element by the template.

Adds 8 unit tests mirroring the React test suite. Also fixes pre-existing
lint errors in useRovingSelection.test.ts (unused function params).
Wire drag-to-move and edge-resize in the Vue adapter via useCalendarDnd
and @big-calendar/dnd. Three bugs fixed along the way:

- useTimeGridView was snapshotting the ComputedRef grid value at setup
  time (const grid = gridRef.value), so the template never re-rendered
  when events changed after a drop. Return the ComputedRef directly so
  Vue's auto-unwrap tracks it as a live dependency.
- useCalendarStore wrapped onEventDrop/onEventResize conditionally, so
  config.onEventDrop was null when attrs settled after store creation.
  Always create the wrapper; read the latest callback at call time via
  the reactive attrs proxy.
- Calendar.vue had a duplicate useCalendarDnd call alongside the story's
  DraggableCalendar wrapper, causing dual-registration warnings from
  Pragmatic DnD. Removed the internal call.

Also activates the Vue package in the storybook-site composed build:
scripts, wait-for-storybooks, core main.ts refs, and project.json.
- vue view components, composables, DnD, top-layer UI, accessibility
- storybook stories matching react coverage (Standard, ScrollToTime,
  TimeWindow, EventCallbacks, Selection, DnD, BackgroundEvents, Resources,
  EventTypeAccessor, ResourceTypeAccessor, Localization)
- composition-mode globals bridge: localStorage cache in core/preview.ts,
  manager.ts addon with Channel.handleEvent patch for correct source routing,
  bc-globals-sync postMessage relay to vue ref iframe
- localizerRef.ts (sync shallowRef) + side-effect withVueLocalizerDecorator
  pattern to avoid async module chain in preview.ts
- bodyNowIndicatorProps: body-spanning now-indicator parity with react
- MCP vue recipe (basic-setup-vue.ts); MCP server MDX docs moved to core
- .gitignore: add playwright-report, test-results, playwright/.auth
- PROGRESS.md: mark vue adapter complete, add angular phase 11 task list
- PROGRESS-ARCHIVE.md: add phase 10 completion summary, test counts
- DECISIONS.md: update active phase range to phase 11+
- DECISIONS-ARCHIVE.md: update header + topic index for phase 10 decisions
…11-1)

- add packages/angular with Angular 21, @analogjs/vite-plugin-angular, @analogjs/vitest-angular
- wire Storybook at port 6009 using @storybook/angular@10.5.0-alpha.9
- add angular ref to composition hub (packages/core/.storybook/main.ts)
- add @big-calendar/angular alias to packages/aliases.ts
- upgrade root Storybook to 10.5.0-alpha.9 (all framework packages) for Angular 21 support
- approve @parcel/watcher, lmdb, msgpackr-extract builds in pnpm-workspace.yaml
… (task 11-2)

- toAngularSignal(): bridge preact ReadonlySignal to Angular Signal via DestroyRef cleanup
- injectCalendarStore(): getter factory; effect() syncs reactive props to CalendarStore
- CalendarProps type mirrors Vue/React adapters
- testing/localizers.ts harness for describe.each coverage
- 25 tests across Temporal and Luxon localizer cases
- vitest.setup.ts: zone.js inline + setupTestBed
…ature parity

Angular adapter: CalendarComponent, MonthViewComponent, TimeGridViewComponent,
AgendaViewComponent, DefaultToolbarComponent, CalendarProvider, CalendarDnd
(directive + service), primitives (BcDialog, BcPopover, BcTooltip, BcEventRoving,
BcRovingSelection), headless inject hooks (injectMonthView, injectTimeGridView,
injectAgendaView, injectCalendarStore), signals bridge (toAngularSignal).

Full canonical story set (Calendar, BackgroundEvents, CustomRendering, EventCallbacks,
EventDragAndDrop, DropFromOutside, EventTypeAccessor, Resources, ResourceTypeAccessor,
Selectable, Localization) with Controls, Actions, and localizer toolbar wired.

Also includes: ADAPTER_STANDARDS.md (cross-framework parity rules), Playwright visual
comparison suite (Angular vs React), MCP angular recipe, Vue test fixes,
storybook-site composition updates.
…rity

- new package: @big-calendar/lit — Lit v3 web components adapter
  - CalendarElement, MonthViewElement, TimeGridViewElement, AgendaViewElement
  - DefaultToolbarElement, BcDialogElement, BcPopoverElement, BcTooltipElement
  - CalendarController (reactive controller, @lit/context provider)
  - CalendarDndController for drag-and-drop support
  - light DOM via createRenderRoot() for shared bc-* CSS
- storybook on port 6010 (@storybook/web-components-vite)
  - 11 canonical stories with Controls + Actions wired
  - 24 MDX documentation files
  - localizer toolbar decorator (bc-globals-sync bridge)
- mcp: added basic-setup-lit recipe (resource count 12→13, recipes 7→8)
- playwright: compare-lit-react.spec.js for visual parity vs React
- root README: added Vue, Angular, Lit to package table + quick-start sections
- fix(vue): create 25 missing index.ts barrel files (vue:build was failing)
- fix(react): create DefaultBackgroundEvent/index.ts (react:build was failing)
- infrastructure: lit registered in storybook-site, compose scripts, core refs
…ring

- Move allDay segments out of bc-allday-slots into sibling bc-allday-segments
  container in the plain layout, matching React/Angular DOM structure
- Fix SelectableWithBackgroundEvents Actions panel by adding fn() directly
  to story args (meta.args propagation insufficient for typed StoryObj)
- Add showAllEvents (bc-show-all-events) class mechanism across core, react,
  lit, and angular adapters
- Fix now-indicator position instability on viewport resize by using
  slot-count * slot-height geometry instead of 100% of time-body height
- Wire --bc-slot-count into Lit and Angular root styles
- Add bc-calendar-dnd, onEventDrop, onEventResize to DropFromOutside story
- Update ADAPTER_STANDARDS with fn() placement rule and DnD persistence rule
…ure parity

Adds the Svelte 5 adapter with signal bridge, context system, composables,
view components, DnD, Storybook stories + MDX docs, 173 unit tests, MCP recipe,
Playwright parity spec, and root README/memory updates.
- nx 22 → 23 (run migrations: releaseTag.pattern, .nx/migrate-runs gitignore)
- pnpm 11.1 → 11.9, vite 8.0 → 8.1, vitest/coverage-v8 4.1.8 → 4.1.9
- eslint 10.4 → 10.6, prettier 3.8 → 3.9, commitlint 21.0 → 21.2
- CI actions: pnpm/action-setup v4→v6, nrwl/nx-set-shas v4→v5,
  upload-pages-artifact v3→v5, deploy-pages v4→v5, codeql v3→v4
- codeql: rename language: → languages: for v4 action schema
- pr-validation: add build target to affected run
- mcp: update resource/recipe counts for Svelte recipe added in Phase 13
The bc-date-cell / bc-today / bc-off-range classes that drive grid cell
borders were previously owned by each DefaultMonthDate component. Any
custom dateCell component had to know to include the outer wrapper or
borders would disappear.

Move the non-replaceable wrapper div into MonthView (React, Vue, Svelte)
and restructure the Angular conditional so the wrapper always frames the
cell whether or not a custom bcMonthDateCell template is supplied. Lit
already hardcoded the wrapper in MonthViewElement and needed no change.

DefaultMonthDate in React, Vue, and Svelte now renders only the inner
bc-date-number button. Update the Svelte and Angular story components to
remove the manual bc-date-cell wrapper they previously had to supply.
@github-advanced-security

Copy link
Copy Markdown

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

@github-advanced-security github-advanced-security AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CodeQL found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

- Replace polynomial regexes in localizer-luxon with indexOf/slice (ReDoS fix)
- Add origin verification to postMessage handler in storybook-shared
- Remove unused imports across playwright and story files
- Wire missing cleanup listener in EventTypeAccessor WeekViewTyped story
- Suppress CodeQL false positives with explanatory comments
Comment thread packages/codemods/src/transforms/flag-removed-props.test.ts Fixed
Comment thread packages/codemods/src/transforms/merge-accessors.test.ts Fixed
Comment thread packages/codemods/src/transforms/rename-callbacks.test.ts Fixed
Comment thread packages/codemods/src/transforms/rename-imports.test.ts Fixed
Comment thread packages/codemods/src/transforms/rename-props.test.ts Fixed
Comment thread packages/codemods/src/transforms/views-prop.test.ts Fixed
Comment thread packages/codemods/src/transforms/wrap-provider.test.ts Fixed
Comment thread packages/lit/src/TimeGridViewElement/TimeGridViewElement.ts Fixed
* adapters) is on the Lit roadmap. For the current release, CSS is the primary
* customization surface and already covers the most common use-cases.
*/
import { html } from 'lit'
Comment thread packages/codemods/src/transforms/flag-removed-props.test.ts Fixed
Comment thread packages/codemods/src/transforms/merge-accessors.test.ts Fixed
Comment thread packages/codemods/src/transforms/rename-callbacks.test.ts Fixed
Comment thread packages/codemods/src/transforms/rename-imports.test.ts Fixed
Comment thread packages/codemods/src/transforms/rename-props.test.ts Fixed
Comment thread packages/codemods/src/transforms/views-prop.test.ts Fixed
Comment thread packages/codemods/src/transforms/wrap-provider.test.ts Fixed
Comment thread packages/codemods/src/transforms/flag-removed-props.test.ts Dismissed
Comment thread packages/codemods/src/transforms/merge-accessors.test.ts Dismissed
Comment thread packages/codemods/src/transforms/rename-callbacks.test.ts Dismissed
Comment thread packages/codemods/src/transforms/rename-imports.test.ts Dismissed
Comment thread packages/codemods/src/transforms/rename-props.test.ts Dismissed
Comment thread packages/codemods/src/transforms/views-prop.test.ts Dismissed
Comment thread packages/codemods/src/transforms/wrap-provider.test.ts Dismissed
Comment thread packages/lit/src/TimeGridViewElement/TimeGridViewElement.ts Dismissed
@bigcalendar bigcalendar merged commit 58eb17e into main Jul 1, 2026
3 checks passed
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.

3 participants