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