gantt-lib 0.122.0 → 0.124.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.mjs CHANGED
@@ -550,6 +550,159 @@ function calculateSuccessorDate(predecessorStart, predecessorEnd, linkType, lag
550
550
  return shiftBusinessDayOffset(anchorDate, offset, weekendPredicate);
551
551
  }
552
552
 
553
+ // src/core/scheduling/criticalPath.ts
554
+ function computeCriticalPath(tasks, options = {}) {
555
+ const { businessDays = false, weekendPredicate } = options;
556
+ const taskById = new Map(tasks.map((task) => [task.id, task]));
557
+ const childIds = /* @__PURE__ */ new Set();
558
+ for (const task of tasks) {
559
+ if (task.parentId) childIds.add(task.parentId);
560
+ }
561
+ const leafTasks = tasks.filter((task) => !childIds.has(task.id));
562
+ const leafIds = new Set(leafTasks.map((task) => task.id));
563
+ const leafIdsByAncestor = /* @__PURE__ */ new Map();
564
+ for (const leaf of leafTasks) {
565
+ let ancestor = leaf.parentId;
566
+ while (ancestor) {
567
+ const set = leafIdsByAncestor.get(ancestor) ?? /* @__PURE__ */ new Set();
568
+ set.add(leaf.id);
569
+ leafIdsByAncestor.set(ancestor, set);
570
+ ancestor = taskById.get(ancestor)?.parentId;
571
+ }
572
+ }
573
+ const durationOf = (task) => getTaskDuration(task.startDate, task.endDate, businessDays, weekendPredicate);
574
+ const projectStartDate = leafTasks.reduce((earliest, task) => {
575
+ const taskStart = parseDateOnly(task.startDate);
576
+ return taskStart.getTime() < earliest.getTime() ? taskStart : earliest;
577
+ }, parseDateOnly(leafTasks[0]?.startDate ?? /* @__PURE__ */ new Date()));
578
+ const offsetFromProjectStart = (date) => {
579
+ const targetDate = parseDateOnly(date);
580
+ if (businessDays && weekendPredicate) {
581
+ return getBusinessDayOffset(projectStartDate, targetDate, weekendPredicate);
582
+ }
583
+ return Math.round((targetDate.getTime() - projectStartDate.getTime()) / DAY_MS);
584
+ };
585
+ const scheduledStart = /* @__PURE__ */ new Map();
586
+ for (const leaf of leafTasks) {
587
+ scheduledStart.set(leaf.id, offsetFromProjectStart(leaf.startDate));
588
+ }
589
+ const succByPred = /* @__PURE__ */ new Map();
590
+ const predBySucc = /* @__PURE__ */ new Map();
591
+ const seenEdges = /* @__PURE__ */ new Set();
592
+ const addEdge = (predecessorId, succId, lag, type) => {
593
+ const edgeKey = `${predecessorId}|${succId}|${type}`;
594
+ if (seenEdges.has(edgeKey)) return;
595
+ seenEdges.add(edgeKey);
596
+ const outEdges = succByPred.get(predecessorId) ?? [];
597
+ outEdges.push({ succId, lag, type });
598
+ succByPred.set(predecessorId, outEdges);
599
+ const inEdges = predBySucc.get(succId) ?? [];
600
+ inEdges.push({ predId: predecessorId, lag, type });
601
+ predBySucc.set(succId, inEdges);
602
+ };
603
+ for (const succ of leafTasks) {
604
+ for (const dep of succ.dependencies ?? []) {
605
+ const lag = getDependencyLag(dep);
606
+ if (leafIds.has(dep.taskId)) {
607
+ addEdge(dep.taskId, succ.id, lag, dep.type);
608
+ continue;
609
+ }
610
+ const descendants = leafIdsByAncestor.get(dep.taskId);
611
+ if (!descendants || descendants.size === 0) continue;
612
+ for (const leafId of descendants) {
613
+ if (leafId === succ.id) continue;
614
+ addEdge(leafId, succ.id, lag, dep.type);
615
+ }
616
+ }
617
+ }
618
+ const indegree = /* @__PURE__ */ new Map();
619
+ for (const leaf of leafTasks) indegree.set(leaf.id, 0);
620
+ for (const edges of succByPred.values()) {
621
+ for (const { succId } of edges) {
622
+ indegree.set(succId, (indegree.get(succId) ?? 0) + 1);
623
+ }
624
+ }
625
+ const order = [];
626
+ const enqueued = /* @__PURE__ */ new Set();
627
+ const queue = leafTasks.filter((leaf) => (indegree.get(leaf.id) ?? 0) === 0).map((leaf) => leaf.id);
628
+ for (const id of queue) enqueued.add(id);
629
+ while (queue.length > 0) {
630
+ const current = queue.shift();
631
+ order.push(current);
632
+ for (const { succId } of succByPred.get(current) ?? []) {
633
+ const next = (indegree.get(succId) ?? 0) - 1;
634
+ indegree.set(succId, next);
635
+ if (next === 0 && !enqueued.has(succId)) {
636
+ enqueued.add(succId);
637
+ queue.push(succId);
638
+ }
639
+ }
640
+ }
641
+ const projectFinish = Math.max(
642
+ 0,
643
+ ...leafTasks.map((leaf) => (scheduledStart.get(leaf.id) ?? 0) + durationOf(leaf))
644
+ );
645
+ const LF = /* @__PURE__ */ new Map();
646
+ const LS = /* @__PURE__ */ new Map();
647
+ for (const leaf of leafTasks) LF.set(leaf.id, projectFinish);
648
+ for (let i = order.length - 1; i >= 0; i--) {
649
+ const id = order[i];
650
+ const task = taskById.get(id);
651
+ const durPred = durationOf(task);
652
+ const outEdges = succByPred.get(id) ?? [];
653
+ let lf = projectFinish;
654
+ if (outEdges.length > 0) {
655
+ const candidates = outEdges.map(({ succId, lag, type }) => {
656
+ const succLs = LS.get(succId) ?? projectFinish;
657
+ const durSucc = durationOf(taskById.get(succId));
658
+ switch (type) {
659
+ case "FS":
660
+ return succLs - lag;
661
+ case "SS":
662
+ return succLs - lag + durPred;
663
+ case "FF":
664
+ return succLs + durSucc - lag;
665
+ case "SF":
666
+ return succLs + durSucc - lag + durPred;
667
+ default:
668
+ return projectFinish;
669
+ }
670
+ });
671
+ lf = Math.min(projectFinish, ...candidates);
672
+ }
673
+ LF.set(id, lf);
674
+ LS.set(id, lf - durPred);
675
+ }
676
+ const critical = /* @__PURE__ */ new Set();
677
+ const ordered = new Set(order);
678
+ for (const leaf of leafTasks) {
679
+ if (!ordered.has(leaf.id)) continue;
680
+ const hasGraphEdge = (succByPred.get(leaf.id)?.length ?? 0) > 0 || (predBySucc.get(leaf.id)?.length ?? 0) > 0;
681
+ if (!hasGraphEdge && (leaf.dependencies?.length ?? 0) > 0) continue;
682
+ const es = scheduledStart.get(leaf.id) ?? 0;
683
+ const ls = LS.get(leaf.id) ?? 0;
684
+ if (ls - es <= 0) critical.add(leaf.id);
685
+ }
686
+ return critical;
687
+ }
688
+ function extendCriticalIdsToParents(criticalLeafIds, tasks) {
689
+ const result = new Set(criticalLeafIds);
690
+ const parentByChild = /* @__PURE__ */ new Map();
691
+ for (const task of tasks) {
692
+ if (task.parentId) parentByChild.set(task.id, task.parentId);
693
+ }
694
+ const stack = Array.from(criticalLeafIds);
695
+ while (stack.length > 0) {
696
+ const id = stack.pop();
697
+ const parentId = parentByChild.get(id);
698
+ if (parentId && !result.has(parentId)) {
699
+ result.add(parentId);
700
+ stack.push(parentId);
701
+ }
702
+ }
703
+ return result;
704
+ }
705
+
553
706
  // src/core/scheduling/commands.ts
