@mantine/schedule 9.6.2 → 9.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 (91) hide show
  1. package/cjs/components/DayView/DayView.cjs +45 -30
  2. package/cjs/components/DayView/DayView.cjs.map +1 -1
  3. package/cjs/components/DayView/DayView.module.cjs.map +1 -1
  4. package/cjs/components/MobileMonthView/get-mobile-month-view-events.cjs +10 -2
  5. package/cjs/components/MobileMonthView/get-mobile-month-view-events.cjs.map +1 -1
  6. package/cjs/components/MonthView/MonthView.cjs +11 -4
  7. package/cjs/components/MonthView/MonthView.cjs.map +1 -1
  8. package/cjs/components/ResourcesDayView/ResourcesDayView.cjs +74 -59
  9. package/cjs/components/ResourcesDayView/ResourcesDayView.cjs.map +1 -1
  10. package/cjs/components/ResourcesDayView/ResourcesDayView.module.cjs.map +1 -1
  11. package/cjs/components/ResourcesMonthView/ResourcesMonthView.cjs +18 -6
  12. package/cjs/components/ResourcesMonthView/ResourcesMonthView.cjs.map +1 -1
  13. package/cjs/components/ResourcesSchedule/ResourcesSchedule.cjs +6 -1
  14. package/cjs/components/ResourcesSchedule/ResourcesSchedule.cjs.map +1 -1
  15. package/cjs/components/ResourcesWeekView/ResourcesWeekView.cjs +84 -57
  16. package/cjs/components/ResourcesWeekView/ResourcesWeekView.cjs.map +1 -1
  17. package/cjs/components/ResourcesWeekView/ResourcesWeekView.module.cjs.map +1 -1
  18. package/cjs/components/Schedule/Schedule.cjs +14 -1
  19. package/cjs/components/Schedule/Schedule.cjs.map +1 -1
  20. package/cjs/components/ScheduleEvent/ScheduleEvent.module.cjs.map +1 -1
  21. package/cjs/components/WeekView/WeekView.cjs +67 -45
  22. package/cjs/components/WeekView/WeekView.cjs.map +1 -1
  23. package/cjs/components/WeekView/WeekView.module.cjs.map +1 -1
  24. package/cjs/hooks/use-day-grid-event-resize.cjs +38 -8
  25. package/cjs/hooks/use-day-grid-event-resize.cjs.map +1 -1
  26. package/cjs/hooks/use-drag-drop-handlers.cjs +126 -10
  27. package/cjs/hooks/use-drag-drop-handlers.cjs.map +1 -1
  28. package/cjs/hooks/use-event-resize.cjs +36 -12
  29. package/cjs/hooks/use-event-resize.cjs.map +1 -1
  30. package/cjs/hooks/use-horizontal-event-resize.cjs +37 -12
  31. package/cjs/hooks/use-horizontal-event-resize.cjs.map +1 -1
  32. package/cjs/hooks/validate-event-resize.cjs +37 -0
  33. package/cjs/hooks/validate-event-resize.cjs.map +1 -0
  34. package/cjs/index.cjs +2 -0
  35. package/cjs/utils/is-event-placement-allowed/is-event-placement-allowed.cjs +52 -0
  36. package/cjs/utils/is-event-placement-allowed/is-event-placement-allowed.cjs.map +1 -0
  37. package/esm/components/DayView/DayView.mjs +45 -30
  38. package/esm/components/DayView/DayView.mjs.map +1 -1
  39. package/esm/components/DayView/DayView.module.mjs.map +1 -1
  40. package/esm/components/MobileMonthView/get-mobile-month-view-events.mjs +10 -2
  41. package/esm/components/MobileMonthView/get-mobile-month-view-events.mjs.map +1 -1
  42. package/esm/components/MonthView/MonthView.mjs +11 -4
  43. package/esm/components/MonthView/MonthView.mjs.map +1 -1
  44. package/esm/components/ResourcesDayView/ResourcesDayView.mjs +74 -59
  45. package/esm/components/ResourcesDayView/ResourcesDayView.mjs.map +1 -1
  46. package/esm/components/ResourcesDayView/ResourcesDayView.module.mjs.map +1 -1
  47. package/esm/components/ResourcesMonthView/ResourcesMonthView.mjs +18 -6
  48. package/esm/components/ResourcesMonthView/ResourcesMonthView.mjs.map +1 -1
  49. package/esm/components/ResourcesSchedule/ResourcesSchedule.mjs +6 -1
  50. package/esm/components/ResourcesSchedule/ResourcesSchedule.mjs.map +1 -1
  51. package/esm/components/ResourcesWeekView/ResourcesWeekView.mjs +84 -57
  52. package/esm/components/ResourcesWeekView/ResourcesWeekView.mjs.map +1 -1
  53. package/esm/components/ResourcesWeekView/ResourcesWeekView.module.mjs.map +1 -1
  54. package/esm/components/Schedule/Schedule.mjs +14 -1
  55. package/esm/components/Schedule/Schedule.mjs.map +1 -1
  56. package/esm/components/ScheduleEvent/ScheduleEvent.module.mjs.map +1 -1
  57. package/esm/components/WeekView/WeekView.mjs +67 -45
  58. package/esm/components/WeekView/WeekView.mjs.map +1 -1
  59. package/esm/components/WeekView/WeekView.module.mjs.map +1 -1
  60. package/esm/hooks/use-day-grid-event-resize.mjs +38 -8
  61. package/esm/hooks/use-day-grid-event-resize.mjs.map +1 -1
  62. package/esm/hooks/use-drag-drop-handlers.mjs +126 -10
  63. package/esm/hooks/use-drag-drop-handlers.mjs.map +1 -1
  64. package/esm/hooks/use-event-resize.mjs +36 -12
  65. package/esm/hooks/use-event-resize.mjs.map +1 -1
  66. package/esm/hooks/use-horizontal-event-resize.mjs +37 -12
  67. package/esm/hooks/use-horizontal-event-resize.mjs.map +1 -1
  68. package/esm/hooks/validate-event-resize.mjs +37 -0
  69. package/esm/hooks/validate-event-resize.mjs.map +1 -0
  70. package/esm/index.mjs +2 -1
  71. package/esm/utils/is-event-placement-allowed/is-event-placement-allowed.mjs +50 -0
  72. package/esm/utils/is-event-placement-allowed/is-event-placement-allowed.mjs.map +1 -0
  73. package/lib/components/DayView/DayView.d.ts +11 -1
  74. package/lib/components/MonthView/MonthView.d.ts +9 -1
  75. package/lib/components/ResourcesDayView/ResourcesDayView.d.ts +11 -1
  76. package/lib/components/ResourcesMonthView/ResourcesMonthView.d.ts +11 -1
  77. package/lib/components/ResourcesSchedule/ResourcesSchedule.d.ts +12 -2
  78. package/lib/components/ResourcesWeekView/ResourcesWeekView.d.ts +11 -1
  79. package/lib/components/Schedule/Schedule.d.ts +12 -2
  80. package/lib/components/WeekView/WeekView.d.ts +11 -1
  81. package/lib/hooks/use-day-grid-event-resize.d.ts +4 -2
  82. package/lib/hooks/use-drag-drop-handlers.d.ts +17 -1
  83. package/lib/hooks/use-event-resize.d.ts +4 -2
  84. package/lib/hooks/use-horizontal-event-resize.d.ts +4 -2
  85. package/lib/hooks/validate-event-resize.d.ts +33 -0
  86. package/lib/types.d.ts +65 -0
  87. package/lib/utils/index.d.ts +2 -0
  88. package/lib/utils/is-event-placement-allowed/is-event-placement-allowed.d.ts +22 -0
  89. package/package.json +6 -6
  90. package/styles.css +29 -0
  91. package/styles.layer.css +29 -0
