react-big-schedule 8.1.0 → 9.0.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.
Files changed (109) hide show
  1. package/README.md +20 -1129
  2. package/dist/calendar/Calendar.d.ts +28 -0
  3. package/dist/calendar/Calendar.js +95 -0
  4. package/dist/calendar/Toolbar.d.ts +18 -0
  5. package/dist/calendar/Toolbar.js +6 -0
  6. package/dist/calendar/recurrence.check.d.ts +1 -0
  7. package/dist/calendar/recurrence.check.js +49 -0
  8. package/dist/calendar/recurrence.d.ts +8 -0
  9. package/dist/calendar/recurrence.js +90 -0
  10. package/dist/calendar/timezone.d.ts +6 -0
  11. package/dist/calendar/timezone.js +14 -0
  12. package/dist/calendar/types.d.ts +187 -0
  13. package/dist/calendar/types.js +1 -0
  14. package/dist/calendar/useEventSources.d.ts +11 -0
  15. package/dist/calendar/useEventSources.js +89 -0
  16. package/dist/calendar/useRecurrence.d.ts +4 -0
  17. package/dist/calendar/useRecurrence.js +15 -0
  18. package/dist/calendar/utils.d.ts +38 -0
  19. package/dist/calendar/utils.js +143 -0
  20. package/dist/calendar/views/DayGridView.d.ts +3 -0
  21. package/dist/calendar/views/DayGridView.js +375 -0
  22. package/dist/calendar/views/ListView.d.ts +4 -0
  23. package/dist/calendar/views/ListView.js +56 -0
  24. package/dist/calendar/views/MultiMonthView.d.ts +4 -0
  25. package/dist/calendar/views/MultiMonthView.js +36 -0
  26. package/dist/calendar/views/TimeGridView.d.ts +3 -0
  27. package/dist/calendar/views/TimeGridView.js +334 -0
  28. package/dist/calendar/views/daygrid/DayCell.d.ts +19 -0
  29. package/dist/calendar/views/daygrid/DayCell.js +17 -0
  30. package/dist/calendar/views/daygrid/EventChip.d.ts +19 -0
  31. package/dist/calendar/views/daygrid/EventChip.js +40 -0
  32. package/dist/calendar/views/daygrid/layout.d.ts +30 -0
  33. package/dist/calendar/views/daygrid/layout.js +63 -0
  34. package/dist/calendar/views/list/bucket.d.ts +8 -0
  35. package/dist/calendar/views/list/bucket.js +37 -0
  36. package/dist/calendar/views/multimonth/Cell.d.ts +12 -0
  37. package/dist/calendar/views/multimonth/Cell.js +44 -0
  38. package/dist/calendar/views/multimonth/Continuous.d.ts +8 -0
  39. package/dist/calendar/views/multimonth/Continuous.js +28 -0
  40. package/dist/calendar/views/multimonth/MonthGrid.d.ts +10 -0
  41. package/dist/calendar/views/multimonth/MonthGrid.js +36 -0
  42. package/dist/calendar/views/multimonth/shared.d.ts +27 -0
  43. package/dist/calendar/views/multimonth/shared.js +40 -0
  44. package/dist/calendar/views/timegrid/DayColumn.d.ts +49 -0
  45. package/dist/calendar/views/timegrid/DayColumn.js +86 -0
  46. package/dist/calendar/views/timegrid/model.d.ts +55 -0
  47. package/dist/calendar/views/timegrid/model.js +102 -0
  48. package/dist/components/AddMore.d.ts +13 -0
  49. package/dist/components/AddMore.js +9 -42
  50. package/dist/components/AddMorePopover.d.ts +13 -0
  51. package/dist/components/AddMorePopover.js +24 -95
  52. package/dist/components/AgendaEventItem.d.ts +10 -0
  53. package/dist/components/AgendaEventItem.js +33 -81
  54. package/dist/components/AgendaResourceEvents.d.ts +10 -0
  55. package/dist/components/AgendaResourceEvents.js +37 -91
  56. package/dist/components/AgendaView.d.ts +9 -0
  57. package/dist/components/AgendaView.js +10 -69
  58. package/dist/components/BodyView.d.ts +11 -0
  59. package/dist/components/BodyView.js +36 -67
  60. package/dist/components/DnDContext.d.ts +48 -0
  61. package/dist/components/DnDContext.js +200 -221
  62. package/dist/components/DnDSource.d.ts +49 -0
  63. package/dist/components/DnDSource.js +125 -120
  64. package/dist/components/EventItem.d.ts +41 -0
  65. package/dist/components/EventItem.js +585 -787
  66. package/dist/components/EventItemPopover.d.ts +12 -0
  67. package/dist/components/EventItemPopover.js +19 -143
  68. package/dist/components/HeaderView.d.ts +14 -0
  69. package/dist/components/HeaderView.js +123 -186
  70. package/dist/components/ResourceEvents.d.ts +54 -0
  71. package/dist/components/ResourceEvents.js +534 -703
  72. package/dist/components/ResourceView.d.ts +26 -0
  73. package/dist/components/ResourceView.js +64 -184
  74. package/dist/components/SchedulerData.d.ts +136 -0
  75. package/dist/components/SchedulerData.js +1296 -1226
  76. package/dist/components/SchedulerHeader.d.ts +25 -0
  77. package/dist/components/SchedulerHeader.js +50 -150
  78. package/dist/components/SelectedArea.d.ts +8 -0
  79. package/dist/components/SelectedArea.js +11 -26
  80. package/dist/components/Summary.d.ts +11 -0
  81. package/dist/components/Summary.js +21 -50
  82. package/dist/components/WrapperFun.d.ts +2 -0
  83. package/dist/components/WrapperFun.js +5 -10
  84. package/dist/components/index.d.ts +44 -0
  85. package/dist/components/index.js +428 -654
  86. package/dist/components/ui/Icons.d.ts +8 -0
  87. package/dist/components/ui/Icons.js +7 -0
  88. package/dist/components/ui/MiniCalendar.d.ts +9 -0
  89. package/dist/components/ui/MiniCalendar.js +17 -0
  90. package/dist/components/ui/Popover.d.ts +13 -0
  91. package/dist/components/ui/Popover.js +80 -0
  92. package/dist/config/default.d.ts +36 -0
  93. package/dist/config/default.js +17 -26
  94. package/dist/config/i18n.d.ts +27 -0
  95. package/dist/config/i18n.js +21 -37
  96. package/dist/config/scheduler.d.ts +12 -0
  97. package/dist/config/scheduler.js +126 -119
  98. package/dist/css/style.css +2 -316
  99. package/dist/helper/behaviors.d.ts +14 -0
  100. package/dist/helper/behaviors.js +75 -75
  101. package/dist/helper/utility.d.ts +26 -0
  102. package/dist/helper/utility.js +23 -30
  103. package/dist/index.d.ts +6 -477
  104. package/dist/index.js +4 -2
  105. package/dist/sample-data/sample1.d.ts +11 -0
  106. package/dist/sample-data/sample1.js +427 -372
  107. package/dist/types.d.ts +267 -0
  108. package/dist/types.js +1 -0
  109. package/package.json +35 -26
