react-yearly-calendar-grid 0.5.13 → 0.6.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/dist/index.js CHANGED
@@ -506,6 +506,11 @@ function YearlyCalendar({
506
506
  const [hoveredResizeHandle, setHoveredResizeHandle] = react.useState(null);
507
507
  const [hoveredCancelButton, setHoveredCancelButton] = react.useState(false);
508
508
  const [hoveredConfirmButton, setHoveredConfirmButton] = react.useState(false);
509
+ const [touchSelectedEvent, setTouchSelectedEvent] = react.useState(null);
510
+ const touchLongPressTimer = react.useRef(
511
+ null
512
+ );
513
+ const touchStartPos = react.useRef(null);
509
514
  const [rangeSelectionStart, setRangeSelectionStart] = react.useState(null);
510
515
  const [rangeSelectionEnd, setRangeSelectionEnd] = react.useState(null);
511
516
  const isRangeSelecting = rangeSelectionStart !== null;
@@ -736,7 +741,14 @@ function YearlyCalendar({
736
741
  const duration = draggingEvent.endDate.getTime() - draggingEvent.date.getTime();
737
742
  newEndDate = new Date(newStartDate.getTime() + duration);
738
743
  }
739
- onEventMove(draggingEvent, newStartDate, newEndDate);
744
+ if (newStartDate.getTime() !== draggingEvent.date.getTime()) {
745
+ setPendingMove({
746
+ event: draggingEvent,
747
+ newStartDate,
748
+ newEndDate,
749
+ isResize: false
750
+ });
751
+ }
740
752
  }
741
753
  setDragOverCell(null);
742
754
  setDragPosition(null);
@@ -765,6 +777,65 @@ function YearlyCalendar({
765
777
  const handleCancelMove = react.useCallback(() => {
766
778
  setPendingMove(null);
767
779
  }, []);
780
+ const handleTouchStart = react.useCallback(
781
+ (e, event) => {
782
+ if (!onEventMove) return;
783
+ const touch = e.touches[0];
784
+ touchStartPos.current = { x: touch.clientX, y: touch.clientY };
785
+ touchLongPressTimer.current = setTimeout(() => {
786
+ setTouchSelectedEvent(event);
787
+ touchLongPressTimer.current = null;
788
+ if (navigator.vibrate) {
789
+ navigator.vibrate(50);
790
+ }
791
+ }, 500);
792
+ },
793
+ [onEventMove]
794
+ );
795
+ const handleTouchMove = react.useCallback(
796
+ (e) => {
797
+ if (touchLongPressTimer.current && touchStartPos.current) {
798
+ const touch = e.touches[0];
799
+ const dx = touch.clientX - touchStartPos.current.x;
800
+ const dy = touch.clientY - touchStartPos.current.y;
801
+ if (Math.abs(dx) > 10 || Math.abs(dy) > 10) {
802
+ clearTimeout(touchLongPressTimer.current);
803
+ touchLongPressTimer.current = null;
804
+ }
805
+ }
806
+ },
807
+ []
808
+ );
809
+ const handleTouchEnd = react.useCallback(() => {
810
+ if (touchLongPressTimer.current) {
811
+ clearTimeout(touchLongPressTimer.current);
812
+ touchLongPressTimer.current = null;
813
+ }
814
+ }, []);
815
+ const handleTouchCellTap = react.useCallback(
816
+ (month, day) => {
817
+ if (!touchSelectedEvent || !onEventMove) return;
818
+ const newStartDate = new Date(year, month, day);
819
+ let newEndDate;
820
+ if (touchSelectedEvent.endDate) {
821
+ const duration = touchSelectedEvent.endDate.getTime() - touchSelectedEvent.date.getTime();
822
+ newEndDate = new Date(newStartDate.getTime() + duration);
823
+ }
824
+ if (newStartDate.getTime() !== touchSelectedEvent.date.getTime()) {
825
+ setPendingMove({
826
+ event: touchSelectedEvent,
827
+ newStartDate,
828
+ newEndDate,
829
+ isResize: false
830
+ });
831
+ }
832
+ setTouchSelectedEvent(null);
833
+ },
834
+ [touchSelectedEvent, year, onEventMove]
835
+ );
836
+ const handleCancelTouchSelect = react.useCallback(() => {
837
+ setTouchSelectedEvent(null);
838
+ }, []);
768
839
  const handleResizeStart = react.useCallback(
769
840
  (e, event, edge) => {
770
841
  e.stopPropagation();
@@ -778,6 +849,7 @@ function YearlyCalendar({
778
849
  );
779
850
  const handleResizeDrop = react.useCallback(
780
851
  (month, day) => {
852
+ var _a;
781
853
  if (!resizingEvent || !onEventMove) return;
782
854
  const { event, edge } = resizingEvent;
783
855
  const dropDate = new Date(year, month, day);
@@ -793,7 +865,16 @@ function YearlyCalendar({
793
865
  }
794
866
  }
795
867
  const finalEndDate = newStartDate.getTime() === newEndDate.getTime() ? void 0 : newEndDate;
796
- onEventMove(event, newStartDate, finalEndDate);
868
+ const startChanged = newStartDate.getTime() !== event.date.getTime();
869
+ const endChanged = (finalEndDate == null ? void 0 : finalEndDate.getTime()) !== ((_a = event.endDate) == null ? void 0 : _a.getTime());
870
+ if (startChanged || endChanged) {
871
+ setPendingMove({
872
+ event,
873
+ newStartDate,
874
+ newEndDate: finalEndDate,
875
+ isResize: true
876
+ });
877
+ }
797
878
  setResizingEvent(null);
798
879
  setDragOverCell(null);
799
880
  setDragPosition(null);
@@ -830,6 +911,50 @@ function YearlyCalendar({
830
911
  return WEEKDAYS[date.getDay()];
831
912
  };
832
913
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, style: styles.container, children: [
914
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
915
+ @keyframes touchSelectedPulse {
916
+ 0%, 100% { box-shadow: 0 0 4px rgba(59, 130, 246, 0.6); }
917
+ 50% { box-shadow: 0 0 12px rgba(59, 130, 246, 1); }
918
+ }
919
+ ` }),
920
+ touchSelectedEvent && /* @__PURE__ */ jsxRuntime.jsxs(
921
+ "div",
922
+ {
923
+ style: {
924
+ position: "absolute",
925
+ top: 0,
926
+ left: 0,
927
+ right: 0,
928
+ zIndex: 100,
929
+ backgroundColor: theme.buttonPrimary,
930
+ color: "#fff",
931
+ padding: "6px 12px",
932
+ display: "flex",
933
+ alignItems: "center",
934
+ justifyContent: "space-between",
935
+ fontSize: 13
936
+ },
937
+ children: [
938
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: isJa ? `\u300C${touchSelectedEvent.title}\u300D\u3092\u79FB\u52D5\u5148\u306E\u65E5\u4ED8\u3092\u30BF\u30C3\u30D7` : `Tap a date to move "${touchSelectedEvent.title}"` }),
939
+ /* @__PURE__ */ jsxRuntime.jsx(
940
+ "button",
941
+ {
942
+ onClick: handleCancelTouchSelect,
943
+ style: {
944
+ background: "rgba(255,255,255,0.2)",
945
+ border: "none",
946
+ color: "#fff",
947
+ padding: "4px 12px",
948
+ borderRadius: 4,
949
+ fontSize: 12,
950
+ cursor: "pointer"
951
+ },
952
+ children: isJa ? "\u30AD\u30E3\u30F3\u30BB\u30EB" : "Cancel"
953
+ }
954
+ )
955
+ ]
956
+ }
957
+ ),
833
958
  draggingEvent && dragOverCell && dragPosition && (() => {
834
959
  const cardTop = dragPosition.y - dragGrabOffsetY;
835
960
  const cardBottom = cardTop + dragCardHeight;
@@ -898,7 +1023,16 @@ function YearlyCalendar({
898
1023
  cursor: isValidDay ? "pointer" : "default",
899
1024
  userSelect: "none"
900
1025
  }),
901
- onClick: () => isValidDay && !isRangeSelecting && handleCellClick(monthIndex, day),
1026
+ onClick: () => {
1027
+ if (!isValidDay) return;
1028
+ if (touchSelectedEvent) {
1029
+ handleTouchCellTap(monthIndex, day);
1030
+ return;
1031
+ }
1032
+ if (!isRangeSelecting) {
1033
+ handleCellClick(monthIndex, day);
1034
+ }
1035
+ },
902
1036
  onDoubleClick: () => isValidDay && handleCellDoubleClick(monthIndex, day),
903
1037
  onMouseDown: () => isValidDay && handleRangeSelectStart(monthIndex, day),
904
1038
  onMouseEnter: () => {
@@ -958,6 +1092,7 @@ function YearlyCalendar({
958
1092
  const spanDays = displayEndDay - displayStartDay + 1;
959
1093
  const isInteractive = !draggingEvent && !resizingEvent;
960
1094
  const isHovered = hoveredEventBar === span.event.id;
1095
+ const isTouchSelected = (touchSelectedEvent == null ? void 0 : touchSelectedEvent.id) === span.event.id;
961
1096
  return /* @__PURE__ */ jsxRuntime.jsxs(
962
1097
  "div",
963
1098
  {
@@ -969,10 +1104,12 @@ function YearlyCalendar({
969
1104
  backgroundColor: getEventColor(span.event),
970
1105
  borderRadius: `${span.isStart ? 4 : 0}px ${span.isStart ? 4 : 0}px ${span.isEnd ? 4 : 0}px ${span.isEnd ? 4 : 0}px`,
971
1106
  opacity: isDraggingThis ? 0.3 : 1,
972
- border: isResizingThis ? "2px dashed rgba(255, 255, 255, 0.8)" : "none",
973
- zIndex: isResizingThis ? 30 : isHovered ? 50 : 10,
1107
+ border: isTouchSelected ? "2px solid rgba(255, 255, 255, 0.9)" : isResizingThis ? "2px dashed rgba(255, 255, 255, 0.8)" : "none",
1108
+ boxShadow: isTouchSelected ? "0 0 8px rgba(59, 130, 246, 0.8)" : "none",
1109
+ zIndex: isTouchSelected ? 60 : isResizingThis ? 30 : isHovered ? 50 : 10,
974
1110
  filter: isHovered ? "brightness(1.1)" : "none",
975
- pointerEvents: isInteractive ? "auto" : "none"
1111
+ pointerEvents: isInteractive ? "auto" : "none",
1112
+ animation: isTouchSelected ? "touchSelectedPulse 1.5s ease-in-out infinite" : "none"
976
1113
  }),
977
1114
  draggable: true,
978
1115
  onDragStart: (e) => handleDragStart(
@@ -982,6 +1119,9 @@ function YearlyCalendar({
982
1119
  span.startDay
983
1120
  ),
984
1121
  onDragEnd: handleDragEnd,
1122
+ onTouchStart: (e) => handleTouchStart(e, span.event),
1123
+ onTouchMove: handleTouchMove,
1124
+ onTouchEnd: handleTouchEnd,
985
1125
  onMouseEnter: (e) => {
986
1126
  setHoveredEventBar(span.event.id);
987
1127
  const rect = e.currentTarget.getBoundingClientRect();
@@ -997,6 +1137,7 @@ function YearlyCalendar({
997
1137
  },
998
1138
  onClick: (e) => {
999
1139
  e.stopPropagation();
1140
+ if (touchSelectedEvent) return;
1000
1141
  onEventClick == null ? void 0 : onEventClick(span.event);
1001
1142
  },
1002
1143
  children: [