@primeui/scheduler-core 0.0.1-alpha.1 → 1.0.0-rc.1

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 (53) hide show
  1. package/LICENSE.md +35 -0
  2. package/README.md +12 -0
  3. package/THIRD-PARTY-NOTICES.txt +191 -0
  4. package/dist/{overlay-BYM9B6nC.d.mts → appointment-slots-DCiNFFed.d.mts} +2 -13
  5. package/dist/calendar/index.mjs +1 -1
  6. package/dist/{chunk-NMX4BW42.mjs → chunks/chunk-2YXHUV2A.mjs} +2 -2
  7. package/dist/{chunk-FIBAZFC4.mjs → chunks/chunk-6Q5FR4PN.mjs} +1 -1
  8. package/dist/{chunk-NX46LPLF.mjs → chunks/chunk-BJFVXDZC.mjs} +2 -2
  9. package/dist/{chunk-6PK5WSKT.mjs → chunks/chunk-EHH5ARHF.mjs} +29 -35
  10. package/dist/{chunk-TNKJPFGI.mjs → chunks/chunk-F2LYNUXG.mjs} +1 -1
  11. package/dist/{chunk-ZUKUKGNK.mjs → chunks/chunk-G7F2OBHW.mjs} +30 -34
  12. package/dist/{chunk-KQGRXTP5.mjs → chunks/chunk-HF32DKZY.mjs} +26 -270
  13. package/dist/chunks/chunk-HWGXSE6Q.mjs +269 -0
  14. package/dist/{chunk-HPC5B3AR.mjs → chunks/chunk-JCNXNPGM.mjs} +3 -3
  15. package/dist/{chunk-6OZAPQZ5.mjs → chunks/chunk-LMZ2J5Z5.mjs} +3 -3
  16. package/dist/{chunk-F5W5HD7S.mjs → chunks/chunk-LYPP7W7B.mjs} +79 -7
  17. package/dist/{chunk-W2SJW3QQ.mjs → chunks/chunk-NKSMQCWJ.mjs} +21 -50
  18. package/dist/{chunk-6VYWVIGM.mjs → chunks/chunk-QBTFRSZM.mjs} +5 -5
  19. package/dist/{chunk-NZGJN7HG.mjs → chunks/chunk-RM6OQCEO.mjs} +2 -2
  20. package/dist/{chunk-2THQAZ26.mjs → chunks/chunk-URRTAW2Q.mjs} +7 -54
  21. package/dist/{chunk-WFUJWDST.mjs → chunks/chunk-XQAYO7CQ.mjs} +1 -1
  22. package/dist/controllers/index.d.mts +3 -3
  23. package/dist/controllers/index.mjs +946 -13
  24. package/dist/event/index.mjs +8 -8
  25. package/dist/index.d.mts +6 -13
  26. package/dist/index.mjs +32 -34
  27. package/dist/interaction/index.d.mts +2 -63
  28. package/dist/interaction/index.mjs +9 -9
  29. package/dist/month/index.mjs +6 -6
  30. package/dist/resource/index.mjs +1 -1
  31. package/dist/time-grid/index.d.mts +9 -2
  32. package/dist/time-grid/index.mjs +12 -13
  33. package/dist/timeline/index.d.mts +11 -1
  34. package/dist/timeline/index.mjs +7 -6
  35. package/dist/{touch-BhsMWsjf.d.mts → touch-B6xcJlyY.d.mts} +1 -1
  36. package/dist/utils/index.d.mts +2 -27
  37. package/dist/utils/index.mjs +16 -17
  38. package/dist/views/index.mjs +8 -8
  39. package/dist/views/timeline/index.mjs +4 -4
  40. package/dist/year/index.mjs +6 -6
  41. package/package.json +61 -10
  42. package/LICENSE +0 -23
  43. package/dist/chunk-5N4ZOBJV.mjs +0 -866
  44. package/dist/chunk-AAVM7UCG.mjs +0 -100
  45. /package/dist/{chunk-DYW6WUHE.mjs → chunks/chunk-6OTDPEJM.mjs} +0 -0
  46. /package/dist/{chunk-UMAMDBU4.mjs → chunks/chunk-73ID2V6E.mjs} +0 -0
  47. /package/dist/{chunk-C7ADJGNV.mjs → chunks/chunk-7TCZNLG7.mjs} +0 -0
  48. /package/dist/{chunk-5KORIWDT.mjs → chunks/chunk-AZRI6PHU.mjs} +0 -0
  49. /package/dist/{chunk-XUBQ2IQS.mjs → chunks/chunk-B4YDYPVO.mjs} +0 -0
  50. /package/dist/{chunk-SYJ5O4KH.mjs → chunks/chunk-IJH6YR4N.mjs} +0 -0
  51. /package/dist/{chunk-QDMZBJDV.mjs → chunks/chunk-P7CIUMQZ.mjs} +0 -0
  52. /package/dist/{chunk-2B3YLWHA.mjs → chunks/chunk-UKD2NVDC.mjs} +0 -0
  53. /package/dist/{chunk-QR2SVYAD.mjs → chunks/chunk-XMU4WSAX.mjs} +0 -0
