@mantine-vue/schedule 3.5.0 → 3.7.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 (29) hide show
  1. package/cjs/index.cjs +925 -185
  2. package/cjs/index.cjs.map +1 -1
  3. package/esm/index.mjs +925 -186
  4. package/esm/index.mjs.map +1 -1
  5. package/lib/component-props.d.ts +11 -1
  6. package/lib/components/DayView/DayView.vue.d.ts +2 -0
  7. package/lib/components/MonthView/MonthView.types.d.ts +9 -1
  8. package/lib/components/MonthView/MonthView.vue.d.ts +2 -0
  9. package/lib/components/MonthView/get-month-view-events/reserve-row.d.ts +7 -0
  10. package/lib/components/ResourcesDayView/ResourcesDayView.types.d.ts +10 -1
  11. package/lib/components/ResourcesDayView/ResourcesDayView.vue.d.ts +2 -0
  12. package/lib/components/ResourcesMonthView/ResourcesMonthView.types.d.ts +10 -1
  13. package/lib/components/ResourcesMonthView/ResourcesMonthView.vue.d.ts +2 -0
  14. package/lib/components/ResourcesSchedule/ResourcesSchedule.types.d.ts +10 -1
  15. package/lib/components/ResourcesSchedule/ResourcesSchedule.vue.d.ts +2 -0
  16. package/lib/components/ResourcesWeekView/ResourcesWeekView.types.d.ts +10 -1
  17. package/lib/components/ResourcesWeekView/ResourcesWeekView.vue.d.ts +2 -0
  18. package/lib/components/Schedule/Schedule.types.d.ts +11 -1
  19. package/lib/components/Schedule/Schedule.vue.d.ts +2 -0
  20. package/lib/components/WeekView/WeekView.vue.d.ts +2 -0
  21. package/lib/hooks/use-event-resize.d.ts +6 -1
  22. package/lib/hooks/use-horizontal-event-resize.d.ts +6 -0
  23. package/lib/hooks/validate-event-resize.d.ts +26 -0
  24. package/lib/types.d.ts +38 -0
  25. package/lib/utils/index.d.ts +2 -0
  26. package/lib/utils/is-event-placement-allowed/is-event-placement-allowed.d.ts +13 -0
  27. package/package.json +4 -4
  28. package/styles.css +494 -441
  29. package/styles.layer.css +494 -441
package/cjs/index.cjs CHANGED
@@ -384,6 +384,45 @@ function isEventsOverlap(event1, event2) {
384
384
  return first.startTimestamp < second.endTimestamp && second.startTimestamp < first.endTimestamp;
385
385
  }
386
386
  //#endregion
387
+ //#region src/utils/is-event-placement-allowed/is-event-placement-allowed.ts
388
+ function isSameEvent(event, other) {
389
+ if (event.id === other.id) return true;
390
+ const eventSeriesId = event.recurringEventId ?? event.recurringInstance?.recurringEventId;
391
+ const otherSeriesId = other.recurringEventId ?? other.recurringInstance?.recurringEventId;
392
+ const eventOccurrenceId = event.recurrenceId ?? event.recurringInstance?.recurrenceId;
393
+ const otherOccurrenceId = other.recurrenceId ?? other.recurringInstance?.recurrenceId;
394
+ return eventSeriesId !== void 0 && eventSeriesId === otherSeriesId && eventOccurrenceId !== void 0 && eventOccurrenceId === otherOccurrenceId;
395
+ }
396
+ var isMidnight = (value) => value.hour() === 0 && value.minute() === 0 && value.second() === 0;
397
+ function spansWholeDays(event) {
398
+ const start = (0, dayjs.default)(event.start);
399
+ const end = (0, dayjs.default)(event.end);
400
+ return isMidnight(start) && (isMidnight(end) || end.hour() === 23 && end.minute() === 59 && end.second() === 59);
401
+ }
402
+ function isEventPlacementAllowed({ event, start, end, events, preventEventOverlap, resourceId }) {
403
+ if (!preventEventOverlap) return {
404
+ allowed: true,
405
+ conflicts: []
406
+ };
407
+ const candidate = {
408
+ ...event,
409
+ start,
410
+ end,
411
+ ...resourceId !== void 0 ? { resourceId } : {}
412
+ };
413
+ const allDay = spansWholeDays(candidate);
414
+ const conflicts = events.filter((other) => {
415
+ if (other.display === "background" || isSameEvent(event, other)) return false;
416
+ if (resourceId !== void 0 && other.resourceId !== resourceId) return false;
417
+ if (spansWholeDays(other) !== allDay || !isEventsOverlap(other, candidate)) return false;
418
+ return typeof preventEventOverlap === "function" ? preventEventOverlap(other, candidate) : true;
419
+ });
420
+ return {
421
+ allowed: conflicts.length === 0,
422
+ conflicts
423
+ };
424
+ }
425
+ //#endregion
387
426
  //#region src/utils/get-visible-events/get-visible-events.ts