554
707
  function buildTaskRangeFromStart(startDate, duration, businessDays = false, weekendPredicate, snapDirection = 1) {
555
708
  const normalizedStart = businessDays && weekendPredicate ? alignToWorkingDay(startDate, snapDirection, weekendPredicate) : normalizeUTCDate(startDate);
@@ -2412,8 +2565,7 @@ function handleGlobalMouseMove(e) {
2412
2565
  activeDrag.weekendPredicate,
2413
2566
  activeDrag.cascadeContext
2414
2567
  );
2415
- const hasTasksWithIncomingDependencies = cascadeResult.some((task) => task.dependencies?.length);
2416
- const previewTasks = hasTasksWithIncomingDependencies ? (() => {
2568
+ const previewTasks = (() => {
2417
2569
  const mergedPreviewTaskById = new Map(activeDrag.cascadeContext?.taskById);
2418
2570
  for (const task of cascadeResult) {
2419
2571
  mergedPreviewTaskById.set(task.id, task);
@@ -2434,7 +2586,7 @@ function handleGlobalMouseMove(e) {
2434
2586
  ) : task.dependencies
2435
2587
  };
2436
2588
  });
2437
- })() : [];
2589
+ })();
2438
2590
  const overrides = /* @__PURE__ */ new Map();
2439
2591
  overrides.set(dragId, { left: newLeft, width: newWidth });
