gantt-lib 0.87.0 → 0.88.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.d.mts CHANGED
@@ -617,6 +617,8 @@ interface TaskRowProps {
617
617
  isWeekend?: (date: Date) => boolean;
618
618
  /** Disable task drag and resize (overrides task.locked) */
619
619
  disableTaskDrag?: boolean;
620
+ /** Active chart view mode */
621
+ viewMode?: 'day' | 'week' | 'month';
620
622
  }
621
623
  /**
622
624
  * TaskRow component - renders a single task row with a task bar
@@ -949,6 +951,8 @@ interface UseTaskDragOptions {
949
951
  businessDays?: boolean;
950
952
  /** Function that returns true for weekends (for businessDays mode) */
951
953
  weekendPredicate?: (date: Date) => boolean;
954
+ /** Active chart view mode */
955
+ viewMode?: 'day' | 'week' | 'month';
952
956
  }
953
957
  /**
954
958
  * Return value from useTaskDrag hook
@@ -965,6 +969,8 @@ interface UseTaskDragReturn {
965
969
  /** Props to spread on the drag handle element */
966
970
  dragHandleProps: {
967
971
  onMouseDown: (e: React.MouseEvent) => void;
972
+ onMouseMove: (e: React.MouseEvent) => void;
973
+ onMouseLeave: () => void;
968
974
  style: React.CSSProperties;
969
975
  };
970
976
  }
package/dist/index.d.ts CHANGED
@@ -617,6 +617,8 @@ interface TaskRowProps {
617
617
  isWeekend?: (date: Date) => boolean;
618
618
  /** Disable task drag and resize (overrides task.locked) */
619
619
  disableTaskDrag?: boolean;
620
+ /** Active chart view mode */
621
+ viewMode?: 'day' | 'week' | 'month';
620
622
  }
621
623
  /**
622
624
  * TaskRow component - renders a single task row with a task bar
@@ -949,6 +951,8 @@ interface UseTaskDragOptions {
949
951
  businessDays?: boolean;
950
952
  /** Function that returns true for weekends (for businessDays mode) */
951
953
  weekendPredicate?: (date: Date) => boolean;
954
+ /** Active chart view mode */
955
+ viewMode?: 'day' | 'week' | 'month';
952
956
  }
953
957
  /**
954
958
  * Return value from useTaskDrag hook
@@ -965,6 +969,8 @@ interface UseTaskDragReturn {
965
969
  /** Props to spread on the drag handle element */
966
970
  dragHandleProps: {
967
971
  onMouseDown: (e: React.MouseEvent) => void;
972
+ onMouseMove: (e: React.MouseEvent) => void;
973
+ onMouseLeave: () => void;
968
974
  style: React.CSSProperties;
969
975
  };
970
976
  }
