@kne/react-calendar 1.0.0 → 1.0.2

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.
@@ -4,7 +4,7 @@ import customParseFormat from 'dayjs/plugin/customParseFormat';
4
4
  import useControlValue from '@kne/use-control-value';
5
5
  import { Popover, Space, Button, Badge, List, Tag, Card, Spin, Empty, Tooltip, Calendar } from 'antd';
6
6
  import { createWithIntlProvider, useIntl } from '@kne/react-intl';
7
- import { jsx, jsxs } from 'react/jsx-runtime';
7
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
8
  import FormInfo, { Input, TextArea, Form, SubmitButton } from '@kne/form-info';
9
9
 
10
10
  function _extends() {
@@ -897,20 +897,43 @@ const ViewPanel = ({
897
897
  });
898
898
  };
899
899
 
900
- const LONG_PRESS_DELAY = 360;
901
- const MOVE_THRESHOLD = 18;
900
+ const LONG_PRESS_DELAY = 400;
901
+ const SCROLL_CANCEL_THRESHOLD = 12;
902
+ const TAP_MOVE_THRESHOLD = 8;
902
903
  const getPopoverKey = slot => slot ? `form:${slot.key}` : null;
903
- const getSlotElementFromTouch = (container, touch) => {
904
- const element = document.elementFromPoint(touch.clientX, touch.clientY);
905
- const slotElement = element == null || element.closest == null ? void 0 : element.closest('[data-slot-index]');
906
- if (!slotElement || !(container != null && container.contains(slotElement))) {
904
+ const getSlotIndexFromPoint = (container, clientX, clientY) => {
905
+ const slotElements = container == null || container.querySelectorAll == null ? void 0 : container.querySelectorAll('[data-slot-index]');
906
+ if (!(slotElements != null && slotElements.length)) {
907
907
  return null;
908
908
  }
909
- return slotElement;
909
+ let closestIndex = null;
910
+ let closestDistance = Infinity;
911
+ for (const candidate of slotElements) {
912
+ const rect = candidate.getBoundingClientRect();
913
+ const index = Number(candidate.getAttribute('data-slot-index'));
914
+ if (Number.isNaN(index)) {
915
+ continue;
916
+ }
917
+ if (clientY >= rect.top && clientY <= rect.bottom && clientX >= rect.left && clientX <= rect.right) {
918
+ return index;
919
+ }
920
+ if (clientX < rect.left || clientX > rect.right) {
921
+ continue;
922
+ }
923
+ const centerY = (rect.top + rect.bottom) / 2;
924
+ const distance = Math.abs(clientY - centerY);
925
+ if (distance < closestDistance) {
926
+ closestDistance = distance;
927
+ closestIndex = index;
928
+ }
929
+ }
930
+ return closestIndex;
910
931
  };
911
- const getTouchPoint = event => {
912
- var _event$changedTouches, _event$touches;
913
- return ((_event$changedTouches = event.changedTouches) == null ? void 0 : _event$changedTouches[0]) || ((_event$touches = event.touches) == null ? void 0 : _event$touches[0]);
932
+ const clearDocumentTextSelection = () => {
933
+ const selection = document.getSelection == null ? void 0 : document.getSelection();
934
+ if (selection && !selection.isCollapsed) {
935
+ selection.removeAllRanges();
936
+ }
914
937
  };
915
938
  const useScheduleSelectionGesture = ({
916
939
  slots,
@@ -930,9 +953,14 @@ const useScheduleSelectionGesture = ({
930
953
  const touchStateRef = useRef(null);
931
954
  const slotsDataRef = useRef(slots);
932
955
  const selectedSlotsRef = useRef(selectedSlots);
956
+ const allowMultiSelectRef = useRef(allowMultiSelect);
933
957
  const suppressTriggerUntilRef = useRef(0);
958
+ const suppressMouseUntilRef = useRef(0);
959
+ const scrollLockRef = useRef(null);
960
+ const handlersRef = useRef({});
934
961
  slotsDataRef.current = slots;
935
962
  selectedSlotsRef.current = selectedSlots;
963
+ allowMultiSelectRef.current = allowMultiSelect;
936
964
  const selectedKeys = useMemo(() => new Set(selectedSlots.map(slot => slot.key)), [selectedSlots]);
937
965
  const selectedAnchorKey = (_selectedSlots = selectedSlots[selectedSlots.length - 1]) == null ? void 0 : _selectedSlots.key;
938
966
  const formPopoverKey = selectedAnchorKey ? `form:${selectedAnchorKey}` : null;
@@ -942,16 +970,55 @@ const useScheduleSelectionGesture = ({
942
970
  longPressTimerRef.current = null;
943
971
  }
944
972
  }, []);
973
+ const unlockContainerScroll = useCallback(() => {
974
+ const container = slotsRef.current;
975
+ if (!container || scrollLockRef.current == null) {
976
+ return;
977
+ }
978
+ const scrollTop = scrollLockRef.current;
979
+ container.style.overflow = '';
980
+ container.style.touchAction = '';
981
+ container.scrollTop = scrollTop;
982
+ scrollLockRef.current = null;
983
+ }, []);
984
+ const lockContainerScroll = useCallback(() => {
985
+ const container = slotsRef.current;
986
+ if (!container || scrollLockRef.current != null) {
987
+ return;
988
+ }
989
+ scrollLockRef.current = container.scrollTop;
990
+ container.style.overflow = 'hidden';
991
+ container.style.touchAction = 'none';
992
+ }, []);
993
+ const resetGestureState = useCallback(() => {
994
+ clearLongPress();
995
+ const container = slotsRef.current;
996
+ const touchState = touchStateRef.current;
997
+ if (container && (touchState == null ? void 0 : touchState.pointerId) != null && container.hasPointerCapture != null && container.hasPointerCapture(touchState.pointerId)) {
998
+ try {
999
+ container.releasePointerCapture(touchState.pointerId);
1000
+ } catch (_unused) {
1001
+ // Ignore capture release errors on stale pointers.
1002
+ }
1003
+ }
1004
+ draggingRef.current = false;
1005
+ dragStartIndexRef.current = null;
1006
+ touchStateRef.current = null;
1007
+ container == null || container.classList.remove('schedule-calendar-touch-dragging');
1008
+ unlockContainerScroll();
1009
+ setDragging(false);
1010
+ }, [clearLongPress, unlockContainerScroll]);
945
1011
  const selectSlots = useCallback(nextSlots => {
946
1012
  selectedSlotsRef.current = nextSlots;
947
1013
  if (!nextSlots.length) {
948
1014
  setActivePopoverKey(null);
1015
+ resetGestureState();
949
1016
  }
950
1017
  setSelectedSlots(nextSlots);
951
1018
  onSlotRangeChange == null || onSlotRangeChange(nextSlots, {
952
1019
  action: nextSlots.length ? 'select' : 'clear'
953
1020
  });
954
- }, [onSlotRangeChange, setSelectedSlots]);
1021
+ }, [onSlotRangeChange, resetGestureState, setSelectedSlots]);
955
1022
  const getSelectableRange = useCallback((startIndex, endIndex) => {
956
1023
  const [start, end] = [Math.min(startIndex, endIndex), Math.max(startIndex, endIndex)];
957
1024
  return slotsDataRef.current.slice(start, end + 1).filter(slot => slot.status === 'free');
@@ -963,13 +1030,18 @@ const useScheduleSelectionGesture = ({
963
1030
  }
964
1031
  }, []);
965
1032
  const startSlotSelection = useCallback((slot, index, {
966
- showPopover: _showPopover = true
1033
+ showPopover: _showPopover = true,
1034
+ lockScroll: _lockScroll = false
967
1035
  } = {}) => {
968
1036
  var _slotsRef$current;
1037
+ clearDocumentTextSelection();
969
1038
  setActivePopoverKey(getPopoverKey(slot));
970
1039
  draggingRef.current = true;
971
1040
  dragStartIndexRef.current = index;
972
1041
  (_slotsRef$current = slotsRef.current) == null || _slotsRef$current.classList.add('schedule-calendar-touch-dragging');
1042
+ if (_lockScroll) {
1043
+ lockContainerScroll();
1044
+ }
973
1045
  setDragging(true);
974
1046
  selectSlots([slot]);
975
1047
  if (!_showPopover) {
@@ -977,44 +1049,58 @@ const useScheduleSelectionGesture = ({
977
1049
  setActivePopoverKey(null);
978
1050
  }
979
1051
  onFreeSlotClick == null || onFreeSlotClick(slot);
980
- }, [onFreeSlotClick, selectSlots]);
1052
+ }, [lockContainerScroll, onFreeSlotClick, selectSlots]);
981
1053
  const finishSelection = useCallback(({
982
1054
  fromTouch: _fromTouch = false
983
1055
  } = {}) => {
984
- var _slotsRef$current2;
985
- clearLongPress();
986
- draggingRef.current = false;
987
- dragStartIndexRef.current = null;
988
- (_slotsRef$current2 = slotsRef.current) == null || _slotsRef$current2.classList.remove('schedule-calendar-touch-dragging');
989
- setDragging(false);
990
- if (selectedSlotsRef.current.length) {
1056
+ const hadSelection = selectedSlotsRef.current.length > 0;
1057
+ resetGestureState();
1058
+ if (hadSelection) {
991
1059
  if (_fromTouch) {
992
1060
  suppressTriggerUntilRef.current = Date.now() + 500;
993
1061
  }
994
1062
  showFormPopoverForSlots(selectedSlotsRef.current);
995
1063
  }
996
- }, [clearLongPress, showFormPopoverForSlots]);
1064
+ }, [resetGestureState, showFormPopoverForSlots]);
997
1065
  const updateSelectionRange = useCallback(index => {
998
1066
  const startIndex = dragStartIndexRef.current;
999
- if (startIndex === null || !allowMultiSelect) {
1067
+ if (startIndex === null || !allowMultiSelectRef.current) {
1000
1068
  return;
1001
1069
  }
1002
1070
  const nextSlots = getSelectableRange(startIndex, index);
1003
1071
  selectSlots(nextSlots);
1004
- }, [allowMultiSelect, getSelectableRange, selectSlots]);
1072
+ }, [getSelectableRange, selectSlots]);
1073
+ const shouldIgnoreMouseSelectionEvent = useCallback(() => {
1074
+ return !!touchStateRef.current || Date.now() < suppressMouseUntilRef.current;
1075
+ }, []);
1005
1076
  const handleMouseDown = useCallback((event, slot, index) => {
1077
+ if (shouldIgnoreMouseSelectionEvent()) {
1078
+ return;
1079
+ }
1006
1080
  if (slot.status !== 'free') {
1007
1081
  return;
1008
1082
  }
1009
1083
  event.preventDefault();
1010
1084
  startSlotSelection(slot, index);
1011
- }, [startSlotSelection]);
1085
+ }, [shouldIgnoreMouseSelectionEvent, startSlotSelection]);
1012
1086
  const handleMouseEnter = useCallback(index => {
1013
- if (!draggingRef.current) {
1087
+ if (shouldIgnoreMouseSelectionEvent() || !draggingRef.current) {
1014
1088
  return;
1015
1089
  }
1016
1090
  updateSelectionRange(index);
1017
- }, [updateSelectionRange]);
1091
+ }, [shouldIgnoreMouseSelectionEvent, updateSelectionRange]);
1092
+ const handleMouseUp = useCallback(() => {
1093
+ if (shouldIgnoreMouseSelectionEvent()) {
1094
+ return;
1095
+ }
1096
+ finishSelection();
1097
+ }, [finishSelection, shouldIgnoreMouseSelectionEvent]);
1098
+ const handleMouseLeave = useCallback(() => {
1099
+ if (shouldIgnoreMouseSelectionEvent()) {
1100
+ return;
1101
+ }
1102
+ finishSelection();
1103
+ }, [finishSelection, shouldIgnoreMouseSelectionEvent]);
1018
1104
  const handlePopoverOpenChange = useCallback((open, currentPopoverKey, {
1019
1105
  isForm: _isForm = false
1020
1106
  } = {}) => {
@@ -1032,26 +1118,79 @@ const useScheduleSelectionGesture = ({
1032
1118
  return prevKey === currentPopoverKey ? null : prevKey;
1033
1119
  });
1034
1120
  }, [selectSlots]);
