react-smart-scheduler 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 react-smart-scheduler contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,393 @@
1
+ <div align="center">
2
+
3
+ # 📅 react-smart-scheduler
4
+
5
+ **A production-ready, open-source React scheduler / calendar component**
6
+
7
+ Day · Week · Month views · Drag & drop · Resize · TypeScript · Zero UI framework dependency
8
+
9
+ [![npm version](https://img.shields.io/npm/v/react-smart-scheduler?color=blue&logo=npm)](https://www.npmjs.com/package/react-smart-scheduler)
10
+ [![npm downloads](https://img.shields.io/npm/dm/react-smart-scheduler?color=green)](https://www.npmjs.com/package/react-smart-scheduler)
11
+ [![bundle size](https://img.shields.io/bundlephobia/minzip/react-smart-scheduler?color=orange)](https://bundlephobia.com/package/react-smart-scheduler)
12
+ [![license](https://img.shields.io/npm/l/react-smart-scheduler?color=purple)](LICENSE)
13
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.x-blue?logo=typescript)](https://www.typescriptlang.org/)
14
+
15
+ [**Live Demo →**](https://yourname.github.io/react-smart-scheduler) &nbsp;|&nbsp;
16
+ [**GitHub →**](https://github.com/yourname/react-smart-scheduler) &nbsp;|&nbsp;
17
+ [**npm →**](https://www.npmjs.com/package/react-smart-scheduler)
18
+
19
+ </div>
20
+
21
+ ---
22
+
23
+ ## ✨ Features
24
+
25
+ | Feature | Status |
26
+ |---|---|
27
+ | Day / Week / Month views | ✅ |
28
+ | Drag events to move (time + day) | ✅ |
29
+ | Drag bottom edge to resize | ✅ |
30
+ | Click empty slot → create event modal | ✅ |
31
+ | Overlap / concurrent event layout | ✅ |
32
+ | Current time indicator ("now" line) | ✅ |
33
+ | Controlled component API | ✅ |
34
+ | Accessible (ARIA roles, keyboard nav) | ✅ |
35
+ | CSS custom-property theming | ✅ |
36
+ | TypeScript — fully typed | ✅ |
37
+ | Zero heavy UI framework deps | ✅ |
38
+ | Source maps included | ✅ |
39
+
40
+ ---
41
+
42
+ ## 📦 Installation
43
+
44
+ ```bash
45
+ npm install react-smart-scheduler
46
+ # or
47
+ yarn add react-smart-scheduler
48
+ # or
49
+ pnpm add react-smart-scheduler
50
+ ```
51
+
52
+ > **Peer dependencies** — make sure these are already in your project:
53
+ > ```bash
54
+ > npm install react react-dom
55
+ > ```
56
+
57
+ ---
58
+
59
+ ## 🚀 Quick start
60
+
61
+ ```tsx
62
+ // 1. Import the component and CSS
63
+ import { Scheduler, CalendarEvent, generateId } from 'react-smart-scheduler';
64
+ import 'react-smart-scheduler/dist/scheduler.css';
65
+
66
+ // 2. Manage your own events (controlled pattern)
67
+ import { useState } from 'react';
68
+
69
+ export default function App() {
70
+ const [events, setEvents] = useState<CalendarEvent[]>([]);
71
+
72
+ return (
73
+ <div style={{ height: '100vh', display: 'flex', flexDirection: 'column' }}>
74
+ <Scheduler
75
+ events={events}
76
+ view="week"
77
+ onEventAdd={(partial) =>
78
+ setEvents((prev) => [...prev, { ...partial, id: generateId() }])
79
+ }
80
+ onEventChange={(updated) =>
81
+ setEvents((prev) =>
82
+ prev.map((e) => (e.id === updated.id ? updated : e))
83
+ )
84
+ }
85
+ onEventDelete={(id) =>
86
+ setEvents((prev) => prev.filter((e) => e.id !== id))
87
+ }
88
+ />
89
+ </div>
90
+ );
91
+ }
92
+ ```
93
+
94
+ ---
95
+
96
+ ## 📖 API
97
+
98
+ ### `<Scheduler />` Props
99
+
100
+ | Prop | Type | Default | Description |
101
+ |---|---|---|---|
102
+ | `events` | `CalendarEvent[]` | **required** | Controlled list of events |
103
+ | `view` | `'day' \| 'week' \| 'month'` | `'week'` | Active view |
104
+ | `date` | `Date` | `new Date()` | Anchor date for the current view |
105
+ | `onEventAdd` | `(e: Omit<CalendarEvent, 'id'>) => void` | — | Fired when user creates an event |
106
+ | `onEventChange` | `(e: CalendarEvent) => void` | — | Fired after drag-move or resize |
107
+ | `onEventDelete` | `(id: string) => void` | — | Fired when user deletes an event |
108
+ | `onViewChange` | `(v: ViewType) => void` | — | Fired when the view changes |
109
+ | `onDateChange` | `(d: Date) => void` | — | Fired when the user navigates |
110
+ | `hourHeight` | `number` | `64` | Pixel height of each hour row |
111
+ | `startHour` | `number` | `0` | First visible hour (0–23) |
112
+ | `endHour` | `number` | `24` | Last visible hour (1–24) |
113
+ | `className` | `string` | `''` | Extra CSS class on the root element |
114
+
115
+ ### `CalendarEvent` type
116
+
117
+ ```ts
118
+ interface CalendarEvent {
119
+ id: string;
120
+ title: string;
121
+ start: Date;
122
+ end: Date;
123
+ color?: string; // any valid CSS colour, e.g. '#3b82f6' or 'royalblue'
124
+ }
125
+ ```
126
+
127
+ To attach custom metadata, **extend** the interface:
128
+
129
+ ```ts
130
+ interface MyEvent extends CalendarEvent {
131
+ roomId: string;
132
+ attendees: string[];
133
+ }
134
+ ```
135
+
136
+ ### Exported utilities
137
+
138
+ ```ts
139
+ import {
140
+ Scheduler, // the main component
141
+ generateId, // generate a unique event id
142
+ pickColor, // pick a colour from the palette deterministically
143
+ EVENT_COLORS, // the default colour palette (string[])
144
+ VERSION, // current library version string
145
+ } from 'react-smart-scheduler';
146
+
147
+ import type {
148
+ CalendarEvent, // event shape
149
+ SchedulerProps, // props interface
150
+ ViewType, // 'day' | 'week' | 'month'
151
+ } from 'react-smart-scheduler';
152
+ ```
153
+
154
+ ---
155
+
156
+ ## 🎨 Theming
157
+
158
+ Override CSS custom properties on `.rss-root` to customise appearance without touching source:
159
+
160
+ ```css
161
+ .rss-root {
162
+ --rss-primary: #6366f1; /* accent colour */
163
+ --rss-primary-light: #eef2ff;
164
+ --rss-border: #d1d5db; /* grid lines */
165
+ --rss-bg: #ffffff; /* surface */
166
+ --rss-bg-alt: #f9fafb; /* alternate bg */
167
+ --rss-today-bg: #eef2ff; /* today column tint */
168
+ --rss-text: #111827;
169
+ --rss-text-muted: #9ca3af;
170
+ --rss-time-gutter-w: 52px;
171
+ --rss-radius: 6px;
172
+ }
173
+ ```
174
+
175
+ ---
176
+
177
+ ## 💡 Usage patterns
178
+
179
+ ### Controlled view + date (recommended)
180
+
181
+ ```tsx
182
+ const [view, setView] = useState<ViewType>('week');
183
+ const [date, setDate] = useState(new Date());
184
+
185
+ <Scheduler
186
+ view={view}
187
+ date={date}
188
+ onViewChange={setView}
189
+ onDateChange={setDate}
190
+ events={events}
191
+ onEventAdd={...}
192
+ onEventChange={...}
193
+ onEventDelete={...}
194
+ />
195
+ ```
196
+
197
+ ### Semi-controlled (internal navigation state)
198
+
199
+ ```tsx
200
+ // Omit view/date/onViewChange/onDateChange — scheduler manages them internally
201
+ <Scheduler
202
+ events={events}
203
+ onEventAdd={handleAdd}
204
+ onEventChange={handleChange}
205
+ onEventDelete={handleDelete}
206
+ />
207
+ ```
208
+
209
+ ### Custom business hours
210
+
211
+ ```tsx
212
+ <Scheduler
213
+ events={events}
214
+ startHour={7}
215
+ endHour={20}
216
+ hourHeight={80}
217
+ ...
218
+ />
219
+ ```
220
+
221
+ ### With Zustand
222
+
223
+ ```ts
224
+ // store.ts
225
+ import { create } from 'zustand';
226
+ import { CalendarEvent, generateId } from 'react-smart-scheduler';
227
+
228
+ const useCalendarStore = create<{
229
+ events: CalendarEvent[];
230
+ add: (p: Omit<CalendarEvent, 'id'>) => void;
231
+ update: (e: CalendarEvent) => void;
232
+ remove: (id: string) => void;
233
+ }>((set) => ({
234
+ events: [],
235
+ add: (p) => set((s) => ({ events: [...s.events, { ...p, id: generateId() }] })),
236
+ update: (e) => set((s) => ({ events: s.events.map((x) => x.id === e.id ? e : x) })),
237
+ remove: (id) => set((s) => ({ events: s.events.filter((x) => x.id !== id) })),
238
+ }));
239
+ ```
240
+
241
+ ---
242
+
243
+ ## 🛠 Development
244
+
245
+ ```bash
246
+ # Clone
247
+ git clone https://github.com/yourname/react-smart-scheduler.git
248
+ cd react-smart-scheduler/packages/react-smart-scheduler
249
+
250
+ # Install
251
+ npm install
252
+
253
+ # Start demo playground (hot-reload at http://localhost:5173)
254
+ npm run dev
255
+
256
+ # Build library → /dist (runs tsc + vite)
257
+ npm run build
258
+
259
+ # Type-check only
260
+ npm run type-check
261
+
262
+ # Preview built demo
263
+ npm run preview
264
+ ```
265
+
266
+ ### Publishing to npm
267
+
268
+ ```bash
269
+ # Log in (first time)
270
+ npm login
271
+
272
+ # Publish (prepublishOnly runs type-check + build automatically)
273
+ npm publish
274
+ ```
275
+
276
+ The `prepublishOnly` hook ensures the published package is always a fresh, type-safe build.
277
+
278
+ ---
279
+
280
+ ## 📸 Demo
281
+
282
+ **[👉 Open live demo](https://yourname.github.io/react-smart-scheduler)**
283
+
284
+ Features you can try:
285
+
286
+ - Switch between **Day**, **Week**, and **Month** views
287
+ - **Click** any empty time slot to open the Create Event modal
288
+ - **Drag** an event to move it (changes time and, in week view, the day)
289
+ - **Drag the bottom edge** of an event to resize its duration
290
+ - **Click** an event chip to edit its title, time, color, or delete it
291
+ - **+ Add random event** button to quickly populate the calendar
292
+
293
+ ---
294
+
295
+ ## 🏗 Architecture
296
+
297
+ ```
298
+ src/
299
+ ├── index.ts — public API entry point
300
+ ├── types.ts — all TypeScript interfaces
301
+ ├── Scheduler.tsx — root + single DndContext + drag math
302
+ ├── scheduler.css — all library styles
303
+
304
+ ├── views/
305
+ │ ├── DayView.tsx — 1-column TimeGrid wrapper
306
+ │ ├── WeekView.tsx — 7-column TimeGrid wrapper
307
+ │ └── MonthView.tsx — 6×7 month grid + draggable pills
308
+
309
+ ├── components/
310
+ │ ├── Header.tsx — navigation + view switcher
311
+ │ ├── TimeGrid.tsx — shared hour-grid backbone
312
+ │ ├── EventItem.tsx — chip: dnd-kit drag + Pointer Capture resize
313
+ │ └── EventModal.tsx — add / edit / delete modal
314
+
315
+ ├── hooks/
316
+ │ └── useScheduler.ts — UI-only state (modal, pending slot)
317
+
318
+ └── utils/
319
+ ├── dateUtils.ts — date-fns wrappers, grid math, navigation
320
+ └── eventUtils.ts — overlap detection, column layout, colours
321
+ ```
322
+
323
+ **Key decisions:**
324
+
325
+ | Decision | Why |
326
+ |---|---|
327
+ | Single `DndContext` at root | Centralised drag-end math; avoids nested context issues |
328
+ | Delta-based drag (not per-cell droppables) | Sub-cell time precision, minimal DOM nodes |
329
+ | Pointer Capture API for resize | Tracks cursor anywhere on screen without document listeners |
330
+ | Controlled component | Consumer owns state — works with any store |
331
+ | CSS custom properties | Zero-runtime theming, no CSS-in-JS required |
332
+
333
+ ---
334
+
335
+ ## 🗺 Roadmap
336
+
337
+ ### v0.2 — Core polish
338
+ - [ ] All-day events row
339
+ - [ ] Multi-day spanning events in week view
340
+ - [ ] Keyboard shortcut to delete selected event
341
+ - [ ] Mini-month navigation widget
342
+
343
+ ### v0.3 — Power features
344
+ - [ ] Drag-to-create (click-drag on empty slot)
345
+ - [ ] Recurring events (RRULE / iCal)
346
+ - [ ] Timezone-aware rendering
347
+ - [ ] External `.ics` import / export
348
+
349
+ ### Future Pro features (opt-in add-ons, core stays free)
350
+ - [ ] Resource / room view (multi-column by resource)
351
+ - [ ] Gantt-style timeline
352
+ - [ ] Custom event render slot (render prop)
353
+ - [ ] Virtual scroll for large event volumes
354
+ - [ ] Backend sync hooks (optimistic updates)
355
+
356
+ ---
357
+
358
+ ## 🤝 Contributing
359
+
360
+ All contributions are welcome — bug fixes, features, docs, tests.
361
+
362
+ 1. Fork & clone the repo
363
+ 2. `npm install` in `packages/react-smart-scheduler`
364
+ 3. Make your changes (`npm run dev` for hot-reload)
365
+ 4. `npm run type-check && npm run build` must pass
366
+ 5. Open a pull request with a clear description of *why*, not just *what*
367
+
368
+ ---
369
+
370
+ ## ❤️ Donate / Support
371
+
372
+ react-smart-scheduler is **free and open-source (MIT)**. Maintaining it takes real effort. If it saves you time, please consider:
373
+
374
+ | | |
375
+ |---|---|
376
+ | ☕ **[Buy Me a Coffee](https://buymeacoffee.com/sathish.hazhtech)** | One-time tip — any amount helps |
377
+ | 🩷 **[GitHub Sponsors](https://github.com/sponsors/satthish)** | Monthly support with perks |
378
+
379
+ Every ⭐ star and share also helps the project grow. Thank you 🙏
380
+
381
+ ---
382
+
383
+ ## 📄 License
384
+
385
+ [MIT](LICENSE) © react-smart-scheduler contributors
386
+
387
+ ---
388
+
389
+ <div align="center">
390
+
391
+ Built with ❤️ and TypeScript &nbsp;·&nbsp; If this saves you time, consider [starring ⭐ the repo](https://github.com/yourname/react-smart-scheduler)
392
+
393
+ </div>
@@ -0,0 +1,87 @@
1
+ import { default as default_2 } from 'react';
2
+
3
+ /**
4
+ * The shape of a single calendar event.
5
+ *
6
+ * To attach custom metadata, extend this interface:
7
+ * interface MyEvent extends CalendarEvent { roomId: string; }
8
+ */
9
+ export declare interface CalendarEvent {
10
+ id: string;
11
+ title: string;
12
+ start: Date;
13
+ end: Date;
14
+ /** Optional hex/named color for the event chip */
15
+ color?: string;
16
+ }
17
+
18
+ /** A small palette of default event colours. */
19
+ export declare const EVENT_COLORS: readonly string[];
20
+
21
+ /** Generate a stable unique id for a new event. */
22
+ export declare function generateId(): string;
23
+
24
+ /** Pick a colour from the palette, cycling based on a hash of the id. */
25
+ export declare function pickColor(id: string): string;
26
+
27
+ /**
28
+ * <Scheduler /> — the root component.
29
+ *
30
+ * Architecture decisions:
31
+ *
32
+ * 1. Fully controlled: events, view, and date are all owned by the parent.
33
+ * The Scheduler only owns transient UI state (drag preview, modal open).
34
+ *
35
+ * 2. Single DndContext: wraps all views so dnd-kit's sensors work across
36
+ * view transitions without needing multiple contexts.
37
+ *
38
+ * 3. Drag math uses delta (pixels moved from drag start) rather than
39
+ * absolute drop coordinates. This avoids needing per-cell droppables
40
+ * and gives sub-cell precision. Column width is measured via
41
+ * ResizeObserver and stored in a mutable ref (not state) to avoid
42
+ * re-renders on window resize.
43
+ *
44
+ * 4. Resize is handled entirely in EventItem via Pointer Capture API,
45
+ * completely independent of dnd-kit. EventItem calls onEventResizeEnd
46
+ * after commit; Scheduler forwards to onEventChange.
47
+ */
48
+ export declare const Scheduler: default_2.FC<SchedulerProps>;
49
+
50
+ /** Props accepted by the top-level <Scheduler /> component. */
51
+ export declare interface SchedulerProps {
52
+ /** Controlled list of events to display */
53
+ events: CalendarEvent[];
54
+ /** Which view to render (default: 'week') */
55
+ view?: ViewType;
56
+ /** The "anchor" date for the current view (default: today) */
57
+ date?: Date;
58
+ /**
59
+ * Called when the user clicks an empty time slot.
60
+ * The consumer is responsible for generating an id and adding
61
+ * the event to their own state.
62
+ */
63
+ onEventAdd?: (event: Omit<CalendarEvent, 'id'>) => void;
64
+ /** Called after a drag-move or resize completes. */
65
+ onEventChange?: (event: CalendarEvent) => void;
66
+ /** Called when the user deletes an event via the event modal. */
67
+ onEventDelete?: (id: string) => void;
68
+ /** Called when the user switches views via the header. */
69
+ onViewChange?: (view: ViewType) => void;
70
+ /** Called when the user navigates forward/back or clicks "Today". */
71
+ onDateChange?: (date: Date) => void;
72
+ /** Height of each hour row in pixels (default: 64). */
73
+ hourHeight?: number;
74
+ /** First hour shown in the time grid (default: 0). */
75
+ startHour?: number;
76
+ /** Last hour shown in the time grid (default: 24). */
77
+ endHour?: number;
78
+ /** Extra CSS class applied to the root element. */
79
+ className?: string;
80
+ }
81
+
82
+ /** Library version — matches package.json version field. */
83
+ export declare const VERSION: "0.1.0";
84
+
85
+ export declare type ViewType = 'day' | 'week' | 'month';
86
+
87
+ export { }