package/dist/index.js CHANGED
@@ -2291,6 +2291,46 @@ function clampDateRangeForIncomingFS(task, range, allTasks, mode, businessDays,
2291
2291
  // src/hooks/useTaskDrag.ts
2292
2292
  var globalActiveDrag = null;
2293
2293
  var globalRafId = null;
2294
+ var globalLockedCursor = null;
2295
+ var GLOBAL_CURSOR_STYLE_ID = "gantt-global-drag-cursor-style";
2296
+ function ensureGlobalCursorStyle() {
2297
+ if (typeof document === "undefined") return;
2298
+ if (document.getElementById(GLOBAL_CURSOR_STYLE_ID)) return;
2299
+ const style = document.createElement("style");
2300
+ style.id = GLOBAL_CURSOR_STYLE_ID;
2301
+ style.textContent = `
2302
+ html.gantt-global-cursor-grabbing,
2303
+ html.gantt-global-cursor-grabbing *,
2304
+ html.gantt-global-cursor-grabbing *::before,
2305
+ html.gantt-global-cursor-grabbing *::after {
2306
+ cursor: grabbing !important;
2307
+ }
2308
+
2309
+ html.gantt-global-cursor-resize,
2310
+ html.gantt-global-cursor-resize *,
2311
+ html.gantt-global-cursor-resize *::before,
2312
+ html.gantt-global-cursor-resize *::after {
2313
+ cursor: ew-resize !important;
2314
+ }
2315
+ `;
2316
+ document.head.appendChild(style);
2317
+ }
2318
+ function applyGlobalCursor(cursor) {
2319
+ if (typeof document === "undefined") return;
2320
+ ensureGlobalCursorStyle();
2321
+ globalLockedCursor = cursor;
2322
+ document.documentElement.classList.remove("gantt-global-cursor-grabbing", "gantt-global-cursor-resize");
2323
+ document.documentElement.classList.add(cursor === "grabbing" ? "gantt-global-cursor-grabbing" : "gantt-global-cursor-resize");
2324
+ document.body.style.cursor = cursor;
2325
+ document.documentElement.style.cursor = cursor;
2326
+ }
2327
+ function clearGlobalCursor() {
2328
+ if (typeof document === "undefined") return;
2329
+ globalLockedCursor = null;
2330
+ document.documentElement.classList.remove("gantt-global-cursor-grabbing", "gantt-global-cursor-resize");
2331
+ document.body.style.cursor = "";
2332
+ document.documentElement.style.cursor = "";
2333
+ }
2294
2334
  function getDayOffsetFromMonthStart(date, monthStart) {
2295
2335
  return Math.round(
2296
2336
  (Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()) - Date.UTC(monthStart.getUTCFullYear(), monthStart.getUTCMonth(), monthStart.getUTCDate())) / (24 * 60 * 60 * 1e3)
@@ -2301,6 +2341,7 @@ function completeDrag() {
2301
2341
  cancelAnimationFrame(globalRafId);
2302
2342
  globalRafId = null;
2303
2343
  }
2344
+ clearGlobalCursor();
2304
2345
  if (globalActiveDrag) {
2305
2346
  globalActiveDrag.onCascadeProgress?.(/* @__PURE__ */ new Map(), []);
2306
2347
  const { onComplete, currentLeft, currentWidth, mode } = globalActiveDrag;
@@ -2313,6 +2354,7 @@ function cancelDrag() {
2313
2354
  cancelAnimationFrame(globalRafId);
2314
2355
  globalRafId = null;
2315
2356
  }
2357
+ clearGlobalCursor();
2316
2358
  if (globalActiveDrag) {
2317
2359
  const { onCancel } = globalActiveDrag;
2318
2360
  globalActiveDrag = null;
@@ -2522,7 +2564,8 @@ var useTaskDrag = (options) => {
2522
2564
  locked = false,
2523
2565
  disableTaskDrag = false,
2524
2566
  businessDays = true,
2525
- weekendPredicate
2567
+ weekendPredicate,
2568
+ viewMode = "day"
2526
2569
  } = options;
2527
2570
  const rawHookTask = allTasks.find((t) => t.id === taskId);
2528
2571
  const hookTask = rawHookTask ? normalizeTaskDatesForType(rawHookTask) : void 0;
@@ -2533,6 +2576,7 @@ var useTaskDrag = (options) => {
2533
2576
  const [dragMode, setDragMode] = (0, import_react2.useState)(null);
2534
2577
  const [currentLeft, setCurrentLeft] = (0, import_react2.useState)(0);
2535
2578
  const [currentWidth, setCurrentWidth] = (0, import_react2.useState)(0);
2579
+ const [hoverCursor, setHoverCursor] = (0, import_react2.useState)("grab");
2536
2580
  const getInitialPosition = (0, import_react2.useCallback)(() => {
2537
2581
  const getUTCDayDifference2 = (date1, date2) => {
2538
2582
  const ms1 = Date.UTC(
@@ -2711,28 +2755,33 @@ var useTaskDrag = (options) => {
2711
2755
  }
2712
2756
  };
2713
2757
  }, []);
2714
- const handleMouseDown = (0, import_react2.useCallback)((e) => {
2758
+ const startDrag = (0, import_react2.useCallback)((e) => {
2715
2759
  if (effectiveLocked) return;
2716
2760
  const target = e.currentTarget;
2717
- const edgeZone = detectEdgeZone(e.clientX, target, edgeZoneWidth);
2761
+ const currentTask = allTasks.find((t) => t.id === taskId);
2762
+ const isSingleDayTask = !!currentTask && !isMilestoneTask(currentTask) && !isTaskParent(taskId, allTasks) && currentWidth <= dayWidth && viewMode === "day";
2718
2763
  let mode = null;
2719
- switch (edgeZone) {
2720
- case "left":
2721
- mode = "resize-left";
2722
- break;
2723
- case "right":
2724
- mode = "resize-right";
2725
- break;
2726
- case "move":
2727
- mode = "move";
2728
- break;
2764
+ if (isSingleDayTask) {
2765
+ mode = "move";
2766
+ } else {
2767
+ const edgeZone = detectEdgeZone(e.clientX, target, edgeZoneWidth);
2768
+ switch (edgeZone) {
2769
+ case "left":
2770
+ mode = "resize-left";
2771
+ break;
2772
+ case "right":
2773
+ mode = "resize-right";
2774
+ break;
2775
+ case "move":
2776
+ mode = "move";
2777
+ break;
2778
+ }
2729
2779
  }
2730
2780
  if (mode === "resize-left" || mode === "resize-right") {
2731
- const currentTask2 = allTasks.find((t) => t.id === taskId);
2732
- if (currentTask2 && isTaskParent(taskId, allTasks)) {
2781
+ if (currentTask && isTaskParent(taskId, allTasks)) {
2733
2782
  mode = "move";
2734
2783
  }
2735
- if (currentTask2 && isMilestoneTask(currentTask2)) {
2784
+ if (currentTask && isMilestoneTask(currentTask)) {
2736
2785
  mode = "move";
2737
2786
  }
2738
2787
  }
@@ -2744,6 +2793,7 @@ var useTaskDrag = (options) => {
2744
2793
  isOwnerRef.current = true;
2745
2794
  setIsDragging(true);
2746
2795
  setDragMode(mode);
2796
+ applyGlobalCursor(mode === "move" ? "grabbing" : "ew-resize");
2747
2797
  if (onDragStateChange) {
2748
2798
  onDragStateChange({
2749
2799
  isDragging: true,
@@ -2753,10 +2803,10 @@ var useTaskDrag = (options) => {
2753
2803
  });
2754
2804
  }
2755
2805
  ensureGlobalListeners();
2756
- const currentTask = allTasks.find((t) => t.id === taskId);
2806
+ const dragTask = allTasks.find((t) => t.id === taskId);
2757
2807
  let hierarchyChain = [];
2758
- if (currentTask) {
2759
- const taskParentId = currentTask.parentId;
2808
+ if (dragTask) {
2809
+ const taskParentId = dragTask.parentId;
2760
2810
  if (taskParentId) {
2761
2811
  const parentTask = allTasks.find((t) => t.id === taskParentId);
2762
2812
  if (parentTask) {
@@ -2793,15 +2843,44 @@ var useTaskDrag = (options) => {
2793
2843
  businessDays,
2794
2844
  weekendPredicate
2795
2845
  };
2796
- }, [edgeZoneWidth, currentLeft, currentWidth, dayWidth, monthStart, taskId, onDragStateChange, handleProgress, handleComplete, handleCancel, allTasks, disableConstraints, onCascadeProgress, onCascade, effectiveLocked]);
2846
+ }, [edgeZoneWidth, currentLeft, currentWidth, dayWidth, monthStart, taskId, onDragStateChange, handleProgress, handleComplete, handleCancel, allTasks, disableConstraints, onCascadeProgress, onCascade, effectiveLocked, viewMode]);
2847
+ const handleMouseDown = (0, import_react2.useCallback)((e) => {
2848
+ startDrag(e);
2849
+ }, [startDrag]);
2850
+ const handleMouseMove = (0, import_react2.useCallback)((e) => {
2851
+ if (disableTaskDrag) {
2852
+ setHoverCursor("grab");
2853
+ return;
2854
+ }
2855
+ if (locked) {
2856
+ setHoverCursor("not-allowed");
2857
+ return;
2858
+ }
2859
+ if (isDragging) {
2860
+ setHoverCursor("grabbing");
2861
+ return;
2862
+ }
2863
+ const target = e.currentTarget;
2864
+ const currentTask = allTasks.find((t) => t.id === taskId);
2865
+ const isSingleDayTask = !!currentTask && !isMilestoneTask(currentTask) && !isTaskParent(taskId, allTasks) && currentWidth <= dayWidth && viewMode === "day";
2866
+ if (isSingleDayTask || currentTask && (isTaskParent(taskId, allTasks) || isMilestoneTask(currentTask))) {
2867
+ setHoverCursor("grab");
2868
+ return;
2869
+ }
2870
+ const edgeZone = detectEdgeZone(e.clientX, target, edgeZoneWidth);
2871
+ setHoverCursor(edgeZone === "move" ? "grab" : "ew-resize");
2872
+ }, [disableTaskDrag, locked, isDragging, allTasks, taskId, currentWidth, dayWidth, viewMode, edgeZoneWidth]);
2873
+ const handleMouseLeave = (0, import_react2.useCallback)(() => {
2874
+ setHoverCursor(disableTaskDrag ? "grab" : locked ? "not-allowed" : isDragging ? "grabbing" : "grab");
2875
+ }, [disableTaskDrag, locked, isDragging]);
2797
2876
  const getCursorStyle = (0, import_react2.useCallback)(() => {
2798
2877
  if (disableTaskDrag) return "grab";
2799
2878
  if (locked) return "not-allowed";
2800
2879
  if (isDragging) {
2801
- return "grabbing";
2880
+ return dragMode === "move" ? "grabbing" : "ew-resize";
2802
2881
  }
2803
- return "grab";
2804
- }, [disableTaskDrag, locked, isDragging]);
2882
+ return hoverCursor;
2883
+ }, [disableTaskDrag, locked, isDragging, dragMode, hoverCursor]);
2805
2884
  return {
2806
2885
  isDragging,
2807
2886
  dragMode,
@@ -2809,6 +2888,8 @@ var useTaskDrag = (options) => {
2809
2888
  currentWidth,
2810
2889
  dragHandleProps: {
2811
2890
  onMouseDown: handleMouseDown,
2891
+ onMouseMove: handleMouseMove,
2892
+ onMouseLeave: handleMouseLeave,
2812
2893
  style: {
2813
2894
  cursor: getCursorStyle(),
2814
2895
  userSelect: "none"
@@ -2820,10 +2901,10 @@ var useTaskDrag = (options) => {
2820
2901
  // src/components/TaskRow/TaskRow.tsx
2821
2902
  var import_jsx_runtime2 = require("react/jsx-runtime");
2822
2903
  var arePropsEqual = (prevProps, nextProps) => {
2823
- return prevProps.task.id === nextProps.task.id && prevProps.task.name === nextProps.task.name && prevProps.task.startDate === nextProps.task.startDate && prevProps.task.endDate === nextProps.task.endDate && prevProps.task.baselineStartDate === nextProps.task.baselineStartDate && prevProps.task.baselineEndDate === nextProps.task.baselineEndDate && prevProps.task.type === nextProps.task.type && prevProps.task.color === nextProps.task.color && prevProps.task.progress === nextProps.task.progress && prevProps.task.accepted === nextProps.task.accepted && prevProps.monthStart.getTime() === nextProps.monthStart.getTime() && prevProps.dayWidth === nextProps.dayWidth && prevProps.rowHeight === nextProps.rowHeight && prevProps.overridePosition?.left === nextProps.overridePosition?.left && prevProps.overridePosition?.width === nextProps.overridePosition?.width && prevProps.allTasks === nextProps.allTasks && prevProps.disableConstraints === nextProps.disableConstraints && prevProps.task.locked === nextProps.task.locked && prevProps.task.divider === nextProps.task.divider && prevProps.highlightExpiredTasks === nextProps.highlightExpiredTasks && prevProps.showBaseline === nextProps.showBaseline && prevProps.isFilterMatch === nextProps.isFilterMatch && prevProps.businessDays === nextProps.businessDays && prevProps.customDays === nextProps.customDays && prevProps.isWeekend === nextProps.isWeekend && prevProps.disableTaskDrag === nextProps.disableTaskDrag;
2904
+ return prevProps.task.id === nextProps.task.id && prevProps.task.name === nextProps.task.name && prevProps.task.startDate === nextProps.task.startDate && prevProps.task.endDate === nextProps.task.endDate && prevProps.task.baselineStartDate === nextProps.task.baselineStartDate && prevProps.task.baselineEndDate === nextProps.task.baselineEndDate && prevProps.task.type === nextProps.task.type && prevProps.task.color === nextProps.task.color && prevProps.task.progress === nextProps.task.progress && prevProps.task.accepted === nextProps.task.accepted && prevProps.monthStart.getTime() === nextProps.monthStart.getTime() && prevProps.dayWidth === nextProps.dayWidth && prevProps.rowHeight === nextProps.rowHeight && prevProps.overridePosition?.left === nextProps.overridePosition?.left && prevProps.overridePosition?.width === nextProps.overridePosition?.width && prevProps.allTasks === nextProps.allTasks && prevProps.disableConstraints === nextProps.disableConstraints && prevProps.task.locked === nextProps.task.locked && prevProps.task.divider === nextProps.task.divider && prevProps.highlightExpiredTasks === nextProps.highlightExpiredTasks && prevProps.showBaseline === nextProps.showBaseline && prevProps.isFilterMatch === nextProps.isFilterMatch && prevProps.businessDays === nextProps.businessDays && prevProps.customDays === nextProps.customDays && prevProps.isWeekend === nextProps.isWeekend && prevProps.disableTaskDrag === nextProps.disableTaskDrag && prevProps.viewMode === nextProps.viewMode;
2824
2905
  };
2825
2906
  var TaskRow = import_react3.default.memo(
2826
- ({ task, monthStart, dayWidth, rowHeight, onTasksChange, onDragStateChange, rowIndex, allTasks, enableAutoSchedule, disableConstraints, overridePosition, onCascadeProgress, onCascade, divider, highlightExpiredTasks, showBaseline = false, isFilterMatch = false, businessDays, customDays, isWeekend: isWeekend3, disableTaskDrag = false }) => {
2907
+ ({ task, monthStart, dayWidth, rowHeight, onTasksChange, onDragStateChange, rowIndex, allTasks, enableAutoSchedule, disableConstraints, overridePosition, onCascadeProgress, onCascade, divider, highlightExpiredTasks, showBaseline = false, isFilterMatch = false, businessDays, customDays, isWeekend: isWeekend3, disableTaskDrag = false, viewMode = "day" }) => {
2827
2908
  const defaultParentBarColor = "#782FC4";
2828
2909
  const { divider: taskDivider } = task;
2829
2910
  const normalizedTask = (0, import_react3.useMemo)(() => normalizeTaskDatesForType(task), [task]);
@@ -2936,7 +3017,8 @@ var TaskRow = import_react3.default.memo(
2936
3017
  onCascadeProgress,
2937
3018
  onCascade,
2938
3019
  businessDays,
2939
- weekendPredicate
3020
+ weekendPredicate,
3021
+ viewMode
2940
3022
  });
2941
3023
  const displayLeft = overridePosition?.left ?? (isDragging ? currentLeft : left);
2942
3024
  const displayWidth = overridePosition?.width ?? (isDragging ? currentWidth : width);
@@ -3012,6 +3094,8 @@ var TaskRow = import_react3.default.memo(
3012
3094
  userSelect: dragHandleProps.style.userSelect
3013
3095
  },
3014
3096
  onMouseDown: dragHandleProps.onMouseDown,
3097
+ onMouseMove: dragHandleProps.onMouseMove,
3098
+ onMouseLeave: dragHandleProps.onMouseLeave,
3015
3099
  children: [
3016
3100
  !milestone && progressWidth > 0 && progressWidth < 100 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
3017
3101
  "div",
@@ -10168,7 +10252,8 @@ function TaskGanttChartInner(props, ref) {
10168
10252
  businessDays,
10169
10253
  customDays,
10170
10254
  isWeekend: isWeekend3,
10171
- disableTaskDrag
10255
+ disableTaskDrag,
10256
+ viewMode
10172
10257
  },
10173
10258
  task.id
10174
10259
  ))