@mantine/schedule 9.6.3 → 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.
- package/cjs/components/DayView/DayView.cjs +45 -30
- package/cjs/components/DayView/DayView.cjs.map +1 -1
- package/cjs/components/DayView/DayView.module.cjs.map +1 -1
- package/cjs/components/MonthView/MonthView.cjs +11 -4
- package/cjs/components/MonthView/MonthView.cjs.map +1 -1
- package/cjs/components/ResourcesDayView/ResourcesDayView.cjs +74 -59
- package/cjs/components/ResourcesDayView/ResourcesDayView.cjs.map +1 -1
- package/cjs/components/ResourcesDayView/ResourcesDayView.module.cjs.map +1 -1
- package/cjs/components/ResourcesMonthView/ResourcesMonthView.cjs +18 -6
- package/cjs/components/ResourcesMonthView/ResourcesMonthView.cjs.map +1 -1
- package/cjs/components/ResourcesSchedule/ResourcesSchedule.cjs +6 -1
- package/cjs/components/ResourcesSchedule/ResourcesSchedule.cjs.map +1 -1
- package/cjs/components/ResourcesWeekView/ResourcesWeekView.cjs +84 -57
- package/cjs/components/ResourcesWeekView/ResourcesWeekView.cjs.map +1 -1
- package/cjs/components/ResourcesWeekView/ResourcesWeekView.module.cjs.map +1 -1
- package/cjs/components/Schedule/Schedule.cjs +14 -1
- package/cjs/components/Schedule/Schedule.cjs.map +1 -1
- package/cjs/components/ScheduleEvent/ScheduleEvent.module.cjs.map +1 -1
- package/cjs/components/WeekView/WeekView.cjs +67 -45
- package/cjs/components/WeekView/WeekView.cjs.map +1 -1
- package/cjs/components/WeekView/WeekView.module.cjs.map +1 -1
- package/cjs/hooks/use-day-grid-event-resize.cjs +38 -8
- package/cjs/hooks/use-day-grid-event-resize.cjs.map +1 -1
- package/cjs/hooks/use-drag-drop-handlers.cjs +126 -10
- package/cjs/hooks/use-drag-drop-handlers.cjs.map +1 -1
- package/cjs/hooks/use-event-resize.cjs +36 -12
- package/cjs/hooks/use-event-resize.cjs.map +1 -1
- package/cjs/hooks/use-horizontal-event-resize.cjs +37 -12
- package/cjs/hooks/use-horizontal-event-resize.cjs.map +1 -1
- package/cjs/hooks/validate-event-resize.cjs +37 -0
- package/cjs/hooks/validate-event-resize.cjs.map +1 -0
- package/cjs/index.cjs +2 -0
- package/cjs/utils/is-event-placement-allowed/is-event-placement-allowed.cjs +52 -0
- package/cjs/utils/is-event-placement-allowed/is-event-placement-allowed.cjs.map +1 -0
- package/esm/components/DayView/DayView.mjs +45 -30
- package/esm/components/DayView/DayView.mjs.map +1 -1
- package/esm/components/DayView/DayView.module.mjs.map +1 -1
- package/esm/components/MonthView/MonthView.mjs +11 -4
- package/esm/components/MonthView/MonthView.mjs.map +1 -1
- package/esm/components/ResourcesDayView/ResourcesDayView.mjs +74 -59
- package/esm/components/ResourcesDayView/ResourcesDayView.mjs.map +1 -1
- package/esm/components/ResourcesDayView/ResourcesDayView.module.mjs.map +1 -1
- package/esm/components/ResourcesMonthView/ResourcesMonthView.mjs +18 -6
- package/esm/components/ResourcesMonthView/ResourcesMonthView.mjs.map +1 -1
- package/esm/components/ResourcesSchedule/ResourcesSchedule.mjs +6 -1
- package/esm/components/ResourcesSchedule/ResourcesSchedule.mjs.map +1 -1
- package/esm/components/ResourcesWeekView/ResourcesWeekView.mjs +84 -57
- package/esm/components/ResourcesWeekView/ResourcesWeekView.mjs.map +1 -1
- package/esm/components/ResourcesWeekView/ResourcesWeekView.module.mjs.map +1 -1
- package/esm/components/Schedule/Schedule.mjs +14 -1
- package/esm/components/Schedule/Schedule.mjs.map +1 -1
- package/esm/components/ScheduleEvent/ScheduleEvent.module.mjs.map +1 -1
- package/esm/components/WeekView/WeekView.mjs +67 -45
- package/esm/components/WeekView/WeekView.mjs.map +1 -1
- package/esm/components/WeekView/WeekView.module.mjs.map +1 -1
- package/esm/hooks/use-day-grid-event-resize.mjs +38 -8
- package/esm/hooks/use-day-grid-event-resize.mjs.map +1 -1
- package/esm/hooks/use-drag-drop-handlers.mjs +126 -10
- package/esm/hooks/use-drag-drop-handlers.mjs.map +1 -1
- package/esm/hooks/use-event-resize.mjs +36 -12
- package/esm/hooks/use-event-resize.mjs.map +1 -1
- package/esm/hooks/use-horizontal-event-resize.mjs +37 -12
- package/esm/hooks/use-horizontal-event-resize.mjs.map +1 -1
- package/esm/hooks/validate-event-resize.mjs +37 -0
- package/esm/hooks/validate-event-resize.mjs.map +1 -0
- package/esm/index.mjs +2 -1
- package/esm/utils/is-event-placement-allowed/is-event-placement-allowed.mjs +50 -0
- package/esm/utils/is-event-placement-allowed/is-event-placement-allowed.mjs.map +1 -0
- package/lib/components/DayView/DayView.d.ts +11 -1
- package/lib/components/MonthView/MonthView.d.ts +9 -1
- package/lib/components/ResourcesDayView/ResourcesDayView.d.ts +11 -1
- package/lib/components/ResourcesMonthView/ResourcesMonthView.d.ts +11 -1
- package/lib/components/ResourcesSchedule/ResourcesSchedule.d.ts +12 -2
- package/lib/components/ResourcesWeekView/ResourcesWeekView.d.ts +11 -1
- package/lib/components/Schedule/Schedule.d.ts +12 -2
- package/lib/components/WeekView/WeekView.d.ts +11 -1
- package/lib/hooks/use-day-grid-event-resize.d.ts +4 -2
- package/lib/hooks/use-drag-drop-handlers.d.ts +17 -1
- package/lib/hooks/use-event-resize.d.ts +4 -2
- package/lib/hooks/use-horizontal-event-resize.d.ts +4 -2
- package/lib/hooks/validate-event-resize.d.ts +33 -0
- package/lib/types.d.ts +65 -0
- package/lib/utils/index.d.ts +2 -0
- package/lib/utils/is-event-placement-allowed/is-event-placement-allowed.d.ts +22 -0
- package/package.json +6 -6
- package/styles.css +29 -0
- 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
|
-
|
|
119
|
-
|
|
120
|
-
if (
|
|
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
|
|
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
|
-
|
|
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: {
|
|
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, {
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
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",
|