@@ -3,15 +3,28 @@ const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
3
3
  const require_clamp_interval_minutes = require("../utils/clamp-interval-minutes/clamp-interval-minutes.cjs");
4
4
  const require_parse_time_string = require("../utils/parse-time-string/parse-time-string.cjs");
5
5
  const require_get_day_relative_percent = require("../utils/get-day-relative-percent/get-day-relative-percent.cjs");
6
+ const require_validate_event_resize = require("./validate-event-resize.cjs");
6
7
  let dayjs = require("dayjs");
7
8
  dayjs = require_runtime.__toESM(dayjs);
8
9
  let react = require("react");
9
10
  //#region packages/@mantine/schedule/src/hooks/use-horizontal-event-resize.ts
10
- function useHorizontalEventResize({ enabled = false, mode = "default", startTime, endTime, intervalMinutes, resizeIntervalMinutes, onEventResize, canResizeEvent, withBackgroundEvents = false }) {
11
+ function useHorizontalEventResize({ enabled = false, mode = "default", startTime, endTime, intervalMinutes, resizeIntervalMinutes, onEventResize, canResizeEvent, events, preventEventOverlap, canResizeEventTo, onEventPlacementRejected, withBackgroundEvents = false }) {
11
12
  const [resizeState, setResizeState] = (0, react.useState)(null);
13
+ const [resizeValid, setResizeValid] = (0, react.useState)(true);
12
14
  const resizeRef = (0, react.useRef)(null);
13
15
  const justResizedRef = (0, react.useRef)(false);
14
16
  const stableOnEventResize = (0, react.useEffectEvent)(onEventResize || (() => {}));
17
+ const stableOnEventPlacementRejected = (0, react.useEffectEvent)(onEventPlacementRejected || (() => {}));
18
+ const validateResize = (0, react.useEffectEvent)((event, start, end, edge) => require_validate_event_resize.validateEventResize({
19
+ event,
20
+ start,
21
+ end,
22
+ edge,
23
+ events,
24
+ preventEventOverlap,
25
+ canResizeEventTo,
26
+ resourceId: event.resourceId
27
+ }));
15
28
  const parsedStartTime = require_parse_time_string.parseTimeString(startTime);
16
29
  const parsedEndTime = require_parse_time_string.parseTimeString(endTime);
17
30
  const startMinutes = parsedStartTime.hours * 60 + parsedStartTime.minutes;
@@ -72,7 +85,12 @@ function useHorizontalEventResize({ enabled = false, mode = "default", startTime
72
85
  };
73
86
  resizeRef.current = state;
74
87
  setResizeState(state);
88
+ setResizeValid(true);
75
89
  }, [enabled, mode]);
90
+ const getResizeRange = (0, react.useCallback)((state) => ({
91
+ start: state.edge === "start" ? percentToDateTime(state.currentLeft, state.eventDate) : state.originalStart,
92
+ end: state.edge === "start" ? state.originalEnd : percentToDateTime(state.currentLeft + state.currentWidth, state.eventDate)
93
+ }), [percentToDateTime]);
76
94
  const isResizing = resizeState !== null;
77
95
  (0, react.useEffect)(() => {
78
96
  if (!isResizing) return;
@@ -110,30 +128,36 @@ function useHorizontalEventResize({ enabled = false, mode = "default", startTime
110
128
  currentWidth: newWidth
111
129
  };
112
130
  setResizeState(resizeRef.current);
131
+ const range = getResizeRange(resizeRef.current);
132
+ setResizeValid(validateResize(state.event, range.start, range.end, state.edge).valid);
113
133
  };
114
134
  const handlePointerUp = () => {
115
135
  const state = resizeRef.current;
116
136
  if (state) {
117
137
  if (state.currentLeft !== state.originalLeft || state.currentWidth !== state.originalWidth) {
118
- let newStart;
119
- let newEnd;
120
- if (state.edge === "start") {
121
- newStart = percentToDateTime(state.currentLeft, state.eventDate);
122
- newEnd = state.originalEnd;
123
- } else {
124
- newStart = state.originalStart;
125
- newEnd = percentToDateTime(state.currentLeft + state.currentWidth, state.eventDate);
126
- }
127
- stableOnEventResize({
138
+ const { start: newStart, end: newEnd } = getResizeRange(state);
139
+ const { valid, conflicts, reason } = validateResize(state.event, newStart, newEnd, state.edge);
140
+ if (valid) stableOnEventResize({
128
141
  eventId: state.eventId,
129
142
  newStart,
130
143
  newEnd,
131
144
  event: state.event
132
145
  });
146
+ else stableOnEventPlacementRejected({
147
+ action: "resize",
148
+ event: state.event,
149
+ start: newStart,
150
+ end: newEnd,
151
+ edge: state.edge,
152
+ resourceId: state.event.resourceId,
153
+ conflicts,
154
+ reason
155
+ });
133
156
  }
134
157
  }
135
158
  resizeRef.current = null;
136
159
  setResizeState(null);
160
+ setResizeValid(true);
137
161
  justResizedRef.current = true;
138
162
  requestAnimationFrame(() => {
139
163
  justResizedRef.current = false;
@@ -174,7 +198,8 @@ function useHorizontalEventResize({ enabled = false, mode = "default", startTime
174
198
  resizingEdge: resizeState?.edge ?? null,
175
199
  getResizePosition,
176
200
  isResizableEvent,
177
- wasResizing
201
+ wasResizing,
202
+ resizeValid
178
203
  };
179
204
  }
180
205
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"use-horizontal-event-resize.cjs","names":["useState","useRef","useEffectEvent","parseTimeString","clampIntervalMinutes","useCallback","getDayRelativePercent"],"sources":["../../src/hooks/use-horizontal-event-resize.ts"],"sourcesContent":["import dayjs from 'dayjs';\nimport { useCallback, useEffect, useEffectEvent, useRef, useState } from 'react';\nimport { DateTimeStringValue, ScheduleEventData, ScheduleMode } from '../types';\nimport { clampIntervalMinutes } from '../utils/clamp-interval-minutes/clamp-interval-minutes';\nimport { getDayRelativePercent } from '../utils/get-day-relative-percent/get-day-relative-percent';\nimport { parseTimeString } from '../utils/parse-time-string/parse-time-string';\n\ntype ResizeEdge = 'start' | 'end';\n\ninterface ResizeState {\n eventId: string | number;\n event: ScheduleEventData;\n edge: ResizeEdge;\n container: HTMLElement;\n originalLeft: number;\n originalWidth: number;\n currentLeft: number;\n currentWidth: number;\n eventDate: string;\n originalStart: DateTimeStringValue;\n originalEnd: DateTimeStringValue;\n dayIndex: number;\n dayCount: number;\n}\n\nexport interface UseHorizontalEventResizeInput {\n enabled?: boolean;\n mode?: ScheduleMode;\n startTime: string;\n endTime: string;\n intervalMinutes: number;\n resizeIntervalMinutes?: number;\n onEventResize?: (data: {\n eventId: string | number;\n newStart: DateTimeStringValue;\n newEnd: DateTimeStringValue;\n event: ScheduleEventData;\n }) => void;\n canResizeEvent?: (event: ScheduleEventData) => boolean;\n withBackgroundEvents?: boolean;\n}\n\nexport function useHorizontalEventResize({\n enabled = false,\n mode = 'default',\n startTime,\n endTime,\n intervalMinutes,\n resizeIntervalMinutes,\n onEventResize,\n canResizeEvent,\n withBackgroundEvents = false,\n}: UseHorizontalEventResizeInput) {\n const [resizeState, setResizeState] = useState<ResizeState | null>(null);\n const resizeRef = useRef<ResizeState | null>(null);\n const justResizedRef = useRef(false);\n const stableOnEventResize = useEffectEvent(onEventResize || (() => {}));\n\n const parsedStartTime = parseTimeString(startTime);\n const parsedEndTime = parseTimeString(endTime);\n const startMinutes = parsedStartTime.hours * 60 + parsedStartTime.minutes;\n const endMinutes = parsedEndTime.hours * 60 + parsedEndTime.minutes;\n const clampedInterval = clampIntervalMinutes(intervalMinutes);\n const clampedResizeInterval = clampIntervalMinutes(resizeIntervalMinutes ?? intervalMinutes);\n const literalRange = endMinutes - startMinutes;\n const totalMinutes = Math.ceil(literalRange / clampedInterval) * clampedInterval;\n\n // Snapped in absolute minutes from midnight so resized edges land on the same grid as\n // dragged events – see the matching comment in `use-event-resize`.\n const clampAndSnap = useCallback(\n (minutes: number): number => {\n const snapped =\n Math.round((startMinutes + minutes) / clampedResizeInterval) * clampedResizeInterval;\n return Math.max(0, Math.min(literalRange, snapped - startMinutes));\n },\n [literalRange, clampedResizeInterval, startMinutes]\n );\n\n const percentToDateTime = useCallback(\n (percent: number, eventDate: string): DateTimeStringValue => {\n const minutes = (percent / 100) * totalMinutes;\n const snappedMinutes = clampAndSnap(minutes);\n const totalMins = startMinutes + snappedMinutes;\n const hours = Math.floor(totalMins / 60);\n const mins = totalMins % 60;\n return `${eventDate} ${String(hours).padStart(2, '0')}:${String(mins).padStart(2, '0')}:00`;\n },\n [totalMinutes, startMinutes, clampAndSnap]\n );\n\n const snapEdgeMinutes = useCallback(\n (minutes: number, direction: 'up' | 'down'): number => {\n const absolute = startMinutes + minutes;\n const snapped =\n direction === 'up'\n ? Math.ceil(absolute / clampedResizeInterval) * clampedResizeInterval\n : Math.floor(absolute / clampedResizeInterval) * clampedResizeInterval;\n return Math.max(0, Math.min(literalRange, snapped - startMinutes));\n },\n [literalRange, clampedResizeInterval, startMinutes]\n );\n\n const percentToMinutes = useCallback(\n (percent: number): number => (percent / 100) * totalMinutes,\n [totalMinutes]\n );\n\n const minutesToPercent = useCallback(\n (minutes: number): number => (minutes / totalMinutes) * 100,\n [totalMinutes]\n );\n\n const handleResizeStart = useCallback(\n ({\n event,\n edge,\n container,\n originalLeft,\n originalWidth,\n eventDate,\n dayIndex = 0,\n dayCount = 1,\n pointerEvent,\n }: {\n event: ScheduleEventData;\n edge: ResizeEdge;\n container: HTMLElement;\n originalLeft: number;\n originalWidth: number;\n eventDate: string;\n dayIndex?: number;\n dayCount?: number;\n pointerEvent: React.PointerEvent;\n }) => {\n if (!enabled || mode === 'static') {\n return;\n }\n\n pointerEvent.preventDefault();\n pointerEvent.stopPropagation();\n\n const state: ResizeState = {\n eventId: event.id,\n event,\n edge,\n container,\n originalLeft,\n originalWidth,\n currentLeft: originalLeft,\n currentWidth: originalWidth,\n eventDate,\n originalStart: dayjs(event.start).format('YYYY-MM-DD HH:mm:ss'),\n originalEnd: dayjs(event.end).format('YYYY-MM-DD HH:mm:ss'),\n dayIndex,\n dayCount,\n };\n\n resizeRef.current = state;\n setResizeState(state);\n },\n [enabled, mode]\n );\n\n const isResizing = resizeState !== null;\n\n useEffect(() => {\n if (!isResizing) {\n return undefined;\n }\n\n const savedUserSelect = document.body.style.userSelect;\n const savedCursor = document.body.style.cursor;\n document.body.style.userSelect = 'none';\n document.body.style.cursor = 'ew-resize';\n\n const handlePointerMove = (e: PointerEvent) => {\n const state = resizeRef.current;\n if (!state) {\n return;\n }\n\n const containerRect = state.container.getBoundingClientRect();\n const rawPercent = getDayRelativePercent({\n clientX: e.clientX,\n containerLeft: containerRect.left,\n containerWidth: containerRect.width,\n dayIndex: state.dayIndex,\n dayCount: state.dayCount,\n });\n const draggedMinutes = clampAndSnap(percentToMinutes(rawPercent));\n\n let newLeft = state.originalLeft;\n let newWidth = state.originalWidth;\n\n if (state.edge === 'end') {\n const leftMinutes = percentToMinutes(state.originalLeft);\n const minEndMinutes = snapEdgeMinutes(leftMinutes + clampedResizeInterval, 'up');\n const endMinutes = Math.max(draggedMinutes, minEndMinutes);\n newWidth = Math.max(0, minutesToPercent(endMinutes) - state.originalLeft);\n } else {\n const rightMinutes = percentToMinutes(state.originalLeft + state.originalWidth);\n const maxStartMinutes = snapEdgeMinutes(rightMinutes - clampedResizeInterval, 'down');\n const startMinutesValue = Math.min(draggedMinutes, maxStartMinutes);\n newLeft = minutesToPercent(startMinutesValue);\n newWidth = Math.max(0, state.originalLeft + state.originalWidth - newLeft);\n }\n\n resizeRef.current = { ...state, currentLeft: newLeft, currentWidth: newWidth };\n setResizeState(resizeRef.current);\n };\n\n const handlePointerUp = () => {\n const state = resizeRef.current;\n if (state) {\n if (\n state.currentLeft !== state.originalLeft ||\n state.currentWidth !== state.originalWidth\n ) {\n let newStart: DateTimeStringValue;\n let newEnd: DateTimeStringValue;\n\n if (state.edge === 'start') {\n newStart = percentToDateTime(state.currentLeft, state.eventDate);\n newEnd = state.originalEnd;\n } else {\n newStart = state.originalStart;\n newEnd = percentToDateTime(state.currentLeft + state.currentWidth, state.eventDate);\n }\n\n stableOnEventResize({\n eventId: state.eventId,\n newStart,\n newEnd,\n event: state.event,\n });\n }\n }\n resizeRef.current = null;\n setResizeState(null);\n justResizedRef.current = true;\n requestAnimationFrame(() => {\n justResizedRef.current = false;\n });\n };\n\n document.addEventListener('pointermove', handlePointerMove);\n document.addEventListener('pointerup', handlePointerUp);\n\n return () => {\n document.body.style.userSelect = savedUserSelect;\n document.body.style.cursor = savedCursor;\n document.removeEventListener('pointermove', handlePointerMove);\n document.removeEventListener('pointerup', handlePointerUp);\n };\n }, [isResizing]);\n\n const getResizePosition = useCallback(\n (eventId: string | number, eventDate?: string) => {\n if (!resizeState || resizeState.eventId !== eventId) {\n return null;\n }\n if (eventDate !== undefined && resizeState.eventDate !== eventDate) {\n return null;\n }\n return { left: resizeState.currentLeft, width: resizeState.currentWidth };\n },\n [resizeState]\n );\n\n const isResizableEvent = useCallback(\n (event: ScheduleEventData) => {\n if (!enabled || mode === 'static') {\n return false;\n }\n if (event.display === 'background' && !withBackgroundEvents) {\n return false;\n }\n return canResizeEvent ? canResizeEvent(event) : true;\n },\n [enabled, mode, canResizeEvent, withBackgroundEvents]\n );\n\n const wasResizing = useCallback(() => justResizedRef.current, []);\n\n return {\n handleResizeStart,\n isResizing,\n resizingEventId: resizeState?.eventId ?? null,\n resizingEdge: resizeState?.edge ?? null,\n getResizePosition,\n isResizableEvent,\n wasResizing,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"use-horizontal-event-resize.cjs","names":["useState","useRef","useEffectEvent","validateEventResize","parseTimeString","clampIntervalMinutes","useCallback","getDayRelativePercent"],"sources":["../../src/hooks/use-horizontal-event-resize.ts"],"sourcesContent":["import dayjs from 'dayjs';\nimport { useCallback, useEffect, useEffectEvent, useRef, useState } from 'react';\nimport { DateTimeStringValue, ScheduleEventData, ScheduleMode } from '../types';\nimport { clampIntervalMinutes } from '../utils/clamp-interval-minutes/clamp-interval-minutes';\nimport { getDayRelativePercent } from '../utils/get-day-relative-percent/get-day-relative-percent';\nimport { parseTimeString } from '../utils/parse-time-string/parse-time-string';\nimport { EventResizeValidationOptions, validateEventResize } from './validate-event-resize';\n\ntype ResizeEdge = 'start' | 'end';\n\ninterface ResizeState {\n eventId: string | number;\n event: ScheduleEventData;\n edge: ResizeEdge;\n container: HTMLElement;\n originalLeft: number;\n originalWidth: number;\n currentLeft: number;\n currentWidth: number;\n eventDate: string;\n originalStart: DateTimeStringValue;\n originalEnd: DateTimeStringValue;\n dayIndex: number;\n dayCount: number;\n}\n\nexport interface UseHorizontalEventResizeInput extends EventResizeValidationOptions {\n enabled?: boolean;\n mode?: ScheduleMode;\n startTime: string;\n endTime: string;\n intervalMinutes: number;\n resizeIntervalMinutes?: number;\n onEventResize?: (data: {\n eventId: string | number;\n newStart: DateTimeStringValue;\n newEnd: DateTimeStringValue;\n event: ScheduleEventData;\n }) => void;\n canResizeEvent?: (event: ScheduleEventData) => boolean;\n withBackgroundEvents?: boolean;\n}\n\nexport function useHorizontalEventResize({\n enabled = false,\n mode = 'default',\n startTime,\n endTime,\n intervalMinutes,\n resizeIntervalMinutes,\n onEventResize,\n canResizeEvent,\n events,\n preventEventOverlap,\n canResizeEventTo,\n onEventPlacementRejected,\n withBackgroundEvents = false,\n}: UseHorizontalEventResizeInput) {\n const [resizeState, setResizeState] = useState<ResizeState | null>(null);\n const [resizeValid, setResizeValid] = useState(true);\n const resizeRef = useRef<ResizeState | null>(null);\n const justResizedRef = useRef(false);\n const stableOnEventResize = useEffectEvent(onEventResize || (() => {}));\n const stableOnEventPlacementRejected = useEffectEvent(onEventPlacementRejected || (() => {}));\n\n const validateResize = useEffectEvent(\n (\n event: ScheduleEventData,\n start: DateTimeStringValue,\n end: DateTimeStringValue,\n edge: 'start' | 'end'\n ) =>\n validateEventResize({\n event,\n start,\n end,\n edge,\n events,\n preventEventOverlap,\n canResizeEventTo,\n resourceId: event.resourceId,\n })\n );\n\n const parsedStartTime = parseTimeString(startTime);\n const parsedEndTime = parseTimeString(endTime);\n const startMinutes = parsedStartTime.hours * 60 + parsedStartTime.minutes;\n const endMinutes = parsedEndTime.hours * 60 + parsedEndTime.minutes;\n const clampedInterval = clampIntervalMinutes(intervalMinutes);\n const clampedResizeInterval = clampIntervalMinutes(resizeIntervalMinutes ?? intervalMinutes);\n const literalRange = endMinutes - startMinutes;\n const totalMinutes = Math.ceil(literalRange / clampedInterval) * clampedInterval;\n\n // Snapped in absolute minutes from midnight so resized edges land on the same grid as\n // dragged events – see the matching comment in `use-event-resize`.\n const clampAndSnap = useCallback(\n (minutes: number): number => {\n const snapped =\n Math.round((startMinutes + minutes) / clampedResizeInterval) * clampedResizeInterval;\n return Math.max(0, Math.min(literalRange, snapped - startMinutes));\n },\n [literalRange, clampedResizeInterval, startMinutes]\n );\n\n const percentToDateTime = useCallback(\n (percent: number, eventDate: string): DateTimeStringValue => {\n const minutes = (percent / 100) * totalMinutes;\n const snappedMinutes = clampAndSnap(minutes);\n const totalMins = startMinutes + snappedMinutes;\n const hours = Math.floor(totalMins / 60);\n const mins = totalMins % 60;\n return `${eventDate} ${String(hours).padStart(2, '0')}:${String(mins).padStart(2, '0')}:00`;\n },\n [totalMinutes, startMinutes, clampAndSnap]\n );\n\n const snapEdgeMinutes = useCallback(\n (minutes: number, direction: 'up' | 'down'): number => {\n const absolute = startMinutes + minutes;\n const snapped =\n direction === 'up'\n ? Math.ceil(absolute / clampedResizeInterval) * clampedResizeInterval\n : Math.floor(absolute / clampedResizeInterval) * clampedResizeInterval;\n return Math.max(0, Math.min(literalRange, snapped - startMinutes));\n },\n [literalRange, clampedResizeInterval, startMinutes]\n );\n\n const percentToMinutes = useCallback(\n (percent: number): number => (percent / 100) * totalMinutes,\n [totalMinutes]\n );\n\n const minutesToPercent = useCallback(\n (minutes: number): number => (minutes / totalMinutes) * 100,\n [totalMinutes]\n );\n\n const handleResizeStart = useCallback(\n ({\n event,\n edge,\n container,\n originalLeft,\n originalWidth,\n eventDate,\n dayIndex = 0,\n dayCount = 1,\n pointerEvent,\n }: {\n event: ScheduleEventData;\n edge: ResizeEdge;\n container: HTMLElement;\n originalLeft: number;\n originalWidth: number;\n eventDate: string;\n dayIndex?: number;\n dayCount?: number;\n pointerEvent: React.PointerEvent;\n }) => {\n if (!enabled || mode === 'static') {\n return;\n }\n\n pointerEvent.preventDefault();\n pointerEvent.stopPropagation();\n\n const state: ResizeState = {\n eventId: event.id,\n event,\n edge,\n container,\n originalLeft,\n originalWidth,\n currentLeft: originalLeft,\n currentWidth: originalWidth,\n eventDate,\n originalStart: dayjs(event.start).format('YYYY-MM-DD HH:mm:ss'),\n originalEnd: dayjs(event.end).format('YYYY-MM-DD HH:mm:ss'),\n dayIndex,\n dayCount,\n };\n\n resizeRef.current = state;\n setResizeState(state);\n setResizeValid(true);\n },\n [enabled, mode]\n );\n\n const getResizeRange = useCallback(\n (state: ResizeState) => ({\n start:\n state.edge === 'start'\n ? percentToDateTime(state.currentLeft, state.eventDate)\n : state.originalStart,\n end:\n state.edge === 'start'\n ? state.originalEnd\n : percentToDateTime(state.currentLeft + state.currentWidth, state.eventDate),\n }),\n [percentToDateTime]\n );\n\n const isResizing = resizeState !== null;\n\n useEffect(() => {\n if (!isResizing) {\n return undefined;\n }\n\n const savedUserSelect = document.body.style.userSelect;\n const savedCursor = document.body.style.cursor;\n document.body.style.userSelect = 'none';\n document.body.style.cursor = 'ew-resize';\n\n const handlePointerMove = (e: PointerEvent) => {\n const state = resizeRef.current;\n if (!state) {\n return;\n }\n\n const containerRect = state.container.getBoundingClientRect();\n const rawPercent = getDayRelativePercent({\n clientX: e.clientX,\n containerLeft: containerRect.left,\n containerWidth: containerRect.width,\n dayIndex: state.dayIndex,\n dayCount: state.dayCount,\n });\n const draggedMinutes = clampAndSnap(percentToMinutes(rawPercent));\n\n let newLeft = state.originalLeft;\n let newWidth = state.originalWidth;\n\n if (state.edge === 'end') {\n const leftMinutes = percentToMinutes(state.originalLeft);\n const minEndMinutes = snapEdgeMinutes(leftMinutes + clampedResizeInterval, 'up');\n const endMinutes = Math.max(draggedMinutes, minEndMinutes);\n newWidth = Math.max(0, minutesToPercent(endMinutes) - state.originalLeft);\n } else {\n const rightMinutes = percentToMinutes(state.originalLeft + state.originalWidth);\n const maxStartMinutes = snapEdgeMinutes(rightMinutes - clampedResizeInterval, 'down');\n const startMinutesValue = Math.min(draggedMinutes, maxStartMinutes);\n newLeft = minutesToPercent(startMinutesValue);\n newWidth = Math.max(0, state.originalLeft + state.originalWidth - newLeft);\n }\n\n resizeRef.current = { ...state, currentLeft: newLeft, currentWidth: newWidth };\n setResizeState(resizeRef.current);\n\n const range = getResizeRange(resizeRef.current);\n setResizeValid(validateResize(state.event, range.start, range.end, state.edge).valid);\n };\n\n const handlePointerUp = () => {\n const state = resizeRef.current;\n if (state) {\n if (\n state.currentLeft !== state.originalLeft ||\n state.currentWidth !== state.originalWidth\n ) {\n const { start: newStart, end: newEnd } = getResizeRange(state);\n const { valid, conflicts, reason } = validateResize(\n state.event,\n newStart,\n newEnd,\n state.edge\n );\n\n if (valid) {\n stableOnEventResize({\n eventId: state.eventId,\n newStart,\n newEnd,\n event: state.event,\n });\n } else {\n stableOnEventPlacementRejected({\n action: 'resize',\n event: state.event,\n start: newStart,\n end: newEnd,\n edge: state.edge,\n resourceId: state.event.resourceId,\n conflicts,\n reason: reason!,\n });\n }\n }\n }\n resizeRef.current = null;\n setResizeState(null);\n setResizeValid(true);\n justResizedRef.current = true;\n requestAnimationFrame(() => {\n justResizedRef.current = false;\n });\n };\n\n document.addEventListener('pointermove', handlePointerMove);\n document.addEventListener('pointerup', handlePointerUp);\n\n return () => {\n document.body.style.userSelect = savedUserSelect;\n document.body.style.cursor = savedCursor;\n document.removeEventListener('pointermove', handlePointerMove);\n document.removeEventListener('pointerup', handlePointerUp);\n };\n }, [isResizing]);\n\n const getResizePosition = useCallback(\n (eventId: string | number, eventDate?: string) => {\n if (!resizeState || resizeState.eventId !== eventId) {\n return null;\n }\n if (eventDate !== undefined && resizeState.eventDate !== eventDate) {\n return null;\n }\n return { left: resizeState.currentLeft, width: resizeState.currentWidth };\n },\n [resizeState]\n );\n\n const isResizableEvent = useCallback(\n (event: ScheduleEventData) => {\n if (!enabled || mode === 'static') {\n return false;\n }\n if (event.display === 'background' && !withBackgroundEvents) {\n return false;\n }\n return canResizeEvent ? canResizeEvent(event) : true;\n },\n [enabled, mode, canResizeEvent, withBackgroundEvents]\n );\n\n const wasResizing = useCallback(() => justResizedRef.current, []);\n\n return {\n handleResizeStart,\n isResizing,\n resizingEventId: resizeState?.eventId ?? null,\n resizingEdge: resizeState?.edge ?? null,\n getResizePosition,\n isResizableEvent,\n wasResizing,\n resizeValid,\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ "use client";
2
+ const require_is_event_placement_allowed = require("../utils/is-event-placement-allowed/is-event-placement-allowed.cjs");
3
+ //#region packages/@mantine/schedule/src/hooks/validate-event-resize.ts
4
+ function validateEventResize({ event, start, end, edge, events, preventEventOverlap, canResizeEventTo, resourceId }) {
5
+ const { allowed, conflicts } = require_is_event_placement_allowed.isEventPlacementAllowed({
6
+ event,
7
+ start,
8
+ end,
9
+ events: events || [],
10
+ preventEventOverlap,
11
+ resourceId
12
+ });
13
+ if (!allowed) return {
14
+ valid: false,
15
+ conflicts,
16
+ reason: "overlap"
17
+ };
18
+ if (canResizeEventTo && canResizeEventTo({
19
+ event,
20
+ start,
21
+ end,
22
+ edge
23
+ }) === false) return {
24
+ valid: false,
25
+ conflicts: [],
26
+ reason: "rejected"
27
+ };
28
+ return {
29
+ valid: true,
30
+ conflicts: [],
31
+ reason: null
32
+ };
33
+ }
34
+ //#endregion
35
+ exports.validateEventResize = validateEventResize;
36
+
37
+ //# sourceMappingURL=validate-event-resize.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-event-resize.cjs","names":["isEventPlacementAllowed"],"sources":["../../src/hooks/validate-event-resize.ts"],"sourcesContent":["import {\n DateTimeStringValue,\n PreventEventOverlap,\n ScheduleCanResizeEventToData,\n ScheduleEventData,\n} from '../types';\nimport { isEventPlacementAllowed } from '../utils/is-event-placement-allowed/is-event-placement-allowed';\n\nexport interface EventResizeValidationOptions {\n /** Events the candidate range is checked against when `preventEventOverlap` is set */\n events?: ScheduleEventData[];\n\n /** If set, resizes that would make the event overlap another event are rejected */\n preventEventOverlap?: PreventEventOverlap;\n\n /** Called on every pointer move to compute live feedback and again before the resize is committed, return `false` to reject the new size */\n canResizeEventTo?: (data: ScheduleCanResizeEventToData) => boolean;\n\n /** Called when a resize is rejected */\n onEventPlacementRejected?: (data: {\n action: 'resize';\n event: ScheduleEventData;\n start: DateTimeStringValue;\n end: DateTimeStringValue;\n edge: 'start' | 'end';\n resourceId?: string | number;\n conflicts: ScheduleEventData[];\n reason: 'overlap' | 'rejected';\n }) => void;\n}\n\nexport interface ValidateEventResizeInput extends EventResizeValidationOptions {\n event: ScheduleEventData;\n start: DateTimeStringValue;\n end: DateTimeStringValue;\n edge: 'start' | 'end';\n resourceId?: string | number;\n}\n\nexport interface ValidateEventResizeResult {\n valid: boolean;\n conflicts: ScheduleEventData[];\n reason: 'overlap' | 'rejected' | null;\n}\n\nexport function validateEventResize({\n event,\n start,\n end,\n edge,\n events,\n preventEventOverlap,\n canResizeEventTo,\n resourceId,\n}: ValidateEventResizeInput): ValidateEventResizeResult {\n const { allowed, conflicts } = isEventPlacementAllowed({\n event,\n start,\n end,\n events: events || [],\n preventEventOverlap,\n resourceId,\n });\n\n if (!allowed) {\n return { valid: false, conflicts, reason: 'overlap' };\n }\n\n if (canResizeEventTo && canResizeEventTo({ event, start, end, edge }) === false) {\n return { valid: false, conflicts: [], reason: 'rejected' };\n }\n\n return { valid: true, conflicts: [], reason: null };\n}\n"],"mappings":";;;AA6CA,SAAgB,oBAAoB,EAClC,OACA,OACA,KACA,MACA,QACA,qBACA,kBACA,cACsD;CACtD,MAAM,EAAE,SAAS,cAAcA,mCAAAA,wBAAwB;EACrD;EACA;EACA;EACA,QAAQ,UAAU,CAAC;EACnB;EACA;CACF,CAAC;CAED,IAAI,CAAC,SACH,OAAO;EAAE,OAAO;EAAO;EAAW,QAAQ;CAAU;CAGtD,IAAI,oBAAoB,iBAAiB;EAAE;EAAO;EAAO;EAAK;CAAK,CAAC,MAAM,OACxE,OAAO;EAAE,OAAO;EAAO,WAAW,CAAC;EAAG,QAAQ;CAAW;CAG3D,OAAO;EAAE,OAAO;EAAM,WAAW,CAAC;EAAG,QAAQ;CAAK;AACpD"}
package/cjs/index.cjs CHANGED
@@ -44,6 +44,7 @@ const require_get_index_from_drag_point = require("./utils/get-index-from-drag-p
44
44
  const require_get_day_relative_percent = require("./utils/get-day-relative-percent/get-day-relative-percent.cjs");
45
45
  const require_get_overlap_clusters = require("./utils/get-overlap-clusters/get-overlap-clusters.cjs");
46
46
  const require_apply_cascade_layout = require("./utils/apply-cascade-layout/apply-cascade-layout.cjs");
47
+ const require_is_event_placement_allowed = require("./utils/is-event-placement-allowed/is-event-placement-allowed.cjs");
47
48
  const require_AgendaView = require("./components/AgendaView/AgendaView.cjs");
48
49
  const require_CurrentTimeIndicator = require("./components/CurrentTimeIndicator/CurrentTimeIndicator.cjs");
49
50
  const require_DragContext = require("./components/DragContext/DragContext.cjs");
@@ -112,6 +113,7 @@ exports.isAfterMinDate = require_is_after_min_date.isAfterMinDate;
112
113
  exports.isAllDayEvent = require_is_all_day_event.isAllDayEvent;
113
114
  exports.isBeforeMaxDate = require_is_before_max_date.isBeforeMaxDate;
114
115
  exports.isEventInTimeRange = require_is_event_in_time_range.isEventInTimeRange;
116
+ exports.isEventPlacementAllowed = require_is_event_placement_allowed.isEventPlacementAllowed;
115
117
  exports.isEventsOverlap = require_is_events_overlap.isEventsOverlap;
116
118
  exports.isInTimeRange = require_is_in_time_range.isInTimeRange;
117
119
  exports.isMultidayEvent = require_is_multiday_event.isMultidayEvent;
@@ -0,0 +1,52 @@
1
+ "use client";
2
+ const require_runtime = require("../../_virtual/_rolldown/runtime.cjs");
3
+ const require_is_events_overlap = require("../is-events-overlap/is-events-overlap.cjs");
4
+ let dayjs = require("dayjs");
5
+ dayjs = require_runtime.__toESM(dayjs);
6
+ //#region packages/@mantine/schedule/src/utils/is-event-placement-allowed/is-event-placement-allowed.ts
7
+ function isSameEvent(event, other) {
8
+ if (event.id === other.id) return true;
9
+ const eventSeriesId = event.recurringEventId ?? event.recurringInstance?.recurringEventId;
10
+ const otherSeriesId = other.recurringEventId ?? other.recurringInstance?.recurringEventId;
11
+ if (eventSeriesId === void 0 || otherSeriesId === void 0) return false;
12
+ const eventOccurrenceId = event.recurrenceId ?? event.recurringInstance?.recurrenceId;
13
+ const otherOccurrenceId = other.recurrenceId ?? other.recurringInstance?.recurrenceId;
14
+ return eventSeriesId === otherSeriesId && eventOccurrenceId !== void 0 && eventOccurrenceId === otherOccurrenceId;
15
+ }
16
+ function isMidnight(value) {
17
+ return value.hour() === 0 && value.minute() === 0 && value.second() === 0;
18
+ }
19
+ function spansWholeDays(event) {
20
+ const start = (0, dayjs.default)(event.start);
21
+ const end = (0, dayjs.default)(event.end);
22
+ if (!isMidnight(start)) return false;
23
+ return isMidnight(end) || end.hour() === 23 && end.minute() === 59 && end.second() === 59;
24
+ }
25
+ function isEventPlacementAllowed({ event, start, end, events, preventEventOverlap, resourceId }) {
26
+ if (!preventEventOverlap) return {
27
+ allowed: true,
28
+ conflicts: []
29
+ };
30
+ const candidate = {
31
+ ...event,
32
+ start,
33
+ end,
34
+ ...resourceId !== void 0 ? { resourceId } : {}
35
+ };
36
+ const candidateIsAllDay = spansWholeDays(candidate);
37
+ const conflicts = events.filter((other) => {
38
+ if (other.display === "background" || isSameEvent(event, other)) return false;
39
+ if (resourceId !== void 0 && other.resourceId !== resourceId) return false;
40
+ if (spansWholeDays(other) !== candidateIsAllDay) return false;
41
+ if (!require_is_events_overlap.isEventsOverlap(other, candidate)) return false;
42
+ return typeof preventEventOverlap === "function" ? preventEventOverlap(other, candidate) : true;
43
+ });
44
+ return {
45
+ allowed: conflicts.length === 0,
46
+ conflicts
47
+ };
48
+ }
49
+ //#endregion
50
+ exports.isEventPlacementAllowed = isEventPlacementAllowed;
51
+
52
+ //# sourceMappingURL=is-event-placement-allowed.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-event-placement-allowed.cjs","names":["isEventsOverlap"],"sources":["../../../src/utils/is-event-placement-allowed/is-event-placement-allowed.ts"],"sourcesContent":["import dayjs from 'dayjs';\nimport { DateTimeStringValue, PreventEventOverlap, ScheduleEventData } from '../../types';\nimport { isEventsOverlap } from '../is-events-overlap/is-events-overlap';\n\nexport interface IsEventPlacementAllowedInput {\n /** Event that is being moved or resized */\n event: ScheduleEventData;\n\n /** Candidate start of the event */\n start: DateTimeStringValue;\n\n /** Candidate end of the event */\n end: DateTimeStringValue;\n\n /** Events the candidate range is checked against */\n events: ScheduleEventData[];\n\n /** If set, placements that overlap another event are rejected */\n preventEventOverlap?: PreventEventOverlap;\n\n /** Target resource, limits the check to events of that resource */\n resourceId?: string | number;\n}\n\nexport interface IsEventPlacementAllowedResult {\n /** True if the candidate range does not conflict with any event */\n allowed: boolean;\n\n /** Events the candidate range collided with */\n conflicts: ScheduleEventData[];\n}\n\nfunction isSameEvent(event: ScheduleEventData, other: ScheduleEventData) {\n if (event.id === other.id) {\n return true;\n }\n\n const eventSeriesId = event.recurringEventId ?? event.recurringInstance?.recurringEventId;\n const otherSeriesId = other.recurringEventId ?? other.recurringInstance?.recurringEventId;\n\n if (eventSeriesId === undefined || otherSeriesId === undefined) {\n return false;\n }\n\n const eventOccurrenceId = event.recurrenceId ?? event.recurringInstance?.recurrenceId;\n const otherOccurrenceId = other.recurrenceId ?? other.recurringInstance?.recurrenceId;\n\n return (\n eventSeriesId === otherSeriesId &&\n eventOccurrenceId !== undefined &&\n eventOccurrenceId === otherOccurrenceId\n );\n}\n\nfunction isMidnight(value: dayjs.Dayjs) {\n return value.hour() === 0 && value.minute() === 0 && value.second() === 0;\n}\n\nfunction spansWholeDays(event: ScheduleEventData) {\n const start = dayjs(event.start);\n const end = dayjs(event.end);\n\n if (!isMidnight(start)) {\n return false;\n }\n\n return isMidnight(end) || (end.hour() === 23 && end.minute() === 59 && end.second() === 59);\n}\n\nexport function isEventPlacementAllowed({\n event,\n start,\n end,\n events,\n preventEventOverlap,\n resourceId,\n}: IsEventPlacementAllowedInput): IsEventPlacementAllowedResult {\n if (!preventEventOverlap) {\n return { allowed: true, conflicts: [] };\n }\n\n const candidate = {\n ...event,\n start,\n end,\n ...(resourceId !== undefined ? { resourceId } : {}),\n } as ScheduleEventData;\n const candidateIsAllDay = spansWholeDays(candidate);\n const conflicts = events.filter((other) => {\n if (other.display === 'background' || isSameEvent(event, other)) {\n return false;\n }\n\n if (resourceId !== undefined && other.resourceId !== resourceId) {\n return false;\n }\n\n if (spansWholeDays(other) !== candidateIsAllDay) {\n return false;\n }\n\n if (!isEventsOverlap(other, candidate)) {\n return false;\n }\n\n return typeof preventEventOverlap === 'function' ? preventEventOverlap(other, candidate) : true;\n });\n\n return { allowed: conflicts.length === 0, conflicts };\n}\n"],"mappings":";;;;;;AAgCA,SAAS,YAAY,OAA0B,OAA0B;CACvE,IAAI,MAAM,OAAO,MAAM,IACrB,OAAO;CAGT,MAAM,gBAAgB,MAAM,oBAAoB,MAAM,mBAAmB;CACzE,MAAM,gBAAgB,MAAM,oBAAoB,MAAM,mBAAmB;CAEzE,IAAI,kBAAkB,KAAA,KAAa,kBAAkB,KAAA,GACnD,OAAO;CAGT,MAAM,oBAAoB,MAAM,gBAAgB,MAAM,mBAAmB;CACzE,MAAM,oBAAoB,MAAM,gBAAgB,MAAM,mBAAmB;CAEzE,OACE,kBAAkB,iBAClB,sBAAsB,KAAA,KACtB,sBAAsB;AAE1B;AAEA,SAAS,WAAW,OAAoB;CACtC,OAAO,MAAM,KAAK,MAAM,KAAK,MAAM,OAAO,MAAM,KAAK,MAAM,OAAO,MAAM;AAC1E;AAEA,SAAS,eAAe,OAA0B;CAChD,MAAM,SAAA,GAAQ,MAAA,QAAA,CAAM,MAAM,KAAK;CAC/B,MAAM,OAAA,GAAM,MAAA,QAAA,CAAM,MAAM,GAAG;CAE3B,IAAI,CAAC,WAAW,KAAK,GACnB,OAAO;CAGT,OAAO,WAAW,GAAG,KAAM,IAAI,KAAK,MAAM,MAAM,IAAI,OAAO,MAAM,MAAM,IAAI,OAAO,MAAM;AAC1F;AAEA,SAAgB,wBAAwB,EACtC,OACA,OACA,KACA,QACA,qBACA,cAC8D;CAC9D,IAAI,CAAC,qBACH,OAAO;EAAE,SAAS;EAAM,WAAW,CAAC;CAAE;CAGxC,MAAM,YAAY;EAChB,GAAG;EACH;EACA;EACA,GAAI,eAAe,KAAA,IAAY,EAAE,WAAW,IAAI,CAAC;CACnD;CACA,MAAM,oBAAoB,eAAe,SAAS;CAClD,MAAM,YAAY,OAAO,QAAQ,UAAU;EACzC,IAAI,MAAM,YAAY,gBAAgB,YAAY,OAAO,KAAK,GAC5D,OAAO;EAGT,IAAI,eAAe,KAAA,KAAa,MAAM,eAAe,YACnD,OAAO;EAGT,IAAI,eAAe,KAAK,MAAM,mBAC5B,OAAO;EAGT,IAAI,CAACA,0BAAAA,gBAAgB,OAAO,SAAS,GACnC,OAAO;EAGT,OAAO,OAAO,wBAAwB,aAAa,oBAAoB,OAAO,SAAS,IAAI;CAC7F,CAAC;CAED,OAAO;EAAE,SAAS,UAAU,WAAW;EAAG;CAAU;AACtD"}
@@ -59,7 +59,7 @@ const varsResolver = createVarsResolver((_theme, { radius, slotHeight, allDaySlo
59
59
  } }));
60
60
  const DayView = factory((_props) => {
61
61
  const props = useProps("DayView", defaultProps, _props);
62
- const { classNames, className, style, styles, unstyled, attributes, vars, __staticSelector, startTime, endTime, intervalMinutes, withSubHourGridLines, eventOverlapMode, eventOverlapRaiseDelay, withAllDaySlot, date, locale, slotLabelFormat, headerFormat, getCurrentTime, withCurrentTimeIndicator, withCurrentTimeBubble, withHeader, radius, onDateChange, onViewChange, previousControlProps, nextControlProps, todayControlProps, viewSelectProps, slotHeight, allDaySlotHeight, scrollAreaProps, events, moreEventsProps, renderEventBody, renderEvent, labels, highlightBusinessHours, businessHours, withEventsDragAndDrop, onEventDrop, canDragEvent, eventDragInterval, onEventDragStart, onEventDragEnd, onTimeSlotClick, onAllDaySlotClick, onEventClick, withInteractiveBackgroundEvents, withDragSlotSelect, onSlotDragEnd, mode, startScrollTime, onExternalEventDrop, withEventResize, onEventResize, canResizeEvent, eventResizeInterval, recurrenceExpansionLimit, getTimeSlotProps, withAgenda, ...others } = props;
62
+ const { classNames, className, style, styles, unstyled, attributes, vars, __staticSelector, startTime, endTime, intervalMinutes, withSubHourGridLines, eventOverlapMode, eventOverlapRaiseDelay, withAllDaySlot, date, locale, slotLabelFormat, headerFormat, getCurrentTime, withCurrentTimeIndicator, withCurrentTimeBubble, withHeader, radius, onDateChange, onViewChange, previousControlProps, nextControlProps, todayControlProps, viewSelectProps, slotHeight, allDaySlotHeight, scrollAreaProps, events, moreEventsProps, renderEventBody, renderEvent, labels, highlightBusinessHours, businessHours, withEventsDragAndDrop, onEventDrop, canDragEvent, eventDragInterval, onEventDragStart, onEventDragEnd, onTimeSlotClick, onAllDaySlotClick, onEventClick, withInteractiveBackgroundEvents, withDragSlotSelect, onSlotDragEnd, mode, startScrollTime, onExternalEventDrop, withEventResize, onEventResize, canResizeEvent, canDropEvent, canDropExternalEvent, canResizeEventTo, preventEventOverlap, onEventPlacementRejected, eventResizeInterval, recurrenceExpansionLimit, getTimeSlotProps, withAgenda, ...others } = props;
63
63
  const [agendaOpen, setAgendaOpen] = useState(false);
64
64
  const getStyles = useStyles({
65
65
  name: __staticSelector,
@@ -187,15 +187,11 @@ const DayView = factory((_props) => {
187
187
  intervalMinutes,
188
188
  eventOverlapMode
189
189
  });
190
- const handleExternalDrop = useCallback((e, slotIndex) => {
191
- if (!onExternalEventDrop) return;
190
+ const getExternalDropDateTime = useCallback((slotIndex) => {
192
191
  const slotDate = dayjs(date).format("YYYY-MM-DD");
193
192
  const slotTime = slots[slotIndex].startTime;
194
- if (eventDragInterval == null) {
195
- onExternalEventDrop(e.dataTransfer, `${slotDate} ${slotTime}`);
196
- return;
197
- }
198
193
  const slotStart = `${slotDate} ${slotTime}`;
194
+ if (eventDragInterval == null) return slotStart;
199
195
  const { start } = calculateDropTime({
200
196
  draggedEvent: {
201
197
  start: slotStart,
@@ -210,9 +206,8 @@ const DayView = factory((_props) => {
210
206
  startTime,
211
207
  endTime
212
208
  });
213
- onExternalEventDrop(e.dataTransfer, dayjs(start).format("YYYY-MM-DD HH:mm:ss"));
209
+ return dayjs(start).format("YYYY-MM-DD HH:mm:ss");
214
210
  }, [
215
- onExternalEventDrop,
216
211
  date,
217
212
  slots,
218
213
  eventDragInterval,
@@ -220,6 +215,10 @@ const DayView = factory((_props) => {
220
215
  startTime,
221
216
  endTime
222
217
  ]);
218
+ const handleExternalDrop = useCallback((e, slotIndex) => {
219
+ if (!onExternalEventDrop) return;
220
+ onExternalEventDrop(e.dataTransfer, getExternalDropDateTime(slotIndex));
221
+ }, [onExternalEventDrop, getExternalDropDateTime]);
223
222
  const getDropTimeForSlot = (slotIndex, draggedEvent) => {
224
223
  const slotTime = slots[slotIndex].startTime;
225
224
  return calculateDropTime({
@@ -242,7 +241,13 @@ const DayView = factory((_props) => {
242
241
  onEventDragStart,
243
242
  onEventDragEnd,
244
243
  calculateDropTarget: getDropTimeForSlot,
245
- onExternalDrop: onExternalEventDrop ? handleExternalDrop : void 0
244
+ onExternalDrop: onExternalEventDrop ? handleExternalDrop : void 0,
245
+ events: expandedEvents,
246
+ preventEventOverlap,
247
+ canDropEvent,
248
+ canDropExternalEvent,
249
+ onEventPlacementRejected,
250
+ getExternalDropDateTime
246
251
  });
247
252
  const updateDragPreview = (slotIndex) => {
248
253
  const draggedEvent = dragDrop.dragContextValue.draggedEvent;
@@ -264,6 +269,10 @@ const DayView = factory((_props) => {
264
269
  resizeIntervalMinutes: eventResizeInterval,
265
270
  onEventResize,
266
271
  canResizeEvent,
272
+ events: expandedEvents,
273
+ preventEventOverlap,
274
+ canResizeEventTo,
275
+ onEventPlacementRejected,
267
276
  withBackgroundEvents: withInteractiveBackgroundEvents
268
277
  });
269
278
  const withDragHandlers = (withEventsDragAndDrop || !!onExternalEventDrop) && mode !== "static";
@@ -301,7 +310,10 @@ const DayView = factory((_props) => {
301
310
  if (!eventResize.wasResizing()) onEventClick(event, e);
302
311
  } : void 0,
303
312
  ...stylesApiProps,
304
- mod: { cascade: eventOverlapMode === "cascade" },
313
+ mod: {
314
+ cascade: eventOverlapMode === "cascade",
315
+ invalid: resizePosition !== null && !eventResize.resizeValid
316
+ },
305
317
  style: {
306
318
  ...stylesApiProps.styles?.event,
307
319
  top: `${eventTop}%`,
@@ -561,25 +573,28 @@ const DayView = factory((_props) => {
561
573
  children: [
562
574
  backgroundTimedEventNodes,
563
575
  eventsNodes,
564
- dragDrop.dragPreview && dragDrop.dragContextValue.draggedEvent && /* @__PURE__ */ jsx(Box, { ...getStyles("dayViewDragPreview", { style: (() => {
565
- const { top, height } = getDayPosition({
566
- event: {
567
- ...dragDrop.dragContextValue.draggedEvent,
568
- start: dragDrop.dragPreview.start,
569
- end: dragDrop.dragPreview.end
570
- },
571
- startTime,
572
- endTime,
573
- intervalMinutes
574
- });
575
- return {
576
- position: "absolute",
577
- insetInlineStart: 0,
578
- insetInlineEnd: 0,
579
- top: `${top}%`,
580
- height: `${height}%`
581
- };
582
- })() }) }),
576
+ dragDrop.dragPreview && dragDrop.dragContextValue.draggedEvent && /* @__PURE__ */ jsx(Box, {
577
+ mod: { invalid: !dragDrop.dropValid },
578
+ ...getStyles("dayViewDragPreview", { style: (() => {
579
+ const { top, height } = getDayPosition({
580
+ event: {
581
+ ...dragDrop.dragContextValue.draggedEvent,
582
+ start: dragDrop.dragPreview.start,
583
+ end: dragDrop.dragPreview.end
584
+ },
585
+ startTime,
586
+ endTime,
587
+ intervalMinutes
588
+ });
589
+ return {
590
+ position: "absolute",
591
+ insetInlineStart: 0,
592
+ insetInlineEnd: 0,
593
+ top: `${top}%`,
594
+ height: `${height}%`
595
+ };
596
+ })() })
597
+ }),
583
598
  showCurrentTimeIndicator && /* @__PURE__ */ jsx(CurrentTimeIndicator, {
584
599
  startOffset: "calc(var(--day-view-slot-labels-width) * -1)",
585
600
  endOffset: "0rem",