gantt-lib 0.86.1 → 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
@@ -303,7 +303,7 @@ declare const progressInRange: (min: number, max: number) => TaskPredicate;
303
303
  */
304
304
  declare const nameContains: (substring: string, caseSensitive?: boolean) => TaskPredicate;
305
305
 
306
- type BuiltInTaskListColumnId = 'number' | 'name' | 'startDate' | 'endDate' | 'duration' | 'progress' | 'dependencies' | 'actions';
306
+ type BuiltInTaskListColumnId = 'selection' | 'number' | 'name' | 'startDate' | 'endDate' | 'duration' | 'progress' | 'dependencies' | 'actions';
307
307
  type TaskListColumnId = BuiltInTaskListColumnId | (string & {});
308
308
  type TaskListColumnAnchor = {
309
309
  after: BuiltInTaskListColumnId | string;
@@ -495,6 +495,12 @@ interface GanttModeProps<TTask extends Task = Task> {
495
495
  onToggleCollapse?: (parentId: string) => void;
496
496
  /** Task IDs to highlight in the task list (for search results) */
497
497
  highlightedTaskIds?: Set<string>;
498
+ /** Enable a leading checkbox column for multi-selecting task rows (default: false) */
499
+ enableTaskMultiSelect?: boolean;
500
+ /** Controlled selected task IDs for multi-select mode */
501
+ selectedTaskIds?: Set<string>;
502
+ /** Callback when multi-selected task IDs change */
503
+ onSelectedTaskIdsChange?: (taskIds: Set<string>) => void;
498
504
  /** Disable task drag and resize on the calendar grid (default: false) */
499
505
  disableTaskDrag?: boolean;
500
506
  /** Show calendar chart area (default: true) */
@@ -611,6 +617,8 @@ interface TaskRowProps {
611
617
  isWeekend?: (date: Date) => boolean;
612
618
  /** Disable task drag and resize (overrides task.locked) */
613
619
  disableTaskDrag?: boolean;
620
+ /** Active chart view mode */
621
+ viewMode?: 'day' | 'week' | 'month';
614
622
  }
615
623
  /**
616
624
  * TaskRow component - renders a single task row with a task bar
@@ -766,6 +774,12 @@ interface TaskListProps {
766
774
  businessDays?: boolean;
767
775
  /** Task IDs highlighted by the active filter */
768
776
  highlightedTaskIds?: Set<string>;
777
+ /** Enable a leading checkbox column for multi-selecting task rows (default: false) */
778
+ enableTaskMultiSelect?: boolean;
779
+ /** Controlled selected task IDs for multi-select mode */
780
+ selectedTaskIds?: Set<string>;
781
+ /** Callback when multi-selected task IDs change */
782
+ onSelectedTaskIdsChange?: (taskIds: Set<string>) => void;
769
783
  /** Filter mode: 'highlight' shows yellow highlight on matches, 'hide' hides non-matching tasks */
770
784
  filterMode?: 'highlight' | 'hide';
771
785
  /** Task IDs that match the filter (used for hide mode). When undefined, no filtering is applied */
@@ -937,6 +951,8 @@ interface UseTaskDragOptions {
937
951
  businessDays?: boolean;
938
952
  /** Function that returns true for weekends (for businessDays mode) */
939
953
  weekendPredicate?: (date: Date) => boolean;
954
+ /** Active chart view mode */
955
+ viewMode?: 'day' | 'week' | 'month';
940
956
  }
941
957
  /**
942
958
  * Return value from useTaskDrag hook
@@ -953,6 +969,8 @@ interface UseTaskDragReturn {
953
969
  /** Props to spread on the drag handle element */
954
970
  dragHandleProps: {
955
971
  onMouseDown: (e: React.MouseEvent) => void;
972
+ onMouseMove: (e: React.MouseEvent) => void;
973
+ onMouseLeave: () => void;
956
974
  style: React.CSSProperties;
957
975
  };
958
976
  }
package/dist/index.d.ts CHANGED
@@ -303,7 +303,7 @@ declare const progressInRange: (min: number, max: number) => TaskPredicate;
303
303
  */
304
304
  declare const nameContains: (substring: string, caseSensitive?: boolean) => TaskPredicate;
305
305
 
306
- type BuiltInTaskListColumnId = 'number' | 'name' | 'startDate' | 'endDate' | 'duration' | 'progress' | 'dependencies' | 'actions';
306
+ type BuiltInTaskListColumnId = 'selection' | 'number' | 'name' | 'startDate' | 'endDate' | 'duration' | 'progress' | 'dependencies' | 'actions';
307
307
  type TaskListColumnId = BuiltInTaskListColumnId | (string & {});
308
308
  type TaskListColumnAnchor = {
309
309
  after: BuiltInTaskListColumnId | string;
@@ -495,6 +495,12 @@ interface GanttModeProps<TTask extends Task = Task> {
495
495
  onToggleCollapse?: (parentId: string) => void;
496
496
  /** Task IDs to highlight in the task list (for search results) */
497
497
  highlightedTaskIds?: Set<string>;
498
+ /** Enable a leading checkbox column for multi-selecting task rows (default: false) */
499
+ enableTaskMultiSelect?: boolean;
500
+ /** Controlled selected task IDs for multi-select mode */
501
+ selectedTaskIds?: Set<string>;
502
+ /** Callback when multi-selected task IDs change */
503
+ onSelectedTaskIdsChange?: (taskIds: Set<string>) => void;
498
504
  /** Disable task drag and resize on the calendar grid (default: false) */
499
505
  disableTaskDrag?: boolean;
500
506
  /** Show calendar chart area (default: true) */
@@ -611,6 +617,8 @@ interface TaskRowProps {
611
617
  isWeekend?: (date: Date) => boolean;
612
618
  /** Disable task drag and resize (overrides task.locked) */
613
619
  disableTaskDrag?: boolean;
620
+ /** Active chart view mode */
621
+ viewMode?: 'day' | 'week' | 'month';
614
622
  }
615
623
  /**
616
624
  * TaskRow component - renders a single task row with a task bar
@@ -766,6 +774,12 @@ interface TaskListProps {
766
774
  businessDays?: boolean;
767
775
  /** Task IDs highlighted by the active filter */
768
776
  highlightedTaskIds?: Set<string>;
777
+ /** Enable a leading checkbox column for multi-selecting task rows (default: false) */
778
+ enableTaskMultiSelect?: boolean;
779
+ /** Controlled selected task IDs for multi-select mode */
780
+ selectedTaskIds?: Set<string>;
781
+ /** Callback when multi-selected task IDs change */
782
+ onSelectedTaskIdsChange?: (taskIds: Set<string>) => void;
769
783
  /** Filter mode: 'highlight' shows yellow highlight on matches, 'hide' hides non-matching tasks */
770
784
  filterMode?: 'highlight' | 'hide';
771
785
  /** Task IDs that match the filter (used for hide mode). When undefined, no filtering is applied */
@@ -937,6 +951,8 @@ interface UseTaskDragOptions {
937
951
  businessDays?: boolean;
938
952
  /** Function that returns true for weekends (for businessDays mode) */
939
953
  weekendPredicate?: (date: Date) => boolean;
954
+ /** Active chart view mode */
955
+ viewMode?: 'day' | 'week' | 'month';
940
956
  }
941
957
  /**
942
958
  * Return value from useTaskDrag hook
@@ -953,6 +969,8 @@ interface UseTaskDragReturn {
953
969
  /** Props to spread on the drag handle element */
954
970
  dragHandleProps: {
955
971
  onMouseDown: (e: React.MouseEvent) => void;
972
+ onMouseMove: (e: React.MouseEvent) => void;
973
+ onMouseLeave: () => void;
956
974
  style: React.CSSProperties;
957
975
  };
958
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",
@@ -4757,6 +4841,8 @@ var TaskListRow = import_react10.default.memo(
4757
4841
  isFilterMatch = false,
4758
4842
  isFilterHideMode = false,
4759
4843
  resolvedColumns,
4844
+ isTaskSelected = false,
4845
+ onTaskSelectionChange,
4760
4846
  taskListMenuCommands = []
4761
4847
  }) => {
4762
4848
  const [editingColumnId, setEditingColumnId] = (0, import_react10.useState)(null);
@@ -5550,6 +5636,23 @@ var TaskListRow = import_react10.default.memo(
5550
5636
  const isSelectedDependencyOwner = selectedChip != null && selectedChip.successorId === task.id;
5551
5637
  const startDateISO = toISODate2(normalizedTask.startDate);
5552
5638
  const endDateISO = editingDuration ? getEndDate(normalizedTask.startDate, durationValue) : toISODate2(normalizedTask.endDate);
5639
+ const selectionCell = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
5640
+ "div",
5641
+ {
5642
+ className: "gantt-tl-cell gantt-tl-cell-selection",
5643
+ onClick: (e) => e.stopPropagation(),
5644
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
5645
+ "input",
5646
+ {
5647
+ type: "checkbox",
5648
+ className: "gantt-tl-selection-checkbox",
5649
+ "aria-label": `\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0437\u0430\u0434\u0430\u0447\u0443 ${taskNumber ? `${taskNumber}. ` : ""}${task.name}`,
5650
+ checked: isTaskSelected,
5651
+ onChange: (event) => onTaskSelectionChange?.(task.id, event.target.checked)
5652
+ }
5653
+ )
5654
+ }
5655
+ );
5553
5656
  const numberCell = /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
5554
5657
  "div",
5555
5658
  {
@@ -6267,6 +6370,7 @@ var TaskListRow = import_react10.default.memo(
6267
6370
  }
6268
6371
  );
6269
6372
  const builtInCells = {
6373
+ selection: selectionCell,
6270
6374
  number: numberCell,
6271
6375
  name: nameCell,
6272
6376
  startDate: startDateCell,
@@ -6419,6 +6523,7 @@ var NewTaskRow = ({
6419
6523
 
6420
6524
  // src/components/TaskList/columns/createBuiltInColumns.tsx
6421
6525
  var BUILT_IN_COLUMN_WIDTHS = {
6526
+ selection: 36,
6422
6527
  number: 40,
6423
6528
  name: 200,
6424
6529
  startDate: 90,
@@ -6429,7 +6534,7 @@ var BUILT_IN_COLUMN_WIDTHS = {
6429
6534
  actions: 80
6430
6535
  };
6431
6536
  function createBuiltInColumns(opts) {
6432
- return [
6537
+ const columns = [
6433
6538
  { id: "number", header: "\u2116", width: BUILT_IN_COLUMN_WIDTHS.number, renderCell: () => null },
6434
6539
  { id: "name", header: "\u0418\u043C\u044F", width: BUILT_IN_COLUMN_WIDTHS.name, renderCell: () => null },
6435
6540
  { id: "startDate", header: "\u041D\u0430\u0447\u0430\u043B\u043E", width: BUILT_IN_COLUMN_WIDTHS.startDate, renderCell: () => null },
@@ -6438,6 +6543,15 @@ function createBuiltInColumns(opts) {
6438
6543
  { id: "progress", header: "%", width: BUILT_IN_COLUMN_WIDTHS.progress, renderCell: () => null },
6439
6544
  { id: "dependencies", header: null, width: BUILT_IN_COLUMN_WIDTHS.dependencies, renderCell: () => null }
6440
6545
  ];
6546
+ if (opts?.enableTaskMultiSelect) {
6547
+ columns.unshift({
6548
+ id: "selection",
6549
+ header: null,
6550
+ width: BUILT_IN_COLUMN_WIDTHS.selection,
6551
+ renderCell: () => null
6552
+ });
6553
+ }
6554
+ return columns;
6441
6555
  }
6442
6556
 
6443
6557
  // src/components/TaskList/columns/resolveTaskListColumns.ts
@@ -6498,6 +6612,7 @@ var import_jsx_runtime14 = require("react/jsx-runtime");
6498
6612
  var LINK_TYPE_ORDER2 = ["FS", "SS", "FF", "SF"];
6499
6613
  var MIN_TASK_LIST_WIDTH = 530;
6500
6614
  var BUILT_IN_CSS_CLASSES = {
6615
+ selection: "gantt-tl-cell-selection",
6501
6616
  number: "gantt-tl-cell-number",
6502
6617
  name: "gantt-tl-cell-name",
6503
6618
  startDate: "gantt-tl-cell-date",
@@ -6573,6 +6688,30 @@ function getTaskNumber(tasks, taskIndex) {
6573
6688
  }
6574
6689
  return `${parentNumber}.${siblingIndex + 1}`;
6575
6690
  }
6691
+ var SelectAllCheckbox = ({
6692
+ checked,
6693
+ indeterminate,
6694
+ onChange
6695
+ }) => {
6696
+ const ref = (0, import_react12.useRef)(null);
6697
+ (0, import_react12.useEffect)(() => {
6698
+ if (ref.current) {
6699
+ ref.current.indeterminate = indeterminate;
6700
+ }
6701
+ }, [indeterminate]);
6702
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
6703
+ "input",
6704
+ {
6705
+ ref,
6706
+ type: "checkbox",
6707
+ className: "gantt-tl-selection-checkbox",
6708
+ "aria-label": "\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0432\u0441\u0435 \u0432\u0438\u0434\u0438\u043C\u044B\u0435 \u0437\u0430\u0434\u0430\u0447\u0438",
6709
+ checked,
6710
+ onChange: (event) => onChange(event.target.checked),
6711
+ onClick: (event) => event.stopPropagation()
6712
+ }
6713
+ );
6714
+ };
6576
6715
  var TaskList = ({
6577
6716
  tasks,
6578
6717
  rowHeight,
@@ -6603,6 +6742,9 @@ var TaskList = ({
6603
6742
  isWeekend: isWeekend3,
6604
6743
  businessDays,
6605
6744
  highlightedTaskIds = /* @__PURE__ */ new Set(),
6745
+ enableTaskMultiSelect = false,
6746
+ selectedTaskIds,
6747
+ onSelectedTaskIdsChange,
6606
6748
  filterMode = "highlight",
6607
6749
  filteredTaskIds = /* @__PURE__ */ new Set(),
6608
6750
  isFilterActive = false,
@@ -6610,6 +6752,14 @@ var TaskList = ({
6610
6752
  hiddenTaskListColumns,
6611
6753
  taskListMenuCommands
6612
6754
  }) => {
6755
+ const [internalSelectedTaskIds, setInternalSelectedTaskIds] = (0, import_react12.useState)(/* @__PURE__ */ new Set());
6756
+ const effectiveSelectedTaskIds = selectedTaskIds ?? internalSelectedTaskIds;
6757
+ const emitSelectedTaskIdsChange = (0, import_react12.useCallback)((nextSelectedTaskIds) => {
6758
+ if (!selectedTaskIds) {
6759
+ setInternalSelectedTaskIds(nextSelectedTaskIds);
6760
+ }
6761
+ onSelectedTaskIdsChange?.(nextSelectedTaskIds);
6762
+ }, [onSelectedTaskIdsChange, selectedTaskIds]);
6613
6763
  const [internalCollapsedParentIds, setInternalCollapsedParentIds] = (0, import_react12.useState)(/* @__PURE__ */ new Set());
6614
6764
  const collapsedParentIds = externalCollapsedParentIds ?? internalCollapsedParentIds;
6615
6765
  const handleToggleCollapse = externalOnToggleCollapse ?? (0, import_react12.useCallback)((parentId) => {
@@ -6656,6 +6806,33 @@ var TaskList = ({
6656
6806
  ),
6657
6807
  [visibleTasks]
6658
6808
  );
6809
+ const visibleTaskIds = (0, import_react12.useMemo)(() => visibleTasks.map((task) => task.id), [visibleTasks]);
6810
+ const selectedVisibleTaskCount = (0, import_react12.useMemo)(
6811
+ () => visibleTaskIds.filter((taskId) => effectiveSelectedTaskIds.has(taskId)).length,
6812
+ [effectiveSelectedTaskIds, visibleTaskIds]
6813
+ );
6814
+ const areAllVisibleTasksSelected = visibleTaskIds.length > 0 && selectedVisibleTaskCount === visibleTaskIds.length;
6815
+ const areSomeVisibleTasksSelected = selectedVisibleTaskCount > 0 && !areAllVisibleTasksSelected;
6816
+ const handleToggleTaskSelection = (0, import_react12.useCallback)((taskId, checked) => {
6817
+ const nextSelectedTaskIds = new Set(effectiveSelectedTaskIds);
6818
+ if (checked) {
6819
+ nextSelectedTaskIds.add(taskId);
6820
+ } else {
6821
+ nextSelectedTaskIds.delete(taskId);
6822
+ }
6823
+ emitSelectedTaskIdsChange(nextSelectedTaskIds);
6824
+ }, [effectiveSelectedTaskIds, emitSelectedTaskIdsChange]);
6825
+ const handleToggleAllVisibleTaskSelection = (0, import_react12.useCallback)((checked) => {
6826
+ const nextSelectedTaskIds = new Set(effectiveSelectedTaskIds);
6827
+ for (const taskId of visibleTaskIds) {
6828
+ if (checked) {
6829
+ nextSelectedTaskIds.add(taskId);
6830
+ } else {
6831
+ nextSelectedTaskIds.delete(taskId);
6832
+ }
6833
+ }
6834
+ emitSelectedTaskIdsChange(nextSelectedTaskIds);
6835
+ }, [effectiveSelectedTaskIds, emitSelectedTaskIdsChange, visibleTaskIds]);
6659
6836
  const originalTaskNumberMap = (0, import_react12.useMemo)(
6660
6837
  () => {
6661
6838
  const numberMap = /* @__PURE__ */ new Map();
@@ -7137,7 +7314,10 @@ var TaskList = ({
7137
7314
  const duplicatedTasks = duplicateTaskSubtree(taskId, orderedTasks);
7138
7315
  onReorder?.(duplicatedTasks);
7139
7316
  }, [orderedTasks, onReorder]);
7140
- const builtInColumns = (0, import_react12.useMemo)(() => createBuiltInColumns({ businessDays }), [businessDays]);
7317
+ const builtInColumns = (0, import_react12.useMemo)(
7318
+ () => createBuiltInColumns({ businessDays, enableTaskMultiSelect }),
7319
+ [businessDays, enableTaskMultiSelect]
7320
+ );
7141
7321
  const resolvedColumns = (0, import_react12.useMemo)(
7142
7322
  () => resolveTaskListColumns(
7143
7323
  builtInColumns,
@@ -7161,6 +7341,24 @@ var TaskList = ({
7161
7341
  style: { "--tasklist-width": `${effectiveTaskListWidth}px` },
7162
7342
  children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "gantt-tl-table", children: [
7163
7343
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "gantt-tl-header", style: { height: `${tableHeaderHeight}px` }, children: resolvedColumns.map((col) => {
7344
+ if (col.id === "selection") {
7345
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
7346
+ "div",
7347
+ {
7348
+ className: "gantt-tl-headerCell gantt-tl-cell-selection",
7349
+ "data-column-id": "selection",
7350
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
7351
+ SelectAllCheckbox,
7352
+ {
7353
+ checked: areAllVisibleTasksSelected,
7354
+ indeterminate: areSomeVisibleTasksSelected,
7355
+ onChange: handleToggleAllVisibleTaskSelection
7356
+ }
7357
+ )
7358
+ },
7359
+ col.id
7360
+ );
7361
+ }
7164
7362
  if (col.id === "dependencies") {
7165
7363
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
7166
7364
  "div",
@@ -7286,6 +7484,8 @@ var TaskList = ({
7286
7484
  isFilterMatch: filterMode === "highlight" ? highlightedTaskIds.has(task.id) : false,
7287
7485
  isFilterHideMode: filterMode === "hide" && isFilterActive,
7288
7486
  resolvedColumns,
7487
+ isTaskSelected: effectiveSelectedTaskIds.has(task.id),
7488
+ onTaskSelectionChange: handleToggleTaskSelection,
7289
7489
  taskListMenuCommands
7290
7490
  }
7291
7491
  ),
@@ -9366,6 +9566,9 @@ function TaskGanttChartInner(props, ref) {
9366
9566
  collapsedParentIds: externalCollapsedParentIds,
9367
9567
  onToggleCollapse: externalOnToggleCollapse,
9368
9568
  highlightedTaskIds,
9569
+ enableTaskMultiSelect = false,
9570
+ selectedTaskIds,
9571
+ onSelectedTaskIdsChange,
9369
9572
  disableTaskDrag = false,
9370
9573
  showChart = true,
9371
9574
  additionalColumns,
@@ -9936,6 +10139,9 @@ function TaskGanttChartInner(props, ref) {
9936
10139
  onDemoteTask: onDemoteTask ?? handleDemoteTask,
9937
10140
  onUngroupTask: onUngroupTask ?? handleUngroupTask,
9938
10141
  highlightedTaskIds: taskListHighlightedTaskIds,
10142
+ enableTaskMultiSelect,
10143
+ selectedTaskIds,
10144
+ onSelectedTaskIdsChange,
9939
10145
  customDays,
9940
10146
  isWeekend: isWeekend3,
9941
10147
  businessDays,
@@ -10046,7 +10252,8 @@ function TaskGanttChartInner(props, ref) {
10046
10252
  businessDays,
10047
10253
  customDays,
10048
10254
  isWeekend: isWeekend3,
10049
- disableTaskDrag
10255
+ disableTaskDrag,
10256
+ viewMode
10050
10257
  },
10051
10258
  task.id
10052
10259
  ))