388
427
  function getVisibleEvents({ maxEvents, totalEvents }) {
389
428
  if (totalEvents <= maxEvents) return {
@@ -956,9 +995,42 @@ function moveEventToAllDay(event, date) {
956
995
  };
957
996
  }
958
997
  //#endregion
998
+ //#region src/hooks/validate-event-resize.ts
999
+ function validateEventResize({ event, start, end, edge, events = [], preventEventOverlap, canResizeEventTo, resourceId }) {
1000
+ const { allowed, conflicts } = isEventPlacementAllowed({
1001
+ event,
1002
+ start,
1003
+ end,
1004
+ events,
1005
+ preventEventOverlap,
1006
+ resourceId
1007
+ });
1008
+ if (!allowed) return {
1009
+ valid: false,
1010
+ conflicts,
1011
+ reason: "overlap"
1012
+ };
1013
+ if (canResizeEventTo?.({
1014
+ event,
1015
+ start,
1016
+ end,
1017
+ edge
1018
+ }) === false) return {
1019
+ valid: false,
1020
+ conflicts: [],
1021
+ reason: "rejected"
1022
+ };
1023
+ return {
1024
+ valid: true,
1025
+ conflicts: [],
1026
+ reason: null
1027
+ };
1028
+ }
1029
+ //#endregion
959
1030
  //#region src/hooks/use-event-resize.ts
960
1031
  function useEventResize(input) {
961
1032
  const resizeState = (0, vue.shallowRef)(null);
1033
+ const resizeValid = (0, vue.shallowRef)(true);
962
1034
  let justResized = false;
963
1035
  let savedUserSelect = null;
964
1036
  const clampAndSnap = (minutes, state) => {
@@ -1000,6 +1072,18 @@ function useEventResize(input) {
1000
1072
  currentTop,
1001
1073
  currentHeight
1002
1074
  };
1075
+ const next = resizeState.value;
1076
+ const start = next.edge === "top" ? percentToDateTime(next.currentTop, next.eventDate, next) : next.originalStart;
1077
+ const end = next.edge === "bottom" ? percentToDateTime(next.currentTop + next.currentHeight, next.eventDate, next) : next.originalEnd;
1078
+ resizeValid.value = validateEventResize({
1079
+ event: next.event,
1080
+ start,
1081
+ end,
1082
+ edge: next.edge === "top" ? "start" : "end",
1083
+ events: input.events?.() ?? [],
1084
+ preventEventOverlap: input.preventEventOverlap?.(),
1085
+ canResizeEventTo: input.canResizeEventTo?.()
1086
+ }).valid;
1003
1087
  });
1004
1088
  const trackPointer = (event) => handlePointerMove(event.clientY);
1005
1089
  const removeDocumentListeners = () => {
@@ -1017,14 +1101,34 @@ function useEventResize(input) {
1017
1101
  if (state && (state.currentTop !== state.originalTop || state.currentHeight !== state.originalHeight)) {
1018
1102
  const newStart = state.edge === "top" ? percentToDateTime(state.currentTop, state.eventDate, state) : state.originalStart;
1019
1103
  const newEnd = state.edge === "bottom" ? percentToDateTime(state.currentTop + state.currentHeight, state.eventDate, state) : state.originalEnd;
1020
- input.onEventResize({
1104
+ const edge = state.edge === "top" ? "start" : "end";
1105
+ const validation = validateEventResize({
1106
+ event: state.event,
1107
+ start: newStart,
1108
+ end: newEnd,
1109
+ edge,
1110
+ events: input.events?.() ?? [],
1111
+ preventEventOverlap: input.preventEventOverlap?.(),
1112
+ canResizeEventTo: input.canResizeEventTo?.()
1113
+ });
1114
+ if (validation.valid) input.onEventResize({
1021
1115
  eventId: state.eventId,
1022
1116
  newStart,
1023
1117
  newEnd,
1024
1118
  event: state.event
1025
1119
  });
1120
+ else input.onEventPlacementRejected?.({
1121
+ action: "resize",
1122
+ event: state.event,
1123
+ start: newStart,
1124
+ end: newEnd,
1125
+ edge,
1126
+ conflicts: validation.conflicts,
1127
+ reason: validation.reason
1128
+ });
1026
1129
  }
1027
1130
  resizeState.value = null;
1131
+ resizeValid.value = true;
1028
1132
  removeDocumentListeners();
1029
1133
  justResized = true;
1030
1134
  requestAnimationFrame(() => {
@@ -1060,6 +1164,7 @@ function useEventResize(input) {
1060
1164
  intervalMinutes,
1061
1165
  minHeightPercent: intervalMinutes / totalMinutes * 100
1062
1166
  };
1167
+ resizeValid.value = true;
1063
1168
  savedUserSelect = document.body.style.userSelect;
1064
1169
  document.body.style.userSelect = "none";
1065
1170
  document.addEventListener("pointermove", trackPointer);
@@ -1080,7 +1185,8 @@ function useEventResize(input) {
1080
1185
  resizingEventId: (0, vue.computed)(() => resizeState.value?.eventId ?? null),
1081
1186
  getResizePosition,
1082
1187
  isResizableEvent,
1083
- wasResizing: () => justResized
1188
+ wasResizing: () => justResized,
1189
+ resizeValid: (0, vue.computed)(() => resizeValid.value)
1084
1190
  };
1085
1191
  }
1086
1192
  var CurrentTimeIndicator_module_default = {
@@ -1303,9 +1409,9 @@ function provideScheduleDragState(input = {}) {
1303
1409
  };
1304
1410
  }
1305
1411
  var ScheduleEvent_module_default = {
1306
- event: "_event_ho258_1",
1307
- eventInner: "_eventInner_ho258_14",
1308
- eventResizeHandle: "_eventResizeHandle_ho258_210"
1412
+ event: "_event_iymqv_1",
1413
+ eventInner: "_eventInner_iymqv_14",
1414
+ eventResizeHandle: "_eventResizeHandle_iymqv_215"
1309
1415
  };
1310
1416
  //#endregion
1311
1417
  //#region src/components/ScheduleEvent/ScheduleEvent.vue?vue&type=script&setup=true&lang.ts
@@ -2983,19 +3089,19 @@ function getDayViewEvents({ events, date, startTime, endTime, intervalMinutes, e
2983
3089
  };
2984
3090
  }
2985
3091
  var DayView_module_default = {
2986
- dayView: "_dayView_10v37_1",
2987
- dayViewDragPreview: "_dayViewDragPreview_10v37_13",
2988
- dayViewScrollArea: "_dayViewScrollArea_10v37_31",
2989
- dayViewInner: "_dayViewInner_10v37_41",
2990
- dayViewTimeSlots: "_dayViewTimeSlots_10v37_45",
2991
- dayViewSlot: "_dayViewSlot_10v37_48",
2992
- dayViewSlotLabels: "_dayViewSlotLabels_10v37_53",
2993
- dayViewSlotLabel: "_dayViewSlotLabel_10v37_53",
2994
- dayViewSlots: "_dayViewSlots_10v37_83",
2995
- dayViewBackgroundEvent: "_dayViewBackgroundEvent_10v37_187",
2996
- dayViewBackgroundEventResizeHandle: "_dayViewBackgroundEventResizeHandle_10v37_216",
2997
- dayViewAllDay: "_dayViewAllDay_10v37_263",
2998
- dayViewAllDayEvents: "_dayViewAllDayEvents_10v37_268"
3092
+ dayView: "_dayView_18224_1",
3093
+ dayViewDragPreview: "_dayViewDragPreview_18224_13",
3094
+ dayViewScrollArea: "_dayViewScrollArea_18224_31",
3095
+ dayViewInner: "_dayViewInner_18224_41",
3096
+ dayViewTimeSlots: "_dayViewTimeSlots_18224_45",
3097
+ dayViewSlot: "_dayViewSlot_18224_48",
3098
+ dayViewSlotLabels: "_dayViewSlotLabels_18224_53",
3099
+ dayViewSlotLabel: "_dayViewSlotLabel_18224_53",
3100
+ dayViewSlots: "_dayViewSlots_18224_83",
3101
+ dayViewBackgroundEvent: "_dayViewBackgroundEvent_18224_196",
3102
+ dayViewBackgroundEventResizeHandle: "_dayViewBackgroundEventResizeHandle_18224_225",
3103
+ dayViewAllDay: "_dayViewAllDay_18224_272",
3104
+ dayViewAllDayEvents: "_dayViewAllDayEvents_18224_277"
2999
3105
  };
3000
3106
  //#endregion
3001
3107
  //#region src/components/DayView/DayView.vue?vue&type=script&setup=true&lang.ts
@@ -3069,6 +3175,9 @@ var DayView_default = /* @__PURE__ */ (0, vue.defineComponent)({
3069
3175
  type: Function,
3070
3176
  default: void 0
3071
3177
  },
3178
+ canDropEvent: {},
3179
+ canDropExternalEvent: {},
3180
+ preventEventOverlap: { type: [Boolean, Function] },
3072
3181
  withDragSlotSelect: { type: Boolean },
3073
3182
  withExternalEventDrop: { type: Boolean },
3074
3183
  startScrollTime: { default: void 0 },
@@ -3077,6 +3186,7 @@ var DayView_default = /* @__PURE__ */ (0, vue.defineComponent)({
3077
3186
  type: Function,
3078
3187
  default: void 0
3079
3188
  },
3189
+ canResizeEventTo: {},
3080
3190
  date: {},
3081
3191
  events: { default: void 0 },
3082
3192
  locale: { default: void 0 },
@@ -3118,6 +3228,7 @@ var DayView_default = /* @__PURE__ */ (0, vue.defineComponent)({
3118
3228
  "slotDragEnd",
3119
3229
  "externalEventDrop",
3120
3230
  "eventResize",
3231
+ "eventPlacementRejected",
3121
3232
  "dateChange",
3122
3233
  "viewChange",
3123
3234
  "eventClick"
@@ -3158,6 +3269,7 @@ var DayView_default = /* @__PURE__ */ (0, vue.defineComponent)({
3158
3269
  const eventRenderers = (0, vue.computed)(() => resolveEventRenderers(props, slots));
3159
3270
  const timeSlotsContainer = (0, vue.ref)(null);
3160
3271
  const slotDropTarget = useSlotDropTarget();
3272
+ const dropDataTransfer = (0, vue.shallowRef)(null);
3161
3273
  const date = (0, vue.computed)(() => toDateString(props.date));
3162
3274
  const datePart = (0, vue.computed)(() => (0, dayjs.default)(date.value).format("YYYY-MM-DD"));
3163
3275
  const now = (0, vue.computed)(() => (0, dayjs.default)(props.getCurrentTime?.() ?? (0, dayjs.default)()));
@@ -3194,6 +3306,10 @@ var DayView_default = /* @__PURE__ */ (0, vue.defineComponent)({
3194
3306
  resizeIntervalMinutes: () => props.eventResizeInterval,
3195
3307
  onEventResize: (data) => emit("eventResize", data),
3196
3308
  canResizeEvent: () => props.canResizeEvent,
3309
+ events: () => expandedEvents.value,
3310
+ preventEventOverlap: () => props.preventEventOverlap,
3311
+ canResizeEventTo: () => props.canResizeEventTo,
3312
+ onEventPlacementRejected: (data) => emit("eventPlacementRejected", data),
3197
3313
  withBackgroundEvents: () => Boolean(props.withInteractiveBackgroundEvents)
3198
3314
  });
3199
3315
  const slotDragSelect = useSlotDragSelect({
@@ -3216,9 +3332,35 @@ var DayView_default = /* @__PURE__ */ (0, vue.defineComponent)({
3216
3332
  isSlotDragging: () => slotDragSelect.isDragging(),
3217
3333
  onDragEnd: () => {
3218
3334
  slotDropTarget.reset();
3335
+ dropDataTransfer.value = null;
3219
3336
  emit("eventDragEnd");
3220
3337
  }
3221
3338
  });
3339
+ const dropValid = (0, vue.computed)(() => {
3340
+ const target = slotDropTarget.dropTarget.value;
3341
+ const interval = target && intervals.value[target.slotIndex];
3342
+ if (!target || !interval) return true;
3343
+ const start = `${target.date} ${interval.startTime}`;
3344
+ const event = dragState.draggedEvent.value;
3345
+ if (event) {
3346
+ const next = moveEventTo(event, start);
3347
+ return isEventPlacementAllowed({
3348
+ event,
3349
+ start: next.newStart,
3350
+ end: next.newEnd,
3351
+ events: expandedEvents.value,
3352
+ preventEventOverlap: props.preventEventOverlap
3353
+ }).allowed && props.canDropEvent?.({
3354
+ event,
3355
+ start: next.newStart,
3356
+ end: next.newEnd
3357
+ }) !== false;
3358
+ }
3359
+ return dropDataTransfer.value ? props.canDropExternalEvent?.({
3360
+ dataTransfer: dropDataTransfer.value,
3361
+ start
3362
+ }) !== false : true;
3363
+ });
3222
3364
  (0, vue.onMounted)(async () => {
3223
3365
  if (!props.startScrollTime) return;
3224
3366
  await (0, vue.nextTick)();
@@ -3236,14 +3378,79 @@ var DayView_default = /* @__PURE__ */ (0, vue.defineComponent)({
3236
3378
  const emitDrop = (nativeEvent, target) => {
3237
3379
  nativeEvent.preventDefault();
3238
3380
  const event = getDropEvent(expandedEvents.value, nativeEvent.dataTransfer);
3239
- if (event) emit("eventDrop", moveEventTo(event, target));
3240
- else if (nativeEvent.dataTransfer) emit("externalEventDrop", nativeEvent.dataTransfer, target);
3381
+ if (event) {
3382
+ const next = moveEventTo(event, target);
3383
+ const validation = isEventPlacementAllowed({
3384
+ event,
3385
+ start: next.newStart,
3386
+ end: next.newEnd,
3387
+ events: expandedEvents.value,
3388
+ preventEventOverlap: props.preventEventOverlap
3389
+ });
3390
+ if (validation.allowed && props.canDropEvent?.({
3391
+ event,
3392
+ start: next.newStart,
3393
+ end: next.newEnd
3394
+ }) !== false) emit("eventDrop", next);
3395
+ else emit("eventPlacementRejected", {
3396
+ action: "drop",
3397
+ event,
3398
+ start: next.newStart,
3399
+ end: next.newEnd,
3400
+ conflicts: validation.conflicts,
3401
+ reason: validation.allowed ? "rejected" : "overlap"
3402
+ });
3403
+ } else if (nativeEvent.dataTransfer) if (props.canDropExternalEvent?.({
3404
+ dataTransfer: nativeEvent.dataTransfer,
3405
+ start: target
3406
+ }) !== false) emit("externalEventDrop", nativeEvent.dataTransfer, target);
3407
+ else emit("eventPlacementRejected", {
3408
+ action: "external-drop",
3409
+ dataTransfer: nativeEvent.dataTransfer,
3410
+ start: target,
3411
+ conflicts: [],
3412
+ reason: "rejected"
3413
+ });
3241
3414
  };
3242
3415
  const emitAllDayDrop = (nativeEvent) => {
3243
3416
  nativeEvent.preventDefault();
3244
3417
  const event = getDropEvent(expandedEvents.value, nativeEvent.dataTransfer);
3245
- if (event) emit("eventDrop", moveEventToAllDay(event, datePart.value));
3246
- else if (nativeEvent.dataTransfer) emit("externalEventDrop", nativeEvent.dataTransfer, `${datePart.value} 00:00:00`);
3418
+ if (event) {
3419
+ const next = moveEventToAllDay(event, datePart.value);
3420
+ const validation = isEventPlacementAllowed({
3421
+ event,
3422
+ start: next.newStart,
3423
+ end: next.newEnd,
3424
+ events: expandedEvents.value,
3425
+ preventEventOverlap: props.preventEventOverlap
3426
+ });
3427
+ if (validation.allowed && props.canDropEvent?.({
3428
+ event,
3429
+ start: next.newStart,
3430
+ end: next.newEnd
3431
+ }) !== false) emit("eventDrop", next);
3432
+ else emit("eventPlacementRejected", {
3433
+ action: "drop",
3434
+ event,
3435
+ start: next.newStart,
3436
+ end: next.newEnd,
3437
+ conflicts: validation.conflicts,
3438
+ reason: validation.allowed ? "rejected" : "overlap"
3439
+ });
3440
+ } else if (nativeEvent.dataTransfer) {
3441
+ const target = `${datePart.value} 00:00:00`;
3442
+ if (props.canDropExternalEvent?.({
3443
+ dataTransfer: nativeEvent.dataTransfer,
3444
+ start: target
3445
+ }) !== false) emit("externalEventDrop", nativeEvent.dataTransfer, target);
3446
+ else emit("eventPlacementRejected", {
3447
+ action: "external-drop",
3448
+ dataTransfer: nativeEvent.dataTransfer,
3449
+ start: target,
3450
+ conflicts: [],
3451
+ reason: "rejected"
3452
+ });
3453
+ }
3247
3454
  };
3248
3455
  const clickAllDaySlot = (nativeEvent) => emit("allDaySlotClick", date.value, nativeEvent);
3249
3456
  const clickTimeSlot = (slotIndex, nativeEvent) => {
@@ -3264,10 +3471,14 @@ var DayView_default = /* @__PURE__ */ (0, vue.defineComponent)({
3264
3471
  startTime: props.startTime,
3265
3472
  endTime: props.endTime
3266
3473
  });
3267
- const handleGridDragOver = (nativeEvent) => slotDropTarget.dragOver(nativeEvent, dropInput());
3474
+ const handleGridDragOver = (nativeEvent) => {
3475
+ dropDataTransfer.value = nativeEvent.dataTransfer;
3476
+ slotDropTarget.dragOver(nativeEvent, dropInput());
3477
+ };
3268
3478
  const handleGridDragLeave = (nativeEvent) => slotDropTarget.dragLeave(nativeEvent, timeSlotsContainer.value);
3269
3479
  const handleGridDrop = (nativeEvent) => {
3270
3480
  const target = slotDropTarget.drop(nativeEvent, dropInput());
3481
+ dropDataTransfer.value = null;
3271
3482
  if (target) emitDrop(nativeEvent, target.target);
3272
3483
  };
3273
3484
  const handleSlotKeydown = (nativeEvent, index) => {
@@ -3491,7 +3702,10 @@ var DayView_default = /* @__PURE__ */ (0, vue.defineComponent)({
3491
3702
  event,
3492
3703
  "auto-size": "",
3493
3704
  mode: (0, vue.unref)(props).mode,
3494
- mod: { cascade: (0, vue.unref)(props).eventOverlapMode === "cascade" },
3705
+ mod: {
3706
+ cascade: (0, vue.unref)(props).eventOverlapMode === "cascade",
3707
+ invalid: (0, vue.unref)(eventResize).getResizePosition(event.id) !== null && !(0, vue.unref)(eventResize).resizeValid.value
3708
+ },
3495
3709
  style: regularEventStyle(event),
3496
3710
  draggable: !isStatic.value && (0, vue.unref)(props).withEventsDragAndDrop === true && ((0, vue.unref)(props).canDragEvent?.(event) ?? true),
3497
3711
  "with-resize": (0, vue.unref)(eventResize).isResizableEvent(event),
@@ -3551,6 +3765,7 @@ var DayView_default = /* @__PURE__ */ (0, vue.defineComponent)({
3551
3765
  "hour-start": slot.isHourStart,
3552
3766
  static: isStatic.value,
3553
3767
  "drop-target": (0, vue.unref)(slotDropTarget).isTarget(datePart.value, index),
3768
+ invalid: (0, vue.unref)(slotDropTarget).isTarget(datePart.value, index) && !dropValid.value,
3554
3769
  "drag-selected": (0, vue.unref)(slotDragSelect).isSlotSelected(index, datePart.value),
3555
3770
  "business-hours": businessHoursMods.value[index]["business-hours"],
3556
3771
  "non-business-hours": businessHoursMods.value[index]["non-business-hours"]
@@ -3596,10 +3811,16 @@ var DayView = (0, _mantine_vue_core.factory)(DayView_default, {
3596
3811
  });
3597
3812
  //#endregion
3598
3813
  //#region src/components/MobileMonthView/get-mobile-month-view-events.ts
3814
+ function getEventEndDay(event) {
3815
+ const startDay = (0, dayjs.default)(event.start).startOf("day");
3816
+ const end = (0, dayjs.default)(event.end);
3817
+ const endDay = end.hour() === 0 && end.minute() === 0 && end.second() === 0 ? end.startOf("day").subtract(1, "day") : end.startOf("day");
3818
+ return endDay.isBefore(startDay) ? startDay : endDay;
3819
+ }
3599
3820
  function groupEventByDate$1(event, groupedEvents) {
3600
3821
  if (isMultidayEvent(event)) {
3601
3822
  const startDate = (0, dayjs.default)(event.start).startOf("day");
3602
- const endDate = (0, dayjs.default)(event.end).startOf("day");
3823
+ const endDate = getEventEndDay(event);
3603
3824
  for (let date = startDate; date.isBefore(endDate) || date.isSame(endDate); date = date.add(1, "day")) {
3604
3825
  const dateKey = date.format("YYYY-MM-DD");
3605
3826
  if (!groupedEvents[dateKey]) groupedEvents[dateKey] = [];
@@ -3615,9 +3836,11 @@ function getMobileMonthViewEvents({ date, events }) {
3615
3836
  const groupedEvents = {};
3616
3837
  if (events === void 0) return groupedEvents;
3617
3838
  const ids = /* @__PURE__ */ new Set();
3839
+ const monthStart = (0, dayjs.default)(date).startOf("month");
3840
+ const monthEnd = (0, dayjs.default)(date).endOf("month");
3618
3841
  for (const event of events) {
3619
3842
  if (event.display === "background") continue;
3620
- if ((0, dayjs.default)(event.start).isSame((0, dayjs.default)(date), "month")) {
3843
+ if (!getEventEndDay(event).isBefore(monthStart, "day") && !(0, dayjs.default)(event.start).isAfter(monthEnd, "day")) {
3621
3844
  groupEventByDate$1(validateEvent(event), groupedEvents);
3622
3845
  if (!ids.has(event.id)) ids.add(event.id);
3623
3846
  else throw new Error(`[@mantine/schedule] MobileMonthView: Duplicated event ids found: ${event.id}`);
@@ -4004,17 +4227,6 @@ function calculateEventPositionInWeek({ eventStart, eventEnd, weekStart, weekEnd
4004
4227
  };
4005
4228
  }
4006
4229
  //#endregion
4007
- //#region src/components/MonthView/get-month-view-events/find-available-row.ts
4008
- function findAvailableRow({ existingEvents, startDayIndex, daysSpanned, weekStart }) {
4009
- let row = 0;
4010
- for (const existing of existingEvents) {
4011
- const existingStart = (0, dayjs.default)(existing.start).startOf("day");
4012
- const existingDayIndex = (existingStart.isBefore(weekStart) || existingStart.isSame(weekStart, "day") ? weekStart : existingStart).diff(weekStart, "day");
4013
- if (existingDayIndex + (existing.position?.width || 0) / 100 * 7 > startDayIndex && existingDayIndex < startDayIndex + daysSpanned) row = Math.max(row, (existing.position?.row || 0) + 1);
4014
- }
4015
- return row;
4016
- }
4017
- //#endregion
4018
4230
  //#region src/components/MonthView/get-month-view-events/get-weeks-in-range.ts
4019
4231
  function getWeeksInRange({ rangeStart, rangeEnd, firstDayOfWeek }) {
4020
4232
  const weeks = [];
@@ -4039,6 +4251,14 @@ function getWeeksInRange({ rangeStart, rangeEnd, firstDayOfWeek }) {
4039
4251
  };
4040
4252
  }
4041
4253
  //#endregion
4254
+ //#region src/components/MonthView/get-month-view-events/reserve-row.ts
4255
+ function reserveRow({ nextRowByDay, startDayIndex, daysSpanned }) {
4256
+ const endDayIndex = startDayIndex + daysSpanned;
4257
+ const row = Math.max(...nextRowByDay.slice(startDayIndex, endDayIndex));
4258
+ nextRowByDay.fill(row + 1, startDayIndex, endDayIndex);
4259
+ return row;
4260
+ }
4261
+ //#endregion
4042
4262
  //#region src/components/MonthView/get-month-view-events/get-month-positioned-events.ts
4043
4263
  function getMonthPositionedEvents({ date, events, firstDayOfWeek = 1, range }) {
4044
4264
  const groupedByWeek = {};
@@ -4049,6 +4269,11 @@ function getMonthPositionedEvents({ date, events, firstDayOfWeek = 1, range }) {
4049
4269
  rangeEnd: range ? (0, dayjs.default)(range.end) : (0, dayjs.default)(date).startOf("month").endOf("month"),
4050
4270
  firstDayOfWeek
4051
4271
  });
4272
+ const weekStates = weeks.map((week) => ({
4273
+ weekStart: (0, dayjs.default)(week[0]).startOf("day"),
4274
+ weekEnd: (0, dayjs.default)(week[6]).endOf("day"),
4275
+ nextRowByDay: Array.from({ length: 7 }).fill(0)
4276
+ }));
4052
4277
  for (let i = 0; i < weeks.length; i++) {
4053
4278
  groupedByWeek[i.toString()] = [];
4054
4279
  backgroundByWeek[i.toString()] = [];
@@ -4059,9 +4284,7 @@ function getMonthPositionedEvents({ date, events, firstDayOfWeek = 1, range }) {
4059
4284
  const eventEnd = rawEnd.hour() === 0 && rawEnd.minute() === 0 && rawEnd.second() === 0 ? rawEnd.startOf("day").subtract(1, "day") : rawEnd.startOf("day");
4060
4285
  const isMultiday = eventEnd.isAfter(eventStart);
4061
4286
  for (let weekIdx = 0; weekIdx < weeks.length; weekIdx++) {
4062
- const week = weeks[weekIdx];
4063
- const weekStart = (0, dayjs.default)(week[0]).startOf("day");
4064
- const weekEnd = (0, dayjs.default)(week[6]).endOf("day");
4287
+ const { weekStart, weekEnd, nextRowByDay } = weekStates[weekIdx];
4065
4288
  if ((eventStart.isBefore(weekEnd) || eventStart.isSame(weekEnd, "day")) && (eventEnd.isAfter(weekStart) || eventEnd.isSame(weekStart, "day"))) {
4066
4289
  const { startDayIndex, daysSpanned, startOffset, width, hanging } = calculateEventPositionInWeek({
4067
4290
  eventStart,
@@ -4083,11 +4306,10 @@ function getMonthPositionedEvents({ date, events, firstDayOfWeek = 1, range }) {
4083
4306
  });
4084
4307
  continue;
4085
4308
  }
4086
- const row = findAvailableRow({
4087
- existingEvents: groupedByWeek[weekIdx.toString()],
4309
+ const row = reserveRow({
4310
+ nextRowByDay,
4088
4311
  startDayIndex,
4089
- daysSpanned,
4090
- weekStart
4312
+ daysSpanned
4091
4313
  });
4092
4314
  const positionedEvent = {
4093
4315
  ...event,
@@ -4263,16 +4485,16 @@ function getRenderableMonthEventSegments({ events, groupedByDay, maxEventsPerDay
4263
4485
  });
4264
4486
  }
4265
4487
  var MonthView_module_default = {
4266
- monthView: "_monthView_hbhp2_1",
4267
- monthViewWeekdays: "_monthViewWeekdays_hbhp2_21",
4268
- monthViewWeek: "_monthViewWeek_hbhp2_21",
4269
- monthViewWeekNumber: "_monthViewWeekNumber_hbhp2_31",
4270
- monthViewWeekday: "_monthViewWeekday_hbhp2_21",
4271
- monthViewWeekdaysCorner: "_monthViewWeekdaysCorner_hbhp2_107",
4272
- monthViewDay: "_monthViewDay_hbhp2_114",
4273
- monthViewDayLabel: "_monthViewDayLabel_hbhp2_255",
4274
- monthViewBackgroundEvent: "_monthViewBackgroundEvent_hbhp2_271",
4275
- monthViewEvents: "_monthViewEvents_hbhp2_296"
4488
+ monthView: "_monthView_98v2r_1",
4489
+ monthViewWeekdays: "_monthViewWeekdays_98v2r_21",
4490
+ monthViewWeek: "_monthViewWeek_98v2r_21",
4491
+ monthViewWeekNumber: "_monthViewWeekNumber_98v2r_31",
4492
+ monthViewWeekday: "_monthViewWeekday_98v2r_21",
4493
+ monthViewWeekdaysCorner: "_monthViewWeekdaysCorner_98v2r_107",
4494
+ monthViewDay: "_monthViewDay_98v2r_114",
4495
+ monthViewDayLabel: "_monthViewDayLabel_98v2r_264",
4496
+ monthViewBackgroundEvent: "_monthViewBackgroundEvent_98v2r_280",
4497
+ monthViewEvents: "_monthViewEvents_98v2r_305"
4276
4498
  };
4277
4499
  //#endregion
4278
4500
  //#region src/components/MonthView/MonthView.vue?vue&type=script&setup=true&lang.ts
@@ -4281,6 +4503,7 @@ var _hoisted_1$5 = [
4281
4503
  "data-weekend",
4282
4504
  "data-static",
4283
4505
  "data-drop-target",
4506
+ "data-invalid",
4284
4507
  "data-drag-selected",
4285
4508
  "data-drag-slot-index",
4286
4509
  "data-drag-slot-group",
@@ -4355,6 +4578,9 @@ var MonthView_default = /* @__PURE__ */ (0, vue.defineComponent)({
4355
4578
  type: Function,
4356
4579
  default: void 0
4357
4580
  },
4581
+ canDropEvent: {},
4582
+ canDropExternalEvent: {},
4583
+ preventEventOverlap: { type: [Boolean, Function] },
4358
4584
  withExternalEventDrop: { type: Boolean },
4359
4585
  withDragSlotSelect: { type: Boolean },
4360
4586
  monthYearSelectProps: { default: void 0 },
@@ -4400,6 +4626,7 @@ var MonthView_default = /* @__PURE__ */ (0, vue.defineComponent)({
4400
4626
  "eventDragEnd",
4401
4627
  "externalEventDrop",
4402
4628
  "slotDragEnd",
4629
+ "eventPlacementRejected",
4403
4630
  "dateChange",
4404
4631
  "viewChange",
4405
4632
  "eventClick"
@@ -4440,6 +4667,7 @@ var MonthView_default = /* @__PURE__ */ (0, vue.defineComponent)({
4440
4667
  const eventRenderers = (0, vue.computed)(() => resolveEventRenderers(props, slots));
4441
4668
  const monthGrid = (0, vue.ref)(null);
4442
4669
  const dropTarget = (0, vue.shallowRef)(null);
4670
+ const dropValid = (0, vue.ref)(true);
4443
4671
  const isStatic = (0, vue.computed)(() => props.mode === "static");
4444
4672
  const month = (0, vue.computed)(() => (0, dayjs.default)(props.date).startOf("month"));
4445
4673
  const maxEventsPerDay = (0, vue.computed)(() => clampMaxEvents(props.maxEventsPerDay));
@@ -4530,7 +4758,29 @@ var MonthView_default = /* @__PURE__ */ (0, vue.defineComponent)({
4530
4758
  const handleDragOver = (nativeEvent, date) => {
4531
4759
  nativeEvent.preventDefault();
4532
4760
  if (nativeEvent.dataTransfer) nativeEvent.dataTransfer.dropEffect = nativeEvent.dataTransfer.types.includes("application/json") ? "move" : "copy";
4533
- highlightDay(toDateString(date));
4761
+ const target = toDateString(date);
4762
+ const dragged = dragState.draggedEvent.value;
4763
+ if (dragged) {
4764
+ const next = moveEventTo(dragged, target);
4765
+ dropValid.value = isEventPlacementAllowed({
4766
+ event: dragged,
4767
+ start: next.newStart,
4768
+ end: next.newEnd,
4769
+ events: expandedEvents.value,
4770
+ preventEventOverlap: props.preventEventOverlap
4771
+ }).allowed && props.canDropEvent?.({
4772
+ event: dragged,
4773
+ start: next.newStart,
4774
+ end: next.newEnd
4775
+ }) !== false;
4776
+ } else if (nativeEvent.dataTransfer) {
4777
+ const start = `${target} 00:00:00`;
4778
+ dropValid.value = props.canDropExternalEvent?.({
4779
+ dataTransfer: nativeEvent.dataTransfer,
4780
+ start
4781
+ }) !== false;
4782
+ }
4783
+ highlightDay(target);
4534
4784
  };
4535
4785
  const handleDragLeave = (nativeEvent) => {
4536
4786
  if (!(nativeEvent.relatedTarget instanceof Node) || !monthGrid.value?.contains(nativeEvent.relatedTarget)) {
@@ -4542,14 +4792,48 @@ var MonthView_default = /* @__PURE__ */ (0, vue.defineComponent)({
4542
4792
  nativeEvent.preventDefault();
4543
4793
  highlightDay.cancel();
4544
4794
  setDropTarget(null);
4795
+ dropValid.value = true;
4545
4796
  const event = getDropEvent(expandedEvents.value, nativeEvent.dataTransfer);
4546
4797
  if (event) {
4547
4798
  const { start } = calculateMonthDropDate({
4548
4799
  draggedEvent: event,
4549
4800
  targetDay: toDateString(date)
4550
4801
  });
4551
- emit("eventDrop", moveEventTo(event, start));
4552
- } else if (nativeEvent.dataTransfer) emit("externalEventDrop", nativeEvent.dataTransfer, toDateString(date));
4802
+ const next = moveEventTo(event, start);
4803
+ const validation = isEventPlacementAllowed({
4804
+ event,
4805
+ start: next.newStart,
4806
+ end: next.newEnd,
4807
+ events: expandedEvents.value,
4808
+ preventEventOverlap: props.preventEventOverlap
4809
+ });
4810
+ if (validation.allowed && props.canDropEvent?.({
4811
+ event,
4812
+ start: next.newStart,
4813
+ end: next.newEnd
4814
+ }) !== false) emit("eventDrop", next);
4815
+ else emit("eventPlacementRejected", {
4816
+ action: "drop",
4817
+ event,
4818
+ start: next.newStart,
4819
+ end: next.newEnd,
4820
+ conflicts: validation.conflicts,
4821
+ reason: validation.allowed ? "rejected" : "overlap"
4822
+ });
4823
+ } else if (nativeEvent.dataTransfer) {
4824
+ const start = `${toDateString(date)} 00:00:00`;
4825
+ if (props.canDropExternalEvent?.({
4826
+ dataTransfer: nativeEvent.dataTransfer,
4827
+ start
4828
+ }) !== false) emit("externalEventDrop", nativeEvent.dataTransfer, toDateString(date));
4829
+ else emit("eventPlacementRejected", {
4830
+ action: "external-drop",
4831
+ dataTransfer: nativeEvent.dataTransfer,
4832
+ start,
4833
+ conflicts: [],
4834
+ reason: "rejected"
4835
+ });
4836
+ }
4553
4837
  };
4554
4838
  const segmentStyle = (position) => ({
4555
4839
  position: "absolute",
@@ -4623,6 +4907,7 @@ var MonthView_default = /* @__PURE__ */ (0, vue.defineComponent)({
4623
4907
  "data-weekend": (0, vue.unref)(props).weekendDays.includes((0, vue.unref)(dayjs.default)(date).day()) || void 0,
4624
4908
  "data-static": isStatic.value || void 0,
4625
4909
  "data-drop-target": dropTarget.value === (0, vue.unref)(toDateString)(date) || void 0,
4910
+ "data-invalid": dropTarget.value === (0, vue.unref)(toDateString)(date) && !dropValid.value || void 0,
4626
4911
  "data-drag-selected": (0, vue.unref)(slotDragSelect).isSlotSelected(weekIndex * 7 + dayIndex, "month") || void 0,
4627
4912
  "data-drag-slot-index": withSlotSelect.value ? weekIndex * 7 + dayIndex : void 0,
4628
4913
  "data-drag-slot-group": withSlotSelect.value ? MONTH_SLOT_GROUP : void 0,
@@ -5072,29 +5357,29 @@ function getWeekViewEvents(input) {
5072
5357
  });
5073
5358
  }
5074
5359
  var WeekView_module_default = {
5075
- weekView: "_weekView_jkexi_1",
5076
- weekViewRoot: "_weekViewRoot_jkexi_22",
5077
- weekViewDragPreview: "_weekViewDragPreview_jkexi_33",
5078
- weekViewInner: "_weekViewInner_jkexi_39",
5079
- weekViewScrollArea: "_weekViewScrollArea_jkexi_45",
5080
- weekViewHeader: "_weekViewHeader_jkexi_51",
5081
- weekViewCorner: "_weekViewCorner_jkexi_66",
5082
- weekViewSlotLabels: "_weekViewSlotLabels_jkexi_77",
5083
- weekViewSlotLabel: "_weekViewSlotLabel_jkexi_77",
5084
- weekViewDay: "_weekViewDay_jkexi_104",
5085
- weekViewDayLabel: "_weekViewDayLabel_jkexi_109",
5086
- weekViewDayNumber: "_weekViewDayNumber_jkexi_147",
5087
- weekViewDayWeekday: "_weekViewDayWeekday_jkexi_163",
5088
- weekViewBackgroundEvent: "_weekViewBackgroundEvent_jkexi_169",
5089
- weekViewBackgroundEventResizeHandle: "_weekViewBackgroundEventResizeHandle_jkexi_198",
5090
- weekViewDaySlots: "_weekViewDaySlots_jkexi_246",
5091
- weekViewDaySlot: "_weekViewDaySlot_jkexi_246",
5092
- weekViewWeekLabel: "_weekViewWeekLabel_jkexi_344",
5093
- weekViewWeekNumber: "_weekViewWeekNumber_jkexi_350",
5094
- weekViewAllDaySlots: "_weekViewAllDaySlots_jkexi_356",
5095
- weekViewAllDaySlotsLabel: "_weekViewAllDaySlotsLabel_jkexi_361",
5096
- weekViewAllDaySlotsEvents: "_weekViewAllDaySlotsEvents_jkexi_368",
5097
- weekViewAllDaySlotsList: "_weekViewAllDaySlotsList_jkexi_375"
5360
+ weekView: "_weekView_1ttnb_1",
5361
+ weekViewRoot: "_weekViewRoot_1ttnb_22",
5362
+ weekViewDragPreview: "_weekViewDragPreview_1ttnb_33",
5363
+ weekViewInner: "_weekViewInner_1ttnb_39",
5364
+ weekViewScrollArea: "_weekViewScrollArea_1ttnb_45",
5365
+ weekViewHeader: "_weekViewHeader_1ttnb_51",
5366
+ weekViewCorner: "_weekViewCorner_1ttnb_66",
5367
+ weekViewSlotLabels: "_weekViewSlotLabels_1ttnb_77",
5368
+ weekViewSlotLabel: "_weekViewSlotLabel_1ttnb_77",
5369
+ weekViewDay: "_weekViewDay_1ttnb_104",
5370
+ weekViewDayLabel: "_weekViewDayLabel_1ttnb_109",
5371
+ weekViewDayNumber: "_weekViewDayNumber_1ttnb_147",
5372
+ weekViewDayWeekday: "_weekViewDayWeekday_1ttnb_163",
5373
+ weekViewBackgroundEvent: "_weekViewBackgroundEvent_1ttnb_169",
5374
+ weekViewBackgroundEventResizeHandle: "_weekViewBackgroundEventResizeHandle_1ttnb_198",
5375
+ weekViewDaySlots: "_weekViewDaySlots_1ttnb_246",
5376
+ weekViewDaySlot: "_weekViewDaySlot_1ttnb_246",
5377
+ weekViewWeekLabel: "_weekViewWeekLabel_1ttnb_353",
5378
+ weekViewWeekNumber: "_weekViewWeekNumber_1ttnb_359",
5379
+ weekViewAllDaySlots: "_weekViewAllDaySlots_1ttnb_365",
5380
+ weekViewAllDaySlotsLabel: "_weekViewAllDaySlotsLabel_1ttnb_370",
5381
+ weekViewAllDaySlotsEvents: "_weekViewAllDaySlotsEvents_1ttnb_377",
5382
+ weekViewAllDaySlotsList: "_weekViewAllDaySlotsList_1ttnb_384"
5098
5383
  };
5099
5384
  //#endregion
5100
5385
  //#region src/components/WeekView/WeekView.vue?vue&type=script&setup=true&lang.ts
@@ -5210,6 +5495,9 @@ var WeekView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5210
5495
  type: Function,
5211
5496
  default: void 0
5212
5497
  },
5498
+ canDropEvent: {},
5499
+ canDropExternalEvent: {},
5500
+ preventEventOverlap: { type: [Boolean, Function] },
5213
5501
  withDragSlotSelect: { type: Boolean },
5214
5502
  withExternalEventDrop: { type: Boolean },
5215
5503
  startScrollTime: { default: void 0 },
@@ -5218,6 +5506,7 @@ var WeekView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5218
5506
  type: Function,
5219
5507
  default: void 0
5220
5508
  },
5509
+ canResizeEventTo: {},
5221
5510
  date: {},
5222
5511
  events: { default: void 0 },
5223
5512
  locale: { default: void 0 },
@@ -5259,6 +5548,7 @@ var WeekView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5259
5548
  "slotDragEnd",
5260
5549
  "externalEventDrop",
5261
5550
  "eventResize",
5551
+ "eventPlacementRejected",
5262
5552
  "dateChange",
5263
5553
  "viewChange",
5264
5554
  "eventClick"
@@ -5303,6 +5593,7 @@ var WeekView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5303
5593
  };
5304
5594
  const daySlotsContainers = /* @__PURE__ */ new Map();
5305
5595
  const slotDropTarget = useSlotDropTarget();
5596
+ const dropDataTransfer = (0, vue.shallowRef)(null);
5306
5597
  const isStatic = (0, vue.computed)(() => props.mode === "static");
5307
5598
  /** The plural names are the deprecated aliases; the canonical prop wins when both are set. */
5308
5599
  const withWeekNumber = (0, vue.computed)(() => props.withWeekNumbers ?? props.withWeekNumber);
@@ -5394,6 +5685,10 @@ var WeekView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5394
5685
  resizeIntervalMinutes: () => props.eventResizeInterval,
5395
5686
  onEventResize: (data) => emit("eventResize", data),
5396
5687
  canResizeEvent: () => props.canResizeEvent,
5688
+ events: () => expandedEvents.value,
5689
+ preventEventOverlap: () => props.preventEventOverlap,
5690
+ canResizeEventTo: () => props.canResizeEventTo,
5691
+ onEventPlacementRejected: (data) => emit("eventPlacementRejected", data),
5397
5692
  withBackgroundEvents: () => Boolean(props.withInteractiveBackgroundEvents)
5398
5693
  });
5399
5694
  const slotDragSelect = useSlotDragSelect({
@@ -5425,9 +5720,35 @@ var WeekView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5425
5720
  isSlotDragging: () => slotDragSelect.isDragging(),
5426
5721
  onDragEnd: () => {
5427
5722
  slotDropTarget.reset();
5723
+ dropDataTransfer.value = null;
5428
5724
  emit("eventDragEnd");
5429
5725
  }
5430
5726
  });
5727
+ const dropValid = (0, vue.computed)(() => {
5728
+ const target = slotDropTarget.dropTarget.value;
5729
+ const interval = target && intervals.value[target.slotIndex];
5730
+ if (!target || !interval) return true;
5731
+ const start = `${target.date} ${interval.startTime}`;
5732
+ const event = dragState.draggedEvent.value;
5733
+ if (event) {
5734
+ const next = moveEventTo(event, start);
5735
+ return isEventPlacementAllowed({
5736
+ event,
5737
+ start: next.newStart,
5738
+ end: next.newEnd,
5739
+ events: expandedEvents.value,
5740
+ preventEventOverlap: props.preventEventOverlap
5741
+ }).allowed && props.canDropEvent?.({
5742
+ event,
5743
+ start: next.newStart,
5744
+ end: next.newEnd
5745
+ }) !== false;
5746
+ }
5747
+ return dropDataTransfer.value ? props.canDropExternalEvent?.({
5748
+ dataTransfer: dropDataTransfer.value,
5749
+ start
5750
+ }) !== false : true;
5751
+ });
5431
5752
  const clickEvent = (event, nativeEvent) => emit("eventClick", event, nativeEvent);
5432
5753
  const dragStart = (event) => {
5433
5754
  dragState.startEventDrag(event);
@@ -5481,15 +5802,80 @@ var WeekView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5481
5802
  const emitDrop = (nativeEvent, target) => {
5482
5803
  nativeEvent.preventDefault();
5483
5804
  const event = getDropEvent(expandedEvents.value, nativeEvent.dataTransfer);
5484
- if (event) emit("eventDrop", moveEventTo(event, target));
5485
- else if (nativeEvent.dataTransfer) emit("externalEventDrop", nativeEvent.dataTransfer, target);
5805
+ if (event) {
5806
+ const next = moveEventTo(event, target);
5807
+ const validation = isEventPlacementAllowed({
5808
+ event,
5809
+ start: next.newStart,
5810
+ end: next.newEnd,
5811
+ events: expandedEvents.value,
5812
+ preventEventOverlap: props.preventEventOverlap
5813
+ });
5814
+ if (validation.allowed && props.canDropEvent?.({
5815
+ event,
5816
+ start: next.newStart,
5817
+ end: next.newEnd
5818
+ }) !== false) emit("eventDrop", next);
5819
+ else emit("eventPlacementRejected", {
5820
+ action: "drop",
5821
+ event,
5822
+ start: next.newStart,
5823
+ end: next.newEnd,
5824
+ conflicts: validation.conflicts,
5825
+ reason: validation.allowed ? "rejected" : "overlap"
5826
+ });
5827
+ } else if (nativeEvent.dataTransfer) if (props.canDropExternalEvent?.({
5828
+ dataTransfer: nativeEvent.dataTransfer,
5829
+ start: target
5830
+ }) !== false) emit("externalEventDrop", nativeEvent.dataTransfer, target);
5831
+ else emit("eventPlacementRejected", {
5832
+ action: "external-drop",
5833
+ dataTransfer: nativeEvent.dataTransfer,
5834
+ start: target,
5835
+ conflicts: [],
5836
+ reason: "rejected"
5837
+ });
5486
5838
  };
5487
5839
  const emitAllDayDrop = (nativeEvent, date) => {
5488
5840
  nativeEvent.preventDefault();
5489
5841
  const dayKey = (0, dayjs.default)(date).format("YYYY-MM-DD");
5490
5842
  const event = getDropEvent(expandedEvents.value, nativeEvent.dataTransfer);
5491
- if (event) emit("eventDrop", moveEventToAllDay(event, dayKey));
5492
- else if (nativeEvent.dataTransfer) emit("externalEventDrop", nativeEvent.dataTransfer, `${dayKey} 00:00:00`);
5843
+ if (event) {
5844
+ const next = moveEventToAllDay(event, dayKey);
5845
+ const validation = isEventPlacementAllowed({
5846
+ event,
5847
+ start: next.newStart,
5848
+ end: next.newEnd,
5849
+ events: expandedEvents.value,
5850
+ preventEventOverlap: props.preventEventOverlap
5851
+ });
5852
+ if (validation.allowed && props.canDropEvent?.({
5853
+ event,
5854
+ start: next.newStart,
5855
+ end: next.newEnd
5856
+ }) !== false) emit("eventDrop", next);
5857
+ else emit("eventPlacementRejected", {
5858
+ action: "drop",
5859
+ event,
5860
+ start: next.newStart,
5861
+ end: next.newEnd,
5862
+ conflicts: validation.conflicts,
5863
+ reason: validation.allowed ? "rejected" : "overlap"
5864
+ });
5865
+ } else if (nativeEvent.dataTransfer) {
5866
+ const target = `${dayKey} 00:00:00`;
5867
+ if (props.canDropExternalEvent?.({
5868
+ dataTransfer: nativeEvent.dataTransfer,
5869
+ start: target
5870
+ }) !== false) emit("externalEventDrop", nativeEvent.dataTransfer, target);
5871
+ else emit("eventPlacementRejected", {
5872
+ action: "external-drop",
5873
+ dataTransfer: nativeEvent.dataTransfer,
5874
+ start: target,
5875
+ conflicts: [],
5876
+ reason: "rejected"
5877
+ });
5878
+ }
5493
5879
  };
5494
5880
  const dropInput = (date) => ({
5495
5881
  container: daySlotsContainers.get(date),
@@ -5500,10 +5886,14 @@ var WeekView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5500
5886
  startTime: props.startTime,
5501
5887
  endTime: props.endTime
5502
5888
  });
5503
- const handleDayDragOver = (nativeEvent, date) => slotDropTarget.dragOver(nativeEvent, dropInput(date));
5889
+ const handleDayDragOver = (nativeEvent, date) => {
5890
+ dropDataTransfer.value = nativeEvent.dataTransfer;
5891
+ slotDropTarget.dragOver(nativeEvent, dropInput(date));
5892
+ };
5504
5893
  const handleDayDragLeave = (nativeEvent, date) => slotDropTarget.dragLeave(nativeEvent, daySlotsContainers.get(date));
5505
5894
  const handleDayDrop = (nativeEvent, date) => {
5506
5895
  const target = slotDropTarget.drop(nativeEvent, dropInput(date));
5896
+ dropDataTransfer.value = null;
5507
5897
  if (target) emitDrop(nativeEvent, target.target);
5508
5898
  };
5509
5899
  const allDayEventStyle = (position) => ({
@@ -5714,6 +6104,7 @@ var WeekView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5714
6104
  "data-drag-slot-index": withSlotSelect.value ? slotIndex : void 0,
5715
6105
  "data-drag-slot-group": withSlotSelect.value ? column.key : void 0,
5716
6106
  "data-drop-target": (0, vue.unref)(slotDropTarget).isTarget(column.key, slotIndex) || void 0,
6107
+ "data-invalid": (0, vue.unref)(slotDropTarget).isTarget(column.key, slotIndex) && !dropValid.value ? true : void 0,
5717
6108
  "data-drag-selected": (0, vue.unref)(slotDragSelect).isSlotSelected(slotIndex, column.key) || void 0,
5718
6109
  "data-business-hours": businessHoursMods.value[dayIndex][slotIndex]["business-hours"] || void 0,
5719
6110
  "data-non-business-hours": businessHoursMods.value[dayIndex][slotIndex]["non-business-hours"] || void 0,
@@ -5730,6 +6121,7 @@ var WeekView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5730
6121
  "data-drag-slot-index",
5731
6122
  "data-drag-slot-group",
5732
6123
  "data-drop-target",
6124
+ "data-invalid",
5733
6125
  "data-drag-selected",
5734
6126
  "data-business-hours",
5735
6127
  "data-non-business-hours",
@@ -5772,7 +6164,10 @@ var WeekView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5772
6164
  event,
5773
6165
  "auto-size": "",
5774
6166
  mode: (0, vue.unref)(props).mode,
5775
- mod: { cascade: (0, vue.unref)(props).eventOverlapMode === "cascade" },
6167
+ mod: {
6168
+ cascade: (0, vue.unref)(props).eventOverlapMode === "cascade",
6169
+ invalid: (0, vue.unref)(eventResize).getResizePosition(event.id) !== null && !(0, vue.unref)(eventResize).resizeValid.value
6170
+ },
5776
6171
  style: regularEventStyle(event),
5777
6172
  draggable: isDraggableEvent(event),
5778
6173
  "with-resize": (0, vue.unref)(eventResize).isResizableEvent(event),
@@ -6237,6 +6632,22 @@ var Schedule_default = /* @__PURE__ */ (0, vue.defineComponent)({
6237
6632
  type: Function,
6238
6633
  default: void 0
6239
6634
  },
6635
+ canDropEvent: {
6636
+ type: Function,
6637
+ default: void 0
6638
+ },
6639
+ canDropExternalEvent: {
6640
+ type: Function,
6641
+ default: void 0
6642
+ },
6643
+ canResizeEventTo: {
6644
+ type: Function,
6645
+ default: void 0
6646
+ },
6647
+ preventEventOverlap: {
6648
+ type: [Boolean, Function],
6649
+ default: void 0
6650
+ },
6240
6651
  withInteractiveBackgroundEvents: {
6241
6652
  type: Boolean,
6242
6653
  default: void 0
@@ -6268,7 +6679,8 @@ var Schedule_default = /* @__PURE__ */ (0, vue.defineComponent)({
6268
6679
  "monthClick",
6269
6680
  "slotDragEnd",
6270
6681
  "externalEventDrop",
6271
- "eventResize"
6682
+ "eventResize",
6683
+ "eventPlacementRejected"
6272
6684
  ],
6273
6685
  setup(__props, { emit: __emit }) {
6274
6686
  const rawProps = __props;
@@ -6327,6 +6739,10 @@ var Schedule_default = /* @__PURE__ */ (0, vue.defineComponent)({
6327
6739
  withExternalEventDrop: props.withExternalEventDrop,
6328
6740
  withEventResize: props.withEventResize,
6329
6741
  canResizeEvent: props.canResizeEvent,
6742
+ canDropEvent: props.canDropEvent,
6743
+ canDropExternalEvent: props.canDropExternalEvent,
6744
+ canResizeEventTo: props.canResizeEventTo,
6745
+ preventEventOverlap: props.preventEventOverlap,
6330
6746
  withInteractiveBackgroundEvents: props.mode === "static" ? false : props.withInteractiveBackgroundEvents,
6331
6747
  recurrenceExpansionLimit: props.recurrenceExpansionLimit,
6332
6748
  ...eventRenderers.value,
@@ -6350,7 +6766,8 @@ var Schedule_default = /* @__PURE__ */ (0, vue.defineComponent)({
6350
6766
  onMonthClick: (month) => emit("monthClick", month),
6351
6767
  onSlotDragEnd: (rangeStart, rangeEnd) => emit("slotDragEnd", rangeStart, rangeEnd),
6352
6768
  onExternalEventDrop: (dataTransfer, dateTime) => emit("externalEventDrop", dataTransfer, dateTime),
6353
- onEventResize: (data) => emit("eventResize", data)
6769
+ onEventResize: (data) => emit("eventResize", data),
6770
+ onEventPlacementRejected: (data) => emit("eventPlacementRejected", data)
6354
6771
  };
6355
6772
  const views = {
6356
6773
  day: DayView,
@@ -6423,6 +6840,7 @@ var Schedule = (0, _mantine_vue_core.factory)(Schedule_default, { classes: Sched
6423
6840
  //#region src/hooks/use-horizontal-event-resize.ts
6424
6841
  function useHorizontalEventResize(input) {
6425
6842
  const state = (0, vue.shallowRef)(null);
6843
+ const resizeValid = (0, vue.ref)(true);
6426
6844
  let justResized = false;
6427
6845
  let savedUserSelect = "";
6428
6846
  const metrics = () => {
@@ -6467,6 +6885,18 @@ function useHorizontalEventResize(input) {
6467
6885
  current.currentWidth = right - current.currentLeft;
6468
6886
  }
6469
6887
  state.value = { ...current };
6888
+ const start = current.edge === "start" ? toDateTime(current.currentLeft, current.eventDate) : current.originalStart;
6889
+ const end = current.edge === "end" ? toDateTime(current.currentLeft + current.currentWidth, current.eventDate) : current.originalEnd;
6890
+ resizeValid.value = validateEventResize({
6891
+ event: current.event,
6892
+ start,
6893
+ end,
6894
+ edge: current.edge,
6895
+ events: input.events?.() ?? [],
6896
+ preventEventOverlap: input.preventEventOverlap?.(),
6897
+ canResizeEventTo: input.canResizeEventTo?.(),
6898
+ resourceId: current.event.resourceId
6899
+ }).valid;
6470
6900
  });
6471
6901
  const trackPointer = (event) => move(event.clientX);
6472
6902
  const cleanup = () => {
@@ -6478,13 +6908,37 @@ function useHorizontalEventResize(input) {
6478
6908
  const finish = () => {
6479
6909
  move.cancel();
6480
6910
  const current = state.value;
6481
- if (current && (current.currentLeft !== current.originalLeft || current.currentWidth !== current.originalWidth)) input.onEventResize({
6482
- eventId: current.event.id,
6483
- newStart: current.edge === "start" ? toDateTime(current.currentLeft, current.eventDate) : current.originalStart,
6484
- newEnd: current.edge === "end" ? toDateTime(current.currentLeft + current.currentWidth, current.eventDate) : current.originalEnd,
6485
- event: current.event
6486
- });
6911
+ if (current && (current.currentLeft !== current.originalLeft || current.currentWidth !== current.originalWidth)) {
6912
+ const start = current.edge === "start" ? toDateTime(current.currentLeft, current.eventDate) : current.originalStart;
6913
+ const end = current.edge === "end" ? toDateTime(current.currentLeft + current.currentWidth, current.eventDate) : current.originalEnd;
6914
+ const validation = validateEventResize({
6915
+ event: current.event,
6916
+ start,
6917
+ end,
6918
+ edge: current.edge,
6919
+ events: input.events?.() ?? [],
6920
+ preventEventOverlap: input.preventEventOverlap?.(),
6921
+ canResizeEventTo: input.canResizeEventTo?.(),
6922
+ resourceId: current.event.resourceId
6923
+ });
6924
+ if (validation.valid) input.onEventResize({
6925
+ eventId: current.event.id,
6926
+ newStart: start,
6927
+ newEnd: end,
6928
+ event: current.event
6929
+ });
6930
+ else input.onEventPlacementRejected?.({
6931
+ action: "resize",
6932
+ event: current.event,
6933
+ start,
6934
+ end,
6935
+ edge: current.edge,
6936
+ conflicts: validation.conflicts,
6937
+ reason: validation.reason
6938
+ });
6939
+ }
6487
6940
  state.value = null;
6941
+ resizeValid.value = true;
6488
6942
  cleanup();
6489
6943
  justResized = true;
6490
6944
  requestAnimationFrame(() => justResized = false);
@@ -6502,6 +6956,7 @@ function useHorizontalEventResize(input) {
6502
6956
  dayIndex: params.dayIndex ?? 0,
6503
6957
  dayCount: params.dayCount ?? 1
6504
6958
  };
6959
+ resizeValid.value = true;
6505
6960
  savedUserSelect = document.body.style.userSelect;
6506
6961
  document.body.style.userSelect = "none";
6507
6962
  document.addEventListener("pointermove", trackPointer);
@@ -6510,6 +6965,7 @@ function useHorizontalEventResize(input) {
6510
6965
  (0, vue.onBeforeUnmount)(cleanup);
6511
6966
  return {
6512
6967
  state,
6968
+ resizeValid,
6513
6969
  get resizingEdge() {
6514
6970
  return state.value?.edge ?? null;
6515
6971
  },
@@ -6620,27 +7076,27 @@ function getResourcesDayViewEvents({ events, resources, date, startTime, endTime
6620
7076
  return result;
6621
7077
  }
6622
7078
  var ResourcesDayView_module_default = {
6623
- resourcesDayView: "_resourcesDayView_bsrxh_1",
6624
- resourcesDayViewRoot: "_resourcesDayViewRoot_bsrxh_22",
6625
- resourcesDayViewScrollArea: "_resourcesDayViewScrollArea_bsrxh_30",
6626
- resourcesDayViewInner: "_resourcesDayViewInner_bsrxh_39",
6627
- resourcesDayViewTimeLabelsRow: "_resourcesDayViewTimeLabelsRow_bsrxh_44",
6628
- resourcesDayViewCorner: "_resourcesDayViewCorner_bsrxh_57",
6629
- resourcesDayViewTimeLabel: "_resourcesDayViewTimeLabel_bsrxh_44",
6630
- resourcesDayViewRow: "_resourcesDayViewRow_bsrxh_96",
6631
- resourcesDayViewResourceLabel: "_resourcesDayViewResourceLabel_bsrxh_100",
6632
- resourcesDayViewGroupColumn: "_resourcesDayViewGroupColumn_bsrxh_124",
6633
- resourcesDayViewGroupColumnEmpty: "_resourcesDayViewGroupColumnEmpty_bsrxh_125",
6634
- resourcesDayViewRowSlots: "_resourcesDayViewRowSlots_bsrxh_153",
6635
- resourcesDayViewRowSlot: "_resourcesDayViewRowSlot_bsrxh_153",
6636
- resourcesDayViewCurrentTimeIndicator: "_resourcesDayViewCurrentTimeIndicator_bsrxh_231",
6637
- resourcesDayViewCurrentTimeIndicatorLine: "_resourcesDayViewCurrentTimeIndicatorLine_bsrxh_243",
6638
- resourcesDayViewCurrentTimeIndicatorThumb: "_resourcesDayViewCurrentTimeIndicatorThumb_bsrxh_249",
6639
- resourcesDayViewCurrentTimeIndicatorTimeBubble: "_resourcesDayViewCurrentTimeIndicatorTimeBubble_bsrxh_259",
6640
- resourcesDayViewBackgroundEvent: "_resourcesDayViewBackgroundEvent_bsrxh_278",
6641
- resourcesDayViewAllDayEvent: "_resourcesDayViewAllDayEvent_bsrxh_306",
6642
- resourcesDayViewEventWrapper: "_resourcesDayViewEventWrapper_bsrxh_312",
6643
- resourcesDayViewResizeHandle: "_resourcesDayViewResizeHandle_bsrxh_316"
7079
+ resourcesDayView: "_resourcesDayView_1ak2d_1",
7080
+ resourcesDayViewRoot: "_resourcesDayViewRoot_1ak2d_22",
7081
+ resourcesDayViewScrollArea: "_resourcesDayViewScrollArea_1ak2d_30",
7082
+ resourcesDayViewInner: "_resourcesDayViewInner_1ak2d_39",
7083
+ resourcesDayViewTimeLabelsRow: "_resourcesDayViewTimeLabelsRow_1ak2d_44",
7084
+ resourcesDayViewCorner: "_resourcesDayViewCorner_1ak2d_57",
7085
+ resourcesDayViewTimeLabel: "_resourcesDayViewTimeLabel_1ak2d_44",
7086
+ resourcesDayViewRow: "_resourcesDayViewRow_1ak2d_96",
7087
+ resourcesDayViewResourceLabel: "_resourcesDayViewResourceLabel_1ak2d_100",
7088
+ resourcesDayViewGroupColumn: "_resourcesDayViewGroupColumn_1ak2d_124",
7089
+ resourcesDayViewGroupColumnEmpty: "_resourcesDayViewGroupColumnEmpty_1ak2d_125",
7090
+ resourcesDayViewRowSlots: "_resourcesDayViewRowSlots_1ak2d_153",
7091
+ resourcesDayViewRowSlot: "_resourcesDayViewRowSlot_1ak2d_153",
7092
+ resourcesDayViewCurrentTimeIndicator: "_resourcesDayViewCurrentTimeIndicator_1ak2d_240",
7093
+ resourcesDayViewCurrentTimeIndicatorLine: "_resourcesDayViewCurrentTimeIndicatorLine_1ak2d_252",
7094
+ resourcesDayViewCurrentTimeIndicatorThumb: "_resourcesDayViewCurrentTimeIndicatorThumb_1ak2d_258",
7095
+ resourcesDayViewCurrentTimeIndicatorTimeBubble: "_resourcesDayViewCurrentTimeIndicatorTimeBubble_1ak2d_268",
7096
+ resourcesDayViewBackgroundEvent: "_resourcesDayViewBackgroundEvent_1ak2d_287",
7097
+ resourcesDayViewAllDayEvent: "_resourcesDayViewAllDayEvent_1ak2d_315",
7098
+ resourcesDayViewEventWrapper: "_resourcesDayViewEventWrapper_1ak2d_321",
7099
+ resourcesDayViewResizeHandle: "_resourcesDayViewResizeHandle_1ak2d_325"
6644
7100
  };
6645
7101
  //#endregion
6646
7102
  //#region src/components/ResourcesDayView/ResourcesDayView.vue?vue&type=script&setup=true&lang.ts
@@ -6765,6 +7221,10 @@ var ResourcesDayView_default = /* @__PURE__ */ (0, vue.defineComponent)({
6765
7221
  type: Function,
6766
7222
  default: void 0
6767
7223
  },
7224
+ canDropEvent: {},
7225
+ canDropExternalEvent: {},
7226
+ canResizeEventTo: {},
7227
+ preventEventOverlap: { type: [Boolean, Function] },
6768
7228
  recurrenceExpansionLimit: { default: void 0 },
6769
7229
  maxEventsPerTimeSlot: { default: void 0 },
6770
7230
  moreEventsProps: { default: void 0 },
@@ -6783,7 +7243,8 @@ var ResourcesDayView_default = /* @__PURE__ */ (0, vue.defineComponent)({
6783
7243
  "timeSlotClick",
6784
7244
  "slotDragEnd",
6785
7245
  "externalEventDrop",
6786
- "eventResize"
7246
+ "eventResize",
7247
+ "eventPlacementRejected"
6787
7248
  ],
6788
7249
  setup(__props, { emit: __emit }) {
6789
7250
  const rawProps = __props;
@@ -6827,6 +7288,7 @@ var ResourcesDayView_default = /* @__PURE__ */ (0, vue.defineComponent)({
6827
7288
  rootElement.value = node instanceof HTMLElement ? node : null;
6828
7289
  };
6829
7290
  const dropTarget = (0, vue.shallowRef)(null);
7291
+ const dropValid = (0, vue.ref)(true);
6830
7292
  const scrolled = (0, vue.ref)(false);
6831
7293
  const scrolledX = (0, vue.ref)(false);
6832
7294
  const isStatic = (0, vue.computed)(() => props.mode === "static");
@@ -6903,6 +7365,10 @@ var ResourcesDayView_default = /* @__PURE__ */ (0, vue.defineComponent)({
6903
7365
  resizeIntervalMinutes: () => props.eventResizeInterval,
6904
7366
  onEventResize: (data) => emit("eventResize", data),
6905
7367
  canResizeEvent: () => props.canResizeEvent,
7368
+ events: () => expandedEvents.value,
7369
+ preventEventOverlap: () => props.preventEventOverlap,
7370
+ canResizeEventTo: () => props.canResizeEventTo,
7371
+ onEventPlacementRejected: (data) => emit("eventPlacementRejected", data),
6906
7372
  withBackgroundEvents: () => Boolean(props.withInteractiveBackgroundEvents)
6907
7373
  });
6908
7374
  (0, vue.onMounted)(async () => {
@@ -6936,15 +7402,51 @@ var ResourcesDayView_default = /* @__PURE__ */ (0, vue.defineComponent)({
6936
7402
  if (!intervals.value[slotIndex]) return;
6937
7403
  const target = getSnappedDropTarget(nativeEvent, slotIndex);
6938
7404
  const event = getDropEvent(expandedEvents.value, nativeEvent.dataTransfer);
6939
- if (event) emit("eventDrop", {
6940
- ...moveEventTo(event, target),
7405
+ if (event) {
7406
+ const next = moveEventTo(event, target);
7407
+ const validation = isEventPlacementAllowed({
7408
+ event,
7409
+ start: next.newStart,
7410
+ end: next.newEnd,
7411
+ events: expandedEvents.value,
7412
+ preventEventOverlap: props.preventEventOverlap,
7413
+ resourceId
7414
+ });
7415
+ if (validation.allowed && props.canDropEvent?.({
7416
+ event,
7417
+ start: next.newStart,
7418
+ end: next.newEnd,
7419
+ resourceId
7420
+ }) !== false) emit("eventDrop", {
7421
+ ...next,
7422
+ resourceId
7423
+ });
7424
+ else emit("eventPlacementRejected", {
7425
+ action: "drop",
7426
+ event,
7427
+ start: next.newStart,
7428
+ end: next.newEnd,
7429
+ resourceId,
7430
+ conflicts: validation.conflicts,
7431
+ reason: validation.allowed ? "rejected" : "overlap"
7432
+ });
7433
+ } else if (nativeEvent.dataTransfer) if (props.canDropExternalEvent?.({
7434
+ dataTransfer: nativeEvent.dataTransfer,
7435
+ start: target,
6941
7436
  resourceId
6942
- });
6943
- else if (nativeEvent.dataTransfer) emit("externalEventDrop", {
7437
+ }) !== false) emit("externalEventDrop", {
6944
7438
  dataTransfer: nativeEvent.dataTransfer,
6945
7439
  dropDateTime: target,
6946
7440
  resourceId
6947
7441
  });
7442
+ else emit("eventPlacementRejected", {
7443
+ action: "external-drop",
7444
+ dataTransfer: nativeEvent.dataTransfer,
7445
+ start: target,
7446
+ resourceId,
7447
+ conflicts: [],
7448
+ reason: "rejected"
7449
+ });
6948
7450
  };
6949
7451
  const getSnappedDropTarget = (nativeEvent, slotIndex) => {
6950
7452
  const interval = intervals.value[slotIndex];
@@ -6975,6 +7477,28 @@ var ResourcesDayView_default = /* @__PURE__ */ (0, vue.defineComponent)({
6975
7477
  */
6976
7478
  const resolveDropTarget = rafThrottle((nativeEvent, resourceId, resourceIndex) => {
6977
7479
  const slotIndex = getSlotIndexAtPoint(nativeEvent, resourceIndex);
7480
+ const target = slotIndex < 0 ? null : getSnappedDropTarget(nativeEvent, slotIndex);
7481
+ const event = dragState.draggedEvent.value;
7482
+ if (target && event) {
7483
+ const next = moveEventTo(event, target);
7484
+ dropValid.value = isEventPlacementAllowed({
7485
+ event,
7486
+ start: next.newStart,
7487
+ end: next.newEnd,
7488
+ events: expandedEvents.value,
7489
+ preventEventOverlap: props.preventEventOverlap,
7490
+ resourceId
7491
+ }).allowed && props.canDropEvent?.({
7492
+ event,
7493
+ start: next.newStart,
7494
+ end: next.newEnd,
7495
+ resourceId
7496
+ }) !== false;
7497
+ } else if (target && nativeEvent.dataTransfer) dropValid.value = props.canDropExternalEvent?.({
7498
+ dataTransfer: nativeEvent.dataTransfer,
7499
+ start: target,
7500
+ resourceId
7501
+ }) !== false;
6978
7502
  setDropTarget(slotIndex < 0 ? null : {
6979
7503
  resourceId,
6980
7504
  slotIndex
@@ -7288,7 +7812,8 @@ var ResourcesDayView_default = /* @__PURE__ */ (0, vue.defineComponent)({
7288
7812
  style: {
7289
7813
  width: "100%",
7290
7814
  height: "100%"
7291
- }
7815
+ },
7816
+ mod: { invalid: (0, vue.unref)(resize).getResizePosition(event.id) !== null && !(0, vue.unref)(resize).resizeValid.value }
7292
7817
  }, { ref_for: true }, {
7293
7818
  ...eventRenderers.value,
7294
7819
  ...stylesApi.value
@@ -7301,6 +7826,7 @@ var ResourcesDayView_default = /* @__PURE__ */ (0, vue.defineComponent)({
7301
7826
  "radius",
7302
7827
  "mode",
7303
7828
  "draggable",
7829
+ "mod",
7304
7830
  "onClick"
7305
7831
  ]), (0, vue.unref)(resize).isResizableEvent(event) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 0 }, (0, vue.renderList)(["start", "end"], (edge) => {
7306
7832
  return (0, vue.createElementVNode)("div", (0, vue.mergeProps)({ key: edge }, { ref_for: true }, (0, vue.unref)(staticStyles)("resourcesDayViewResizeHandle"), {
@@ -7346,6 +7872,7 @@ var ResourcesDayView_default = /* @__PURE__ */ (0, vue.defineComponent)({
7346
7872
  "data-business-hours": businessHoursMods.value[slotIndex]["business-hours"] || void 0,
7347
7873
  "data-non-business-hours": businessHoursMods.value[slotIndex]["non-business-hours"] || void 0,
7348
7874
  "data-drop-target": dropTarget.value?.resourceId === resource.id && dropTarget.value.slotIndex === slotIndex || void 0,
7875
+ "data-invalid": dropTarget.value?.resourceId === resource.id && dropTarget.value.slotIndex === slotIndex && !dropValid.value || void 0,
7349
7876
  "data-drag-selected": (0, vue.unref)(slotSelect).isSlotSelected(slotIndex, String(resource.id)) || void 0,
7350
7877
  "data-static": isStatic.value || void 0,
7351
7878
  "data-drag-slot-index": (0, vue.unref)(props).withDragSlotSelect ? slotIndex : void 0,
@@ -7376,6 +7903,7 @@ var ResourcesDayView_default = /* @__PURE__ */ (0, vue.defineComponent)({
7376
7903
  "data-business-hours",
7377
7904
  "data-non-business-hours",
7378
7905
  "data-drop-target",
7906
+ "data-invalid",
7379
7907
  "data-drag-selected",
7380
7908
  "data-static",
7381
7909
  "data-drag-slot-index",
@@ -7498,31 +8026,31 @@ function getResourcesWeekViewEvents({ events, resources, weekdays, startTime, en
7498
8026
  };
7499
8027
  }
7500
8028
  var ResourcesWeekView_module_default = {
7501
- resourcesWeekView: "_resourcesWeekView_1rg4q_1",
7502
- resourcesWeekViewRoot: "_resourcesWeekViewRoot_1rg4q_19",
7503
- resourcesWeekViewScrollArea: "_resourcesWeekViewScrollArea_1rg4q_26",
7504
- resourcesWeekViewInner: "_resourcesWeekViewInner_1rg4q_34",
7505
- resourcesWeekViewHeaderRows: "_resourcesWeekViewHeaderRows_1rg4q_39",
7506
- resourcesWeekViewCorner: "_resourcesWeekViewCorner_1rg4q_48",
7507
- resourcesWeekViewHeaderContent: "_resourcesWeekViewHeaderContent_1rg4q_63",
7508
- resourcesWeekViewDayLabelsRow: "_resourcesWeekViewDayLabelsRow_1rg4q_67",
7509
- resourcesWeekViewDayLabel: "_resourcesWeekViewDayLabel_1rg4q_67",
7510
- resourcesWeekViewTimeLabelsRow: "_resourcesWeekViewTimeLabelsRow_1rg4q_94",
7511
- resourcesWeekViewTimeLabel: "_resourcesWeekViewTimeLabel_1rg4q_94",
7512
- resourcesWeekViewRow: "_resourcesWeekViewRow_1rg4q_121",
7513
- resourcesWeekViewResourceLabel: "_resourcesWeekViewResourceLabel_1rg4q_125",
7514
- resourcesWeekViewGroupColumn: "_resourcesWeekViewGroupColumn_1rg4q_149",
7515
- resourcesWeekViewGroupColumnEmpty: "_resourcesWeekViewGroupColumnEmpty_1rg4q_150",
7516
- resourcesWeekViewRowSlots: "_resourcesWeekViewRowSlots_1rg4q_178",
7517
- resourcesWeekViewRowSlot: "_resourcesWeekViewRowSlot_1rg4q_178",
7518
- resourcesWeekViewBackgroundEvent: "_resourcesWeekViewBackgroundEvent_1rg4q_250",
7519
- resourcesWeekViewAllDayEvent: "_resourcesWeekViewAllDayEvent_1rg4q_278",
7520
- resourcesWeekViewEventWrapper: "_resourcesWeekViewEventWrapper_1rg4q_283",
7521
- resourcesWeekViewResizeHandle: "_resourcesWeekViewResizeHandle_1rg4q_287",
7522
- resourcesWeekViewCurrentTimeIndicator: "_resourcesWeekViewCurrentTimeIndicator_1rg4q_364",
7523
- resourcesWeekViewCurrentTimeIndicatorLine: "_resourcesWeekViewCurrentTimeIndicatorLine_1rg4q_376",
7524
- resourcesWeekViewCurrentTimeIndicatorThumb: "_resourcesWeekViewCurrentTimeIndicatorThumb_1rg4q_382",
7525
- resourcesWeekViewCurrentTimeIndicatorTimeBubble: "_resourcesWeekViewCurrentTimeIndicatorTimeBubble_1rg4q_392"
8029
+ resourcesWeekView: "_resourcesWeekView_1g2tz_1",
8030
+ resourcesWeekViewRoot: "_resourcesWeekViewRoot_1g2tz_19",
8031
+ resourcesWeekViewScrollArea: "_resourcesWeekViewScrollArea_1g2tz_26",
8032
+ resourcesWeekViewInner: "_resourcesWeekViewInner_1g2tz_34",
8033
+ resourcesWeekViewHeaderRows: "_resourcesWeekViewHeaderRows_1g2tz_39",
8034
+ resourcesWeekViewCorner: "_resourcesWeekViewCorner_1g2tz_48",
8035
+ resourcesWeekViewHeaderContent: "_resourcesWeekViewHeaderContent_1g2tz_63",
8036
+ resourcesWeekViewDayLabelsRow: "_resourcesWeekViewDayLabelsRow_1g2tz_67",
8037
+ resourcesWeekViewDayLabel: "_resourcesWeekViewDayLabel_1g2tz_67",
8038
+ resourcesWeekViewTimeLabelsRow: "_resourcesWeekViewTimeLabelsRow_1g2tz_94",
8039
+ resourcesWeekViewTimeLabel: "_resourcesWeekViewTimeLabel_1g2tz_94",
8040
+ resourcesWeekViewRow: "_resourcesWeekViewRow_1g2tz_121",
8041
+ resourcesWeekViewResourceLabel: "_resourcesWeekViewResourceLabel_1g2tz_125",
8042
+ resourcesWeekViewGroupColumn: "_resourcesWeekViewGroupColumn_1g2tz_149",
8043
+ resourcesWeekViewGroupColumnEmpty: "_resourcesWeekViewGroupColumnEmpty_1g2tz_150",
8044
+ resourcesWeekViewRowSlots: "_resourcesWeekViewRowSlots_1g2tz_178",
8045
+ resourcesWeekViewRowSlot: "_resourcesWeekViewRowSlot_1g2tz_178",
8046
+ resourcesWeekViewBackgroundEvent: "_resourcesWeekViewBackgroundEvent_1g2tz_259",
8047
+ resourcesWeekViewAllDayEvent: "_resourcesWeekViewAllDayEvent_1g2tz_287",
8048
+ resourcesWeekViewEventWrapper: "_resourcesWeekViewEventWrapper_1g2tz_292",
8049
+ resourcesWeekViewResizeHandle: "_resourcesWeekViewResizeHandle_1g2tz_296",
8050
+ resourcesWeekViewCurrentTimeIndicator: "_resourcesWeekViewCurrentTimeIndicator_1g2tz_373",
8051
+ resourcesWeekViewCurrentTimeIndicatorLine: "_resourcesWeekViewCurrentTimeIndicatorLine_1g2tz_385",
8052
+ resourcesWeekViewCurrentTimeIndicatorThumb: "_resourcesWeekViewCurrentTimeIndicatorThumb_1g2tz_391",
8053
+ resourcesWeekViewCurrentTimeIndicatorTimeBubble: "_resourcesWeekViewCurrentTimeIndicatorTimeBubble_1g2tz_401"
7526
8054
  };
7527
8055
  //#endregion
7528
8056
  //#region src/components/ResourcesWeekView/ResourcesWeekView.vue?vue&type=script&setup=true&lang.ts
@@ -7656,6 +8184,10 @@ var ResourcesWeekView_default = /* @__PURE__ */ (0, vue.defineComponent)({
7656
8184
  type: Function,
7657
8185
  default: void 0
7658
8186
  },
8187
+ canDropEvent: {},
8188
+ canDropExternalEvent: {},
8189
+ canResizeEventTo: {},
8190
+ preventEventOverlap: { type: [Boolean, Function] },
7659
8191
  recurrenceExpansionLimit: { default: void 0 },
7660
8192
  maxEventsPerTimeSlot: { default: void 0 },
7661
8193
  moreEventsProps: { default: void 0 },
@@ -7688,7 +8220,8 @@ var ResourcesWeekView_default = /* @__PURE__ */ (0, vue.defineComponent)({
7688
8220
  "timeSlotClick",
7689
8221
  "slotDragEnd",
7690
8222
  "externalEventDrop",
7691
- "eventResize"
8223
+ "eventResize",
8224
+ "eventPlacementRejected"
7692
8225
  ],
7693
8226
  setup(__props, { emit: __emit }) {
7694
8227
  const rawProps = __props;
@@ -7732,6 +8265,7 @@ var ResourcesWeekView_default = /* @__PURE__ */ (0, vue.defineComponent)({
7732
8265
  rootElement.value = node instanceof HTMLElement ? node : null;
7733
8266
  };
7734
8267
  const dropTarget = (0, vue.shallowRef)(null);
8268
+ const dropValid = (0, vue.ref)(true);
7735
8269
  const scrolledX = (0, vue.ref)(false);
7736
8270
  const isStatic = (0, vue.computed)(() => props.mode === "static");
7737
8271
  const intervals = (0, vue.computed)(() => getDayTimeIntervals({
@@ -7820,6 +8354,10 @@ var ResourcesWeekView_default = /* @__PURE__ */ (0, vue.defineComponent)({
7820
8354
  resizeIntervalMinutes: () => props.eventResizeInterval,
7821
8355
  onEventResize: (data) => emit("eventResize", data),
7822
8356
  canResizeEvent: () => props.canResizeEvent,
8357
+ events: () => props.events ?? [],
8358
+ preventEventOverlap: () => props.preventEventOverlap,
8359
+ canResizeEventTo: () => props.canResizeEventTo,
8360
+ onEventPlacementRejected: (data) => emit("eventPlacementRejected", data),
7823
8361
  withBackgroundEvents: () => Boolean(props.withInteractiveBackgroundEvents)
7824
8362
  });
7825
8363
  (0, vue.onMounted)(async () => {
@@ -7862,15 +8400,51 @@ var ResourcesWeekView_default = /* @__PURE__ */ (0, vue.defineComponent)({
7862
8400
  if (!day || !interval) return;
7863
8401
  const target = getSnappedDropTarget(nativeEvent, day, flatIndex, interval.startTime);
7864
8402
  const event = getDropEvent(props.events, nativeEvent.dataTransfer);
7865
- if (event) emit("eventDrop", {
7866
- ...moveEventTo(event, target),
8403
+ if (event) {
8404
+ const next = moveEventTo(event, target);
8405
+ const validation = isEventPlacementAllowed({
8406
+ event,
8407
+ start: next.newStart,
8408
+ end: next.newEnd,
8409
+ events: props.events ?? [],
8410
+ preventEventOverlap: props.preventEventOverlap,
8411
+ resourceId
8412
+ });
8413
+ if (validation.allowed && props.canDropEvent?.({
8414
+ event,
8415
+ start: next.newStart,
8416
+ end: next.newEnd,
8417
+ resourceId
8418
+ }) !== false) emit("eventDrop", {
8419
+ ...next,
8420
+ resourceId
8421
+ });
8422
+ else emit("eventPlacementRejected", {
8423
+ action: "drop",
8424
+ event,
8425
+ start: next.newStart,
8426
+ end: next.newEnd,
8427
+ resourceId,
8428
+ conflicts: validation.conflicts,
8429
+ reason: validation.allowed ? "rejected" : "overlap"
8430
+ });
8431
+ } else if (nativeEvent.dataTransfer) if (props.canDropExternalEvent?.({
8432
+ dataTransfer: nativeEvent.dataTransfer,
8433
+ start: target,
7867
8434
  resourceId
7868
- });
7869
- else if (nativeEvent.dataTransfer) emit("externalEventDrop", {
8435
+ }) !== false) emit("externalEventDrop", {
7870
8436
  dataTransfer: nativeEvent.dataTransfer,
7871
8437
  dropDateTime: target,
7872
8438
  resourceId
7873
8439
  });
8440
+ else emit("eventPlacementRejected", {
8441
+ action: "external-drop",
8442
+ dataTransfer: nativeEvent.dataTransfer,
8443
+ start: target,
8444
+ resourceId,
8445
+ conflicts: [],
8446
+ reason: "rejected"
8447
+ });
7874
8448
  };
7875
8449
  const getSnappedDropTarget = (nativeEvent, day, flatIndex, slotStartTime) => {
7876
8450
  if (props.eventDragInterval == null) return `${day} ${slotStartTime}`;
@@ -7901,6 +8475,31 @@ var ResourcesWeekView_default = /* @__PURE__ */ (0, vue.defineComponent)({
7901
8475
  */
7902
8476
  const resolveDropTarget = rafThrottle((nativeEvent, resourceId, resourceIndex) => {
7903
8477
  const flatIndex = getFlatIndexAtPoint(nativeEvent, resourceIndex);
8478
+ const count = slotsPerDay.value;
8479
+ const day = weekdays.value[Math.floor(flatIndex / count)];
8480
+ const interval = intervals.value[flatIndex % count];
8481
+ const target = flatIndex >= 0 && day && interval ? getSnappedDropTarget(nativeEvent, day, flatIndex, interval.startTime) : null;
8482
+ const event = dragState.draggedEvent.value;
8483
+ if (target && event) {
8484
+ const next = moveEventTo(event, target);
8485
+ dropValid.value = isEventPlacementAllowed({
8486
+ event,
8487
+ start: next.newStart,
8488
+ end: next.newEnd,
8489
+ events: props.events ?? [],
8490
+ preventEventOverlap: props.preventEventOverlap,
8491
+ resourceId
8492
+ }).allowed && props.canDropEvent?.({
8493
+ event,
8494
+ start: next.newStart,
8495
+ end: next.newEnd,
8496
+ resourceId
8497
+ }) !== false;
8498
+ } else if (target && nativeEvent.dataTransfer) dropValid.value = props.canDropExternalEvent?.({
8499
+ dataTransfer: nativeEvent.dataTransfer,
8500
+ start: target,
8501
+ resourceId
8502
+ }) !== false;
7904
8503
  setDropTarget(flatIndex < 0 ? null : {
7905
8504
  resourceId,
7906
8505
  flatIndex
@@ -8262,7 +8861,8 @@ var ResourcesWeekView_default = /* @__PURE__ */ (0, vue.defineComponent)({
8262
8861
  style: {
8263
8862
  width: "100%",
8264
8863
  height: "100%"
8265
- }
8864
+ },
8865
+ mod: { invalid: (0, vue.unref)(resize).getResizePosition(entry.event.id) !== null && !(0, vue.unref)(resize).resizeValid.value }
8266
8866
  }, { ref_for: true }, {
8267
8867
  ...eventRenderers.value,
8268
8868
  ...stylesApi.value
@@ -8275,6 +8875,7 @@ var ResourcesWeekView_default = /* @__PURE__ */ (0, vue.defineComponent)({
8275
8875
  "radius",
8276
8876
  "mode",
8277
8877
  "draggable",
8878
+ "mod",
8278
8879
  "onClick"
8279
8880
  ]), (0, vue.unref)(resize).isResizableEvent(entry.event) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 0 }, (0, vue.renderList)(["start", "end"], (edge) => {
8280
8881
  return (0, vue.createElementVNode)("div", (0, vue.mergeProps)({ key: edge }, { ref_for: true }, (0, vue.unref)(staticStyles)("resourcesWeekViewResizeHandle"), {
@@ -8322,6 +8923,7 @@ var ResourcesWeekView_default = /* @__PURE__ */ (0, vue.defineComponent)({
8322
8923
  "data-business-hours": businessHoursMods.value[dayIndex][slotIndex]["business-hours"] || void 0,
8323
8924
  "data-non-business-hours": businessHoursMods.value[dayIndex][slotIndex]["non-business-hours"] || void 0,
8324
8925
  "data-drop-target": dropTarget.value?.resourceId === resource.id && dropTarget.value.flatIndex === dayIndex * slotsPerDay.value + slotIndex || void 0,
8926
+ "data-invalid": dropTarget.value?.resourceId === resource.id && dropTarget.value.flatIndex === dayIndex * slotsPerDay.value + slotIndex && !dropValid.value || void 0,
8325
8927
  "data-drag-selected": (0, vue.unref)(slotSelect).isSlotSelected(dayIndex * slotsPerDay.value + slotIndex, String(resource.id)) || void 0,
8326
8928
  "data-static": isStatic.value || void 0,
8327
8929
  "data-drag-slot-index": (0, vue.unref)(props).withDragSlotSelect ? dayIndex * slotsPerDay.value + slotIndex : void 0,
@@ -8353,6 +8955,7 @@ var ResourcesWeekView_default = /* @__PURE__ */ (0, vue.defineComponent)({
8353
8955
  "data-business-hours",
8354
8956
  "data-non-business-hours",
8355
8957
  "data-drop-target",
8958
+ "data-invalid",
8356
8959
  "data-drag-selected",
8357
8960
  "data-static",
8358
8961
  "data-drag-slot-index",
@@ -8485,23 +9088,23 @@ function getResourcesMonthViewLayout({ days, events, resourceId, maxRows }) {
8485
9088
  };
8486
9089
  }
8487
9090
  var ResourcesMonthView_module_default = {
8488
- resourcesMonthView: "_resourcesMonthView_uqbdi_1",
8489
- resourcesMonthViewRoot: "_resourcesMonthViewRoot_uqbdi_17",
8490
- resourcesMonthViewScrollArea: "_resourcesMonthViewScrollArea_uqbdi_24",
8491
- resourcesMonthViewInner: "_resourcesMonthViewInner_uqbdi_33",
8492
- resourcesMonthViewDayLabelsRow: "_resourcesMonthViewDayLabelsRow_uqbdi_37",
8493
- resourcesMonthViewCorner: "_resourcesMonthViewCorner_uqbdi_46",
8494
- resourcesMonthViewDayLabel: "_resourcesMonthViewDayLabel_uqbdi_37",
8495
- resourcesMonthViewDayLabelWeekday: "_resourcesMonthViewDayLabelWeekday_uqbdi_85",
8496
- resourcesMonthViewDayLabelNumber: "_resourcesMonthViewDayLabelNumber_uqbdi_92",
8497
- resourcesMonthViewRow: "_resourcesMonthViewRow_uqbdi_97",
8498
- resourcesMonthViewResourceLabel: "_resourcesMonthViewResourceLabel_uqbdi_101",
8499
- resourcesMonthViewGroupColumn: "_resourcesMonthViewGroupColumn_uqbdi_120",
8500
- resourcesMonthViewGroupColumnEmpty: "_resourcesMonthViewGroupColumnEmpty_uqbdi_121",
8501
- resourcesMonthViewRowSlots: "_resourcesMonthViewRowSlots_uqbdi_149",
8502
- resourcesMonthViewCell: "_resourcesMonthViewCell_uqbdi_154",
8503
- resourcesMonthViewEventWrapper: "_resourcesMonthViewEventWrapper_uqbdi_230",
8504
- resourcesMonthViewResizeHandle: "_resourcesMonthViewResizeHandle_uqbdi_231"
9091
+ resourcesMonthView: "_resourcesMonthView_1rka1_1",
9092
+ resourcesMonthViewRoot: "_resourcesMonthViewRoot_1rka1_17",
9093
+ resourcesMonthViewScrollArea: "_resourcesMonthViewScrollArea_1rka1_24",
9094
+ resourcesMonthViewInner: "_resourcesMonthViewInner_1rka1_33",
9095
+ resourcesMonthViewDayLabelsRow: "_resourcesMonthViewDayLabelsRow_1rka1_37",
9096
+ resourcesMonthViewCorner: "_resourcesMonthViewCorner_1rka1_46",
9097
+ resourcesMonthViewDayLabel: "_resourcesMonthViewDayLabel_1rka1_37",
9098
+ resourcesMonthViewDayLabelWeekday: "_resourcesMonthViewDayLabelWeekday_1rka1_85",
9099
+ resourcesMonthViewDayLabelNumber: "_resourcesMonthViewDayLabelNumber_1rka1_92",
9100
+ resourcesMonthViewRow: "_resourcesMonthViewRow_1rka1_97",
9101
+ resourcesMonthViewResourceLabel: "_resourcesMonthViewResourceLabel_1rka1_101",
9102
+ resourcesMonthViewGroupColumn: "_resourcesMonthViewGroupColumn_1rka1_120",
9103
+ resourcesMonthViewGroupColumnEmpty: "_resourcesMonthViewGroupColumnEmpty_1rka1_121",
9104
+ resourcesMonthViewRowSlots: "_resourcesMonthViewRowSlots_1rka1_149",
9105
+ resourcesMonthViewCell: "_resourcesMonthViewCell_1rka1_154",
9106
+ resourcesMonthViewEventWrapper: "_resourcesMonthViewEventWrapper_1rka1_239",
9107
+ resourcesMonthViewResizeHandle: "_resourcesMonthViewResizeHandle_1rka1_240"
8505
9108
  };
8506
9109
  //#endregion
8507
9110
  //#region src/components/ResourcesMonthView/ResourcesMonthView.vue?vue&type=script&setup=true&lang.ts
@@ -8610,6 +9213,10 @@ var ResourcesMonthView_default = /* @__PURE__ */ (0, vue.defineComponent)({
8610
9213
  type: Function,
8611
9214
  default: void 0
8612
9215
  },
9216
+ canDropEvent: {},
9217
+ canDropExternalEvent: {},
9218
+ canResizeEventTo: {},
9219
+ preventEventOverlap: { type: [Boolean, Function] },
8613
9220
  withExternalEventDrop: { type: Boolean },
8614
9221
  withDragSlotSelect: { type: Boolean },
8615
9222
  labels: { default: void 0 },
@@ -8633,7 +9240,8 @@ var ResourcesMonthView_default = /* @__PURE__ */ (0, vue.defineComponent)({
8633
9240
  "eventDragEnd",
8634
9241
  "slotDragEnd",
8635
9242
  "externalEventDrop",
8636
- "eventResize"
9243
+ "eventResize",
9244
+ "eventPlacementRejected"
8637
9245
  ],
8638
9246
  setup(__props, { emit: __emit }) {
8639
9247
  const rawProps = __props;
@@ -8677,6 +9285,7 @@ var ResourcesMonthView_default = /* @__PURE__ */ (0, vue.defineComponent)({
8677
9285
  rootElement.value = node instanceof HTMLElement ? node : null;
8678
9286
  };
8679
9287
  const dropTarget = (0, vue.shallowRef)(null);
9288
+ const dropValid = (0, vue.ref)(true);
8680
9289
  const isStatic = (0, vue.computed)(() => props.mode === "static");
8681
9290
  const month = (0, vue.computed)(() => (0, dayjs.default)(props.date).startOf("month"));
8682
9291
  const monthString = (0, vue.computed)(() => month.value.format("YYYY-MM-DD"));
@@ -8692,6 +9301,7 @@ var ResourcesMonthView_default = /* @__PURE__ */ (0, vue.defineComponent)({
8692
9301
  expansionLimit: props.recurrenceExpansionLimit
8693
9302
  }));
8694
9303
  const resizeState = (0, vue.shallowRef)(null);
9304
+ const resizeValid = (0, vue.ref)(true);
8695
9305
  let justResized = false;
8696
9306
  const effectiveEvents = (0, vue.computed)(() => {
8697
9307
  const state = resizeState.value;
@@ -8764,18 +9374,57 @@ var ResourcesMonthView_default = /* @__PURE__ */ (0, vue.defineComponent)({
8764
9374
  draggedEvent: dragged,
8765
9375
  targetDay: day
8766
9376
  });
8767
- emit("eventDrop", {
9377
+ const start = (0, dayjs.default)(next.start).format("YYYY-MM-DD HH:mm:ss");
9378
+ const end = (0, dayjs.default)(next.end).format("YYYY-MM-DD HH:mm:ss");
9379
+ const validation = isEventPlacementAllowed({
9380
+ event: dragged,
9381
+ start,
9382
+ end,
9383
+ events: expandedEvents.value,
9384
+ preventEventOverlap: props.preventEventOverlap,
9385
+ resourceId
9386
+ });
9387
+ if (validation.allowed && props.canDropEvent?.({
9388
+ event: dragged,
9389
+ start,
9390
+ end,
9391
+ resourceId
9392
+ }) !== false) emit("eventDrop", {
8768
9393
  eventId: dragged.id,
8769
- newStart: (0, dayjs.default)(next.start).format("YYYY-MM-DD HH:mm:ss"),
8770
- newEnd: (0, dayjs.default)(next.end).format("YYYY-MM-DD HH:mm:ss"),
9394
+ newStart: start,
9395
+ newEnd: end,
8771
9396
  event: dragged,
8772
9397
  resourceId
8773
9398
  });
8774
- } else if (nativeEvent.dataTransfer) emit("externalEventDrop", {
8775
- dataTransfer: nativeEvent.dataTransfer,
8776
- dropDateTime: `${day} 00:00:00`,
8777
- resourceId
8778
- });
9399
+ else emit("eventPlacementRejected", {
9400
+ action: "drop",
9401
+ event: dragged,
9402
+ start,
9403
+ end,
9404
+ resourceId,
9405
+ conflicts: validation.conflicts,
9406
+ reason: validation.allowed ? "rejected" : "overlap"
9407
+ });
9408
+ } else if (nativeEvent.dataTransfer) {
9409
+ const start = `${day} 00:00:00`;
9410
+ if (props.canDropExternalEvent?.({
9411
+ dataTransfer: nativeEvent.dataTransfer,
9412
+ start,
9413
+ resourceId
9414
+ }) !== false) emit("externalEventDrop", {
9415
+ dataTransfer: nativeEvent.dataTransfer,
9416
+ dropDateTime: start,
9417
+ resourceId
9418
+ });
9419
+ else emit("eventPlacementRejected", {
9420
+ action: "external-drop",
9421
+ dataTransfer: nativeEvent.dataTransfer,
9422
+ start,
9423
+ resourceId,
9424
+ conflicts: [],
9425
+ reason: "rejected"
9426
+ });
9427
+ }
8779
9428
  };
8780
9429
  const setDropTarget = (next) => {
8781
9430
  const current = dropTarget.value;
@@ -8790,6 +9439,36 @@ var ResourcesMonthView_default = /* @__PURE__ */ (0, vue.defineComponent)({
8790
9439
  */
8791
9440
  const resolveDropTarget = rafThrottle((nativeEvent, resourceId, resourceIndex) => {
8792
9441
  const dayIndex = indexAtPoint(nativeEvent, resourceIndex);
9442
+ const day = days.value[dayIndex];
9443
+ const dragged = dragState.draggedEvent.value;
9444
+ if (day && dragged) {
9445
+ const next = calculateMonthDropDate({
9446
+ draggedEvent: dragged,
9447
+ targetDay: day
9448
+ });
9449
+ const start = (0, dayjs.default)(next.start).format("YYYY-MM-DD HH:mm:ss");
9450
+ const end = (0, dayjs.default)(next.end).format("YYYY-MM-DD HH:mm:ss");
9451
+ dropValid.value = isEventPlacementAllowed({
9452
+ event: dragged,
9453
+ start,
9454
+ end,
9455
+ events: expandedEvents.value,
9456
+ preventEventOverlap: props.preventEventOverlap,
9457
+ resourceId
9458
+ }).allowed && props.canDropEvent?.({
9459
+ event: dragged,
9460
+ start,
9461
+ end,
9462
+ resourceId
9463
+ }) !== false;
9464
+ } else if (day && nativeEvent.dataTransfer) {
9465
+ const start = `${day} 00:00:00`;
9466
+ dropValid.value = props.canDropExternalEvent?.({
9467
+ dataTransfer: nativeEvent.dataTransfer,
9468
+ start,
9469
+ resourceId
9470
+ }) !== false;
9471
+ }
8793
9472
  setDropTarget(dayIndex < 0 ? null : {
8794
9473
  resourceId,
8795
9474
  dayIndex
@@ -8912,6 +9591,16 @@ var ResourcesMonthView_default = /* @__PURE__ */ (0, vue.defineComponent)({
8912
9591
  ...calculateResizeDates(state.event, state.edge, days.value[dayIndex]),
8913
9592
  dayIndex
8914
9593
  };
9594
+ resizeValid.value = validateEventResize({
9595
+ event: state.event,
9596
+ start: resizeState.value.start,
9597
+ end: resizeState.value.end,
9598
+ edge: state.edge,
9599
+ events: expandedEvents.value,
9600
+ preventEventOverlap: props.preventEventOverlap,
9601
+ canResizeEventTo: props.canResizeEventTo,
9602
+ resourceId: state.event.resourceId
9603
+ }).valid;
8915
9604
  };
8916
9605
  const stopResizeListeners = () => {
8917
9606
  document.removeEventListener("pointermove", handleResizeMove);
@@ -8922,12 +9611,33 @@ var ResourcesMonthView_default = /* @__PURE__ */ (0, vue.defineComponent)({
8922
9611
  const state = resizeState.value;
8923
9612
  stopResizeListeners();
8924
9613
  resizeState.value = null;
8925
- if (emitChange && state && (state.start !== state.originalStart || state.end !== state.originalEnd)) emit("eventResize", {
8926
- eventId: state.event.id,
8927
- newStart: state.start,
8928
- newEnd: state.end,
8929
- event: state.event
8930
- });
9614
+ if (emitChange && state && (state.start !== state.originalStart || state.end !== state.originalEnd)) {
9615
+ const validation = validateEventResize({
9616
+ event: state.event,
9617
+ start: state.start,
9618
+ end: state.end,
9619
+ edge: state.edge,
9620
+ events: expandedEvents.value,
9621
+ preventEventOverlap: props.preventEventOverlap,
9622
+ canResizeEventTo: props.canResizeEventTo,
9623
+ resourceId: state.event.resourceId
9624
+ });
9625
+ if (validation.valid) emit("eventResize", {
9626
+ eventId: state.event.id,
9627
+ newStart: state.start,
9628
+ newEnd: state.end,
9629
+ event: state.event
9630
+ });
9631
+ else emit("eventPlacementRejected", {
9632
+ action: "resize",
9633
+ event: state.event,
9634
+ start: state.start,
9635
+ end: state.end,
9636
+ edge: state.edge,
9637
+ conflicts: validation.conflicts,
9638
+ reason: validation.reason
9639
+ });
9640
+ }
8931
9641
  justResized = true;
8932
9642
  requestAnimationFrame(() => justResized = false);
8933
9643
  };
@@ -8953,6 +9663,7 @@ var ResourcesMonthView_default = /* @__PURE__ */ (0, vue.defineComponent)({
8953
9663
  end,
8954
9664
  dayIndex: -1
8955
9665
  };
9666
+ resizeValid.value = true;
8956
9667
  document.addEventListener("pointermove", handleResizeMove);
8957
9668
  document.addEventListener("pointerup", handleResizeEnd);
8958
9669
  document.addEventListener("pointercancel", handleResizeCancel);
@@ -9081,6 +9792,7 @@ var ResourcesMonthView_default = /* @__PURE__ */ (0, vue.defineComponent)({
9081
9792
  mode: (0, vue.unref)(props).mode,
9082
9793
  draggable: isDraggableEvent(entry.event),
9083
9794
  "is-resizing": isResizingEvent(entry.event),
9795
+ mod: { invalid: isResizingEvent(entry.event) && !resizeValid.value },
9084
9796
  style: {
9085
9797
  "width": "100%",
9086
9798
  "height": "100%"
@@ -9098,6 +9810,7 @@ var ResourcesMonthView_default = /* @__PURE__ */ (0, vue.defineComponent)({
9098
9810
  "mode",
9099
9811
  "draggable",
9100
9812
  "is-resizing",
9813
+ "mod",
9101
9814
  "onClick"
9102
9815
  ]),
9103
9816
  isResizableEvent(entry.event) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", (0, vue.mergeProps)({
@@ -9135,6 +9848,7 @@ var ResourcesMonthView_default = /* @__PURE__ */ (0, vue.defineComponent)({
9135
9848
  mode: (0, vue.unref)(props).mode,
9136
9849
  draggable: isDraggableEvent(segment.event),
9137
9850
  "is-resizing": isResizingEvent(segment.event),
9851
+ mod: { invalid: isResizingEvent(segment.event) && !resizeValid.value },
9138
9852
  style: {
9139
9853
  "width": "100%",
9140
9854
  "height": "100%"
@@ -9153,6 +9867,7 @@ var ResourcesMonthView_default = /* @__PURE__ */ (0, vue.defineComponent)({
9153
9867
  "mode",
9154
9868
  "draggable",
9155
9869
  "is-resizing",
9870
+ "mod",
9156
9871
  "onClick"
9157
9872
  ]),
9158
9873
  isResizableEvent(segment.event) && segment.hanging !== "start" && segment.hanging !== "both" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", (0, vue.mergeProps)({
@@ -9208,6 +9923,7 @@ var ResourcesMonthView_default = /* @__PURE__ */ (0, vue.defineComponent)({
9208
9923
  }, { ref_for: true }, (0, vue.unref)(staticStyles)("resourcesMonthViewCell"), {
9209
9924
  "data-weekend": (0, vue.unref)(props).weekendDays.includes((0, vue.unref)(dayjs.default)(day).day()) || void 0,
9210
9925
  "data-drop-target": dropTarget.value?.resourceId === resource.id && dropTarget.value.dayIndex === dayIndex || void 0,
9926
+ "data-invalid": dropTarget.value?.resourceId === resource.id && dropTarget.value.dayIndex === dayIndex && !dropValid.value || void 0,
9211
9927
  "data-drag-selected": (0, vue.unref)(slotSelect).isSlotSelected(dayIndex, String(resource.id)) || void 0,
9212
9928
  "data-static": isStatic.value || void 0,
9213
9929
  "data-drag-slot-index": (0, vue.unref)(props).withDragSlotSelect ? dayIndex : void 0,
@@ -9235,6 +9951,7 @@ var ResourcesMonthView_default = /* @__PURE__ */ (0, vue.defineComponent)({
9235
9951
  }, 1040, [
9236
9952
  "data-weekend",
9237
9953
  "data-drop-target",
9954
+ "data-invalid",
9238
9955
  "data-drag-selected",
9239
9956
  "data-static",
9240
9957
  "data-drag-slot-index",
@@ -9309,6 +10026,22 @@ var ResourcesSchedule_default = /* @__PURE__ */ (0, vue.defineComponent)({
9309
10026
  type: Function,
9310
10027
  default: void 0
9311
10028
  },
10029
+ canDropEvent: {
10030
+ type: Function,
10031
+ default: void 0
10032
+ },
10033
+ canDropExternalEvent: {
10034
+ type: Function,
10035
+ default: void 0
10036
+ },
10037
+ canResizeEventTo: {
10038
+ type: Function,
10039
+ default: void 0
10040
+ },
10041
+ preventEventOverlap: {
10042
+ type: [Boolean, Function],
10043
+ default: void 0
10044
+ },
9312
10045
  withInteractiveBackgroundEvents: {
9313
10046
  type: Boolean,
9314
10047
  default: void 0
@@ -9335,7 +10068,8 @@ var ResourcesSchedule_default = /* @__PURE__ */ (0, vue.defineComponent)({
9335
10068
  "dayClick",
9336
10069
  "slotDragEnd",
9337
10070
  "externalEventDrop",
9338
- "eventResize"
10071
+ "eventResize",
10072
+ "eventPlacementRejected"
9339
10073
  ],
9340
10074
  setup(__props, { emit: __emit }) {
9341
10075
  const rawProps = __props;
@@ -9397,6 +10131,9 @@ var ResourcesSchedule_default = /* @__PURE__ */ (0, vue.defineComponent)({
9397
10131
  renderResourceLabel: props.renderResourceLabel,
9398
10132
  withEventsDragAndDrop: isStatic.value ? false : props.withEventsDragAndDrop,
9399
10133
  canDragEvent: props.canDragEvent,
10134
+ canDropEvent: props.canDropEvent,
10135
+ canDropExternalEvent: props.canDropExternalEvent,
10136
+ preventEventOverlap: props.preventEventOverlap,
9400
10137
  withDragSlotSelect: props.withDragSlotSelect,
9401
10138
  recurrenceExpansionLimit: props.recurrenceExpansionLimit,
9402
10139
  withInteractiveBackgroundEvents: isStatic.value ? false : props.withInteractiveBackgroundEvents,
@@ -9408,6 +10145,7 @@ var ResourcesSchedule_default = /* @__PURE__ */ (0, vue.defineComponent)({
9408
10145
  onEventClick: (event, nativeEvent) => emit("eventClick", event, nativeEvent),
9409
10146
  onSlotDragEnd: (data) => emit("slotDragEnd", data),
9410
10147
  onExternalEventDrop: (data) => emit("externalEventDrop", data),
10148
+ onEventPlacementRejected: (data) => emit("eventPlacementRejected", data),
9411
10149
  ...eventRenderers.value,
9412
10150
  ...stylesApi.value
9413
10151
  }));
@@ -9415,6 +10153,7 @@ var ResourcesSchedule_default = /* @__PURE__ */ (0, vue.defineComponent)({
9415
10153
  onTimeSlotClick: (data) => emit("timeSlotClick", data),
9416
10154
  withEventResize: isStatic.value ? false : props.withEventResize,
9417
10155
  canResizeEvent: props.canResizeEvent,
10156
+ canResizeEventTo: props.canResizeEventTo,
9418
10157
  onEventResize: (data) => emit("eventResize", data)
9419
10158
  }));
9420
10159
  const activeView = (0, vue.computed)(() => {
@@ -9544,6 +10283,7 @@ exports.isAfterMinDate = isAfterMinDate;
9544
10283
  exports.isAllDayEvent = isAllDayEvent;
9545
10284
  exports.isBeforeMaxDate = isBeforeMaxDate;
9546
10285
  exports.isEventInTimeRange = isEventInTimeRange;
10286
+ exports.isEventPlacementAllowed = isEventPlacementAllowed;
9547
10287
  exports.isEventsOverlap = isEventsOverlap;
9548
10288
  exports.isInTimeRange = isInTimeRange;
9549
10289
  exports.isMultiDayEvent = isMultiDayEvent;