2440
2592
  for (const task of cascadeResult) {
@@ -2837,10 +2989,10 @@ var useTaskDrag = (options) => {
2837
2989
  // src/components/TaskRow/TaskRow.tsx
2838
2990
  import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
2839
2991
  var arePropsEqual = (prevProps, nextProps) => {
2840
- 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.previewPositionStore === nextProps.previewPositionStore && prevProps.allTasks === nextProps.allTasks && prevProps.disableConstraints === nextProps.disableConstraints && prevProps.task.locked === nextProps.task.locked && prevProps.task.synced === nextProps.task.synced && 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.disableDependencyEditing === nextProps.disableDependencyEditing && prevProps.isDependencyDragActive === nextProps.isDependencyDragActive && prevProps.viewMode === nextProps.viewMode;
2992
+ 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.previewPositionStore === nextProps.previewPositionStore && prevProps.allTasks === nextProps.allTasks && prevProps.disableConstraints === nextProps.disableConstraints && prevProps.task.locked === nextProps.task.locked && prevProps.task.synced === nextProps.task.synced && prevProps.task.divider === nextProps.task.divider && prevProps.highlightExpiredTasks === nextProps.highlightExpiredTasks && prevProps.isCritical === nextProps.isCritical && 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.disableDependencyEditing === nextProps.disableDependencyEditing && prevProps.isDependencyDragActive === nextProps.isDependencyDragActive && prevProps.viewMode === nextProps.viewMode;
2841
2993
  };
2842
2994
  var TaskRow = React2.memo(
2843
- ({ task, monthStart, dayWidth, rowHeight, onTasksChange, onDragStateChange, rowIndex, allTasks, enableAutoSchedule, disableConstraints, overridePosition, previewPositionStore, onCascadeProgress, onCascade, divider, highlightExpiredTasks, showBaseline = false, isFilterMatch = false, businessDays, customDays, isWeekend: isWeekend3, disableTaskDrag = false, disableDependencyEditing = false, onDependencyPortPointerDown, isDependencyDragActive = false, viewMode = "day" }) => {
2995
+ ({ task, monthStart, dayWidth, rowHeight, onTasksChange, onDragStateChange, rowIndex, allTasks, enableAutoSchedule, disableConstraints, overridePosition, previewPositionStore, onCascadeProgress, onCascade, divider, highlightExpiredTasks, isCritical = false, showBaseline = false, isFilterMatch = false, businessDays, customDays, isWeekend: isWeekend3, disableTaskDrag = false, disableDependencyEditing = false, onDependencyPortPointerDown, isDependencyDragActive = false, viewMode = "day" }) => {
2844
2996
  const defaultParentBarColor = "#782FC4";
2845
2997
  const { divider: taskDivider } = task;
2846
2998
  const normalizedTask = useMemo2(() => normalizeTaskDatesForType(task), [task]);
@@ -3030,7 +3182,7 @@ var TaskRow = React2.memo(
3030
3182
  "div",
3031
3183
  {
3032
3184
  "data-taskbar": true,
3033
- className: `gantt-tr-taskBar ${isDragging ? "gantt-tr-dragging" : ""} ${task.locked ? "gantt-tr-locked" : ""} ${task.synced === false ? "gantt-tr-unsynced" : ""} ${isParent ? "gantt-tr-parentBar" : ""} ${milestone ? "gantt-tr-milestone" : ""}`,
3185
+ className: `gantt-tr-taskBar ${isDragging ? "gantt-tr-dragging" : ""} ${task.locked ? "gantt-tr-locked" : ""} ${task.synced === false ? "gantt-tr-unsynced" : ""} ${isParent ? "gantt-tr-parentBar" : ""} ${milestone ? "gantt-tr-milestone" : ""} ${isCritical ? "gantt-tr-critical" : ""}`,
3034
3186
  style: {
3035
3187
  left: `${visualLeft}px`,
3036
3188
  ...barStyle,
@@ -3445,6 +3597,7 @@ var DependencyLines = React6.memo(({
3445
3597
  rowIndexByTaskId,
3446
3598
  dragOverrides,
3447
3599
  selectedDep,
3600
+ criticalTaskIds,
3448
3601
  businessDays = true,
3449
3602
  weekendPredicate,
3450
3603
  onDependencyClick
@@ -3583,6 +3736,9 @@ var DependencyLines = React6.memo(({
3583
3736
  const to = { x: finalToX, y: toY };
3584
3737
  const path = calculateDependencyPath(from, to, arrivesFromRight);
3585
3738
  const hasCycle = cycleInfo.has(edge.predecessorId) || cycleInfo.has(edge.successorId);
3739
+ const isCritical = Boolean(
3740
+ criticalTaskIds?.has(edge.predecessorId) && criticalTaskIds.has(edge.successorId)
3741
+ );
3586
3742
  lines2.push({
3587
3743
  id: `${edge.predecessorId}-${edge.successorId}-${edge.type}`,
3588
3744
  predecessorId: edge.predecessorId,
@@ -3595,12 +3751,13 @@ var DependencyLines = React6.memo(({
3595
3751
  toX: finalToX,
3596
3752
  fromY,
3597
3753
  reverseOrder,
3598
- isVirtual
3754
+ isVirtual,
3755
+ isCritical
3599
3756
  });
3600
3757
  }
3601
3758
  }
3602
3759
  return lines2;
3603
- }, [tasks, allTasks, taskPositions, taskIndices, cycleInfo, collapsedParentIds]);
3760
+ }, [tasks, allTasks, taskPositions, taskIndices, cycleInfo, collapsedParentIds, criticalTaskIds]);
3604
3761
  const svgHeight = totalHeight ?? tasks.length * rowHeight;
3605
3762
  return /* @__PURE__ */ jsxs5(
3606
3763
  "svg",
@@ -3687,20 +3844,41 @@ var DependencyLines = React6.memo(({
3687
3844
  }
3688
3845
  )
3689
3846
  }
3847
+ ),
3848
+ /* @__PURE__ */ jsx7(
3849
+ "marker",
3850
+ {
3851
+ id: "arrowhead-critical",
3852
+ markerWidth: "8",
3853
+ markerHeight: "6",
3854
+ markerUnits: "userSpaceOnUse",
3855
+ refX: "7",
3856
+ refY: "3",
3857
+ orient: "auto",
3858
+ children: /* @__PURE__ */ jsx7(
3859
+ "polygon",
3860
+ {
3861
+ points: "0 0, 8 3, 0 6",
3862
+ fill: "var(--gantt-critical-path-color, #dc2626)"
3863
+ }
3864
+ )
3865
+ }
3690
3866
  )
3691
3867
  ] }),
3692
- lines.map(({ id, predecessorId, successorId, linkType, path, hasCycle, lag, fromX, toX, fromY, reverseOrder, isVirtual }) => {
3868
+ lines.map(({ id, predecessorId, successorId, linkType, path, hasCycle, lag, fromX, toX, fromY, reverseOrder, isVirtual, isCritical }) => {
3693
3869
  const isHovered = hoveredLineId === id;
3694
3870
  const isSelected = selectedDep != null && id === `${selectedDep.predecessorId}-${selectedDep.successorId}-${selectedDep.linkType}`;
3695
3871
  let pathClassName = "gantt-dependency-path";
3696
3872
  if (isSelected) pathClassName += " gantt-dependency-selected";
3697
3873
  else if (hasCycle) pathClassName += " gantt-dependency-cycle";
3874
+ else if (isCritical) pathClassName += " gantt-dependency-critical";
3698
3875
  if (isVirtual && !isSelected) pathClassName += " gantt-dependency-virtual";
3699
3876
  let markerEnd;
3700
3877
  if (isSelected) markerEnd = "url(#arrowhead-selected)";
3701
3878
  else if (hasCycle) markerEnd = "url(#arrowhead-cycle)";
3879
+ else if (isCritical) markerEnd = "url(#arrowhead-critical)";
3702
3880
  else markerEnd = "url(#arrowhead)";
3703
- const lagColor = isSelected ? "#ef4444" : hasCycle ? "var(--gantt-dependency-cycle-color, #ef4444)" : "var(--gantt-dependency-line-color, #666666)";
3881
+ const lagColor = isSelected ? "#ef4444" : hasCycle ? "var(--gantt-dependency-cycle-color, #ef4444)" : isCritical ? "var(--gantt-critical-path-color, #dc2626)" : "var(--gantt-dependency-line-color, #666666)";
3704
3882
  return /* @__PURE__ */ jsxs5(React6.Fragment, { children: [
3705
3883
  /* @__PURE__ */ jsxs5(
3706
3884
  "g",
@@ -7386,6 +7564,7 @@ var TaskList = ({
7386
7564
  disableTaskListReorder = false,
7387
7565
  editingTaskId: propEditingTaskId,
7388
7566
  enableAddTask = true,
7567
+ addTaskLabel = "\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0440\u0430\u0431\u043E\u0442\u0443",
7389
7568
  defaultTaskDurationDays = DEFAULT_TASK_DURATION_DAYS,
7390
7569
  collapsedParentIds: externalCollapsedParentIds,
7391
7570
  onToggleCollapse: externalOnToggleCollapse,
@@ -8479,7 +8658,7 @@ var TaskList = ({
8479
8658
  nestingDepth: 0
8480
8659
  }
8481
8660
  ),
8482
- enableAddTask && onAdd && !isCreating && !pendingInsert && /* @__PURE__ */ jsx16(
8661
+ enableAddTask && onAdd && !isCreating && !pendingInsert && /* @__PURE__ */ jsxs12(
8483
8662
  "button",
8484
8663
  {
8485
8664
  className: `gantt-tl-add-btn${!reorderDisabled && dragOverTarget?.index === visibleTasks.length ? " gantt-tl-add-btn-drag-over" : ""}`,
@@ -8505,7 +8684,10 @@ var TaskList = ({
8505
8684
  handleDrop(visibleTasks.length, e);
8506
8685
  },
8507
8686
  type: "button",
8508
- children: "+ \u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0440\u0430\u0431\u043E\u0442\u0443"
8687
+ children: [
8688
+ "+ ",
8689
+ addTaskLabel
8690
+ ]
8509
8691
  }
8510
8692
  )
8511
8693
  ] })
@@ -12401,6 +12583,7 @@ function TaskGanttChartInner(props, ref) {
12401
12583
  onDemoteTask,
12402
12584
  onUngroupTask,
12403
12585
  enableAddTask = true,
12586
+ addTaskLabel = "\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0440\u0430\u0431\u043E\u0442\u0443",
12404
12587
  defaultTaskDurationDays,
12405
12588
  taskFilter,
12406
12589
  filterMode = "highlight",
@@ -12427,6 +12610,7 @@ function TaskGanttChartInner(props, ref) {
12427
12610
  onTaskDateChangeModeChange: externalOnTaskDateChangeModeChange
12428
12611
  } = props;
12429
12612
  const dayWidth = !isTableMatrixMode ? props.dayWidth ?? 40 : 40;
12613
+ const criticalPathMode = !isTableMatrixMode && !isPlanFactMode ? props.criticalPathMode : void 0;
12430
12614
  const viewMode = !isTableMatrixMode && !isPlanFactMode ? props.viewMode ?? "day" : "day";
12431
12615
  const customDays = !isTableMatrixMode ? props.customDays : void 0;
12432
12616
  const isWeekend3 = !isTableMatrixMode ? props.isWeekend : void 0;
@@ -12626,10 +12810,23 @@ function TaskGanttChartInner(props, ref) {
12626
12810
  [resolvedRowContentLines, rowHeight]
12627
12811
  );
12628
12812
  const normalizedTasks = useMemo13(() => normalizeHierarchyTasks(tasks), [tasks]);
12813
+ const [previewTasksById, setPreviewTasksById] = useState12(/* @__PURE__ */ new Map());
12814
+ const previewNormalizedTasks = useMemo13(() => {
12815
+ if (previewTasksById.size === 0) return normalizedTasks;
12816
+ return normalizedTasks.map((task) => previewTasksById.get(task.id) ?? task);
12817
+ }, [normalizedTasks, previewTasksById]);
12629
12818
  const isCustomWeekend = useMemo13(
12630
12819
  () => createCustomDayPredicate({ customDays, isWeekend: isWeekend3 }),
12631
12820
  [customDays, isWeekend3]
12632
12821
  );
12822
+ const criticalTaskIds = useMemo13(() => {
12823
+ if (!criticalPathMode) return /* @__PURE__ */ new Set();
12824
+ const leafCritical = computeCriticalPath(previewNormalizedTasks, {
12825
+ businessDays,
12826
+ weekendPredicate: isCustomWeekend
12827
+ });
12828
+ return extendCriticalIdsToParents(leafCritical, previewNormalizedTasks);
12829
+ }, [criticalPathMode, previewNormalizedTasks, businessDays, isCustomWeekend]);
12633
12830
  const dateRangeTasks = useMemo13(() => {
12634
12831
  if (isPlanFactMode) {
12635
12832
  return getPlanFactRangeTasks(normalizedTasks);
@@ -12674,8 +12871,11 @@ function TaskGanttChartInner(props, ref) {
12674
12871
  if (filterMode === "hide" && taskFilter) {
12675
12872
  tasks2 = tasks2.filter(taskFilter);
12676
12873
  }
12874
+ if (criticalPathMode === "hide") {
12875
+ tasks2 = tasks2.filter((task) => criticalTaskIds.has(task.id));
12876
+ }
12677
12877
  return tasks2;
12678
- }, [normalizedTasks, collapsedParentIds, filterMode, taskFilter]);
12878
+ }, [normalizedTasks, collapsedParentIds, filterMode, taskFilter, criticalPathMode, criticalTaskIds]);
12679
12879
  const matchedTaskIds = useMemo13(() => {
12680
12880
  if (!taskFilter) return /* @__PURE__ */ new Set();
12681
12881
  return new Set(visibleTasks.filter(taskFilter).map((task) => task.id));
@@ -12868,7 +13068,6 @@ function TaskGanttChartInner(props, ref) {
12868
13068
  }, [effectiveRowHeight, tasks, visibleTasks]);
12869
13069
  const [dragGuideLines, setDragGuideLines] = useState12(null);
12870
13070
  const [draggedTaskOverride, setDraggedTaskOverride] = useState12(null);
12871
- const [previewTasksById, setPreviewTasksById] = useState12(/* @__PURE__ */ new Map());
12872
13071
  useEffect10(() => {
12873
13072
  const result = validateDependencies(tasks);
12874
13073
  setValidationResult(result);
@@ -12996,14 +13195,10 @@ function TaskGanttChartInner(props, ref) {
12996
13195
  }
12997
13196
  setCascadeOverrides((current) => arePositionMapsEqual(current, renderedOverrides) ? current : renderedOverrides);
12998
13197
  setPreviewTasksById((current) => {
12999
- const next = previewTasks.length > 0 ? new Map(previewTasks.filter((task) => renderedTaskIds.has(task.id)).map((task) => [task.id, task])) : /* @__PURE__ */ new Map();
13198
+ const next = previewTasks.length > 0 ? new Map(previewTasks.map((task) => [task.id, task])) : /* @__PURE__ */ new Map();
13000
13199
  return arePreviewTaskMapsEqual(current, next) ? current : next;
13001
13200
  });
13002
13201
  }, [previewPositionStore]);
13003
- const previewNormalizedTasks = useMemo13(() => {
13004
- if (previewTasksById.size === 0) return normalizedTasks;
13005
- return normalizedTasks.map((task) => previewTasksById.get(task.id) ?? task);
13006
- }, [normalizedTasks, previewTasksById]);
13007
13202
  const previewVisibleTasks = useMemo13(() => {
13008
13203
  if (previewTasksById.size === 0) return visibleTasks;
13009
13204
  return visibleTasks.map((task) => previewTasksById.get(task.id) ?? task);
@@ -13431,6 +13626,7 @@ function TaskGanttChartInner(props, ref) {
13431
13626
  disableTaskDrag: disableTaskDrag || disableTaskListReorder,
13432
13627
  editingTaskId,
13433
13628
  enableAddTask,
13629
+ addTaskLabel,
13434
13630
  defaultTaskDurationDays,
13435
13631
  collapsedParentIds,
13436
13632
  onToggleCollapse: handleToggleCollapse,
@@ -13602,7 +13798,8 @@ function TaskGanttChartInner(props, ref) {
13602
13798
  selectedDep: selectedChip,
13603
13799
  businessDays,
13604
13800
  weekendPredicate: isCustomWeekend,
13605
- onDependencyClick: handleDependencyLineClick
13801
+ onDependencyClick: handleDependencyLineClick,
13802
+ criticalTaskIds: criticalPathMode ? criticalTaskIds : void 0
13606
13803
  }
13607
13804
  ),
13608
13805
  dependencyLineMenu && /* @__PURE__ */ jsxs16(
@@ -13672,6 +13869,9 @@ function TaskGanttChartInner(props, ref) {
13672
13869
  } else {
13673
13870
  setDragGuideLines((current) => current === null ? current : null);
13674
13871
  setDraggedTaskOverride((current) => current === null ? current : null);
13872
+ previewPositionStore.clear();
13873
+ setCascadeOverrides((current) => current.size === 0 ? current : /* @__PURE__ */ new Map());
13874
+ setPreviewTasksById((current) => current.size === 0 ? current : /* @__PURE__ */ new Map());
13675
13875
  }
13676
13876
  },
13677
13877
  rowIndex: index,
@@ -13684,6 +13884,7 @@ function TaskGanttChartInner(props, ref) {
13684
13884
  highlightExpiredTasks,
13685
13885
  showBaseline,
13686
13886
  isFilterMatch: filterMode === "highlight" ? matchedTaskIds.has(task.id) : false,
13887
+ isCritical: criticalTaskIds.has(task.id),
13687
13888
  businessDays,
13688
13889
  customDays,
13689
13890
  isWeekend: isWeekend3,
@@ -13805,6 +14006,7 @@ export {
13805
14006
  cascadeByLinks,
13806
14007
  clampDateRangeForIncomingFS,
13807
14008
  clampTaskRangeForIncomingFS,
14009
+ computeCriticalPath,
13808
14010
  computeLagFromDates,
13809
14011
  computeParentDates,
13810
14012
  computeParentProgress,
@@ -13813,6 +14015,7 @@ export {
13813
14015
  detectCycles,
13814
14016
  detectEdgeZone,
13815
14017
  expired,
14018
+ extendCriticalIdsToParents,
13816
14019
  findParentId,
13817
14020
  flattenHierarchy,
13818
14021
  formatDateLabel,