@mui/x-date-pickers-pro 9.2.0 → 9.3.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.
@@ -12,16 +12,10 @@ var React = _interopRequireWildcard(require("react"));
12
12
  var _useEventCallback = _interopRequireDefault(require("@mui/utils/useEventCallback"));
13
13
  var _domUtils = require("@mui/x-internals/domUtils");
14
14
  var _dateUtils = require("../internals/utils/date-utils");
15
- const isEnabledButtonElement = element => (0, _domUtils.isHTMLElement)(element) && element.tagName === 'BUTTON' && !element.disabled;
16
15
  /**
17
- * Finds the closest ancestor element (or the element itself) that has the specified data attribute.
18
- * This is needed because drag/touch events can target child elements (e.g., text spans)
19
- * inside the button, which don't have the data attributes directly.
20
- *
21
- * @param element The element to start searching from.
22
- * @param dataAttribute The data attribute name — must be a single lowercase word
23
- * (e.g., 'timestamp', 'position') because `dataset[attr]` uses camelCase
24
- * while `.closest()` uses kebab-case, and these only align for single-word names.
16
+ * Returns the element (or its closest ancestor) carrying `data-{attr}`.
17
+ * Single-word `attr` only `dataset[attr]` (camelCase) and `.closest()`
18
+ * (kebab-case) only agree for single-word names.
25
19
  */
