{"_id":"@ascentsparksoftware/react-calendar","_rev":"2-8996417639ad1affc0742dadcff52775","name":"@ascentsparksoftware/react-calendar","dist-tags":{"latest":"1.0.1"},"versions":{"1.0.0":{"name":"@ascentsparksoftware/react-calendar","version":"1.0.0","keywords":["react","react-19","calendar","scheduler","timeline","resource-scheduler","recurrence","rrule","timezone","nextjs","ssr","oklch","theme-agnostic","drag-and-drop","accessibility"],"author":{"name":"Ascentspark Software Private Limited"},"license":"MIT","_id":"@ascentsparksoftware/react-calendar@1.0.0","maintainers":[{"name":"coderkane","email":"partha@ascentspark.com"}],"homepage":"https://github.com/ascentspark/react-calendar#readme","bugs":{"url":"https://github.com/ascentspark/react-calendar/issues"},"dist":{"shasum":"d1b439fb6d7ce47e42f72257bdbfbb2c25f2654b","tarball":"https://registry.npmjs.org/@ascentsparksoftware/react-calendar/-/react-calendar-1.0.0.tgz","fileCount":20,"integrity":"sha512-h4eqRJ4WSonEFfXNebhmPmnNBiEoN2hHs5f8fDf5hnUvuhp7RJAR+yNHiKqoL454pHAdHCVFAzxjlEL4t9SDxA==","signatures":[{"sig":"MEUCIQD/RKrySUifvSkrbqPQ8X5/xW9fMhsq3mG6ssnui2zL5gIgGWu5nGAqX664MLijZARInqS8Fo595cDyy+EWDnyjUIE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ascentsparksoftware%2freact-calendar@1.0.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":753834},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./export":{"types":"./dist/export.d.ts","import":"./dist/export.js"},"./date-fns":{"types":"./dist/date-fns.d.ts","import":"./dist/date-fns.js"},"./recurrence":{"types":"./dist/recurrence.d.ts","import":"./dist/recurrence.js"},"./styles.css":"./dist/styles.css","./package.json":"./package.json"},"gitHead":"c435ae95692d5d7dd169a27ac2fadd0f76a18f5e","scripts":{"test":"vitest run","build":"tsup","typecheck":"tsc --noEmit"},"_npmUser":{"name":"coderkane","email":"partha@ascentspark.com"},"repository":{"url":"git+https://github.com/ascentspark/react-calendar.git","type":"git"},"_npmVersion":"11.16.0","description":"Modern, theme-agnostic calendar & scheduler for React — month/week/day, resource timeline, agenda and year views, timezone-correct, with RRULE recurrence, OKLCH theming and a touch-first interaction layer. SSR/Next.js-safe.","directories":{},"sideEffects":["*.css"],"_nodeVersion":"24.18.0","dependencies":{"rrule":"^2.8.1","date-fns":"^4.1.0","date-fns-tz":"^3.2.0"},"publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","jsdom":"^26.1.0","react":"^19.2.0","vitest":"^4.0.8","react-dom":"^19.2.0","fast-check":"^4.9.0","@types/react":"^19.2.0","@types/react-dom":"^19.2.0","@testing-library/dom":"^10.4.1","@testing-library/react":"^16.3.0"},"peerDependencies":{"react":"^19.0.0","react-dom":"^19.0.0"},"_npmOperationalInternal":{"tmp":"tmp/react-calendar_1.0.0_1783641718596_0.9162473414362278","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@ascentsparksoftware/react-calendar","version":"1.0.1","description":"Modern, theme-agnostic calendar & scheduler for React — month/week/day, resource timeline, agenda and year views, timezone-correct, with RRULE recurrence, OKLCH theming and a touch-first interaction layer. SSR/Next.js-safe.","keywords":["react","react-19","calendar","scheduler","timeline","resource-scheduler","recurrence","rrule","timezone","nextjs","ssr","oklch","theme-agnostic","drag-and-drop","accessibility"],"license":"MIT","author":{"name":"Ascentspark Software Private Limited"},"homepage":"https://github.com/ascentspark/react-calendar#readme","repository":{"type":"git","url":"git+https://github.com/ascentspark/react-calendar.git"},"bugs":{"url":"https://github.com/ascentspark/react-calendar/issues"},"type":"module","main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./date-fns":{"types":"./dist/date-fns.d.ts","import":"./dist/date-fns.js"},"./recurrence":{"types":"./dist/recurrence.d.ts","import":"./dist/recurrence.js"},"./export":{"types":"./dist/export.d.ts","import":"./dist/export.js"},"./styles.css":"./dist/styles.css","./package.json":"./package.json"},"sideEffects":["*.css"],"scripts":{"build":"tsup","test":"vitest run","typecheck":"tsc --noEmit"},"peerDependencies":{"react":"^19.0.0","react-dom":"^19.0.0"},"dependencies":{"date-fns":"^4.1.0","date-fns-tz":"^3.2.0","rrule":"^2.8.1"},"devDependencies":{"@testing-library/dom":"^10.4.1","@testing-library/react":"^16.3.0","@types/react":"^19.2.0","@types/react-dom":"^19.2.0","fast-check":"^4.9.0","jsdom":"^26.1.0","react":"^19.2.0","react-dom":"^19.2.0","tsup":"^8.5.0","vitest":"^4.0.8"},"publishConfig":{"access":"public","provenance":true},"gitHead":"39041349e5ab0ac54202ffd17193b6860696a8b1","_id":"@ascentsparksoftware/react-calendar@1.0.1","_nodeVersion":"24.18.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-hHT8wvy3NEy06nq2otG4VMsMw4Jvm/17tvMpIMPMF8xB7zDQtJr2BjU7suD8Nz2opi+NSh7FBKaS/risknosyg==","shasum":"e46225becbdba128a1e1967052d9933ca9701573","tarball":"https://registry.npmjs.org/@ascentsparksoftware/react-calendar/-/react-calendar-1.0.1.tgz","fileCount":20,"unpackedSize":753826,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ascentsparksoftware%2freact-calendar@1.0.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIDjcP36r7wujmDaeMAe8S0juvKVBWGw3GJ1fBlryZmO4AiB+geHaI9vIiCVrnGk0Wq7U3yUO5FSleICMzzGMCH4yeQ=="}]},"_npmUser":{"name":"coderkane","email":"partha@ascentspark.com"},"directories":{},"maintainers":[{"name":"coderkane","email":"partha@ascentspark.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/react-calendar_1.0.1_1783642263901_0.06981647718956085"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-10T00:01:58.214Z","modified":"2026-07-10T00:11:04.497Z","1.0.0":"2026-07-10T00:01:58.761Z","1.0.1":"2026-07-10T00:11:04.098Z"},"bugs":{"url":"https://github.com/ascentspark/react-calendar/issues"},"author":{"name":"Ascentspark Software Private Limited"},"license":"MIT","homepage":"https://github.com/ascentspark/react-calendar#readme","keywords":["react","react-19","calendar","scheduler","timeline","resource-scheduler","recurrence","rrule","timezone","nextjs","ssr","oklch","theme-agnostic","drag-and-drop","accessibility"],"repository":{"type":"git","url":"git+https://github.com/ascentspark/react-calendar.git"},"description":"Modern, theme-agnostic calendar & scheduler for React — month/week/day, resource timeline, agenda and year views, timezone-correct, with RRULE recurrence, OKLCH theming and a touch-first interaction layer. SSR/Next.js-safe.","maintainers":[{"name":"coderkane","email":"partha@ascentspark.com"}],"readme":"<div align=\"center\">\n\n# @ascentsparksoftware/react-calendar\n\nA modern, theme-agnostic **calendar & scheduler** for React — month, week, day, year,\nagenda and a resource **timeline** — headless-first, SSR/Next.js-safe, timezone-correct,\nwith RFC 5545 recurrence and a touch-first drag/resize engine.\n\nby&nbsp;<a href=\"https://ascentspark.com\" target=\"_blank\" rel=\"noopener\"><img src=\"https://cdn.ascentspark.com/assets/images/asc-logo-full.svg\" alt=\"Ascentspark\" height=\"22\" valign=\"middle\"></a>\n\n[![npm version](https://img.shields.io/npm/v/@ascentsparksoftware/react-calendar.svg?color=087ea4)](https://www.npmjs.com/package/@ascentsparksoftware/react-calendar)\n[![downloads](https://img.shields.io/npm/dm/@ascentsparksoftware/react-calendar.svg)](https://www.npmjs.com/package/@ascentsparksoftware/react-calendar)\n[![React 19](https://img.shields.io/badge/React-19-087ea4.svg)](https://react.dev)\n[![license MIT](https://img.shields.io/github/license/ascentspark/react-calendar?color=3b82f6)](https://github.com/ascentspark/react-calendar/blob/main/LICENSE)\n\n**[✨ Features](#features)** &nbsp;·&nbsp;\n**[🚀 Quick start](#quick-start)** &nbsp;·&nbsp;\n**[🎨 Theming](#theming)** &nbsp;·&nbsp;\n**[🧩 API](#api)** &nbsp;·&nbsp;\n**[♿ Accessibility](#accessibility)** &nbsp;·&nbsp;\n**[🔢 Versions](#versions)**\n\n</div>\n\n---\n\nA complete scheduling toolkit you drop into a React app as plain components. Render your own\nevents through the built-in views — `month`, `week`/`work-week`/`day`, `year`, `agenda`, and a\nresource **timeline** (dispatch board) — pass your data as props, and read interactions back as\ntyped callbacks. Feature-for-feature parity with\n[`@ascentsparksoftware/angular-calendar`](https://github.com/ascentspark/angular-calendar):\nboth packages share the same headless core.\n\nEverything is **headless-first**: all date math, recurrence expansion, overlap-lane layout and\nview-model construction are pure functions with no DOM, unit-tested in isolation, and exported\nfor advanced use. The presentational components render those view models and never compute them\ninline. It is **timezone-correct from day one** (an explicit IANA zone travels through the whole\nmodel — it never leans on the host's local `Date`), renders caller content as **plain text only**\n(never `dangerouslySetInnerHTML`; Trusted-Types / strict-CSP clean), and derives its entire\npalette from a few color inputs so it drops onto any brand in light or dark with **WCAG 2.2 AA**\ncontrast guaranteed.\n\n## Features\n\n- **Seven views** — `month`, `week`, `work-week`, `day` (a shared time-grid), `year`, `agenda`,\n  and a hierarchical resource **`timeline`** with a configurable time axis, collapsible resource\n  groups, working-hours / block-out shading, horizontal or vertical orientation, and row\n  virtualization for long resource lists.\n- **Plain function components + hooks.** StrictMode-clean, React-Compiler-safe, no wrapper\n  around your state — props in, callbacks out.\n- **SSR / Next.js-safe** — `\"use client\"` entries, no `window`/`document` at module scope, all\n  DOM work inside effects. Drop it behind `next/dynamic` or render it directly in a client\n  component.\n- **Timezone-correct** — a pluggable date adapter carries an explicit IANA zone through the whole\n  model. Default adapter is `date-fns` + `date-fns-tz`; a Temporal adapter is a drop-in later.\n- **RFC 5545 recurrence** — RRULE series expansion behind an adapter (default `rrule`), exceptions,\n  and **edit this / this-and-following / all** semantics, plus a standalone recurrence editor.\n- **Touch-first interactions** — a custom pointer-events layer for drag / create / resize with\n  snap, long-press, and sub-pixel projection; fully keyboard-operable move/resize. External\n  **drag-in** (native HTML drag-and-drop, no extra deps) drops jobs from an outside list onto a\n  timeline lane. A `validateChange` hook vetoes or adjusts any proposed change.\n- **Theme-agnostic** — `baseColor` + `accentColor` + `themeMode` + a `statusColors` map derive the\n  whole palette as scoped `--cal-*` CSS variables (OKLCH pipeline), with guaranteed AA contrast.\n  Any single token is host-overridable, and a **token bridge** defers chosen tokens to your design\n  system's own CSS variables.\n- **Bring your own markup** — render props override the event chip, day cell, \"+N more\"\n  overflow, resource header and the event-detail dialog body, so you keep full control of\n  rendering.\n- **Accessible** — correct ARIA `grid` / roving-tabindex patterns, focus trap + opener restore in\n  the dialog, visible `:focus-visible` rings, `prefers-reduced-motion`, localisable screen-reader\n  strings.\n- **Export** — iCalendar (`.ics`), CSV (RFC 4180), Excel (SpreadsheetML) and printable HTML, all as\n  pure serializers in a tree-shakable secondary entry point.\n- **Tree-shakable** — heavy features (`/date-fns`, `/recurrence`, `/export`) are secondary entry\n  points; you only pay for what you import. `sideEffects` limited to CSS, no `any`, strict\n  TypeScript.\n\n## Install\n\n```bash\nnpm install @ascentsparksoftware/react-calendar\n```\n\nPeer dependencies: `react` and `react-dom` `^19`.\n\n## Quick start\n\n```tsx\nimport { CalendarProvider, CalMonthView, CalTimeGridView } from '@ascentsparksoftware/react-calendar';\nimport { DateFnsDateAdapter } from '@ascentsparksoftware/react-calendar/date-fns';\nimport '@ascentsparksoftware/react-calendar/styles.css';\n\nconst adapter = new DateFnsDateAdapter(); // keep the instance stable (module scope or useMemo)\n\nexport function Schedule({ events, date, view }) {\n  return (\n    <CalendarProvider dateAdapter={adapter} defaults={{ weekStartsOn: 1 }}>\n      {view === 'month' ? (\n        <CalMonthView\n          events={events}\n          viewDate={date}\n          eventClicked={({ event }) => console.log(event.id)}\n        />\n      ) : (\n        <CalTimeGridView\n          events={events}\n          viewDate={date}\n          days={view === 'day' ? 1 : 7}\n          anchorToWeek={view === 'day' ? false : null}\n          editable\n          eventChanged={({ change }) => save(change)}\n        />\n      )}\n    </CalendarProvider>\n  );\n}\n```\n\nEvents are plain objects — `{ id, title, start, end, allDay?, status?, resourceId?,\nrecurrenceRule?, meta? }` — where `start`/`end` are `Date`s or `{ epochMs, zone }` pairs.\nThe calendar never mutates them.\n\n### Recurrence\n\n```tsx\nimport { RruleRecurrenceAdapter } from '@ascentsparksoftware/react-calendar/recurrence';\n\n<CalendarProvider dateAdapter={adapter} recurrenceAdapter={new RruleRecurrenceAdapter()}>\n```\n\nAny event carrying a `recurrenceRule` (RRULE string) expands into concrete occurrences in\nevery view, windowed to the visible period.\n\n### Next.js\n\nThe package ships `\"use client\"` entries. In an App Router page, either render the views from\nany client component, or load them lazily:\n\n```tsx\nconst CalTimelineView = dynamic(\n  () => import('@ascentsparksoftware/react-calendar').then((m) => m.CalTimelineView),\n  { ssr: false },\n);\n```\n\n## Theming\n\nHigh-level inputs derive the full palette (OKLCH, AA-guaranteed) as `--cal-*` custom\nproperties scoped to the component host:\n\n```tsx\n<CalMonthView\n  events={events}\n  viewDate={date}\n  baseColor=\"#101418\"\n  accentColor=\"#22c55e\"\n  themeMode=\"dark\"\n  statusColors={{ confirmed: '#22c55e', pending: '#eab308', cancelled: '#ef4444' }}\n/>\n```\n\nEach `statusColors` key yields `--cal-event-<key>` / `-ink` / `-soft` triplets used by event\nchips (`status: 'confirmed'` on the event picks them up). For the long tail, override any\nsingle token with CSS on the host, or **bridge tokens to your design system** so the calendar\nfollows your app's theme switching:\n\n```tsx\n<CalendarProvider\n  dateAdapter={adapter}\n  tokenBridge={{ '--cal-accent': '--brand-500', '--cal-bg': '--surface', '--cal-ink': '--text' }}\n>\n```\n\nBridged tokens win over the derived theme; unbridged tokens keep their derived values. The\ntheming machinery (`deriveTheme`, `applyTheme`, token names) is exported for standalone use.\n\n## API\n\n### Components\n\n| Component | Purpose |\n|---|---|\n| `CalMonthView` | Month grid, multi-day spanning chips, \"+N more\" overflow popover |\n| `CalTimeGridView` | Week/work-week/day time grid (`days` 1–7, `anchorToWeek`, `orientation`), all-day band, drag/resize/create |\n| `CalTimelineView` | Resource timeline (rows or columns via `orientation`), grouping, virtualization, drag across resources |\n| `CalAgendaView` | Chronological list, `hideEmptyDays` |\n| `CalYearView` | 12-month overview with event densities |\n| `CalEventDialog` | Accessible event-detail dialog (focus trap, opener restore, `renderEventDetail`) |\n| `CalRecurrenceEditor` | RRULE editor (`RecurrenceParts` in/out) |\n| `CalTimezonePicker` | IANA zone select |\n\n### Common props (all views)\n\n`events`, `viewDate`, `today`, `timezone`, `locale`, `calendarSystem`, `weekStartsOn`,\ntheming (`baseColor`, `accentColor`, `themeMode`, `statusColors`, `accentInk`), and the\ncallbacks `eventClicked`, `viewPeriodChanged`. Time-based views add `hour12`, `slotMinutes`,\n`dayStartMinutes`/`dayEndMinutes`, `snapMinutes`, `editable`, `validateChange`,\n`eventChanged`, `slotSelected`, `externalDrop`. Render props: `renderEvent`, `renderCell`,\n`renderOverflow`, `renderResourceHeader`, `renderEventDetail`.\n\n### Provider\n\n```tsx\n<CalendarProvider\n  defaults={{ locale: 'en-GB', weekStartsOn: 1, slotMinutes: 15, hour12: false }}\n  dateAdapter={adapter}\n  recurrenceAdapter={rrule}\n  tokenBridge={bridge}\n  virtualization={{ rowThreshold: 60 }}\n  intl={myIntl}      // visible strings\n  a11y={myA11y}      // screen-reader strings\n>\n```\n\n### Headless core\n\nThe pure machinery is exported for custom views: `buildMonthView`, `buildTimeGridView`,\n`buildTimelineView`, `buildAgendaView`, `buildYearView`, `expandRecurringEvents`,\n`packColumns`, `packRows`, `computeDragTimes`, `detectConflicts`, projection and\nvirtual-window helpers, plus the full theming API.\n\n## Accessibility\n\nARIA `grid`/`listbox` patterns with roving tabindex, every interaction keyboard-operable\n(arrow keys move/resize a grabbed event, Enter commits, Escape cancels — with live-region\nannouncements), focus trap + opener focus restore in the dialog, `prefers-reduced-motion`\nhonoured, and AA contrast guaranteed by the theme pipeline in both modes. Screen-reader and\nvisible strings are both replaceable wholesale for localisation.\n\n## Versions\n\n| Package line | React | Status |\n|---|---|---|\n| 1.x | ^19.0.0 | Active |\n\nThe package major is decoupled from the React major; the peer range is what matters.\nAngular consumer? Use\n[`@ascentsparksoftware/angular-calendar`](https://www.npmjs.com/package/@ascentsparksoftware/angular-calendar)\n— same core, same tokens, same behavior.\n\n## Security\n\n- Caller content is rendered as **text nodes only** — never `dangerouslySetInnerHTML`, no HTML\n  parsing of your data.\n- Print/export builds documents via `DOMParser` (Trusted-Types-safe), not string-injected HTML.\n- No `eval`, no `Function`, no dynamic script.\n- See [`SECURITY.md`](./SECURITY.md) for reporting.\n\n## License\n\n[MIT](./LICENSE) © Ascentspark Software Private Limited\n","readmeFilename":"README.md"}