@@ -1,13 +1,946 @@
1
- export { RESIZE_EDGE_SIZE, TIMELINE_RESIZE_EDGE_SIZE, calculateDragClickOffset, calculateResizeDeltas, calculateResizePreviewPosition, calculateResizePreviewStyle, calculateTimedDragDelta, calculateTimedDragPreview, calculateTimedResizePreview, calculateTimelineDragDelta, calculateTimelineResizeDeltas, canDropTimedPreviewEvent, cloneEventForSlotTracking, createAppointmentSlotTrackingState, createTimelineDragState, createTimelineResizeState, detectResizeEdgeForAllDay, detectResizeEdgeForTimeline, dispatchTimedPointerEnd, dispatchTimedPointerMove, finalizeMonthDrag, finalizeMonthResize, finalizeTimedDrag, finalizeTimedResize, finalizeTimelineDrag, finalizeTimelineResize, findColumnIndexForDate, findEventPositionInGrid, getDragGhostStyle, getSlotTrackingKey, getTimedPreviewStyle, getTimelineDragGhostStyle, hasTimedDropConstraints, isAppointmentSlotTrackingView, processMonthDragMove, processMonthResizeMove, processTimedDragMove, processTimedResizeMove, processTimelineDragMove, processTimelineResizeMove, resolveTimedPointerStart, resolveTimelineSnapDuration, syncAppointmentSlotTracking, updateTimelineDragState } from '../chunk-5N4ZOBJV.mjs';
2
- export { getTimeFromYPosition, getYPositionFromTime } from '../chunk-2THQAZ26.mjs';
3
- import '../chunk-SYJ5O4KH.mjs';
4
- import '../chunk-NX46LPLF.mjs';
5
- import '../chunk-2B3YLWHA.mjs';
6
- import '../chunk-NZGJN7HG.mjs';
7
- import '../chunk-HPC5B3AR.mjs';
8
- import '../chunk-5KORIWDT.mjs';
9
- import '../chunk-FIBAZFC4.mjs';
10
- import '../chunk-WFUJWDST.mjs';
11
- import '../chunk-TNKJPFGI.mjs';
12
- import '../chunk-DYW6WUHE.mjs';
13
- import '../chunk-QR2SVYAD.mjs';
1
+ import { DEFAULT_DRAG_MIN_DISTANCE, applyDeltaToEvent, findOverlappingEvents, applyResizeToEvent, detectResizeEdge, createResizeState, createDragState, snapToSlot, getYPositionFromTime, getSchedulerEventDropDelta, getSchedulerTimelineResizePreview } from '../chunks/chunk-URRTAW2Q.mjs';
2
+ export { getTimeFromYPosition, getYPositionFromTime } from '../chunks/chunk-URRTAW2Q.mjs';
3
+ import { hasOverlapInAnyAssignedResource, getEventResourceIds } from '../chunks/chunk-IJH6YR4N.mjs';
4
+ import '../chunks/chunk-BJFVXDZC.mjs';
5
+ import { getTimelineVisibleDayStarts, timeToTimelinePixels, timelinePixelsToTime } from '../chunks/chunk-HF32DKZY.mjs';
6
+ import '../chunks/chunk-UKD2NVDC.mjs';
7
+ import { updateSlotsAvailability, getSlotsForTimeRange } from '../chunks/chunk-RM6OQCEO.mjs';
8
+ import { canDropEvent } from '../chunks/chunk-JCNXNPGM.mjs';
9
+ import { getSchedulerEventSurfaceStyle } from '../chunks/chunk-AZRI6PHU.mjs';
10
+ import '../chunks/chunk-6Q5FR4PN.mjs';
11
+ import '../chunks/chunk-P7CIUMQZ.mjs';
12
+ import { addDays, isSameDay } from '../chunks/chunk-XQAYO7CQ.mjs';
13
+ import '../chunks/chunk-F2LYNUXG.mjs';
14
+ import { differenceInCalendarDays, addCalendarDaysToDate, moveDateToCalendarDay } from '../chunks/chunk-6OTDPEJM.mjs';
15
+ import { flattenResourceTree } from '../chunks/chunk-XMU4WSAX.mjs';
16
+
17
+ // src/controllers/month.controller.ts
18
+ var RESIZE_EDGE_SIZE = 12;
19
+ function detectResizeEdgeForAllDay(relativeX, elementWidth, threshold = RESIZE_EDGE_SIZE) {
20
+ if (relativeX <= threshold) return "start";
21
+ if (relativeX >= elementWidth - threshold) return "end";
22
+ return null;
23
+ }
24
+ function calculateDragClickOffset(eventStart, clickedDate, calendarOptions) {
25
+ return differenceInCalendarDays(eventStart, clickedDate, calendarOptions);
26
+ }
27
+ function processMonthDragMove(state, targetDate, dragClickDayOffset, mouseX, mouseY, calendarOptions) {
28
+ const result = {
29
+ dragGhostPosition: {
30
+ x: mouseX - state.offsetX,
31
+ y: mouseY - state.offsetY
32
+ },
33
+ dropTargetDate: targetDate,
34
+ delta: state.delta,
35
+ previewEvent: null,
36
+ shouldEmitDragStart: !state.isDragging && state.hasMovedMinDistance,
37
+ shouldEmitDrag: false
38
+ };
39
+ if (targetDate) {
40
+ const originalEvent = state.originalEvent;
41
+ const originalStart = typeof originalEvent.start === "string" ? new Date(originalEvent.start) : originalEvent.start;
42
+ const targetStartDate = addCalendarDaysToDate(targetDate, -dragClickDayOffset, calendarOptions);
43
+ const daysDelta = differenceInCalendarDays(originalStart, targetStartDate, calendarOptions);
44
+ result.delta = { days: daysDelta, milliseconds: 0 };
45
+ result.previewEvent = applyDeltaToEvent(originalEvent, result.delta, calendarOptions);
46
+ result.shouldEmitDrag = true;
47
+ }
48
+ return result;
49
+ }
50
+ function finalizeMonthDrag(state, context, calendarOptions) {
51
+ const { originalEvent, delta, isDragging } = state;
52
+ if (!isDragging || delta.days === 0) {
53
+ return {
54
+ success: false,
55
+ newEvent: null,
56
+ delta,
57
+ wasBlocked: false
58
+ };
59
+ }
60
+ const newEvent = applyDeltaToEvent(originalEvent, delta, calendarOptions);
61
+ if (!context.eventOverlap) {
62
+ const overlapping = findOverlappingEvents(newEvent, context.parsedEvents);
63
+ if (overlapping.length > 0) {
64
+ return {
65
+ success: false,
66
+ newEvent: null,
67
+ delta,
68
+ wasBlocked: true
69
+ };
70
+ }
71
+ }
72
+ return {
73
+ success: true,
74
+ newEvent,
75
+ delta,
76
+ wasBlocked: false
77
+ };
78
+ }
79
+ function calculateResizeDeltas(originalEvent, targetDate, resizeEdge, calendarOptions) {
80
+ const originalStart = typeof originalEvent.start === "string" ? new Date(originalEvent.start) : originalEvent.start;
81
+ const originalEnd = originalEvent.end ? typeof originalEvent.end === "string" ? new Date(originalEvent.end) : originalEvent.end : new Date(originalStart);
82
+ let startDelta = 0;
83
+ let endDelta = 0;
84
+ if (resizeEdge === "start") {
85
+ const newStart = moveDateToCalendarDay(originalStart, targetDate, calendarOptions);
86
+ startDelta = newStart.getTime() - originalStart.getTime();
87
+ if (newStart > originalEnd) {
88
+ startDelta = originalEnd.getTime() - originalStart.getTime();
89
+ }
90
+ } else {
91
+ const newEnd = moveDateToCalendarDay(originalEnd, targetDate, calendarOptions);
92
+ endDelta = newEnd.getTime() - originalEnd.getTime();
93
+ if (newEnd < originalStart) {
94
+ endDelta = originalStart.getTime() - originalEnd.getTime();
95
+ }
96
+ }
97
+ return { startDelta, endDelta };
98
+ }
99
+ function calculateResizePreviewPosition(previewEvent, grid, originalRow) {
100
+ const previewStart = typeof previewEvent.start === "string" ? new Date(previewEvent.start) : previewEvent.start;
101
+ const previewEnd = previewEvent.end ? typeof previewEvent.end === "string" ? new Date(previewEvent.end) : previewEvent.end : previewStart;
102
+ const results = [];
103
+ for (let weekIndex = 0; weekIndex < grid.length; weekIndex++) {
104
+ const week = grid[weekIndex];
105
+ const weekStart = week[0].date;
106
+ const weekEnd = addDays(weekStart, 6);
107
+ weekEnd.setHours(23, 59, 59, 999);
108
+ if (previewStart <= weekEnd && previewEnd >= weekStart) {
109
+ let startCol = -1;
110
+ let endCol = 6;
111
+ for (let col = 0; col < 7; col++) {
112
+ const cellDate = week[col].date;
113
+ if (startCol === -1 && (isSameDay(cellDate, previewStart) || cellDate > previewStart)) {
114
+ startCol = col;
115
+ }
116
+ if (isSameDay(cellDate, previewEnd) || cellDate >= previewEnd) {
117
+ endCol = col;
118
+ break;
119
+ }
120
+ }
121
+ if (previewStart < weekStart) startCol = 0;
122
+ if (startCol === -1) startCol = 0;
123
+ if (previewEnd > weekEnd) endCol = 6;
124
+ results.push({
125
+ weekIndex,
126
+ startCol,
127
+ endCol,
128
+ row: originalRow,
129
+ event: previewEvent
130
+ });
131
+ }
132
+ }
133
+ return results;
134
+ }
135
+ function processMonthResizeMove(state, targetDate, grid, calendarOptions) {
136
+ const { startDelta, endDelta } = calculateResizeDeltas(state.originalEvent, targetDate, state.resizeEdge, calendarOptions);
137
+ const previewEvent = applyResizeToEvent(state.originalEvent, startDelta, endDelta);
138
+ const previewData = calculateResizePreviewPosition(previewEvent, grid, state.originalRow ?? 0);
139
+ return {
140
+ resizeTargetDate: targetDate,
141
+ startDelta,
142
+ endDelta,
143
+ previewEvent,
144
+ previewData
145
+ };
146
+ }
147
+ function finalizeMonthResize(state, context) {
148
+ const { originalEvent, startDelta, endDelta, isResizing } = state;
149
+ if (!isResizing || startDelta === 0 && endDelta === 0) {
150
+ return {
151
+ success: false,
152
+ newEvent: null,
153
+ wasBlocked: false
154
+ };
155
+ }
156
+ const newEvent = applyResizeToEvent(originalEvent, startDelta, endDelta);
157
+ if (!context.eventOverlap) {
158
+ const overlapping = findOverlappingEvents(newEvent, context.parsedEvents);
159
+ if (overlapping.length > 0) {
160
+ return {
161
+ success: false,
162
+ newEvent: null,
163
+ wasBlocked: true
164
+ };
165
+ }
166
+ }
167
+ return {
168
+ success: true,
169
+ newEvent,
170
+ wasBlocked: false
171
+ };
172
+ }
173
+ function findEventPositionInGrid(event, grid, getWeekEventPositions) {
174
+ for (let weekIndex = 0; weekIndex < grid.length; weekIndex++) {
175
+ const week = grid[weekIndex];
176
+ const positions = getWeekEventPositions(week);
177
+ for (const pos of positions) {
178
+ if (pos.event.id === event.id) {
179
+ return { weekIndex, startCol: pos.startCol, endCol: pos.endCol, row: pos.row };
180
+ }
181
+ }
182
+ }
183
+ return null;
184
+ }
185
+ function getDragGhostStyle(position, dimensions, event) {
186
+ return {
187
+ position: "fixed",
188
+ left: `${position.x}px`,
189
+ top: `${position.y}px`,
190
+ width: dimensions ? `${dimensions.width}px` : "auto",
191
+ height: dimensions ? `${dimensions.height}px` : "auto",
192
+ ...getSchedulerEventSurfaceStyle(event, {}),
193
+ background: "var(--p-scheduler-event-background)",
194
+ color: "var(--p-scheduler-event-color)",
195
+ padding: "0.25rem 0.5rem",
196
+ borderRadius: "var(--p-scheduler-event-border-radius)",
197
+ fontSize: "0.75rem",
198
+ fontWeight: "500",
199
+ lineHeight: "1.2",
200
+ pointerEvents: "none",
201
+ zIndex: "9999",
202
+ opacity: "0.9",
203
+ boxShadow: "var(--p-scheduler-event-shadow)",
204
+ whiteSpace: "nowrap",
205
+ overflow: "hidden",
206
+ textOverflow: "ellipsis",
207
+ display: "flex",
208
+ alignItems: "center",
209
+ boxSizing: "border-box"
210
+ };
211
+ }
212
+
213
+ // src/controllers/timed.controller.ts
214
+ function resolveTimedPointerStart(input) {
215
+ if (!input.canDrag && !input.canResize) {
216
+ return { mode: "none" };
217
+ }
218
+ if (!input.rect) {
219
+ return { mode: "none" };
220
+ }
221
+ const rect = input.rect;
222
+ const relativeY = input.pointer.clientY - rect.top;
223
+ const resizeEdge = input.canResize ? detectResizeEdge(relativeY, 0, rect.height) : null;
224
+ if (resizeEdge) {
225
+ return {
226
+ mode: "resize",
227
+ resizeState: createResizeState(input.event, resizeEdge, input.pointer.clientY)
228
+ };
229
+ }
230
+ if (!input.canDrag) {
231
+ return { mode: "none" };
232
+ }
233
+ const offsetX = input.pointer.clientX - rect.left;
234
+ const offsetY = input.pointer.clientY - rect.top;
235
+ return {
236
+ mode: "drag",
237
+ dragState: createDragState(input.event, input.pointer.clientX, input.pointer.clientY, offsetX, offsetY)
238
+ };
239
+ }
240
+ function dispatchTimedPointerMove(hasDragState, hasResizeState, handlers, pointer) {
241
+ if (hasDragState) {
242
+ handlers.onDrag(pointer);
243
+ return;
244
+ }
245
+ if (hasResizeState) {
246
+ handlers.onResize(pointer);
247
+ }
248
+ }
249
+ function dispatchTimedPointerEnd(hasDragState, hasResizeState, handlers, pointer) {
250
+ if (hasDragState) {
251
+ handlers.onDrag(pointer);
252
+ return;
253
+ }
254
+ if (hasResizeState) {
255
+ handlers.onResize(pointer);
256
+ }
257
+ }
258
+ function calculateTimedDragDelta(state, columnWidth, slotHeight, slotDuration, snapDuration) {
259
+ const dxPixels = state.currentX - state.startX;
260
+ const dyPixels = state.currentY - state.startY;
261
+ const daysDelta = Math.round(dxPixels / columnWidth);
262
+ const minutesDelta = dyPixels / slotHeight * slotDuration;
263
+ const snappedMinutes = snapToSlot(minutesDelta, snapDuration);
264
+ const msDelta = snappedMinutes * 60 * 1e3;
265
+ return {
266
+ daysDelta,
267
+ millisecondsDelta: msDelta,
268
+ delta: { days: daysDelta, milliseconds: msDelta }
269
+ };
270
+ }
271
+ function findColumnIndexForDate(date, columns) {
272
+ return columns.findIndex((col) => {
273
+ const d1 = col.date;
274
+ return d1.getFullYear() === date.getFullYear() && d1.getMonth() === date.getMonth() && d1.getDate() === date.getDate();
275
+ });
276
+ }
277
+ function calculateTimedDragPreview(previewEvent, columns, slotMinTime, slotDuration, slotHeight) {
278
+ const previewStart = typeof previewEvent.start === "string" ? new Date(previewEvent.start) : previewEvent.start;
279
+ const previewColIndex = findColumnIndexForDate(previewStart, columns);
280
+ if (previewColIndex < 0 || previewColIndex >= columns.length) {
281
+ return null;
282
+ }
283
+ const previewEnd = previewEvent.end ? typeof previewEvent.end === "string" ? new Date(previewEvent.end) : previewEvent.end : new Date(previewStart.getTime() + 30 * 60 * 1e3);
284
+ const top = getYPositionFromTime(previewStart, slotMinTime, slotDuration, slotHeight);
285
+ const endY = getYPositionFromTime(previewEnd, slotMinTime, slotDuration, slotHeight);
286
+ const height = endY - top;
287
+ return {
288
+ colIndex: previewColIndex,
289
+ top,
290
+ height: Math.max(height, slotHeight / 2)
291
+ };
292
+ }
293
+ function processTimedDragMove(state, columnWidth, columns, context, snapDuration, calendarOptions) {
294
+ const { delta } = calculateTimedDragDelta(state, columnWidth, context.slotHeight, context.slotDuration, snapDuration);
295
+ const previewEvent = applyDeltaToEvent(state.originalEvent, delta, calendarOptions);
296
+ const preview = calculateTimedDragPreview(previewEvent, columns, context.slotMinTime, context.slotDuration, context.slotHeight);
297
+ if (!preview) {
298
+ return null;
299
+ }
300
+ return {
301
+ delta,
302
+ previewEvent,
303
+ previewColIndex: preview.colIndex,
304
+ previewTop: preview.top,
305
+ previewHeight: preview.height
306
+ };
307
+ }
308
+ function finalizeTimedDrag(state, context, calendarOptions) {
309
+ const { originalEvent, delta, isDragging } = state;
310
+ if (!isDragging || delta.days === 0 && delta.milliseconds === 0) {
311
+ return {
312
+ success: false,
313
+ newEvent: null,
314
+ delta,
315
+ wasBlocked: false
316
+ };
317
+ }
318
+ const newEvent = applyDeltaToEvent(originalEvent, delta, calendarOptions);
319
+ if (!context.eventOverlap) {
320
+ const overlapping = findOverlappingEvents(newEvent, context.parsedEvents);
321
+ if (overlapping.length > 0) {
322
+ return {
323
+ success: false,
324
+ newEvent: null,
325
+ delta,
326
+ wasBlocked: true
327
+ };
328
+ }
329
+ }
330
+ return {
331
+ success: true,
332
+ newEvent,
333
+ delta,
334
+ wasBlocked: false
335
+ };
336
+ }
337
+ function calculateTimedResizePreview(previewEvent, columns, slotMinTime, slotDuration, slotHeight) {
338
+ const previewStart = typeof previewEvent.start === "string" ? new Date(previewEvent.start) : previewEvent.start;
339
+ const previewColIndex = findColumnIndexForDate(previewStart, columns);
340
+ if (previewColIndex < 0) {
341
+ return null;
342
+ }
343
+ const previewEnd = previewEvent.end ? typeof previewEvent.end === "string" ? new Date(previewEvent.end) : previewEvent.end : new Date(previewStart.getTime() + 30 * 60 * 1e3);
344
+ const top = getYPositionFromTime(previewStart, slotMinTime, slotDuration, slotHeight);
345
+ const endY = getYPositionFromTime(previewEnd, slotMinTime, slotDuration, slotHeight);
346
+ const height = endY - top;
347
+ return {
348
+ colIndex: previewColIndex,
349
+ top,
350
+ height: Math.max(height, slotHeight / 2)
351
+ };
352
+ }
353
+ function processTimedResizeMove(state, columns, context) {
354
+ const { originalEvent, startDelta, endDelta } = state;
355
+ const previewEvent = applyResizeToEvent(originalEvent, startDelta, endDelta);
356
+ const preview = calculateTimedResizePreview(previewEvent, columns, context.slotMinTime, context.slotDuration, context.slotHeight);
357
+ if (!preview) {
358
+ return null;
359
+ }
360
+ return {
361
+ previewEvent,
362
+ previewColIndex: preview.colIndex,
363
+ previewTop: preview.top,
364
+ previewHeight: preview.height
365
+ };
366
+ }
367
+ function finalizeTimedResize(state, context) {
368
+ const { originalEvent, startDelta, endDelta, isResizing } = state;
369
+ if (!isResizing || startDelta === 0 && endDelta === 0) {
370
+ return {
371
+ success: false,
372
+ newEvent: null,
373
+ startDelta,
374
+ endDelta,
375
+ wasBlocked: false
376
+ };
377
+ }
378
+ const newEvent = applyResizeToEvent(originalEvent, startDelta, endDelta);
379
+ if (!context.eventOverlap) {
380
+ const overlapping = findOverlappingEvents(newEvent, context.parsedEvents);
381
+ if (overlapping.length > 0) {
382
+ return {
383
+ success: false,
384
+ newEvent: null,
385
+ startDelta,
386
+ endDelta,
387
+ wasBlocked: true
388
+ };
389
+ }
390
+ }
391
+ return {
392
+ success: true,
393
+ newEvent,
394
+ startDelta,
395
+ endDelta,
396
+ wasBlocked: false
397
+ };
398
+ }
399
+ function getTimedPreviewStyle(top, height, event) {
400
+ return {
401
+ position: "absolute",
402
+ top: `${top}px`,
403
+ height: `${height}px`,
404
+ left: "var(--p-scheduler-timed-event-inset-inline-start, 2px)",
405
+ right: "var(--p-scheduler-timed-event-inset-inline-end, 4px)",
406
+ zIndex: "100",
407
+ pointerEvents: "none",
408
+ opacity: "0.7",
409
+ ...getSchedulerEventSurfaceStyle(event, {}),
410
+ background: "var(--p-scheduler-event-background)",
411
+ borderColor: "var(--p-scheduler-event-border-color)",
412
+ color: "var(--p-scheduler-event-color)"
413
+ };
414
+ }
415
+ function hasTimedDropConstraints(eventConstraint, eventAllow, blockedIntervals) {
416
+ return Boolean(eventConstraint || eventAllow || blockedIntervals);
417
+ }
418
+ function toEventDate(value) {
419
+ if (!value) {
420
+ return null;
421
+ }
422
+ if (value instanceof Date) {
423
+ return new Date(value);
424
+ }
425
+ const parsed = new Date(value);
426
+ if (Number.isNaN(parsed.getTime())) {
427
+ return null;
428
+ }
429
+ return parsed;
430
+ }
431
+ function canDropTimedPreviewEvent(input) {
432
+ if (!input.previewEvent || !input.originalEvent) {
433
+ return true;
434
+ }
435
+ const start = toEventDate(input.previewEvent.start);
436
+ if (!start) {
437
+ return true;
438
+ }
439
+ const end = toEventDate(input.previewEvent.end) ?? start;
440
+ const resourceId = input.resourceId ?? input.previewEvent.resourceId;
441
+ return canDropEvent(start, end, false, input.view, input.originalEvent, input.eventConstraint, input.eventAllow, input.businessHours, input.blockedIntervals, resourceId);
442
+ }
443
+
444
+ // src/controllers/timeline.controller.ts
445
+ function resolveTimelineSnapDuration(slotDuration, explicitSnapDuration) {
446
+ if (explicitSnapDuration !== void 0) return explicitSnapDuration;
447
+ if (slotDuration >= 60 && slotDuration % 30 === 0) return 30;
448
+ if (slotDuration >= 30 && slotDuration % 15 === 0) return 15;
449
+ return slotDuration;
450
+ }
451
+ var TIMELINE_RESIZE_EDGE_SIZE = 12;
452
+ var TIMELINE_DRAG_VIEWS = /* @__PURE__ */ new Set(["timelineDay", "timelineWeek", "timelineMonth", "resourceTimelineDay", "resourceTimelineWeek", "resourceTimelineMonth"]);
453
+ function isTimelineDragView(view) {
454
+ return typeof view === "string" && TIMELINE_DRAG_VIEWS.has(view);
455
+ }
456
+ function getStartOfDayTime(date) {
457
+ const copy = new Date(date);
458
+ copy.setHours(0, 0, 0, 0);
459
+ return copy.getTime();
460
+ }
461
+ function getMinutesOfDay(date) {
462
+ return date.getHours() * 60 + date.getMinutes() + date.getSeconds() / 60 + date.getMilliseconds() / 6e4;
463
+ }
464
+ function clampTimelineDragStartToVisibleRange(input) {
465
+ const { originalStart, originalEnd, targetStart, minTimeMinutes, visibleMinutesPerDay } = input;
466
+ if (!originalEnd) return targetStart;
467
+ const durationMs = originalEnd.getTime() - originalStart.getTime();
468
+ if (durationMs <= 0 || durationMs > visibleMinutesPerDay * 6e4) {
469
+ return targetStart;
470
+ }
471
+ const originalEndMinutes = getMinutesOfDay(originalEnd);
472
+ const visibleEndMinutes = minTimeMinutes + visibleMinutesPerDay;
473
+ const originalFitsSingleVisibleDay = getStartOfDayTime(originalStart) === getStartOfDayTime(originalEnd) && getMinutesOfDay(originalStart) >= minTimeMinutes && originalEndMinutes <= visibleEndMinutes && originalEndMinutes >= minTimeMinutes;
474
+ if (!originalFitsSingleVisibleDay) {
475
+ return targetStart;
476
+ }
477
+ const targetDayStart = new Date(targetStart);
478
+ targetDayStart.setHours(0, 0, 0, 0);
479
+ const minStartMs = targetDayStart.getTime() + minTimeMinutes * 6e4;
480
+ const maxStartMs = targetDayStart.getTime() + visibleEndMinutes * 6e4 - durationMs;
481
+ if (maxStartMs < minStartMs) {
482
+ return targetStart;
483
+ }
484
+ return new Date(Math.min(Math.max(targetStart.getTime(), minStartMs), maxStartMs));
485
+ }
486
+ function detectResizeEdgeForTimeline(relativeX, elementWidth, threshold = TIMELINE_RESIZE_EDGE_SIZE) {
487
+ if (relativeX <= threshold) return "start";
488
+ if (relativeX >= elementWidth - threshold) return "end";
489
+ return null;
490
+ }
491
+ function createTimelineDragState(event, startX, startY, offsetX, offsetY) {
492
+ return {
493
+ event: { ...event },
494
+ originalEvent: { ...event },
495
+ startX,
496
+ startY,
497
+ currentX: startX,
498
+ currentY: startY,
499
+ offsetX,
500
+ offsetY,
501
+ delta: { days: 0, milliseconds: 0 },
502
+ isDragging: false,
503
+ hasMovedMinDistance: false
504
+ };
505
+ }
506
+ function updateTimelineDragState(state, currentX, currentY, minDistance = DEFAULT_DRAG_MIN_DISTANCE) {
507
+ const dx = currentX - state.startX;
508
+ const dy = currentY - state.startY;
509
+ const distance = Math.sqrt(dx * dx + dy * dy);
510
+ return {
511
+ ...state,
512
+ currentX,
513
+ currentY,
514
+ hasMovedMinDistance: state.hasMovedMinDistance || distance >= minDistance,
515
+ isDragging: state.hasMovedMinDistance || distance >= minDistance
516
+ };
517
+ }
518
+ function calculateTimelineDragDelta(state, context) {
519
+ const { viewStart, viewEnd, totalWidth, slotDuration, snapDuration, minTimeMinutes, maxTimeMinutes, view } = context;
520
+ const dxPixels = state.currentX - state.startX;
521
+ const snapMinutes = snapDuration ?? slotDuration;
522
+ const timelineView = isTimelineDragView(view) ? view : null;
523
+ if (timelineView && minTimeMinutes !== void 0 && maxTimeMinutes !== void 0) {
524
+ const visibleDayStarts = getTimelineVisibleDayStarts(timelineView, viewStart, viewEnd);
525
+ if (visibleDayStarts.length > 0) {
526
+ const originalStart = state.originalEvent.start instanceof Date ? state.originalEvent.start : new Date(state.originalEvent.start);
527
+ const originalEnd = state.originalEvent.end ? state.originalEvent.end instanceof Date ? state.originalEvent.end : new Date(state.originalEvent.end) : null;
528
+ const visibleMinutesPerDay = Math.max(1, maxTimeMinutes - minTimeMinutes);
529
+ const dayWidth = totalWidth / Math.max(1, visibleDayStarts.length);
530
+ const sourceStartX = timeToTimelinePixels({
531
+ date: originalStart,
532
+ view: timelineView,
533
+ cells: [],
534
+ visibleDayStarts,
535
+ dayWidth,
536
+ minTimeMin: minTimeMinutes,
537
+ visibleMinutesPerDay,
538
+ totalWidth
539
+ });
540
+ const targetStart = timelinePixelsToTime({
541
+ x: sourceStartX + dxPixels,
542
+ view: timelineView,
543
+ visibleDayStarts,
544
+ dayWidth,
545
+ minTimeMin: minTimeMinutes,
546
+ visibleMinutesPerDay,
547
+ totalWidth,
548
+ snapDurationMin: snapMinutes
549
+ });
550
+ const clampedTargetStart = clampTimelineDragStartToVisibleRange({
551
+ originalStart,
552
+ originalEnd,
553
+ targetStart,
554
+ minTimeMinutes,
555
+ visibleMinutesPerDay
556
+ });
557
+ return getSchedulerEventDropDelta(originalStart, clampedTargetStart, context);
558
+ }
559
+ }
560
+ let totalDuration;
561
+ if (minTimeMinutes !== void 0 && maxTimeMinutes !== void 0) {
562
+ const businessMinutesPerDay = maxTimeMinutes - minTimeMinutes;
563
+ const dayCount = Math.ceil((viewEnd.getTime() - viewStart.getTime()) / (24 * 60 * 60 * 1e3));
564
+ totalDuration = dayCount * businessMinutesPerDay * 60 * 1e3;
565
+ } else {
566
+ totalDuration = viewEnd.getTime() - viewStart.getTime();
567
+ }
568
+ const msPerPixel = totalDuration / totalWidth;
569
+ const rawTimeDelta = dxPixels * msPerPixel;
570
+ const slotMs = snapMinutes * 60 * 1e3;
571
+ const snappedTimeDelta = Math.round(rawTimeDelta / slotMs) * slotMs;
572
+ return { days: 0, milliseconds: snappedTimeDelta };
573
+ }
574
+ function processTimelineDragMove(state, mouseX, mouseY, context, minDistance = DEFAULT_DRAG_MIN_DISTANCE) {
575
+ const updatedState = updateTimelineDragState(state, mouseX, mouseY, minDistance);
576
+ const delta = calculateTimelineDragDelta(updatedState, context);
577
+ const result = {
578
+ dragGhostPosition: {
579
+ x: mouseX - updatedState.offsetX,
580
+ y: mouseY - updatedState.offsetY
581
+ },
582
+ delta,
583
+ previewEvent: null,
584
+ shouldEmitDragStart: !state.isDragging && updatedState.hasMovedMinDistance,
585
+ shouldEmitDrag: false
586
+ };
587
+ if (updatedState.hasMovedMinDistance) {
588
+ result.previewEvent = applyDeltaToEvent(state.originalEvent, delta, context);
589
+ result.shouldEmitDrag = true;
590
+ }
591
+ return result;
592
+ }
593
+ function finalizeTimelineDrag(state, delta, context) {
594
+ const { originalEvent, isDragging } = state;
595
+ const hasTimeDelta = delta.days !== 0 || delta.milliseconds !== 0;
596
+ const hasResourceTargetDelta = context.targetResourceId !== void 0 && context.targetResourceId !== originalEvent.resourceId || context.targetResourceIds !== void 0 && (context.targetResourceIds.length !== (originalEvent.resourceIds?.length ?? 0) || context.targetResourceIds.some((resourceId, index) => resourceId !== originalEvent.resourceIds?.[index]));
597
+ if (!isDragging || !hasTimeDelta && !hasResourceTargetDelta) {
598
+ return { success: false, newEvent: null, delta, wasBlocked: false };
599
+ }
600
+ const newEvent = applyDeltaToEvent(originalEvent, delta, context);
601
+ if (context.overlapPolicy === "prevent" && context.allEvents) {
602
+ const candidateEvent = {
603
+ ...newEvent,
604
+ resourceId: context.targetResourceId ?? newEvent.resourceId,
605
+ resourceIds: context.targetResourceIds ?? newEvent.resourceIds
606
+ };
607
+ if (hasOverlapInAnyAssignedResource(candidateEvent, context.allEvents)) {
608
+ return { success: false, newEvent: null, delta, wasBlocked: true };
609
+ }
610
+ } else if (!context.eventOverlap) {
611
+ const overlapping = findOverlappingEvents(newEvent, context.parsedEvents);
612
+ if (overlapping.length > 0) {
613
+ return { success: false, newEvent: null, delta, wasBlocked: true };
614
+ }
615
+ }
616
+ return { success: true, newEvent, delta, wasBlocked: false };
617
+ }
618
+ function createTimelineResizeState(event, edge, startX, startY) {
619
+ return {
620
+ event: { ...event },
621
+ originalEvent: { ...event },
622
+ edge,
623
+ startX,
624
+ currentX: startX,
625
+ startY,
626
+ currentY: startY,
627
+ startDelta: 0,
628
+ endDelta: 0,
629
+ visualStartPx: 0,
630
+ visualEndPx: 0,
631
+ isResizing: false
632
+ };
633
+ }
634
+ function calculateTimelineResizeDeltas(state, context) {
635
+ const { viewStart, viewEnd, totalWidth, slotDuration, snapDuration, minTimeMinutes, maxTimeMinutes } = context;
636
+ let totalDuration;
637
+ if (minTimeMinutes !== void 0 && maxTimeMinutes !== void 0) {
638
+ const businessMinutesPerDay = maxTimeMinutes - minTimeMinutes;
639
+ const dayCount = Math.ceil((viewEnd.getTime() - viewStart.getTime()) / (24 * 60 * 60 * 1e3));
640
+ totalDuration = dayCount * businessMinutesPerDay * 60 * 1e3;
641
+ } else {
642
+ totalDuration = viewEnd.getTime() - viewStart.getTime();
643
+ }
644
+ const dxPixels = state.currentX - state.startX;
645
+ const msPerPixel = totalDuration / totalWidth;
646
+ const rawTimeDelta = dxPixels * msPerPixel;
647
+ const snapMs = (snapDuration ?? slotDuration) * 60 * 1e3;
648
+ const snappedTimeDelta = Math.round(rawTimeDelta / snapMs) * snapMs;
649
+ const originalEvent = state.originalEvent;
650
+ const originalStart = typeof originalEvent.start === "string" ? new Date(originalEvent.start) : originalEvent.start;
651
+ const originalEnd = originalEvent.end ? typeof originalEvent.end === "string" ? new Date(originalEvent.end) : originalEvent.end : new Date(originalStart.getTime() + 60 * 60 * 1e3);
652
+ const preview = getSchedulerTimelineResizePreview({
653
+ edge: state.edge,
654
+ event: originalEvent,
655
+ start: originalStart,
656
+ end: originalEnd,
657
+ deltaMs: snappedTimeDelta,
658
+ snapMinutes: snapMs / 6e4
659
+ });
660
+ return { startDelta: preview.startDelta, endDelta: preview.endDelta };
661
+ }
662
+ function calculateBusinessTimeOffset(datetime, viewStart, minTimeMinutes, maxTimeMinutes) {
663
+ const msPerDay = 24 * 60 * 60 * 1e3;
664
+ const businessMinutesPerDay = maxTimeMinutes - minTimeMinutes;
665
+ const msPerBusinessDay = businessMinutesPerDay * 60 * 1e3;
666
+ const viewStartDay = new Date(viewStart);
667
+ viewStartDay.setHours(0, 0, 0, 0);
668
+ const targetDay = new Date(datetime);
669
+ targetDay.setHours(0, 0, 0, 0);
670
+ const daysDiff = Math.floor((targetDay.getTime() - viewStartDay.getTime()) / msPerDay);
671
+ const fullDaysOffset = daysDiff * msPerBusinessDay;
672
+ const timeMinutes = datetime.getHours() * 60 + datetime.getMinutes();
673
+ const clampedMinutes = Math.max(minTimeMinutes, Math.min(maxTimeMinutes, timeMinutes));
674
+ const minutesIntoBusinessDay = clampedMinutes - minTimeMinutes;
675
+ return fullDaysOffset + minutesIntoBusinessDay * 60 * 1e3;
676
+ }
677
+ function calculateResizePreviewStyle(originalEvent, startDelta, endDelta, context) {
678
+ const { viewStart, viewEnd, minTimeMinutes, maxTimeMinutes } = context;
679
+ const originalStart = typeof originalEvent.start === "string" ? new Date(originalEvent.start) : originalEvent.start;
680
+ const originalEnd = originalEvent.end ? typeof originalEvent.end === "string" ? new Date(originalEvent.end) : originalEvent.end : new Date(originalStart.getTime() + 60 * 60 * 1e3);
681
+ const newStart = new Date(originalStart.getTime() + startDelta);
682
+ const newEnd = new Date(originalEnd.getTime() + endDelta);
683
+ let leftPercent;
684
+ let widthPercent;
685
+ if (minTimeMinutes !== void 0 && maxTimeMinutes !== void 0) {
686
+ const businessMinutesPerDay = maxTimeMinutes - minTimeMinutes;
687
+ const dayCount = Math.ceil((viewEnd.getTime() - viewStart.getTime()) / (24 * 60 * 60 * 1e3));
688
+ const totalBusinessMs = dayCount * businessMinutesPerDay * 60 * 1e3;
689
+ const startOffset = calculateBusinessTimeOffset(newStart, viewStart, minTimeMinutes, maxTimeMinutes);
690
+ const endOffset = calculateBusinessTimeOffset(newEnd, viewStart, minTimeMinutes, maxTimeMinutes);
691
+ leftPercent = startOffset / totalBusinessMs * 100;
692
+ widthPercent = (endOffset - startOffset) / totalBusinessMs * 100;
693
+ } else {
694
+ const totalDuration = viewEnd.getTime() - viewStart.getTime();
695
+ leftPercent = (newStart.getTime() - viewStart.getTime()) / totalDuration * 100;
696
+ widthPercent = (newEnd.getTime() - newStart.getTime()) / totalDuration * 100;
697
+ }
698
+ return {
699
+ left: `calc(${leftPercent}% + 2px)`,
700
+ width: `calc(${Math.max(widthPercent, 1)}% - 4px)`
701
+ };
702
+ }
703
+ function processTimelineResizeMove(state, mouseX, context) {
704
+ const updatedState = {
705
+ ...state,
706
+ currentX: mouseX,
707
+ isResizing: Math.abs(mouseX - state.startX) > 2
708
+ };
709
+ const { startDelta, endDelta } = calculateTimelineResizeDeltas(updatedState, context);
710
+ const previewEvent = applyResizeToEvent(state.originalEvent, startDelta, endDelta);
711
+ const previewStyle = calculateResizePreviewStyle(state.originalEvent, startDelta, endDelta, context);
712
+ return {
713
+ startDelta,
714
+ endDelta,
715
+ previewEvent,
716
+ previewStyle
717
+ };
718
+ }
719
+ function finalizeTimelineResize(state, startDelta, endDelta, context) {
720
+ const { originalEvent, isResizing } = state;
721
+ if (!isResizing || startDelta === 0 && endDelta === 0) {
722
+ return { success: false, newEvent: null, wasBlocked: false };
723
+ }
724
+ const newEvent = applyResizeToEvent(originalEvent, startDelta, endDelta);
725
+ if (context.overlapPolicy === "prevent" && context.allEvents) {
726
+ const candidateEvent = {
727
+ ...newEvent,
728
+ resourceId: context.targetResourceId ?? newEvent.resourceId,
729
+ resourceIds: context.targetResourceIds ?? newEvent.resourceIds
730
+ };
731
+ if (hasOverlapInAnyAssignedResource(candidateEvent, context.allEvents)) {
732
+ return { success: false, newEvent: null, wasBlocked: true };
733
+ }
734
+ } else if (!context.eventOverlap) {
735
+ const overlapping = findOverlappingEvents(newEvent, context.parsedEvents);
736
+ if (overlapping.length > 0) {
737
+ return { success: false, newEvent: null, wasBlocked: true };
738
+ }
739
+ }
740
+ return { success: true, newEvent, wasBlocked: false };
741
+ }
742
+ function getTimelineDragGhostStyle(position, dimensions, event) {
743
+ return {
744
+ position: "fixed",
745
+ left: `${position.x}px`,
746
+ top: `${position.y}px`,
747
+ width: dimensions ? `${dimensions.width}px` : "auto",
748
+ height: dimensions ? `${dimensions.height}px` : "auto",
749
+ ...getSchedulerEventSurfaceStyle(event, {}),
750
+ background: "var(--p-scheduler-event-background)",
751
+ color: "var(--p-scheduler-event-color)",
752
+ padding: "0.25rem 0.375rem",
753
+ borderRadius: "var(--p-scheduler-event-border-radius)",
754
+ borderInlineStart: "var(--p-scheduler-event-accent-width) solid var(--p-scheduler-event-border-accent)",
755
+ pointerEvents: "none",
756
+ zIndex: "9999",
757
+ opacity: "0.9",
758
+ boxShadow: "var(--p-scheduler-event-shadow)",
759
+ overflow: "hidden",
760
+ display: "flex",
761
+ flexDirection: "column",
762
+ justifyContent: "center",
763
+ alignItems: "flex-start",
764
+ gap: "0.125rem",
765
+ boxSizing: "border-box"
766
+ };
767
+ }
768
+
769
+ // src/controllers/slot-tracking.controller.ts
770
+ var APPOINTMENT_SLOT_TIMED_VIEWS = /* @__PURE__ */ new Set(["day", "week", "resourceDay", "resourceWeek", "dateDay", "dateWeek"]);
771
+ var RESOURCE_SCOPED_SLOT_TRACKING_VIEWS = /* @__PURE__ */ new Set(["resourceDay", "resourceWeek", "dateDay", "dateWeek"]);
772
+ function createAppointmentSlotTrackingState() {
773
+ return {
774
+ initialized: false,
775
+ snapshots: /* @__PURE__ */ new Map(),
776
+ previousEvents: []
777
+ };
778
+ }
779
+ function isAppointmentSlotTrackingView(view) {
780
+ return APPOINTMENT_SLOT_TIMED_VIEWS.has(view);
781
+ }
782
+ function requiresResourceScopedSlotTracking(view) {
783
+ return RESOURCE_SCOPED_SLOT_TRACKING_VIEWS.has(view);
784
+ }
785
+ function getSlotTrackingKey(slot) {
786
+ const slotStart = slot.start instanceof Date ? slot.start : new Date(slot.start);
787
+ const slotEnd = slot.end instanceof Date ? slot.end : new Date(slot.end);
788
+ const resourceKey = slot.resourceId === void 0 ? "" : String(slot.resourceId);
789
+ return `${String(slot.id)}|${slotStart.getTime()}|${slotEnd.getTime()}|${resourceKey}`;
790
+ }
791
+ function cloneEventForSlotTracking(event) {
792
+ return {
793
+ ...event,
794
+ start: event.start instanceof Date ? new Date(event.start) : event.start,
795
+ end: event.end instanceof Date ? new Date(event.end) : event.end,
796
+ resourceIds: event.resourceIds ? [...event.resourceIds] : event.resourceIds
797
+ };
798
+ }
799
+ function resolveEventDate(value) {
800
+ if (!value) return null;
801
+ const parsed = value instanceof Date ? new Date(value) : new Date(value);
802
+ return Number.isNaN(parsed.getTime()) ? null : parsed;
803
+ }
804
+ function resolveEventRangeForSlotTracking(event) {
805
+ const start = resolveEventDate(event.start);
806
+ if (!start) return null;
807
+ const end = resolveEventDate(event.end);
808
+ if (end) {
809
+ return { start, end };
810
+ }
811
+ const durationMinutes = typeof event.duration === "number" && event.duration > 0 ? event.duration : 30;
812
+ return { start, end: new Date(start.getTime() + durationMinutes * 6e4) };
813
+ }
814
+ function getEventScheduleSignature(event) {
815
+ const range = resolveEventRangeForSlotTracking(event);
816
+ const resources = getEventResourceIds(event).map((id) => String(id)).sort().join(",");
817
+ const startKey = range ? range.start.getTime() : "invalid";
818
+ const endKey = range ? range.end.getTime() : "invalid";
819
+ return `${startKey}|${endKey}|${resources}`;
820
+ }
821
+ function doesEventOverlapSlot(event, slot) {
822
+ const range = resolveEventRangeForSlotTracking(event);
823
+ if (!range) return false;
824
+ const slotStart = slot.start instanceof Date ? slot.start : new Date(slot.start);
825
+ const slotEnd = slot.end instanceof Date ? slot.end : new Date(slot.end);
826
+ const overlaps = range.start < slotEnd && range.end > slotStart;
827
+ if (!overlaps) {
828
+ return false;
829
+ }
830
+ if (slot.resourceId === void 0) {
831
+ return true;
832
+ }
833
+ const eventResourceIds = getEventResourceIds(event);
834
+ return eventResourceIds.includes(slot.resourceId);
835
+ }
836
+ function resolveResourceScopes(context) {
837
+ if (!requiresResourceScopedSlotTracking(context.view)) {
838
+ return [void 0];
839
+ }
840
+ const leaves = flattenResourceTree(context.resources).filter((resource) => !resource.children || resource.children.length === 0);
841
+ return leaves.length > 0 ? leaves : [void 0];
842
+ }
843
+ function collectVisibleAppointmentSlots(context) {
844
+ const resourceScopes = resolveResourceScopes(context);
845
+ const slots = [];
846
+ for (const resource of resourceScopes) {
847
+ slots.push(...getSlotsForTimeRange(context.options, context.viewRange.start, context.viewRange.end, resource, context.slotMinTime, context.slotMaxTime));
848
+ }
849
+ return slots;
850
+ }
851
+ function buildSlotTrackingSnapshot(context, eventList) {
852
+ const slots = collectVisibleAppointmentSlots(context);
853
+ const updatedSlots = updateSlotsAvailability(slots, eventList);
854
+ const snapshot = /* @__PURE__ */ new Map();
855
+ for (const slot of updatedSlots) {
856
+ snapshot.set(getSlotTrackingKey(slot), {
857
+ slot,
858
+ bookedCount: slot.bookedCount ?? 0
859
+ });
860
+ }
861
+ return snapshot;
862
+ }
863
+ function findBookingCandidate(slot, currentEvents, previousEvents) {
864
+ const previousById = new Map(previousEvents.map((event) => [event.id, getEventScheduleSignature(event)]));
865
+ for (const event of currentEvents) {
866
+ const previousSignature = previousById.get(event.id);
867
+ const currentSignature = getEventScheduleSignature(event);
868
+ if (previousSignature === currentSignature) {
869
+ continue;
870
+ }
871
+ if (doesEventOverlapSlot(event, slot)) {
872
+ return event;
873
+ }
874
+ }
875
+ return null;
876
+ }
877
+ function findCancellationCandidate(slot, currentEvents, previousEvents) {
878
+ const currentById = new Map(currentEvents.map((event) => [event.id, getEventScheduleSignature(event)]));
879
+ for (const event of previousEvents) {
880
+ const currentSignature = currentById.get(event.id);
881
+ const previousSignature = getEventScheduleSignature(event);
882
+ if (currentSignature === previousSignature) {
883
+ continue;
884
+ }
885
+ if (doesEventOverlapSlot(event, slot)) {
886
+ return event;
887
+ }
888
+ }
889
+ return null;
890
+ }
891
+ function syncAppointmentSlotTracking(state, context, currentEvents) {
892
+ if (!context.options.enabled || !isAppointmentSlotTrackingView(context.view)) {
893
+ return {
894
+ state: createAppointmentSlotTrackingState(),
895
+ changes: []
896
+ };
897
+ }
898
+ const currentSnapshot = buildSlotTrackingSnapshot(context, currentEvents);
899
+ if (!state.initialized) {
900
+ return {
901
+ state: {
902
+ initialized: true,
903
+ snapshots: currentSnapshot,
904
+ previousEvents: currentEvents.map(cloneEventForSlotTracking)
905
+ },
906
+ changes: []
907
+ };
908
+ }
909
+ const changes = [];
910
+ const previousSnapshot = state.snapshots;
911
+ const previousEvents = state.previousEvents;
912
+ for (const [slotKey, currentState] of currentSnapshot.entries()) {
913
+ const previousState = previousSnapshot.get(slotKey);
914
+ const previousBookedCount = previousState?.bookedCount ?? 0;
915
+ const currentBookedCount = currentState.bookedCount;
916
+ if (currentBookedCount > previousBookedCount) {
917
+ const bookingEvent = findBookingCandidate(currentState.slot, currentEvents, previousEvents);
918
+ if (bookingEvent) {
919
+ changes.push({
920
+ type: "book",
921
+ slot: currentState.slot,
922
+ event: bookingEvent
923
+ });
924
+ }
925
+ } else if (currentBookedCount < previousBookedCount) {
926
+ const canceledEvent = findCancellationCandidate(currentState.slot, currentEvents, previousEvents);
927
+ if (canceledEvent) {
928
+ changes.push({
929
+ type: "cancel",
930
+ slot: currentState.slot,
931
+ event: canceledEvent
932
+ });
933
+ }
934
+ }
935
+ }
936
+ return {
937
+ state: {
938
+ initialized: true,
939
+ snapshots: currentSnapshot,
940
+ previousEvents: currentEvents.map(cloneEventForSlotTracking)
941
+ },
942
+ changes
943
+ };
944
+ }
945
+
946
+ export { RESIZE_EDGE_SIZE, TIMELINE_RESIZE_EDGE_SIZE, calculateDragClickOffset, calculateResizeDeltas, calculateResizePreviewPosition, calculateResizePreviewStyle, calculateTimedDragDelta, calculateTimedDragPreview, calculateTimedResizePreview, calculateTimelineDragDelta, calculateTimelineResizeDeltas, canDropTimedPreviewEvent, cloneEventForSlotTracking, createAppointmentSlotTrackingState, createTimelineDragState, createTimelineResizeState, detectResizeEdgeForAllDay, detectResizeEdgeForTimeline, dispatchTimedPointerEnd, dispatchTimedPointerMove, finalizeMonthDrag, finalizeMonthResize, finalizeTimedDrag, finalizeTimedResize, finalizeTimelineDrag, finalizeTimelineResize, findColumnIndexForDate, findEventPositionInGrid, getDragGhostStyle, getSlotTrackingKey, getTimedPreviewStyle, getTimelineDragGhostStyle, hasTimedDropConstraints, isAppointmentSlotTrackingView, processMonthDragMove, processMonthResizeMove, processTimedDragMove, processTimedResizeMove, processTimelineDragMove, processTimelineResizeMove, resolveTimedPointerStart, resolveTimelineSnapDuration, syncAppointmentSlotTracking, updateTimelineDragState };