26
20
  const getClosestElementWithDataAttribute = (element, dataAttribute) => {
27
21
  if (!element) {
@@ -38,95 +32,40 @@ const resolveDateFromTarget = (target, adapter, timezone) => {
38
32
  if (!timestampString) {
39
33
  return null;
40
34
  }
41
- const timestamp = Number(timestampString);
42
- return adapter.date(new Date(timestamp).toISOString(), timezone);
43
- };
44
- const isSameAsDraggingDate = event => {
45
- const target = (0, _domUtils.getTarget)(event.nativeEvent);
46
- if (!(0, _domUtils.isHTMLElement)(target)) {
47
- return false;
48
- }
49
- const element = getClosestElementWithDataAttribute(target, 'timestamp');
50
- return element?.dataset.timestamp === event.dataTransfer.getData('draggingDate');
51
- };
52
35
 
53
- /**
54
- * Resolves a button element from a given element.
55
- * Searches both upward (ancestors) and downward (children) since:
56
- * - Touch events may target child elements inside the button (e.g., TouchRipple)
57
- * - `elementFromPoint` may return wrapper divs containing the button
58
- */
59
- const resolveButtonElement = element => {
60
- if (!element) {
36
+ // Guard against malformed `data-timestamp` — `Number('abc')` is `NaN` and
37
+ // `new Date(NaN).toISOString()` throws, which would otherwise wedge the
38
+ // gesture mid-`pointerover`.
39
+ const timestamp = Number(timestampString);
40
+ if (!Number.isFinite(timestamp)) {
61
41
  return null;
62
42
  }
63
-
64
- // Check if element itself is a valid button
65
- if (isEnabledButtonElement(element)) {
66
- return element;
67
- }
68
-
69
- // Search upward - element could be a child of the button (e.g., text span, TouchRipple)
70
- const closestButton = element.closest('button');
71
- if (isEnabledButtonElement(closestButton)) {
72
- return closestButton;
73
- }
74
-
75
- // Search downward (breadth-first, max 3 levels) - element could be a wrapper containing the button.
76
- // Day cells have shallow DOM, so a small depth limit keeps this efficient.
77
- const queue = Array.from(element.children).map(el => ({
78
- el,
79
- depth: 1
80
- }));
81
- const maxDepth = 3;
82
- while (queue.length > 0) {
83
- const {
84
- el: current,
85
- depth
86
- } = queue.shift();
87
- if (isEnabledButtonElement(current)) {
88
- return current;
89
- }
90
- if (depth < maxDepth) {
91
- queue.push(...Array.from(current.children).map(el => ({
92
- el,
93
- depth: depth + 1
94
- })));
95
- }
96
- }
97
- return null;
98
- };
99
- const resolveElementFromTouch = (event, ignoreTouchTarget) => {
100
- // don't parse multi-touch result
101
- if (event.changedTouches?.length === 1 && event.touches.length <= 1) {
102
- const element = document.elementFromPoint(event.changedTouches[0].clientX, event.changedTouches[0].clientY);
103
- // `elementFromPoint` could have resolved preview div or wrapping div
104
- // might need to recursively find the nested button
105
- const buttonElement = resolveButtonElement(element);
106
- if (ignoreTouchTarget && buttonElement === event.changedTouches[0].target) {
107
- return null;
108
- }
109
- return buttonElement;
110
- }
111
- return null;
43
+ return adapter.date(new Date(timestamp).toISOString(), timezone);
112
44
  };
113
45
  const useDragRangeEvents = ({
114
46
  adapter,
115
47
  setRangeDragDay,
116
48
  setIsDragging,
117
- isDragging,
118
49
  onDatePositionChange,
119
50
  onDrop,
120
51
  disableDragEditing,
121
52
  dateRange,
122
53
  timezone
123
54
  }) => {
124
- const emptyDragImgRef = React.useRef(null);
125
- React.useEffect(() => {
126
- // Preload the image - required for Safari support: https://stackoverflow.com/a/40923520/3303436
127
- emptyDragImgRef.current = document.createElement('img');
128
- emptyDragImgRef.current.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
129
- }, []);
55
+ const isDraggingRef = React.useRef(false);
56
+ const pointerIdRef = React.useRef(null);
57
+ const sourceDateRef = React.useRef(null);
58
+ const sourcePositionRef = React.useRef(null);
59
+ const didMoveRef = React.useRef(false);
60
+ // Last cell the pointer hovered. Used to dedupe `pointerover` (which fires
61
+ // repeatedly within the same cell), and as the drop fallback for
62
+ // `pointercancel` (whose `event.target` is unreliable across browsers).
63
+ const lastHoveredCellRef = React.useRef(null);
64
+ // Each entry removes one document listener the gesture installed.
65
+ const listenerCleanupsRef = React.useRef([]);
66
+ // Outstanding capture-phase click suppressor, if any. Tracked so back-to-back
67
+ // drags can tear the prior one down before installing a new one.
68
+ const clickSuppressorRef = React.useRef(null);
130
69
  const isElementDraggable = day => {
131
70
  if (day == null) {
132
71
  return false;
@@ -136,146 +75,276 @@ const useDragRangeEvents = ({
136
75
  const isSelectedEndDate = (0, _dateUtils.isEndOfRange)(adapter, day, dateRange);
137
76
  return shouldInitDragging && (isSelectedStartDate || isSelectedEndDate);
138
77
  };
139
- const handleDragStart = (0, _useEventCallback.default)(event => {
140
- const newDate = resolveDateFromTarget((0, _domUtils.getTarget)(event.nativeEvent), adapter, timezone);
141
- if (!isElementDraggable(newDate)) {
142
- return;
78
+
79
+ // Resets every ref the gesture mutated and removes any listeners installed
80
+ // during the gesture. Safe to call from event handlers and from unmount.
81
+ // Only reads refs, so its closure never changes — memoized for stable
82
+ // identity (referenced by `cleanup` and the unmount effect).
83
+ const clearGestureState = (0, _useEventCallback.default)(() => {
84
+ isDraggingRef.current = false;
85
+ pointerIdRef.current = null;
86
+ sourceDateRef.current = null;
87
+ sourcePositionRef.current = null;
88
+ didMoveRef.current = false;
89
+ lastHoveredCellRef.current = null;
90
+ listenerCleanupsRef.current.forEach(teardown => teardown());
91
+ listenerCleanupsRef.current = [];
92
+ // Also tear down any in-flight click suppressor — without this, an
93
+ // unmount in the brief window between `pointerup` and the
94
+ // `setTimeout(0)` teardown leaves a capture-phase listener attached
95
+ // to `document` that swallows the next click on unrelated UI.
96
+ clickSuppressorRef.current?.();
97
+ });
98
+ const cleanup = (0, _useEventCallback.default)(() => {
99
+ const wasActive = didMoveRef.current;
100
+ clearGestureState();
101
+ // A press without movement never activated drag UI, so skip the re-render.
102
+ if (wasActive) {
103
+ setIsDragging(false);
104
+ setRangeDragDay(null);
143
105
  }
144
- event.stopPropagation();
145
- if (emptyDragImgRef.current) {
146
- event.dataTransfer.setDragImage(emptyDragImgRef.current, 0, 0);
106
+ });
107
+ const installClickSuppressor = doc => {
108
+ // Tear down a prior outstanding suppressor first; back-to-back drags
109
+ // would otherwise race two listeners on the document.
110
+ clickSuppressorRef.current?.();
111
+
112
+ // suppress and teardown reference each other, so forward-declare suppress.
113
+ let suppress;
114
+ const teardown = () => {
115
+ doc.removeEventListener('click', suppress, {
116
+ capture: true
117
+ });
118
+ if (clickSuppressorRef.current === teardown) {
119
+ clickSuppressorRef.current = null;
120
+ }
121
+ };
122
+ suppress = clickEvent => {
123
+ clickEvent.preventDefault();
124
+ // `stopImmediatePropagation` (rather than just `stopPropagation`) so
125
+ // other capture-phase click listeners on `document` — analytics, focus
126
+ // traps, third-party overlays — don't observe the synthesized
127
+ // post-drag click as if the user intentionally clicked the cell.
128
+ clickEvent.stopImmediatePropagation();
129
+ teardown();
130
+ };
131
+ doc.addEventListener('click', suppress, {
132
+ capture: true
133
+ });
134
+ clickSuppressorRef.current = teardown;
135
+ // If no click ever fires (drop on a different cell, browser doesn't
136
+ // synthesize), tear the listener down so it doesn't leak.
137
+ setTimeout(teardown, 0);
138
+ };
139
+ const finalizeGesture = (event, ownerDoc, eventType) => {
140
+ const wasMoved = didMoveRef.current;
141
+ const sourceDate = sourceDateRef.current;
142
+
143
+ // For `pointerup`, the drop target is whatever element the pointer was
144
+ // actually over at release time — releasing into a gap or off the calendar
145
+ // resolves to `null` and cancels, matching native HTML5 drag.
146
+ // For `pointercancel`, `event.target` can be unreliable (browsers vary on
147
+ // whether it's the current under-pointer element or the gesture's start
148
+ // element). Fall back to the last cell the user hovered, which is the
149
+ // closest expression of their intent.
150
+ let dropOrigin;
151
+ if (eventType === 'pointercancel') {
152
+ dropOrigin = lastHoveredCellRef.current;
153
+ } else {
154
+ dropOrigin = event.target instanceof HTMLElement ? event.target : null;
147
155
  }
148
- setRangeDragDay(newDate);
149
- event.dataTransfer.effectAllowed = 'move';
150
- setIsDragging(true);
151
- // Use currentTarget (the element the handler is attached to) rather than target
152
- // because we need the button's dataset, not a potential child element's dataset.
153
- const element = getClosestElementWithDataAttribute(event.currentTarget, 'timestamp');
154
- const buttonDataset = element?.dataset;
155
- if (buttonDataset?.timestamp) {
156
- event.dataTransfer.setData('draggingDate', buttonDataset.timestamp);
156
+ const dropCell = getClosestElementWithDataAttribute(dropOrigin, 'timestamp');
157
+ const newDate = dropCell ? resolveDateFromTarget(dropCell, adapter, timezone) : null;
158
+ // Resolve the focusable `<button>` separately from `dropCell`. Today
159
+ // `data-timestamp` lives on the button itself, but a future custom slot
160
+ // could put it on a wrapper; in that case the cell isn't focusable and
161
+ // the disabled state lives on the inner button.
162
+ const dropButton = dropOrigin?.closest('button') ?? dropCell?.querySelector('button') ?? null;
163
+
164
+ // `shouldDisableDate` / min-max / readOnly mark the day's button as
165
+ // `disabled`. `pointerup` still lands on a disabled `<button>` in
166
+ // Chromium/WebKit, so guard explicitly — `DateRangeCalendar.handleDrop`
167
+ // doesn't re-validate the date.
168
+ const isDropDisabled = dropButton?.disabled === true;
169
+ cleanup();
170
+ if (eventType === 'pointerup' && wasMoved && dropCell) {
171
+ // The click that follows pointerup on a day cell would re-enter the
172
+ // day's selection logic and undo the drop (or, when the drag returned
173
+ // to the source, replace the range with a single-day selection).
174
+ // Swallow it. Gated on `dropCell` so a release outside the calendar
175
+ // doesn't swallow an unrelated click on the host UI.
176
+ installClickSuppressor(ownerDoc);
157
177
  }
158
- if (buttonDataset?.position) {
159
- onDatePositionChange(buttonDataset.position);
178
+ if (wasMoved && newDate && sourceDate && !isDropDisabled && !adapter.isEqual(newDate, sourceDate)) {
179
+ dropButton?.focus();
180
+ onDrop(newDate);
160
181
  }
161
- });
162
- const handleTouchStart = (0, _useEventCallback.default)(event => {
163
- const target = resolveElementFromTouch(event);
164
- if (!target) {
165
- return;
182
+ };
183
+
184
+ // `touchmove`-blocks-scroll listener. Attached eagerly in
185
+ // `handlePointerDown` for touch pointers only. Mouse/pen don't fire touch
186
+ // events. Stable at hook level so the listener identity is consistent
187
+ // across renders.
188
+ const onTouchMove = (0, _useEventCallback.default)(touchEvent => {
189
+ if (isDraggingRef.current) {
190
+ // `touch-action: none` on the source cell isn't enough once the finger
191
+ // crosses cell boundaries.
192
+ touchEvent.preventDefault();
166
193
  }
167
- const newDate = resolveDateFromTarget(target, adapter, timezone);
168
- if (!isElementDraggable(newDate)) {
194
+ });
195
+ const handlePointerDown = (0, _useEventCallback.default)(event => {
196
+ // Ignore secondary mouse buttons (middle = 1, right = 2). `> 0` rather
197
+ // than `!== 0` keeps the gesture permissive when `event.button` is left
198
+ // unset by a synthetic event (some test environments).
199
+ if (event.button > 0) {
169
200
  return;
170
201
  }
171
- setRangeDragDay(newDate);
172
- });
173
- const handleDragEnter = (0, _useEventCallback.default)(event => {
174
- if (!isDragging) {
202
+
203
+ // Secondary multi-touch pointers (second finger, etc.) are explicitly
204
+ // not-primary; let them pass through without disturbing the active gesture.
205
+ if (event.isPrimary === false) {
175
206
  return;
176
207
  }
177
- event.preventDefault();
178
- event.stopPropagation();
179
- event.dataTransfer.dropEffect = 'move';
180
- setRangeDragDay(resolveDateFromTarget((0, _domUtils.getTarget)(event.nativeEvent), adapter, timezone));
181
- });
182
- const handleTouchMove = (0, _useEventCallback.default)(event => {
183
- const target = resolveElementFromTouch(event);
184
- if (!target) {
208
+ const newDate = resolveDateFromTarget(event.currentTarget, adapter, timezone);
209
+ if (!isElementDraggable(newDate)) {
185
210
  return;
186
211
  }
187
- const newDate = resolveDateFromTarget(target, adapter, timezone);
188
- if (newDate) {
189
- setRangeDragDay(newDate);
212
+
213
+ // A fresh primary pointerdown definitionally ends any previous gesture
214
+ // (covers pen+touch, where each pointer type has its own primary, and
215
+ // the recovery case where the original gesture's `pointerup` was lost).
216
+ if (pointerIdRef.current != null) {
217
+ cleanup();
190
218
  }
191
219
 
192
- // this prevents initiating drag when user starts touchmove outside and then moves over a draggable element
193
- const targetsAreIdentical = target === event.changedTouches[0].target;
194
- if (!targetsAreIdentical || !isElementDraggable(newDate)) {
195
- return;
220
+ // Touch implicitly captures the pointer on `pointerdown`, pinning all
221
+ // subsequent events to the source. Release so sibling cells receive their
222
+ // own `pointerover`. jsdom lacks the API; Safari 15 / some Android WebViews
223
+ // race between the `hasPointerCapture` check and the release call and throw
224
+ // `InvalidPointerId` — benign, swallow it.
225
+ try {
226
+ if (typeof event.currentTarget.hasPointerCapture === 'function' && event.currentTarget.hasPointerCapture(event.pointerId)) {
227
+ event.currentTarget.releasePointerCapture(event.pointerId);
228
+ }
229
+ } catch {
230
+ // already released, nothing to do
196
231
  }
197
232
 
198
- // on mobile we should only initialize dragging state after move is detected
199
- setIsDragging(true);
233
+ // Note: deliberately not calling `event.preventDefault()` here. Doing so
234
+ // would suppress the synthesized click that follows pointerup, which is
235
+ // load-bearing for tap-to-advance on an endpoint cell. The iOS magnifier
236
+ // is held off by `touch-action: none` + `user-select: none` on the cell.
200
237
 
201
- // Use currentTarget (the element the handler is attached to) rather than target
202
- // because we need the button's dataset, not a potential child element's dataset.
203
- const element = getClosestElementWithDataAttribute(event.currentTarget, 'position');
204
- const buttonDataset = element?.dataset;
205
- if (buttonDataset?.position) {
206
- onDatePositionChange(buttonDataset.position);
207
- }
208
- });
209
- const handleDragLeave = (0, _useEventCallback.default)(event => {
210
- if (!isDragging) {
211
- return;
238
+ pointerIdRef.current = event.pointerId;
239
+ isDraggingRef.current = true;
240
+ sourceDateRef.current = newDate;
241
+ didMoveRef.current = false;
242
+ lastHoveredCellRef.current = event.currentTarget;
243
+
244
+ // Walk up rather than reading `currentTarget.dataset` directly so the
245
+ // hook keeps working if a future slot puts `data-position` on a wrapper
246
+ // around the cell (mirrors how we resolve `data-timestamp`).
247
+ const positionHost = getClosestElementWithDataAttribute(event.currentTarget, 'position');
248
+ sourcePositionRef.current = positionHost?.dataset.position ?? null;
249
+
250
+ // Use the owner document (matters for iframe-hosted pickers) for all
251
+ // document-level listeners.
252
+ const ownerDoc = event.currentTarget.ownerDocument ?? document;
253
+
254
+ // Drag UI activation is deferred until the first real move — a pure
255
+ // press on an endpoint must leave selection state alone so the click
256
+ // handler can advance it normally.
257
+
258
+ const onPointerUp = pointerEvent => {
259
+ if (pointerEvent.pointerId !== pointerIdRef.current) {
260
+ return;
261
+ }
262
+ finalizeGesture(pointerEvent, ownerDoc, 'pointerup');
263
+ };
264
+ const onPointerCancel = pointerEvent => {
265
+ if (pointerEvent.pointerId !== pointerIdRef.current) {
266
+ return;
267
+ }
268
+ // Spec intent of `pointercancel` is "UA interrupted, not the user".
269
+ // After real movement, commit the drop the user worked for; the snap-back
270
+ // would otherwise be silent and inexplicable.
271
+ finalizeGesture(pointerEvent, ownerDoc, 'pointercancel');
272
+ };
273
+ const onKeyDown = keyEvent => {
274
+ if (keyEvent.key !== 'Escape' || !didMoveRef.current) {
275
+ // No visible drag to cancel. Leave the gesture intact and let
276
+ // Escape propagate (host modal/popover can still close on it).
277
+ // A press without movement behaves identically to a tap on
278
+ // release — letting cleanup run here would only half-collapse
279
+ // the gesture without suppressing the eventual tap-to-advance.
280
+ return;
281
+ }
282
+ keyEvent.preventDefault();
283
+ cleanup();
284
+ };
285
+ ownerDoc.addEventListener('pointerup', onPointerUp);
286
+ ownerDoc.addEventListener('pointercancel', onPointerCancel);
287
+ ownerDoc.addEventListener('keydown', onKeyDown);
288
+ listenerCleanupsRef.current.push(() => ownerDoc.removeEventListener('pointerup', onPointerUp), () => ownerDoc.removeEventListener('pointercancel', onPointerCancel), () => ownerDoc.removeEventListener('keydown', onKeyDown));
289
+
290
+ // For touch input, attach the scroll-suppression listener up front rather
291
+ // than lazily on first movement. The Pointer Events spec latches
292
+ // `touch-action: none` from the source cell over the rest of the gesture,
293
+ // but real-world WebKit/Chromium versions don't always honor that —
294
+ // attaching eagerly closes that window. Mouse and pen don't fire touch
295
+ // events so they don't need it.
296
+ if (event.pointerType === 'touch') {
297
+ ownerDoc.addEventListener('touchmove', onTouchMove, {
298
+ passive: false
299
+ });
300
+ listenerCleanupsRef.current.push(() => ownerDoc.removeEventListener('touchmove', onTouchMove));
212
301
  }
213
- event.preventDefault();
214
- event.stopPropagation();
215
302
  });
216
- const handleDragOver = (0, _useEventCallback.default)(event => {
217
- if (!isDragging) {
303
+
304
+ // Use `pointerover` (bubbles) rather than `pointerenter`: React's
305
+ // `onPointerEnter` is implemented on top of over/out.
306
+ const handlePointerOver = (0, _useEventCallback.default)(event => {
307
+ if (!isDraggingRef.current || event.pointerId !== pointerIdRef.current) {
218
308
  return;
219
309
  }
220
- event.preventDefault();
221
- event.stopPropagation();
222
- event.dataTransfer.dropEffect = 'move';
223
- });
224
- const handleTouchEnd = (0, _useEventCallback.default)(event => {
225
- if (!isDragging) {
310
+ if (lastHoveredCellRef.current === event.currentTarget) {
226
311
  return;
227
312
  }
228
- setRangeDragDay(null);
229
- setIsDragging(false);
230
- const target = resolveElementFromTouch(event, true);
231
- if (!target) {
313
+ const newDate = resolveDateFromTarget(event.currentTarget, adapter, timezone);
314
+ if (!newDate) {
232
315
  return;
233
316
  }
317
+ lastHoveredCellRef.current = event.currentTarget;
318
+ const isDifferentFromSource = sourceDateRef.current && !adapter.isEqual(newDate, sourceDateRef.current);
319
+ if (!didMoveRef.current && isDifferentFromSource) {
320
+ // A custom day slot could strip `data-position`; without it the preview
321
+ // would compute against the wrong endpoint, so abort the drag rather
322
+ // than rendering something misleading.
323
+ if (!sourcePositionRef.current) {
324
+ if (process.env.NODE_ENV !== 'production') {
325
+ console.warn('MUI X: A drag was initiated on a day cell missing `data-position`. ' + 'Drag editing requires the cell to advertise which range endpoint it represents.');
326
+ }
327
+ return;
328
+ }
234
329
 
235
- // make sure the focused element is the element where touch ended
236
- target.focus();
237
- const newDate = resolveDateFromTarget(target, adapter, timezone);
238
- if (newDate) {
239
- onDrop(newDate);
240
- }
241
- });
242
- const handleDragEnd = (0, _useEventCallback.default)(event => {
243
- if (!isDragging) {
244
- return;
330
+ // First real move: activate drag UI and tell the parent which endpoint
331
+ // is being dragged so the preview computes against the correct side.
332
+ didMoveRef.current = true;
333
+ onDatePositionChange(sourcePositionRef.current);
334
+ setIsDragging(true);
245
335
  }
246
- event.preventDefault();
247
- event.stopPropagation();
248
- setIsDragging(false);
249
- setRangeDragDay(null);
250
- });
251
- const handleDrop = (0, _useEventCallback.default)(event => {
252
- if (!isDragging) {
253
- return;
254
- }
255
- event.preventDefault();
256
- event.stopPropagation();
257
- setIsDragging(false);
258
- setRangeDragDay(null);
259
- // make sure the focused element is the element where drop ended
260
- event.currentTarget.focus();
261
- if (isSameAsDraggingDate(event)) {
262
- return;
263
- }
264
- const newDate = resolveDateFromTarget((0, _domUtils.getTarget)(event.nativeEvent), adapter, timezone);
265
- if (newDate) {
266
- onDrop(newDate);
336
+ if (didMoveRef.current) {
337
+ setRangeDragDay(newDate);
267
338
  }
268
339
  });
340
+
341
+ // On unmount, clear gesture state so a remount can start fresh and any
342
+ // detached DOM nodes still referenced by gesture refs can be GC'd.
343
+ // `clearGestureState` is `useEventCallback`-stable, so the effect runs once.
344
+ React.useEffect(() => () => clearGestureState(), [clearGestureState]);
269
345
  return {
270
- onDragStart: handleDragStart,
271
- onDragEnter: handleDragEnter,
272
- onDragLeave: handleDragLeave,
273
- onDragOver: handleDragOver,
274
- onDragEnd: handleDragEnd,
275
- onDrop: handleDrop,
276
- onTouchStart: handleTouchStart,
277
- onTouchMove: handleTouchMove,
278
- onTouchEnd: handleTouchEnd
346
+ onPointerDown: handlePointerDown,
347
+ onPointerOver: handlePointerOver
279
348
  };
280
349
  };
281
350
  const useDragRange = ({
@@ -310,7 +379,6 @@ const useDragRange = ({
310
379
  onDatePositionChange,
311
380
  onDrop,
312
381
  setIsDragging,
313
- isDragging,
314
382
  setRangeDragDay: handleRangeDragDayChange,
315
383
  disableDragEditing,
316
384
  dateRange,