1121
+ handlersRef.current = {
1122
+ clearLongPress,
1123
+ finishSelection,
1124
+ onFreeSlotClick,
1125
+ resetGestureState,
1126
+ selectSlots,
1127
+ showFormPopoverForSlots,
1128
+ startSlotSelection,
1129
+ updateSelectionRange
1130
+ };
1035
1131
  useEffect(() => {
1036
1132
  const container = slotsRef.current;
1037
1133
  if (!container) {
1038
1134
  return undefined;
1039
1135
  }
1040
- const clearTouchState = () => {
1041
- clearLongPress();
1042
- if (!draggingRef.current) {
1043
- var _slotsRef$current3;
1044
- (_slotsRef$current3 = slotsRef.current) == null || _slotsRef$current3.classList.remove('schedule-calendar-touch-dragging');
1136
+ const releasePointerCapture = pointerId => {
1137
+ if (pointerId == null || !(container.hasPointerCapture != null && container.hasPointerCapture(pointerId))) {
1138
+ return;
1139
+ }
1140
+ try {
1141
+ container.releasePointerCapture(pointerId);
1142
+ } catch (_unused2) {
1143
+ // Ignore capture release errors on stale pointers.
1045
1144
  }
1145
+ };
1146
+ const clearPendingTouch = () => {
1147
+ handlersRef.current.clearLongPress();
1046
1148
  touchStateRef.current = null;
1047
1149
  };
1048
- const handleTouchStart = event => {
1049
- if (event.touches.length !== 1) {
1150
+ const isStillOnSameSlot = (touchState, clientX, clientY) => {
1151
+ const currentIndex = getSlotIndexFromPoint(container, clientX, clientY);
1152
+ return currentIndex === touchState.index;
1153
+ };
1154
+ const shouldCancelPendingGesture = (touchState, clientX, clientY) => {
1155
+ const moveX = Math.abs(clientX - touchState.x);
1156
+ const moveY = Math.abs(clientY - touchState.y);
1157
+ if (moveY > SCROLL_CANCEL_THRESHOLD) {
1158
+ return true;
1159
+ }
1160
+ if (!isStillOnSameSlot(touchState, clientX, clientY)) {
1161
+ return true;
1162
+ }
1163
+ if (!allowMultiSelectRef.current && (moveX > TAP_MOVE_THRESHOLD || moveY > TAP_MOVE_THRESHOLD)) {
1164
+ return true;
1165
+ }
1166
+ return false;
1167
+ };
1168
+ const activateLongPress = touchState => {
1169
+ var _slotsRef$current2;
1170
+ if (!isStillOnSameSlot(touchState, touchState.lastX, touchState.lastY)) {
1050
1171
  return;
1051
1172
  }
1052
- const touch = event.touches[0];
1053
- const slotElement = getSlotElementFromTouch(container, touch);
1054
- if (!slotElement) {
1173
+ touchState.longPressed = true;
1174
+ touchState.active = true;
1175
+ clearDocumentTextSelection();
1176
+ try {
1177
+ container.setPointerCapture(touchState.pointerId);
1178
+ } catch (_unused3) {
1179
+ // Continue when capture is unavailable.
1180
+ }
1181
+ (_slotsRef$current2 = slotsRef.current) == null || _slotsRef$current2.classList.add('schedule-calendar-touch-dragging');
1182
+ handlersRef.current.startSlotSelection(touchState.slot, touchState.index, {
1183
+ showPopover: false,
1184
+ lockScroll: true
1185
+ });
1186
+ };
1187
+ const handlePointerDown = event => {
1188
+ var _event$target;
1189
+ if (event.pointerType === 'mouse' || event.isPrimary === false) {
1190
+ return;
1191
+ }
1192
+ const slotElement = (_event$target = event.target) == null || _event$target.closest == null ? void 0 : _event$target.closest('[data-slot-index]');
1193
+ if (!slotElement || !container.contains(slotElement)) {
1055
1194
  return;
1056
1195
  }
1057
1196
  const index = Number(slotElement.getAttribute('data-slot-index'));
@@ -1059,115 +1198,138 @@ const useScheduleSelectionGesture = ({
1059
1198
  if (Number.isNaN(index) || (slot == null ? void 0 : slot.status) !== 'free') {
1060
1199
  return;
1061
1200
  }
1062
- clearTouchState();
1201
+ handlersRef.current.resetGestureState();
1063
1202
  touchStateRef.current = {
1064
- identifier: touch.identifier,
1065
- x: touch.clientX,
1066
- y: touch.clientY,
1203
+ pointerId: event.pointerId,
1204
+ x: event.clientX,
1205
+ y: event.clientY,
1206
+ lastX: event.clientX,
1207
+ lastY: event.clientY,
1067
1208
  slot,
1068
1209
  index,
1069
1210
  moved: false,
1070
1211
  longPressed: false,
1071
- active: false
1212
+ active: false,
1213
+ selectionTriggered: false
1072
1214
  };
1215
+ if (!allowMultiSelectRef.current) {
1216
+ return;
1217
+ }
1073
1218
  longPressTimerRef.current = window.setTimeout(() => {
1074
- var _slotsRef$current4;
1075
1219
  const touchState = touchStateRef.current;
1076
- if (!touchState) {
1220
+ if (!touchState || touchState.pointerId !== event.pointerId || touchState.moved) {
1077
1221
  return;
1078
1222
  }
1079
- touchState.longPressed = true;
1080
- touchState.active = true;
1081
- (_slotsRef$current4 = slotsRef.current) == null || _slotsRef$current4.classList.add('schedule-calendar-touch-dragging');
1082
- startSlotSelection(slot, index, {
1083
- showPopover: false
1084
- });
1223
+ activateLongPress(touchState);
1085
1224
  longPressTimerRef.current = null;
1086
1225
  }, LONG_PRESS_DELAY);
1087
1226
  };
1088
- const handleTouchMove = event => {
1227
+ const handlePointerMove = event => {
1089
1228
  const touchState = touchStateRef.current;
1090
- if (!touchState) {
1091
- return;
1092
- }
1093
- const touch = Array.from(event.touches).find(item => item.identifier === touchState.identifier) || event.touches[0];
1094
- if (!touch) {
1229
+ if (!touchState || event.pointerId !== touchState.pointerId) {
1095
1230
  return;
1096
1231
  }
1232
+ touchState.lastX = event.clientX;
1233
+ touchState.lastY = event.clientY;
1097
1234
  if (!touchState.active) {
1098
- const moveX = Math.abs(touch.clientX - touchState.x);
1099
- const moveY = Math.abs(touch.clientY - touchState.y);
1100
- if (moveX > MOVE_THRESHOLD || moveY > MOVE_THRESHOLD) {
1235
+ if (shouldCancelPendingGesture(touchState, event.clientX, event.clientY)) {
1101
1236
  touchState.moved = true;
1102
- clearTouchState();
1237
+ clearPendingTouch();
1103
1238
  }
1104
1239
  return;
1105
1240
  }
1106
1241
  event.preventDefault();
1107
- const slotElement = getSlotElementFromTouch(container, touch);
1108
- if (!slotElement) {
1109
- return;
1110
- }
1111
- const index = Number(slotElement.getAttribute('data-slot-index'));
1112
- if (!Number.isNaN(index)) {
1113
- updateSelectionRange(index);
1242
+ event.stopPropagation();
1243
+ clearDocumentTextSelection();
1244
+ const index = getSlotIndexFromPoint(container, event.clientX, event.clientY);
1245
+ if (index !== null) {
1246
+ handlersRef.current.updateSelectionRange(index);
1114
1247
  }
1115
1248
  };
1116
- const handleTouchEnd = event => {
1249
+ const handlePointerUp = event => {
1117
1250
  const touchState = touchStateRef.current;
1118
- if (!touchState) {
1119
- return;
1120
- }
1121
- const touch = Array.from(event.changedTouches || []).find(item => item.identifier === touchState.identifier) || getTouchPoint(event);
1122
- if (!touch) {
1123
- clearTouchState();
1251
+ if (!touchState || event.pointerId !== touchState.pointerId) {
1124
1252
  return;
1125
1253
  }
1254
+ releasePointerCapture(event.pointerId);
1255
+ suppressMouseUntilRef.current = Date.now() + 700;
1126
1256
  if (touchState.active) {
1127
1257
  event.preventDefault();
1258
+ touchState.selectionTriggered = true;
1259
+ const index = getSlotIndexFromPoint(container, event.clientX, event.clientY);
1260
+ if (index !== null) {
1261
+ handlersRef.current.updateSelectionRange(index);
1262
+ }
1128
1263
  suppressTriggerUntilRef.current = Date.now() + 500;
1129
- finishSelection({
1264
+ handlersRef.current.finishSelection({
1130
1265
  fromTouch: true
1131
1266
  });
1132
- touchStateRef.current = null;
1133
1267
  return;
1134
1268
  }
1135
- const quickTap = !touchState.longPressed && !touchState.moved;
1136
- clearTouchState();
1269
+ handlersRef.current.clearLongPress();
1270
+ const quickTap = !touchState.moved && !touchState.longPressed && Math.abs(event.clientX - touchState.x) <= TAP_MOVE_THRESHOLD && Math.abs(event.clientY - touchState.y) <= TAP_MOVE_THRESHOLD && isStillOnSameSlot(touchState, event.clientX, event.clientY);
1271
+ const {
1272
+ slot
1273
+ } = touchState;
1274
+ touchStateRef.current = null;
1137
1275
  if (quickTap) {
1276
+ touchState.selectionTriggered = true;
1138
1277
  suppressTriggerUntilRef.current = Date.now() + 500;
1139
- selectSlots([touchState.slot]);
1140
- showFormPopoverForSlots([touchState.slot]);
1141
- onFreeSlotClick == null || onFreeSlotClick(touchState.slot);
1278
+ handlersRef.current.selectSlots([slot]);
1279
+ handlersRef.current.showFormPopoverForSlots([slot]);
1280
+ handlersRef.current.onFreeSlotClick == null || handlersRef.current.onFreeSlotClick(slot);
1281
+ return;
1142
1282
  }
1283
+ handlersRef.current.resetGestureState();
1143
1284
  };
1144
1285
  const handleContextMenu = event => {
1145
- if (touchStateRef.current || draggingRef.current) {
1286
+ var _touchStateRef$curren;
1287
+ if ((_touchStateRef$curren = touchStateRef.current) != null && _touchStateRef$curren.active || draggingRef.current) {
1146
1288
  event.preventDefault();
1147
1289
  }
1148
1290
  };
1149
- container.addEventListener('touchstart', handleTouchStart, {
1291
+ const handleSelectStart = event => {
1292
+ var _touchStateRef$curren2;
1293
+ if (!((_touchStateRef$curren2 = touchStateRef.current) != null && _touchStateRef$curren2.active) && !draggingRef.current) {
1294
+ return;
1295
+ }
1296
+ event.preventDefault();
1297
+ };
1298
+ const handleTouchMove = event => {
1299
+ var _touchStateRef$curren3;
1300
+ if (!draggingRef.current && !((_touchStateRef$curren3 = touchStateRef.current) != null && _touchStateRef$curren3.active)) {
1301
+ return;
1302
+ }
1303
+ event.preventDefault();
1304
+ };
1305
+ const touchOptions = {
1306
+ passive: false,
1307
+ capture: true
1308
+ };
1309
+ container.addEventListener('pointerdown', handlePointerDown, {
1150
1310
  passive: true
1151
1311
  });
1152
- container.addEventListener('touchmove', handleTouchMove, {
1312
+ container.addEventListener('pointermove', handlePointerMove, {
1153
1313
  passive: false
1154
1314
  });
1155
- container.addEventListener('touchend', handleTouchEnd, {
1315
+ container.addEventListener('pointerup', handlePointerUp, {
1156
1316
  passive: false
1157
1317
  });
1158
- container.addEventListener('touchcancel', handleTouchEnd, {
1318
+ container.addEventListener('pointercancel', handlePointerUp, {
1159
1319
  passive: false
1160
1320
  });
1321
+ container.addEventListener('touchmove', handleTouchMove, touchOptions);
1161
1322
  container.addEventListener('contextmenu', handleContextMenu);
1323
+ container.addEventListener('selectstart', handleSelectStart);
1162
1324
  return () => {
1163
- clearTouchState();
1164
- container.removeEventListener('touchstart', handleTouchStart);
1165
- container.removeEventListener('touchmove', handleTouchMove);
1166
- container.removeEventListener('touchend', handleTouchEnd);
1167
- container.removeEventListener('touchcancel', handleTouchEnd);
1168
- container.removeEventListener('contextmenu', handleContextMenu);
1325
+ var _touchStateRef$curren4;
1326
+ releasePointerCapture((_touchStateRef$curren4 = touchStateRef.current) == null ? void 0 : _touchStateRef$curren4.pointerId);
1327
+ handlersRef.current.clearLongPress();
1328
+ handlersRef.current.resetGestureState();
1329
+ longPressTimerRef.current = null;
1330
+ container.removeEventListener('touchmove', handleTouchMove, touchOptions);
1169
1331
  };
1170
- }, [clearLongPress, finishSelection, onFreeSlotClick, selectSlots, showFormPopoverForSlots, startSlotSelection, updateSelectionRange]);
1332
+ }, []);
1171
1333
  return {
1172
1334
  activePopoverKey,
1173
1335
  dragging,
@@ -1180,6 +1342,8 @@ const useScheduleSelectionGesture = ({
1180
1342
  finishSelection,
1181
1343
  handleMouseDown,
1182
1344
  handleMouseEnter,
1345
+ handleMouseUp,
1346
+ handleMouseLeave,
1183
1347
  handlePopoverOpenChange
1184
1348
  };
1185
1349
  };
@@ -1259,6 +1423,7 @@ const SlotItem = ({
1259
1423
  if (content) {
1260
1424
  const customNode = /*#__PURE__*/jsx("div", {
1261
1425
  "data-slot-index": slot.index,
1426
+ "data-slot-status": slot.status,
1262
1427
  onContextMenu: onContextMenu,
1263
1428
  onMouseDown: onMouseDown,
1264
1429
  onPointerDown: onPointerDown,
@@ -1318,19 +1483,10 @@ const SlotItem = ({
1318
1483
  }
1319
1484
  return node;
1320
1485
  };
1321
- const inner = /*#__PURE__*/jsxs("button", {
1322
- type: "button",
1323
- className: classNames(style$1['slot-item'], style$1[`slot-${slot.status}`], {
1324
- [style$1['slot-selected']]: selected
1325
- }),
1326
- "data-slot-index": slot.index,
1327
- disabled: slot.status === 'disabled',
1328
- onContextMenu: onContextMenu,
1329
- onMouseDown: onMouseDown,
1330
- onPointerDown: onPointerDown,
1331
- onMouseEnter: onMouseEnter,
1332
- onMouseUp: onMouseUp,
1333
- onClick: onClick,
1486
+ const slotClassName = classNames(style$1['slot-item'], style$1[`slot-${slot.status}`], {
1487
+ [style$1['slot-selected']]: selected
1488
+ });
1489
+ const slotChildren = /*#__PURE__*/jsxs(Fragment, {
1334
1490
  children: [/*#__PURE__*/jsx("span", {
1335
1491
  className: style$1['slot-dot']
1336
1492
  }), /*#__PURE__*/jsx("span", {
@@ -1354,6 +1510,36 @@ const SlotItem = ({
1354
1510
  children: slot.events.map(event => event.title).join('、')
1355
1511
  }) : null]
1356
1512
  });
1513
+ const slotHandlers = {
1514
+ onContextMenu,
1515
+ onMouseDown,
1516
+ onPointerDown,
1517
+ onMouseEnter,
1518
+ onMouseUp,
1519
+ onClick
1520
+ };
1521
+ const inner = slot.status === 'disabled' ? /*#__PURE__*/jsx("button", {
1522
+ type: "button",
1523
+ className: slotClassName,
1524
+ "data-slot-index": slot.index,
1525
+ "data-slot-status": slot.status,
1526
+ disabled: true,
1527
+ onContextMenu: onContextMenu,
1528
+ onMouseDown: onMouseDown,
1529
+ onPointerDown: onPointerDown,
1530
+ onMouseEnter: onMouseEnter,
1531
+ onMouseUp: onMouseUp,
1532
+ onClick: onClick,
1533
+ children: slotChildren
1534
+ }) : /*#__PURE__*/jsx("div", _extends({
1535
+ role: "button",
1536
+ tabIndex: 0,
1537
+ className: slotClassName,
1538
+ "data-slot-index": slot.index,
1539
+ "data-slot-status": slot.status
1540
+ }, slotHandlers, {
1541
+ children: slotChildren
1542
+ }));
1357
1543
  return wrapWithPopover(inner);
1358
1544
  };
1359
1545
 
@@ -1392,9 +1578,10 @@ const SchedulePanel = ({
1392
1578
  selectedKeys,
1393
1579
  selectSlots,
1394
1580
  slotsRef,
1395
- finishSelection,
1396
1581
  handleMouseDown,
1397
1582
  handleMouseEnter,
1583
+ handleMouseUp,
1584
+ handleMouseLeave,
1398
1585
  handlePopoverOpenChange
1399
1586
  } = useScheduleSelectionGesture({
1400
1587
  slots,
@@ -1467,8 +1654,8 @@ const SchedulePanel = ({
1467
1654
  [style$1['slots-dragging']]: dragging
1468
1655
  }),
1469
1656
  onScroll: onScroll,
1470
- onMouseUp: () => finishSelection(),
1471
- onMouseLeave: () => finishSelection(),
1657
+ onMouseUp: handleMouseUp,
1658
+ onMouseLeave: handleMouseLeave,
1472
1659
  children: [/*#__PURE__*/jsx(PanelScrollShadow, {
1473
1660
  visible: scrolled
1474
1661
  }), /*#__PURE__*/jsx("div", {
@@ -1498,7 +1685,7 @@ const SchedulePanel = ({
1498
1685
  },
1499
1686
  onMouseDown: event => handleMouseDown(event, slot, index),
1500
1687
  onMouseEnter: () => handleMouseEnter(index),
1501
- onMouseUp: () => finishSelection(),
1688
+ onMouseUp: handleMouseUp,
1502
1689
  onClick: undefined
1503
1690
  }, slot.key);
1504
1691
  })