@@ -0,0 +1,3 @@
1
+ import type { CalendarViewProps } from '../types';
2
+ declare function TimeGridView(props: CalendarViewProps): import("react").JSX.Element;
3
+ export default TimeGridView;
@@ -0,0 +1,334 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
+ import { getViewRange, listDays, normalizeEvent, parseTime, tipText } from '../utils';
4
+ import DayColumn, { eventArg, eventStyle, joinClasses } from './timegrid/DayColumn';
5
+ import { buildAllDayBars, buildDays, isoWeek, spanOf } from './timegrid/model';
6
+ const DRAG_THRESHOLD = 4;
7
+ const ALLDAY_LANE_H = 20;
8
+ /** One shared minute timer for the now indicator. */
9
+ function useNow(enabled) {
10
+ const [tick, setTick] = useState(() => Date.now());
11
+ useEffect(() => {
12
+ if (!enabled)
13
+ return undefined;
14
+ setTick(Date.now());
15
+ const id = setInterval(() => setTick(Date.now()), 60_000);
16
+ return () => clearInterval(id);
17
+ }, [enabled]);
18
+ return tick;
19
+ }
20
+ const fmtDate = (d) => d.format('YYYY-MM-DD');
21
+ function TimeGridView(props) {
22
+ const { view, date, events, dayjs, goTo, editable, firstDay = 0, weekNumbers } = props;
23
+ const isDay = view === 'timeGridDay';
24
+ const slotDur = props.slotDuration ?? 30;
25
+ const slotH = props.slotHeight ?? 28;
26
+ const minMin = parseTime(props.slotMinTime ?? '00:00');
27
+ const maxMin = Math.max(parseTime(props.slotMaxTime ?? '24:00'), minMin + slotDur);
28
+ const ppm = slotH / slotDur;
29
+ const timeFormat = props.eventTimeFormat ?? 'h:mma';
30
+ const propsRef = useRef(props);
31
+ propsRef.current = props;
32
+ const [overrides, setOverrides] = useState({});
33
+ // a new events array from the parent is the source of truth again
34
+ useEffect(() => setOverrides({}), [events]);
35
+ const days = useMemo(() => listDays(getViewRange(view, date, firstDay), isDay || (props.weekends ?? true)), [view, date, firstDay, isDay, props.weekends]);
36
+ const range = useMemo(() => ({ start: days[0].startOf('day'), end: days[days.length - 1].add(1, 'day').startOf('day') }), [days]);
37
+ const normalized = useMemo(() => events
38
+ .map(e => normalizeEvent(dayjs, overrides[String(e.id)] ?? e))
39
+ .filter(e => e.start.isBefore(range.end) && e.end.isAfter(range.start)), [events, overrides, dayjs, range]);
40
+ const dayData = useMemo(() => buildDays(days, normalized, minMin, maxMin, props.businessHours), [days, normalized, minMin, maxMin, props.businessHours]);
41
+ const { bars, lanes } = useMemo(() => buildAllDayBars(days, normalized), [days, normalized]);
42
+ const geo = useMemo(() => ({ minMin, maxMin, slotDur, slotH, ppm }), [minMin, maxMin, slotDur, slotH, ppm]);
43
+ const nowTick = useNow(!!props.nowIndicator);
44
+ const now = useMemo(() => dayjs(nowTick), [dayjs, nowTick]);
45
+ const nowMin = now.hour() * 60 + now.minute();
46
+ const render = useMemo(() => ({ view, timeFormat, eventContent: props.eventContent, eventClassNames: props.eventClassNames, now }), [view, timeFormat, props.eventContent, props.eventClassNames, now]);
47
+ const canEdit = useCallback((e) => {
48
+ const base = e.editable ?? editable ?? false;
49
+ return [e.startEditable ?? base, e.durationEditable ?? base];
50
+ }, [editable]);
51
+ const scrollRef = useRef(null);
52
+ const colsRef = useRef(null);
53
+ const allDayRef = useRef(null);
54
+ useEffect(() => {
55
+ const el = scrollRef.current;
56
+ if (el)
57
+ el.scrollTop = Math.max(0, (parseTime(props.scrollTime ?? '08:00') - minMin) * ppm);
58
+ }, [minMin, ppm]);
59
+ // ---- interaction state (only the touched column re-renders) ----
60
+ const [sel, setSel] = useState(null);
61
+ const [adSel, setAdSel] = useState(null);
62
+ const [preview, setPreview] = useState(null);
63
+ const gesture = useRef(null);
64
+ const last = useRef({});
65
+ const cleanup = useRef(null);
66
+ useEffect(() => () => cleanup.current?.(), []);
67
+ const snap = useCallback((m, mode) => Math[mode](m / slotDur) * slotDur, [slotDur]);
68
+ const hit = useCallback((x, y) => {
69
+ const cols = colsRef.current?.getBoundingClientRect();
70
+ const ad = allDayRef.current?.getBoundingClientRect();
71
+ if (!cols)
72
+ return null;
73
+ const dayIdx = Math.max(0, Math.min(days.length - 1, Math.floor(((x - cols.left) / cols.width) * days.length)));
74
+ const allDay = !!ad && y >= ad.top && y <= ad.bottom;
75
+ const minute = Math.max(minMin, Math.min(maxMin, minMin + (y - cols.top) / ppm));
76
+ return { dayIdx, allDay, minute };
77
+ }, [days.length, minMin, maxMin, ppm]);
78
+ const abort = useCallback(() => {
79
+ cleanup.current?.();
80
+ cleanup.current = null;
81
+ gesture.current = null;
82
+ last.current = {};
83
+ for (const el of scrollRef.current?.querySelectorAll('.rbs-tg-dragging') ?? [])
84
+ el.classList.remove('rbs-tg-dragging');
85
+ setSel(null);
86
+ setAdSel(null);
87
+ setPreview(null);
88
+ }, []);
89
+ const emitChange = useCallback((kind, p) => {
90
+ const src = p.ev.source;
91
+ const next = p.allDay
92
+ ? { ...src, start: fmtDate(p.start), end: fmtDate(p.end), allDay: true }
93
+ : { ...src, start: p.start.format(), end: p.end.format(), allDay: false };
94
+ const key = String(src.id);
95
+ setOverrides(o => ({ ...o, [key]: next }));
96
+ const info = {
97
+ event: next,
98
+ oldEvent: src,
99
+ revert: () => setOverrides(o => {
100
+ const copy = { ...o };
101
+ delete copy[key];
102
+ return copy;
103
+ }),
104
+ };
105
+ const cb = kind === 'drop' ? propsRef.current.onEventDrop : propsRef.current.onEventResize;
106
+ cb?.(info);
107
+ }, []);
108
+ const onMove = useCallback((e) => {
109
+ const g = gesture.current;
110
+ if (!g)
111
+ return;
112
+ if (!g.moved) {
113
+ if (Math.hypot(e.clientX - g.x, e.clientY - g.y) < DRAG_THRESHOLD)
114
+ return;
115
+ g.moved = true;
116
+ }
117
+ const h = hit(e.clientX, e.clientY);
118
+ if (!h)
119
+ return;
120
+ if (g.kind === 'slot') {
121
+ if (!propsRef.current.selectable)
122
+ return;
123
+ if (g.allDay) {
124
+ const s = { from: Math.min(g.dayIdx, h.dayIdx), to: Math.max(g.dayIdx, h.dayIdx) };
125
+ last.current.adSel = s;
126
+ setAdSel(s);
127
+ }
128
+ else {
129
+ const start = snap(Math.min(g.min0, h.minute), 'floor');
130
+ const end = Math.max(snap(Math.max(g.min0, h.minute), 'ceil'), start + slotDur);
131
+ const s = { dayIdx: g.dayIdx, start, end: Math.min(end, maxMin) };
132
+ last.current.sel = s;
133
+ setSel(s);
134
+ }
135
+ }
136
+ else if (g.kind === 'move') {
137
+ const [startEditable] = canEdit(g.ev.source);
138
+ if (!startEditable)
139
+ return;
140
+ const day = days[h.dayIdx];
141
+ const ev = g.ev;
142
+ const ms = ev.end.diff(ev.start);
143
+ let p;
144
+ if (h.allDay) {
145
+ const start = ev.allDay ? ev.start.add(day.diff(g.downDay, 'day'), 'day') : day.startOf('day');
146
+ const end = ev.allDay ? ev.end.add(day.diff(g.downDay, 'day'), 'day') : start.add(1, 'day');
147
+ p = { ev, start, end, allDay: true };
148
+ }
149
+ else if (ev.allDay) {
150
+ const start = day.startOf('day').add(snap(h.minute, 'floor'), 'minute');
151
+ p = { ev, start, end: start.add(1, 'hour'), allDay: false };
152
+ }
153
+ else {
154
+ const raw = day.startOf('day').add(h.minute - g.grab, 'minute');
155
+ const base = raw.startOf('day');
156
+ const start = base.add(snap(raw.diff(base, 'minute'), 'round'), 'minute');
157
+ p = { ev, start, end: start.add(ms, 'millisecond'), allDay: false };
158
+ }
159
+ last.current.preview = p;
160
+ setPreview(p);
161
+ }
162
+ else {
163
+ const [, durationEditable] = canEdit(g.ev.source);
164
+ if (!durationEditable)
165
+ return;
166
+ const day = days[g.dayIdx];
167
+ const ev = g.ev;
168
+ const min = snap(h.minute, 'round');
169
+ const minEnd = ev.start.add(slotDur, 'minute');
170
+ let end = day.startOf('day').add(min, 'minute');
171
+ if (end.isBefore(minEnd))
172
+ end = minEnd;
173
+ const p = { ev, start: ev.start, end, allDay: false };
174
+ last.current.preview = p;
175
+ setPreview(p);
176
+ }
177
+ }, [hit, snap, slotDur, maxMin, days, canEdit]);
178
+ const begin = useCallback((e, g) => {
179
+ if (e.button !== 0)
180
+ return;
181
+ cleanup.current?.();
182
+ gesture.current = g;
183
+ last.current = {};
184
+ const onUp = (ev) => {
185
+ const cur = gesture.current;
186
+ const l = last.current;
187
+ abort();
188
+ if (!cur)
189
+ return;
190
+ const p = propsRef.current;
191
+ if (cur.kind === 'slot') {
192
+ const day = days[cur.dayIdx];
193
+ if (!cur.moved) {
194
+ const date = cur.allDay ? day.startOf('day') : day.startOf('day').add(snap(cur.min0, 'floor'), 'minute');
195
+ p.onDateClick?.({ date, allDay: cur.allDay, jsEvent: ev });
196
+ }
197
+ else if (l.adSel) {
198
+ p.onSelect?.({
199
+ start: days[l.adSel.from].startOf('day'),
200
+ end: days[l.adSel.to].add(1, 'day').startOf('day'),
201
+ allDay: true,
202
+ });
203
+ }
204
+ else if (l.sel) {
205
+ const base = days[l.sel.dayIdx].startOf('day');
206
+ p.onSelect?.({ start: base.add(l.sel.start, 'minute'), end: base.add(l.sel.end, 'minute'), allDay: false });
207
+ }
208
+ }
209
+ else if (!cur.moved) {
210
+ if (cur.kind === 'move')
211
+ p.onEventClick?.({ event: cur.ev.source, jsEvent: ev });
212
+ }
213
+ else if (l.preview &&
214
+ !(l.preview.start.isSame(cur.ev.start) &&
215
+ l.preview.end.isSame(cur.ev.end) &&
216
+ l.preview.allDay === cur.ev.allDay)) {
217
+ emitChange(cur.kind === 'move' ? 'drop' : 'resize', l.preview);
218
+ }
219
+ };
220
+ const onKey = (ev) => ev.key === 'Escape' && abort();
221
+ window.addEventListener('pointermove', onMove);
222
+ window.addEventListener('pointerup', onUp, { once: true });
223
+ window.addEventListener('pointercancel', abort, { once: true });
224
+ window.addEventListener('keydown', onKey);
225
+ cleanup.current = () => {
226
+ window.removeEventListener('pointermove', onMove);
227
+ window.removeEventListener('pointerup', onUp);
228
+ window.removeEventListener('pointercancel', abort);
229
+ window.removeEventListener('keydown', onKey);
230
+ };
231
+ }, [abort, onMove, days, snap, emitChange]);
232
+ const onSlotDown = useCallback((e, dayIdx) => {
233
+ const h = hit(e.clientX, e.clientY);
234
+ if (h)
235
+ begin(e, { kind: 'slot', x: e.clientX, y: e.clientY, moved: false, dayIdx, allDay: false, min0: h.minute });
236
+ }, [hit, begin]);
237
+ const onAllDaySlotDown = (e) => {
238
+ const h = hit(e.clientX, e.clientY);
239
+ if (h)
240
+ begin(e, { kind: 'slot', x: e.clientX, y: e.clientY, moved: false, dayIdx: h.dayIdx, allDay: true, min0: 0 });
241
+ };
242
+ const onEventDown = useCallback((e, ev, dayIdx) => {
243
+ e.stopPropagation();
244
+ const h = hit(e.clientX, e.clientY);
245
+ if (!h)
246
+ return;
247
+ const downDay = days[dayIdx];
248
+ const grab = ev.allDay ? 0 : downDay.startOf('day').add(h.minute, 'minute').diff(ev.start, 'minute');
249
+ begin(e, { kind: 'move', x: e.clientX, y: e.clientY, moved: false, ev, downDay, grab });
250
+ if (canEdit(ev.source)[0])
251
+ e.currentTarget.classList.add('rbs-tg-dragging');
252
+ }, [hit, begin, days, canEdit]);
253
+ const onResizeDown = useCallback((e, ev, dayIdx) => {
254
+ e.stopPropagation();
255
+ begin(e, { kind: 'resize', x: e.clientX, y: e.clientY, moved: false, ev, dayIdx });
256
+ }, [begin]);
257
+ const onEventActivate = useCallback((e, ev) => {
258
+ // mouse clicks are handled on pointerup; this is the keyboard path (Enter/Space)
259
+ if (e.detail === 0)
260
+ propsRef.current.onEventClick?.({ event: ev.source, jsEvent: e });
261
+ }, []);
262
+ const onSlotActivate = useCallback((d) => {
263
+ propsRef.current.onDateClick?.({ date: d, allDay: false, jsEvent: new MouseEvent('click') });
264
+ }, []);
265
+ // ---- all-day row ----
266
+ const maxLanes = typeof props.dayMaxEvents === 'number' ? props.dayMaxEvents : 3;
267
+ const overflow = lanes > maxLanes;
268
+ const visLanes = overflow ? maxLanes - 1 : lanes;
269
+ const rows = Math.max(1, visLanes + (overflow ? 1 : 0));
270
+ const hiddenPerDay = useMemo(() => {
271
+ const counts = days.map(() => 0);
272
+ for (const b of bars)
273
+ if (b.lane >= visLanes)
274
+ for (let i = b.si; i <= b.ei; i++)
275
+ counts[i] += 1;
276
+ return counts;
277
+ }, [bars, days, visLanes]);
278
+ const adGhost = preview?.allDay ? spanOf(days, preview) : null;
279
+ const n = days.length;
280
+ const showWeek = weekNumbers && !isDay;
281
+ const weekLabel = `W${isoWeek(days[0])}`;
282
+ const scrollMax = props.height === undefined ? 700 : undefined;
283
+ const hours = [];
284
+ for (let h = Math.ceil(minMin / 60); h * 60 < maxMin; h++)
285
+ hours.push(h);
286
+ const today = dayjs();
287
+ return (_jsx("div", { className: "rbs-tg", "data-view": view, children: _jsxs("div", { ref: scrollRef, className: "rbs-tg-scroll", style: { maxHeight: scrollMax }, children: [_jsxs("div", { className: "rbs-tg-sticky", children: [_jsxs("div", { className: "rbs-tg-row rbs-tg-head", children: [_jsx("div", { className: "rbs-tg-corner", children: showWeek ? weekLabel : '' }), days.map(d => {
288
+ const isToday = d.isSame(today, 'day');
289
+ return (_jsx("div", { className: joinClasses('rbs-tg-hcell', isToday && 'rbs-tg-today'), children: _jsxs("button", { type: "button", className: "rbs-tg-daylink", onClick: () => props.onNavLinkDayClick ? props.onNavLinkDayClick(d) : !isDay && goTo('timeGridDay', d), children: [_jsx("span", { className: "rbs-tg-dow", children: d.format('ddd') }), _jsx("span", { className: "rbs-tg-dom", children: d.format('D') })] }) }, d.valueOf()));
290
+ })] }), _jsxs("div", { className: "rbs-tg-row rbs-tg-allday", children: [_jsx("div", { className: "rbs-tg-corner rbs-tg-allday-label", children: "all-day" }), _jsxs("div", { ref: allDayRef, className: "rbs-tg-allday-cols", style: { height: rows * ALLDAY_LANE_H + 6 }, onPointerDown: onAllDaySlotDown, children: [days.map((d, i) => (_jsx("div", { className: joinClasses('rbs-tg-allday-cell', d.isSame(today, 'day') && 'rbs-tg-today'), style: { left: `${(i / n) * 100}%`, width: `${100 / n}%` } }, d.valueOf()))), adSel && (_jsx("div", { className: "rbs-tg-select", style: {
291
+ left: `${(adSel.from / n) * 100}%`,
292
+ width: `${((adSel.to - adSel.from + 1) / n) * 100}%`,
293
+ top: 0,
294
+ bottom: 0,
295
+ } })), bars
296
+ .filter(b => b.lane < visLanes)
297
+ .map(b => {
298
+ const arg = eventArg(render, b.ev, b.isStart, b.isEnd);
299
+ const [startEditable] = canEdit(b.ev.source);
300
+ return (_jsx("button", { type: "button", "aria-label": `${b.ev.source.title}, all day`, "data-tip": tipText(b.ev), "data-tip-color": b.ev.source.color, className: joinClasses('rbs-tg-bar', !b.isStart && 'rbs-tg-bar-cont-start', !b.isEnd && 'rbs-tg-bar-cont-end', startEditable && 'rbs-tg-ev-editable', b.ev.source.classNames, render.eventClassNames?.(arg)), style: {
301
+ ...eventStyle(b.ev),
302
+ left: `${(b.si / n) * 100}%`,
303
+ width: `calc(${((b.ei - b.si + 1) / n) * 100}% - 2px)`,
304
+ top: b.lane * ALLDAY_LANE_H + 2,
305
+ height: ALLDAY_LANE_H - 2,
306
+ }, onPointerDown: e => {
307
+ const idx = Math.max(b.si, Math.min(b.ei, hit(e.clientX, e.clientY)?.dayIdx ?? b.si));
308
+ onEventDown(e, b.ev, idx);
309
+ }, onClick: e => onEventActivate(e.nativeEvent, b.ev), children: render.eventContent ? (render.eventContent(arg)) : (_jsx("span", { className: "rbs-tg-ev-title", children: b.ev.source.title })) }, `${b.ev.id}-${b.si}`));
310
+ }), overflow &&
311
+ hiddenPerDay.map((count, i) => count > 0 ? (_jsxs("button", { type: "button", className: "rbs-tg-more", style: { left: `${(i / n) * 100}%`, width: `${100 / n}%`, top: visLanes * ALLDAY_LANE_H + 2 }, onPointerDown: e => e.stopPropagation(), onClick: () => goTo('timeGridDay', days[i]), children: ["+", count, " more"] }, days[i].valueOf())) : null), adGhost && preview && (_jsx("div", { className: "rbs-tg-bar rbs-tg-ghost", style: {
312
+ ...eventStyle(preview.ev),
313
+ left: `${(adGhost.si / n) * 100}%`,
314
+ width: `calc(${((adGhost.ei - adGhost.si + 1) / n) * 100}% - 2px)`,
315
+ top: 2,
316
+ height: ALLDAY_LANE_H - 2,
317
+ }, children: _jsx("span", { className: "rbs-tg-ev-title", children: preview.ev.source.title }) }))] })] })] }), _jsxs("div", { className: "rbs-tg-row rbs-tg-body", children: [_jsx("div", { className: "rbs-tg-axis", style: { height: (maxMin - minMin) * ppm }, children: hours.map(h => (_jsx("div", { className: "rbs-tg-hour", style: { top: (h * 60 - minMin) * ppm }, children: h * 60 > minMin ? today.startOf('day').add(h, 'hour').format('h A') : '' }, h))) }), _jsx("div", { ref: colsRef, role: "grid", "aria-label": "Time grid", className: "rbs-tg-cols", children: dayData.map((data, i) => {
318
+ const base = data.day.startOf('day');
319
+ const winStart = base.add(minMin, 'minute');
320
+ const winEnd = base.add(maxMin, 'minute');
321
+ const pv = preview && !preview.allDay && preview.start.isBefore(winEnd) && preview.end.isAfter(winStart)
322
+ ? preview
323
+ : null;
324
+ const isToday = data.day.isSame(today, 'day');
325
+ return (_jsx(DayColumn, { data: data, dayIdx: i, isToday: isToday, geo: geo, render: render, nowMin: props.nowIndicator && isToday ? nowMin : null, selStart: sel?.dayIdx === i ? sel.start : null, selEnd: sel?.dayIdx === i ? sel.end : null, ghost: pv
326
+ ? {
327
+ ev: pv.ev,
328
+ sMin: Math.max(pv.start.diff(base, 'minute'), minMin),
329
+ eMin: Math.min(pv.end.diff(base, 'minute'), maxMin),
330
+ }
331
+ : null, canEdit: canEdit, onSlotDown: onSlotDown, onEventDown: onEventDown, onResizeDown: onResizeDown, onEventActivate: onEventActivate, onSlotActivate: onSlotActivate }, data.day.valueOf()));
332
+ }) })] })] }) }));
333
+ }
334
+ export default TimeGridView;
@@ -0,0 +1,19 @@
1
+ import type { Dayjs } from 'dayjs';
2
+ export interface DayCellProps {
3
+ dayKey: string;
4
+ date: Dayjs;
5
+ label: string;
6
+ title: string;
7
+ isToday: boolean;
8
+ isOther: boolean;
9
+ hidden: boolean;
10
+ focusable: boolean;
11
+ selected: boolean;
12
+ dropping: boolean;
13
+ /** background-event colour tinting this cell */
14
+ bgColor?: string;
15
+ className: string;
16
+ }
17
+ declare function DayCell({ dayKey, label, title, isToday, isOther, hidden, focusable, selected, dropping, bgColor, className, }: DayCellProps): import("react").JSX.Element;
18
+ declare const _default: import("react").MemoExoticComponent<typeof DayCell>;
19
+ export default _default;
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { memo } from 'react';
3
+ function DayCell({ dayKey, label, title, isToday, isOther, hidden, focusable, selected, dropping, bgColor, className, }) {
4
+ const cls = [
5
+ 'rbs-dg-cell',
6
+ isToday && 'rbs-dg-today',
7
+ isOther && 'rbs-dg-other',
8
+ selected && 'rbs-dg-selected',
9
+ dropping && 'rbs-dg-drop',
10
+ bgColor && 'rbs-dg-bg',
11
+ className,
12
+ ]
13
+ .filter(Boolean)
14
+ .join(' ');
15
+ return (_jsx("div", { className: cls, role: "gridcell", "data-date": dayKey, tabIndex: focusable ? 0 : -1, "aria-label": title, style: bgColor ? { '--rbs-bg': bgColor } : undefined, children: !hidden && (_jsx("button", { type: "button", className: "rbs-dg-num", "data-nav": dayKey, tabIndex: -1, "aria-hidden": "true", children: label })) }));
16
+ }
17
+ export default memo(DayCell);
@@ -0,0 +1,19 @@
1
+ import type { CalendarOptions, CalendarViewName } from '../../types';
2
+ import type { PEvent } from './layout';
3
+ export interface ChipProps extends Pick<CalendarOptions, 'eventContent' | 'eventClassNames' | 'eventTimeFormat'> {
4
+ ev: PEvent;
5
+ view: CalendarViewName;
6
+ isStart: boolean;
7
+ isEnd: boolean;
8
+ /** Grid placement inside the week layer; omitted in the "+N more" popover. */
9
+ col?: number;
10
+ span?: number;
11
+ lane?: number;
12
+ canMove?: boolean;
13
+ canResize?: boolean;
14
+ dragging?: boolean;
15
+ now: number;
16
+ }
17
+ declare function EventChip({ ev, view, isStart, isEnd, col, span, lane, canMove, canResize, dragging, now, eventContent, eventClassNames, eventTimeFormat, }: ChipProps): import("react").JSX.Element;
18
+ declare const _default: import("react").MemoExoticComponent<typeof EventChip>;
19
+ export default _default;
@@ -0,0 +1,40 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { memo } from 'react';
3
+ import { tipText } from '../../utils';
4
+ function EventChip({ ev, view, isStart, isEnd, col, span = 1, lane = 0, canMove, canResize, dragging, now, eventContent, eventClassNames, eventTimeFormat, }) {
5
+ const { ne } = ev;
6
+ const src = ne.source;
7
+ const block = src.display !== 'list-item' && (src.display === 'block' || ne.allDay || ev.sVal !== ev.eVal);
8
+ const timeText = !ne.allDay && isStart ? ne.start.format(eventTimeFormat ?? 'HH:mm') : '';
9
+ const arg = {
10
+ event: src,
11
+ view,
12
+ timeText,
13
+ isStart,
14
+ isEnd,
15
+ isPast: ne.end.valueOf() <= now,
16
+ isFuture: ne.start.valueOf() > now,
17
+ isToday: ev.sVal <= now && now < ev.eVal + 86400000,
18
+ };
19
+ const extra = eventClassNames?.(arg) ?? [];
20
+ const cls = [
21
+ 'rbs-dg-ev',
22
+ block ? 'rbs-dg-ev--block' : 'rbs-dg-ev--dot',
23
+ !isStart && 'rbs-dg-ev--cont-l',
24
+ !isEnd && 'rbs-dg-ev--cont-r',
25
+ dragging && 'rbs-dg-ev--dragging',
26
+ canMove && 'rbs-dg-ev--movable',
27
+ ...(src.classNames ?? []),
28
+ ...(Array.isArray(extra) ? extra : [extra]),
29
+ ]
30
+ .filter(Boolean)
31
+ .join(' ');
32
+ const style = {
33
+ ...(col === undefined ? null : { gridColumn: `${col + 1} / span ${span}`, gridRow: lane + 1 }),
34
+ ...(src.color ? { '--rbs-ev': src.color } : null),
35
+ ...(src.textColor ? { '--rbs-ev-fg': src.textColor } : null),
36
+ };
37
+ const label = `${src.title}, ${ne.allDay ? 'all day' : ne.start.format(eventTimeFormat ?? 'HH:mm')}`;
38
+ return (_jsxs("button", { type: "button", className: cls, style: style, "data-eid": String(ne.id), "data-drag": col === undefined ? undefined : '', "aria-label": label, "data-tip": tipText(ne), "data-tip-color": src.color, children: [eventContent ? (eventContent(arg)) : (_jsxs(_Fragment, { children: [!block && _jsx("span", { className: "rbs-dg-dot" }), timeText && _jsx("span", { className: "rbs-dg-time", children: timeText }), _jsx("span", { className: "rbs-dg-title", children: src.title })] })), canResize && block && isEnd && _jsx("span", { className: "rbs-dg-resizer", "data-resize": "" })] }));
39
+ }
40
+ export default memo(EventChip);
@@ -0,0 +1,30 @@
1
+ import type { NormalizedEvent } from '../../utils';
2
+ export declare const DAY = 86400000;
3
+ export declare const HEAD_H = 26;
4
+ export declare const LANE_H = 22;
5
+ /** An event with its first/last visible day (local midnight values). */
6
+ export interface PEvent {
7
+ ne: NormalizedEvent;
8
+ sVal: number;
9
+ eVal: number;
10
+ }
11
+ export interface Seg {
12
+ ev: PEvent;
13
+ colStart: number;
14
+ colEnd: number;
15
+ isStart: boolean;
16
+ isEnd: boolean;
17
+ lane: number;
18
+ }
19
+ export interface RowLayout {
20
+ shown: Seg[];
21
+ /** Hidden-event count per column ("+N more"). */
22
+ more: number[];
23
+ /** Lane rows to reserve (shown lanes + the "more" row). */
24
+ rows: number;
25
+ }
26
+ export declare function prepare(ne: NormalizedEvent): PEvent;
27
+ /** Cut events into one week row and pack them into lanes. `limitFor(lanes)` -> max visible lanes (Infinity = all). */
28
+ export declare function layoutRow(vals: number[], active: boolean[], events: PEvent[], limitFor: (lanes: number) => number): RowLayout;
29
+ /** ISO week number of the Thursday in a row. */
30
+ export declare function isoWeek(ms: number): number;
@@ -0,0 +1,63 @@
1
+ export const DAY = 86400000;
2
+ export const HEAD_H = 26;
3
+ export const LANE_H = 22;
4
+ export function prepare(ne) {
5
+ const sVal = ne.start.startOf('day').valueOf();
6
+ const eVal = Math.max(sVal, ne.end.subtract(1, 'millisecond').startOf('day').valueOf());
7
+ return { ne, sVal, eVal };
8
+ }
9
+ /** Cut events into one week row and pack them into lanes. `limitFor(lanes)` -> max visible lanes (Infinity = all). */
10
+ export function layoutRow(vals, active, events, limitFor) {
11
+ const segs = [];
12
+ for (const ev of events) {
13
+ let a = -1;
14
+ let b = -1;
15
+ for (let i = 0; i < vals.length; i++) {
16
+ if (active[i] && vals[i] >= ev.sVal && vals[i] <= ev.eVal) {
17
+ if (a < 0)
18
+ a = i;
19
+ b = i;
20
+ }
21
+ }
22
+ if (a < 0)
23
+ continue;
24
+ segs.push({ ev, colStart: a, colEnd: b, isStart: vals[a] === ev.sVal, isEnd: vals[b] === ev.eVal, lane: 0 });
25
+ }
26
+ segs.sort((x, y) => x.colStart - y.colStart ||
27
+ y.colEnd - y.colStart - (x.colEnd - x.colStart) ||
28
+ Number(y.ev.ne.allDay) - Number(x.ev.ne.allDay) ||
29
+ x.ev.ne.start.valueOf() - y.ev.ne.start.valueOf());
30
+ const ends = [];
31
+ for (const s of segs) {
32
+ let lane = ends.findIndex(e => e < s.colStart);
33
+ if (lane < 0) {
34
+ lane = ends.length;
35
+ ends.push(0);
36
+ }
37
+ ends[lane] = s.colEnd;
38
+ s.lane = lane;
39
+ }
40
+ const limit = limitFor(ends.length);
41
+ const more = vals.map(() => 0);
42
+ if (limit >= ends.length)
43
+ return { shown: segs, more, rows: ends.length };
44
+ const shown = [];
45
+ for (const s of segs) {
46
+ if (s.lane < limit)
47
+ shown.push(s);
48
+ else
49
+ for (let i = s.colStart; i <= s.colEnd; i++)
50
+ if (active[i])
51
+ more[i]++;
52
+ }
53
+ return { shown, more, rows: limit + 1 };
54
+ }
55
+ /** ISO week number of the Thursday in a row. */
56
+ export function isoWeek(ms) {
57
+ const d = new Date(ms);
58
+ const t = Date.UTC(d.getFullYear(), d.getMonth(), d.getDate());
59
+ const day = new Date(t).getUTCDay() || 7;
60
+ const thu = t + (4 - day) * DAY;
61
+ const yearStart = Date.UTC(new Date(thu).getUTCFullYear(), 0, 1);
62
+ return Math.ceil(((thu - yearStart) / DAY + 1) / 7);
63
+ }
@@ -0,0 +1,8 @@
1
+ import type { Dayjs } from 'dayjs';
2
+ import type { DateRange } from '../../types';
3
+ import type { NormalizedEvent } from '../../utils';
4
+ export declare const dayKey: (d: Dayjs) => string;
5
+ /** Bucket events by every day they cover inside `range` (all-day first, then by start). O(events x days covered). */
6
+ export declare function bucketByDay(events: NormalizedEvent[], range: DateRange): Map<string, NormalizedEvent[]>;
7
+ /** "9:00 AM – 10:00 AM", "all-day" or a clipped range for the given day of a multi-day event. */
8
+ export declare function timeText(e: NormalizedEvent, day: Dayjs, fmt?: string): string;
@@ -0,0 +1,37 @@
1
+ export const dayKey = (d) => d.format('YYYY-MM-DD');
2
+ const visible = (e) => e.source.display !== 'background' && e.source.display !== 'none';
3
+ /** Bucket events by every day they cover inside `range` (all-day first, then by start). O(events x days covered). */
4
+ export function bucketByDay(events, range) {
5
+ const map = new Map();
6
+ for (const e of events) {
7
+ if (!visible(e) || !e.start.isBefore(range.end) || !e.end.isAfter(range.start))
8
+ continue;
9
+ let d = e.start.isAfter(range.start) ? e.start.startOf('day') : range.start;
10
+ for (; d.isBefore(e.end) && d.isBefore(range.end); d = d.add(1, 'day')) {
11
+ const key = dayKey(d);
12
+ const list = map.get(key);
13
+ if (list)
14
+ list.push(e);
15
+ else
16
+ map.set(key, [e]);
17
+ }
18
+ }
19
+ for (const list of map.values()) {
20
+ list.sort((a, b) => Number(b.allDay) - Number(a.allDay) || a.start.valueOf() - b.start.valueOf());
21
+ }
22
+ return map;
23
+ }
24
+ /** "9:00 AM – 10:00 AM", "all-day" or a clipped range for the given day of a multi-day event. */
25
+ export function timeText(e, day, fmt = 'h:mm A') {
26
+ if (e.allDay)
27
+ return 'all-day';
28
+ const startsToday = e.start.isSame(day, 'day');
29
+ const endsToday = !e.end.isAfter(day.add(1, 'day').startOf('day'));
30
+ if (startsToday && endsToday)
31
+ return `${e.start.format(fmt)} – ${e.end.format(fmt)}`;
32
+ if (startsToday)
33
+ return `${e.start.format(fmt)} –`;
34
+ if (endsToday)
35
+ return `– ${e.end.format(fmt)}`;
36
+ return 'all-day';
37
+ }
@@ -0,0 +1,12 @@
1
+ import type { Dayjs } from 'dayjs';
2
+ import { type MonthShared } from './shared';
3
+ interface CellProps {
4
+ day: Dayjs;
5
+ shared: MonthShared;
6
+ tabbable: boolean;
7
+ /** day belongs to another month (continuous mode tints, never hides) */
8
+ alt?: boolean;
9
+ }
10
+ declare function Cell({ day, shared, tabbable, alt }: CellProps): import("react").JSX.Element;
11
+ declare const _default: import("react").MemoExoticComponent<typeof Cell>;
12
+ export default _default;
@@ -0,0 +1,44 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { memo } from 'react';
3
+ import { tipText } from '../../utils';
4
+ import { dayKey } from '../list/bucket';
5
+ import { dayTip, dayTitle, MAX_CHIPS } from './shared';
6
+ function Cell({ day, shared, tabbable, alt }) {
7
+ const { buckets, bgBuckets, today, compact, view, onDateClick, onEventClick, goTo, eventClassNames, eventContent, dayCellClassNames, } = shared;
8
+ const list = buckets.get(dayKey(day));
9
+ const bg = bgBuckets.get(dayKey(day))?.[0]?.source;
10
+ const isToday = day.isSame(today, 'day');
11
+ const extra = dayCellClassNames?.({ date: day, isToday, isOther: false });
12
+ const extraCls = Array.isArray(extra) ? extra.join(' ') : (extra ?? '');
13
+ const cls = `rbs-mm-cell${isToday ? ' rbs-mm-today' : ''}${list ? ' rbs-mm-busy' : ''}${alt ? ' rbs-mm-alt' : ''}${bg ? ' rbs-mm-bg' : ''} ${extraCls}`;
14
+ const nowD = today;
15
+ return (_jsxs("div", { role: "gridcell", className: cls, "data-day": dayKey(day), style: bg ? { '--rbs-bg': bg.color ?? 'var(--rbs-accent)' } : undefined, tabIndex: tabbable ? 0 : -1, "data-tip": dayTip(day, list), "aria-label": dayTitle(day, list), "aria-current": isToday ? 'date' : undefined, onClick: ev => onDateClick?.({ date: day, allDay: true, jsEvent: ev }), onKeyDown: ev => {
16
+ if (ev.key === 'Enter' && ev.target === ev.currentTarget) {
17
+ onDateClick?.({ date: day, allDay: true, jsEvent: ev });
18
+ }
19
+ }, children: [_jsx("span", { className: "rbs-mm-num", children: day.date() }), list && compact && _jsx("span", { className: "rbs-mm-dot" }), list && !compact && (_jsxs("span", { className: "rbs-mm-chips", children: [list.slice(0, MAX_CHIPS).map(e => {
20
+ const isStart = e.start.isSame(day, 'day');
21
+ const arg = {
22
+ event: e.source,
23
+ view,
24
+ timeText: e.allDay ? '' : e.start.format('h:mma'),
25
+ isStart,
26
+ isEnd: !e.end.isAfter(day.add(1, 'day')),
27
+ isPast: e.end.isBefore(nowD),
28
+ isFuture: e.start.isAfter(nowD),
29
+ isToday,
30
+ };
31
+ const ec = eventClassNames?.(arg);
32
+ return (_jsx("button", { type: "button", tabIndex: -1, "data-tip": tipText(e), "data-tip-color": e.source.color, className: `rbs-mm-chip ${(e.source.classNames ?? []).join(' ')} ${Array.isArray(ec) ? ec.join(' ') : (ec ?? '')}`, style: {
33
+ background: e.source.color ?? 'var(--rbs-accent)',
34
+ color: e.source.textColor ?? 'var(--rbs-event-fg)',
35
+ }, onClick: ev => {
36
+ ev.stopPropagation();
37
+ onEventClick?.({ event: e.source, jsEvent: ev });
38
+ }, children: eventContent ? eventContent(arg) : e.source.title }, e.id));
39
+ }), list.length > MAX_CHIPS && (_jsxs("button", { type: "button", tabIndex: -1, className: "rbs-mm-more", onClick: ev => {
40
+ ev.stopPropagation();
41
+ goTo('dayGridDay', day);
42
+ }, children: ["+", list.length - MAX_CHIPS, " more"] }))] }))] }));
43
+ }
44
+ export default memo(Cell);
@@ -0,0 +1,8 @@
1
+ import type { DateRange } from '../../types';
2
+ import { type MonthShared } from './shared';
3
+ declare function Continuous({ range, shared }: {
4
+ range: DateRange;
5
+ shared: MonthShared;
6
+ }): import("react").JSX.Element;
7
+ declare const _default: import("react").MemoExoticComponent<typeof Continuous>;
8
+ export default _default;