gantt-lib 0.0.6 → 0.0.7

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
@@ -39,6 +39,7 @@ __export(index_exports, {
39
39
  TodayIndicator: () => TodayIndicator_default,
40
40
  buildAdjacencyList: () => buildAdjacencyList,
41
41
  calculateBezierPath: () => calculateBezierPath,
42
+ calculateDependencyPath: () => calculateDependencyPath,
42
43
  calculateGridLines: () => calculateGridLines,
43
44
  calculateGridWidth: () => calculateGridWidth,
44
45
  calculateOrthogonalPath: () => calculateOrthogonalPath,
@@ -295,7 +296,7 @@ function validateDependencies(tasks) {
295
296
  errors
296
297
  };
297
298
  }
298
- function getSuccessorChain(draggedTaskId, allTasks) {
299
+ function getSuccessorChain(draggedTaskId, allTasks, linkTypes = ["FS"]) {
299
300
  const successorMap = /* @__PURE__ */ new Map();
300
301
  for (const task of allTasks) {
301
302
  successorMap.set(task.id, []);
@@ -303,7 +304,7 @@ function getSuccessorChain(draggedTaskId, allTasks) {
303
304
  for (const task of allTasks) {
304
305
  if (!task.dependencies) continue;
305
306
  for (const dep of task.dependencies) {
306
- if (dep.type === "FS") {
307
+ if (linkTypes.includes(dep.type)) {
307
308
  const list = successorMap.get(dep.taskId) ?? [];
308
309
  list.push(task.id);
309
310
  successorMap.set(dep.taskId, list);
@@ -525,6 +526,43 @@ var calculateBezierPath = (from, to) => {
525
526
  const cp2y = to.y - (to.y > from.y ? cpOffset : -cpOffset);
526
527
  return `M ${Math.round(from.x)} ${Math.round(from.y)} C ${Math.round(cp1x)} ${Math.round(cp1y)}, ${Math.round(cp2x)} ${Math.round(cp2y)}, ${Math.round(to.x)} ${Math.round(to.y)}`;
527
528
  };
529
+ var calculateDependencyPath = (from, to, arrivesFromRight) => {
530
+ const fx = Math.round(from.x);
531
+ const fy = Math.round(from.y);
532
+ const tx = Math.round(to.x);
533
+ const ty = Math.round(to.y);
534
+ if (fy === ty) {
535
+ return `M ${fx} ${fy} H ${tx}`;
536
+ }
537
+ const C = 2;
538
+ const goingDown = ty > fy;
539
+ const dirY = goingDown ? 1 : -1;
540
+ if (arrivesFromRight) {
541
+ const goingRight = tx >= fx;
542
+ const dirX = goingRight ? 1 : -1;
543
+ if (Math.abs(ty - fy) >= C && Math.abs(tx - fx) >= C) {
544
+ return [
545
+ `M ${fx} ${fy}`,
546
+ `H ${tx - dirX * C}`,
547
+ `L ${tx} ${fy + dirY * C}`,
548
+ `V ${ty}`
549
+ ].join(" ");
550
+ }
551
+ return `M ${fx} ${fy} H ${tx} V ${ty}`;
552
+ } else {
553
+ const goingRight = tx >= fx;
554
+ const dirX = goingRight ? 1 : -1;
555
+ if (Math.abs(ty - fy) >= C && Math.abs(tx - fx) >= C) {
556
+ return [
557
+ `M ${fx} ${fy}`,
558
+ `H ${tx - dirX * C}`,
559
+ `L ${tx} ${fy + dirY * C}`,
560
+ `V ${ty}`
561
+ ].join(" ");
562
+ }
563
+ return `M ${fx} ${fy} H ${tx} V ${ty}`;
564
+ }
565
+ };
528
566
  var calculateOrthogonalPath = (from, to) => {
529
567
  const fx = Math.round(from.x);
530
568
  const fy = Math.round(from.y);
@@ -551,6 +589,36 @@ var calculateOrthogonalPath = (from, to) => {
551
589
 
552
590
  // src/hooks/useTaskDrag.ts
553
591
  var import_react2 = require("react");
592
+ function getTransitiveCascadeChain(draggedTaskId, allTasks, firstLevelLinkTypes) {
593
+ const allTypesSuccessorMap = /* @__PURE__ */ new Map();
594
+ for (const task of allTasks) {
595
+ allTypesSuccessorMap.set(task.id, []);
596
+ }
597
+ for (const task of allTasks) {
598
+ if (!task.dependencies) continue;
599
+ for (const dep of task.dependencies) {
600
+ const list = allTypesSuccessorMap.get(dep.taskId) ?? [];
601
+ list.push(task);
602
+ allTypesSuccessorMap.set(dep.taskId, list);
603
+ }
604
+ }
605
+ const directSuccessors = getSuccessorChain(draggedTaskId, allTasks, firstLevelLinkTypes);
606
+ const chain = [...directSuccessors];
607
+ const visited = /* @__PURE__ */ new Set([draggedTaskId, ...directSuccessors.map((t) => t.id)]);
608
+ const queue = [...directSuccessors];
609
+ while (queue.length > 0) {
610
+ const current = queue.shift();
611
+ const successors = allTypesSuccessorMap.get(current.id) ?? [];
612
+ for (const successor of successors) {
613
+ if (!visited.has(successor.id)) {
614
+ visited.add(successor.id);
615
+ chain.push(successor);
616
+ queue.push(successor);
617
+ }
618
+ }
619
+ }
620
+ return chain;
621
+ }
554
622
  var globalActiveDrag = null;
555
623
  var globalRafId = null;
556
624
  function completeDrag() {
@@ -579,25 +647,43 @@ function cancelDrag() {
579
647
  function snapToGrid(pixels, dayWidth) {
580
648
  return Math.round(pixels / dayWidth) * dayWidth;
581
649
  }
582
- function recalculateIncomingLags(task, newStartDate, allTasks) {
650
+ function recalculateIncomingLags(task, newStartDate, newEndDate, allTasks) {
583
651
  if (!task.dependencies) return [];
584
652
  const taskById = new Map(allTasks.map((t) => [t.id, t]));
585
653
  return task.dependencies.map((dep) => {
586
- if (dep.type !== "FS") return dep;
587
- const predecessor = taskById.get(dep.taskId);
588
- if (!predecessor) return dep;
589
- const predEnd = new Date(predecessor.endDate);
590
- const lagMs = Date.UTC(
591
- newStartDate.getUTCFullYear(),
592
- newStartDate.getUTCMonth(),
593
- newStartDate.getUTCDate()
594
- ) - Date.UTC(
595
- predEnd.getUTCFullYear(),
596
- predEnd.getUTCMonth(),
597
- predEnd.getUTCDate()
598
- );
599
- const lagDays = Math.round(lagMs / (24 * 60 * 60 * 1e3));
600
- return { ...dep, lag: lagDays };
654
+ if (dep.type === "FS") {
655
+ const predecessor = taskById.get(dep.taskId);
656
+ if (!predecessor) return dep;
657
+ const predEnd = new Date(predecessor.endDate);
658
+ const lagMs = Date.UTC(newStartDate.getUTCFullYear(), newStartDate.getUTCMonth(), newStartDate.getUTCDate()) - Date.UTC(predEnd.getUTCFullYear(), predEnd.getUTCMonth(), predEnd.getUTCDate());
659
+ const lagDays = Math.round(lagMs / (24 * 60 * 60 * 1e3));
660
+ return { ...dep, lag: lagDays };
661
+ }
662
+ if (dep.type === "SS") {
663
+ const predecessor = taskById.get(dep.taskId);
664
+ if (!predecessor) return dep;
665
+ const predStart = new Date(predecessor.startDate);
666
+ const lagMs = Date.UTC(newStartDate.getUTCFullYear(), newStartDate.getUTCMonth(), newStartDate.getUTCDate()) - Date.UTC(predStart.getUTCFullYear(), predStart.getUTCMonth(), predStart.getUTCDate());
667
+ const lagDays = Math.max(0, Math.round(lagMs / (24 * 60 * 60 * 1e3)));
668
+ return { ...dep, lag: lagDays };
669
+ }
670
+ if (dep.type === "FF") {
671
+ const predecessor = taskById.get(dep.taskId);
672
+ if (!predecessor) return dep;
673
+ const predEnd = new Date(predecessor.endDate);
674
+ const lagMs = Date.UTC(newEndDate.getUTCFullYear(), newEndDate.getUTCMonth(), newEndDate.getUTCDate()) - Date.UTC(predEnd.getUTCFullYear(), predEnd.getUTCMonth(), predEnd.getUTCDate());
675
+ const lagDays = Math.round(lagMs / (24 * 60 * 60 * 1e3));
676
+ return { ...dep, lag: lagDays };
677
+ }
678
+ if (dep.type === "SF") {
679
+ const predecessor = taskById.get(dep.taskId);
680
+ if (!predecessor) return dep;
681
+ const predStart = new Date(predecessor.startDate);
682
+ const lagMs = Date.UTC(newEndDate.getUTCFullYear(), newEndDate.getUTCMonth(), newEndDate.getUTCDate()) - Date.UTC(predStart.getUTCFullYear(), predStart.getUTCMonth(), predStart.getUTCDate()) + 24 * 60 * 60 * 1e3;
683
+ const lagDays = Math.min(0, Math.round(lagMs / (24 * 60 * 60 * 1e3)));
684
+ return { ...dep, lag: lagDays };
685
+ }
686
+ return dep;
601
687
  });
602
688
  }
603
689
  function handleGlobalMouseMove(e) {
@@ -628,12 +714,12 @@ function handleGlobalMouseMove(e) {
628
714
  newWidth = Math.max(dayWidth, snappedWidth);
629
715
  break;
630
716
  }
631
- if (mode === "move" && allTasks.length > 0 && !globalActiveDrag.disableConstraints) {
717
+ if ((mode === "move" || mode === "resize-left") && allTasks.length > 0 && !globalActiveDrag.disableConstraints) {
632
718
  const currentTask = allTasks.find((t) => t.id === globalActiveDrag?.taskId);
633
719
  if (currentTask && currentTask.dependencies && currentTask.dependencies.length > 0) {
634
720
  let minAllowedLeft = 0;
635
721
  for (const dep of currentTask.dependencies) {
636
- if (dep.type !== "FS") continue;
722
+ if (dep.type !== "FS" && dep.type !== "SS") continue;
637
723
  const predecessor = globalActiveDrag.allTasks.find((t) => t.id === dep.taskId);
638
724
  if (!predecessor) continue;
639
725
  const predStart = new Date(predecessor.startDate);
@@ -649,25 +735,91 @@ function handleGlobalMouseMove(e) {
649
735
  }
650
736
  newLeft = Math.max(minAllowedLeft, newLeft);
651
737
  }
738
+ if (mode === "resize-left") {
739
+ const rightEdge = globalActiveDrag.initialLeft + globalActiveDrag.initialWidth;
740
+ newWidth = Math.max(globalActiveDrag.dayWidth, rightEdge - newLeft);
741
+ }
742
+ }
743
+ if ((mode === "move" || mode === "resize-right") && allTasks.length > 0 && !globalActiveDrag.disableConstraints) {
744
+ const currentTask = allTasks.find((t) => t.id === globalActiveDrag?.taskId);
745
+ if (currentTask && currentTask.dependencies && currentTask.dependencies.length > 0) {
746
+ for (const dep of currentTask.dependencies) {
747
+ if (dep.type !== "SF") continue;
748
+ const predecessor = globalActiveDrag.allTasks.find((t) => t.id === dep.taskId);
749
+ if (!predecessor) continue;
750
+ const predStart = new Date(predecessor.startDate);
751
+ const predStartOffset = Math.round(
752
+ (Date.UTC(predStart.getUTCFullYear(), predStart.getUTCMonth(), predStart.getUTCDate()) - Date.UTC(globalActiveDrag.monthStart.getUTCFullYear(), globalActiveDrag.monthStart.getUTCDate(), globalActiveDrag.monthStart.getUTCDate())) / (24 * 60 * 60 * 1e3)
753
+ );
754
+ const predStartLeft = Math.round(predStartOffset * globalActiveDrag.dayWidth);
755
+ const sfBoundaryRight = predStartLeft;
756
+ if (mode === "move") {
757
+ const proposedEndRight = newLeft + globalActiveDrag.initialWidth;
758
+ if (proposedEndRight > sfBoundaryRight) {
759
+ newLeft = Math.max(globalActiveDrag.initialLeft, sfBoundaryRight - globalActiveDrag.initialWidth);
760
+ }
761
+ } else {
762
+ const currentEndRight = newLeft + newWidth;
763
+ if (currentEndRight > sfBoundaryRight) {
764
+ newWidth = Math.max(globalActiveDrag.dayWidth, sfBoundaryRight - newLeft);
765
+ }
766
+ }
767
+ }
768
+ }
652
769
  }
653
- if ((mode === "move" || mode === "resize-right") && !globalActiveDrag.disableConstraints && globalActiveDrag.cascadeChain.length > 0 && globalActiveDrag.onCascadeProgress) {
770
+ const activeChain = mode === "resize-right" ? globalActiveDrag.cascadeChainEnd : (
771
+ // FS + FF
772
+ mode === "resize-left" ? globalActiveDrag.cascadeChainStart : (
773
+ // SS + SF
774
+ /* move */
775
+ globalActiveDrag.cascadeChain
776
+ )
777
+ );
778
+ if ((mode === "move" || mode === "resize-right" || mode === "resize-left" && globalActiveDrag.cascadeChainStart.length > 0) && !globalActiveDrag.disableConstraints && activeChain.length > 0 && globalActiveDrag.onCascadeProgress) {
654
779
  const deltaDays = mode === "resize-right" ? Math.round((newWidth - globalActiveDrag.initialWidth) / globalActiveDrag.dayWidth) : Math.round((newLeft - globalActiveDrag.initialLeft) / globalActiveDrag.dayWidth);
655
780
  const overrides = /* @__PURE__ */ new Map();
656
- for (const chainTask of globalActiveDrag.cascadeChain) {
781
+ const draggedTaskId = globalActiveDrag.taskId;
782
+ const dayWidth2 = globalActiveDrag.dayWidth;
783
+ const monthStart = globalActiveDrag.monthStart;
784
+ for (const chainTask of activeChain) {
657
785
  const chainStart = new Date(chainTask.startDate);
658
786
  const chainEnd = new Date(chainTask.endDate);
659
787
  const chainStartOffset = Math.round(
660
788
  (Date.UTC(chainStart.getUTCFullYear(), chainStart.getUTCMonth(), chainStart.getUTCDate()) - Date.UTC(
661
- globalActiveDrag.monthStart.getUTCFullYear(),
662
- globalActiveDrag.monthStart.getUTCMonth(),
663
- globalActiveDrag.monthStart.getUTCDate()
789
+ monthStart.getUTCFullYear(),
790
+ monthStart.getUTCMonth(),
791
+ monthStart.getUTCDate()
792
+ )) / (24 * 60 * 60 * 1e3)
793
+ );
794
+ const chainEndOffset = Math.round(
795
+ (Date.UTC(chainEnd.getUTCFullYear(), chainEnd.getUTCMonth(), chainEnd.getUTCDate()) - Date.UTC(
796
+ monthStart.getUTCFullYear(),
797
+ monthStart.getUTCMonth(),
798
+ monthStart.getUTCDate()
664
799
  )) / (24 * 60 * 60 * 1e3)
665
800
  );
666
801
  const chainDuration = Math.round(
667
802
  (Date.UTC(chainEnd.getUTCFullYear(), chainEnd.getUTCMonth(), chainEnd.getUTCDate()) - Date.UTC(chainStart.getUTCFullYear(), chainStart.getUTCMonth(), chainStart.getUTCDate())) / (24 * 60 * 60 * 1e3)
668
803
  );
669
- const chainLeft = Math.round((chainStartOffset + deltaDays) * globalActiveDrag.dayWidth);
670
- const chainWidth = Math.round((chainDuration + 1) * globalActiveDrag.dayWidth);
804
+ const hasFFDepOnDragged = chainTask.dependencies?.some(
805
+ (dep) => dep.taskId === draggedTaskId && dep.type === "FF"
806
+ );
807
+ const hasSFDepOnDragged = chainTask.dependencies?.some(
808
+ (dep) => dep.taskId === draggedTaskId && dep.type === "SF"
809
+ );
810
+ let chainLeft;
811
+ if (hasFFDepOnDragged || hasSFDepOnDragged) {
812
+ chainLeft = Math.round((chainEndOffset + deltaDays - chainDuration) * dayWidth2);
813
+ } else {
814
+ chainLeft = Math.round((chainStartOffset + deltaDays) * dayWidth2);
815
+ }
816
+ const chainWidth = Math.round((chainDuration + 1) * dayWidth2);
817
+ const hasSSDepOnDragged = chainTask.dependencies?.some(
818
+ (dep) => dep.taskId === draggedTaskId && dep.type === "SS"
819
+ );
820
+ if (hasSSDepOnDragged && (mode === "move" || mode === "resize-left")) {
821
+ chainLeft = Math.max(chainLeft, newLeft);
822
+ }
671
823
  overrides.set(chainTask.id, { left: chainLeft, width: chainWidth });
672
824
  }
673
825
  globalActiveDrag.onCascadeProgress(overrides);
@@ -778,19 +930,32 @@ var useTaskDrag = (options) => {
778
930
  }
779
931
  if (wasOwner) {
780
932
  if (!disableConstraints && onCascade && allTasks.length > 0) {
781
- const chain = getSuccessorChain(taskId, allTasks);
782
- if (chain.length > 0) {
783
- const origEndMs = Date.UTC(
784
- initialEndDate.getUTCFullYear(),
785
- initialEndDate.getUTCMonth(),
786
- initialEndDate.getUTCDate()
787
- );
788
- const newEndMs = Date.UTC(
789
- newEndDate.getUTCFullYear(),
790
- newEndDate.getUTCMonth(),
791
- newEndDate.getUTCDate()
792
- );
793
- const deltaDays = Math.round((newEndMs - origEndMs) / (24 * 60 * 60 * 1e3));
933
+ const origStartMs = Date.UTC(
934
+ initialStartDate.getUTCFullYear(),
935
+ initialStartDate.getUTCMonth(),
936
+ initialStartDate.getUTCDate()
937
+ );
938
+ const newStartMs = Date.UTC(
939
+ newStartDate.getUTCFullYear(),
940
+ newStartDate.getUTCMonth(),
941
+ newStartDate.getUTCDate()
942
+ );
943
+ const deltaFromStart = Math.round((newStartMs - origStartMs) / (24 * 60 * 60 * 1e3));
944
+ const origEndMs = Date.UTC(
945
+ initialEndDate.getUTCFullYear(),
946
+ initialEndDate.getUTCMonth(),
947
+ initialEndDate.getUTCDate()
948
+ );
949
+ const newEndMs = Date.UTC(
950
+ newEndDate.getUTCFullYear(),
951
+ newEndDate.getUTCMonth(),
952
+ newEndDate.getUTCDate()
953
+ );
954
+ const deltaFromEnd = Math.round((newEndMs - origEndMs) / (24 * 60 * 60 * 1e3));
955
+ const deltaDays = deltaFromStart === 0 ? deltaFromEnd : deltaFromStart;
956
+ const isResizeLeft = deltaFromStart !== 0 && deltaFromEnd === 0;
957
+ const chainForCompletion = deltaFromStart === 0 ? getTransitiveCascadeChain(taskId, allTasks, ["FS", "FF"]) : isResizeLeft ? getTransitiveCascadeChain(taskId, allTasks, ["SS", "SF"]) : getTransitiveCascadeChain(taskId, allTasks, ["FS", "SS", "FF", "SF"]);
958
+ if (chainForCompletion.length > 0) {
794
959
  const draggedTaskData = allTasks.find((t) => t.id === taskId);
795
960
  const cascadedTasks = [
796
961
  {
@@ -798,10 +963,10 @@ var useTaskDrag = (options) => {
798
963
  startDate: newStartDate.toISOString(),
799
964
  endDate: newEndDate.toISOString(),
800
965
  ...draggedTaskData?.dependencies && {
801
- dependencies: recalculateIncomingLags(draggedTaskData, newStartDate, allTasks)
966
+ dependencies: recalculateIncomingLags(draggedTaskData, newStartDate, newEndDate, allTasks)
802
967
  }
803
968
  },
804
- ...chain.map((chainTask) => {
969
+ ...chainForCompletion.map((chainTask) => {
805
970
  const origStart = new Date(chainTask.startDate);
806
971
  const origEnd = new Date(chainTask.endDate);
807
972
  const newStart = new Date(Date.UTC(
@@ -823,7 +988,7 @@ var useTaskDrag = (options) => {
823
988
  }
824
989
  if (allTasks.length > 0 && onDragEnd) {
825
990
  const currentTaskData = allTasks.find((t) => t.id === taskId);
826
- const updatedDependencies = currentTaskData?.dependencies ? recalculateIncomingLags(currentTaskData, newStartDate, allTasks) : void 0;
991
+ const updatedDependencies = currentTaskData?.dependencies ? recalculateIncomingLags(currentTaskData, newStartDate, newEndDate, allTasks) : void 0;
827
992
  onDragEnd({ id: taskId, startDate: newStartDate, endDate: newEndDate, updatedDependencies });
828
993
  } else if (onDragEnd) {
829
994
  onDragEnd({ id: taskId, startDate: newStartDate, endDate: newEndDate });
@@ -899,7 +1064,10 @@ var useTaskDrag = (options) => {
899
1064
  onCancel: handleCancel,
900
1065
  allTasks,
901
1066
  disableConstraints,
902
- cascadeChain: (mode === "move" || mode === "resize-right") && !disableConstraints ? getSuccessorChain(taskId, allTasks) : [],
1067
+ cascadeChain: !disableConstraints ? getTransitiveCascadeChain(taskId, allTasks, ["FS", "SS", "FF", "SF"]) : [],
1068
+ cascadeChainFS: !disableConstraints ? getTransitiveCascadeChain(taskId, allTasks, ["FS"]) : [],
1069
+ cascadeChainStart: !disableConstraints ? getTransitiveCascadeChain(taskId, allTasks, ["SS", "SF"]) : [],
1070
+ cascadeChainEnd: !disableConstraints ? getTransitiveCascadeChain(taskId, allTasks, ["FS", "FF"]) : [],
903
1071
  onCascadeProgress
904
1072
  };
905
1073
  }, [edgeZoneWidth, currentLeft, currentWidth, dayWidth, monthStart, taskId, onDragStateChange, handleProgress, handleComplete, handleCancel, allTasks, disableConstraints, onCascadeProgress, onCascade]);
@@ -988,6 +1156,8 @@ var TaskRow = import_react3.default.memo(
988
1156
  const durationDays = Math.round(
989
1157
  (currentEndDate.getTime() - currentStartDate.getTime()) / (1e3 * 60 * 60 * 24)
990
1158
  ) + 1;
1159
+ const estimatedTextWidth = durationDays >= 10 ? 76 : 62;
1160
+ const showProgressInside = progressWidth > 0 && displayWidth > estimatedTextWidth;
991
1161
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
992
1162
  "div",
993
1163
  {
@@ -1024,6 +1194,10 @@ var TaskRow = import_react3.default.memo(
1024
1194
  durationDays,
1025
1195
  " \u0434"
1026
1196
  ] }),
1197
+ progressWidth > 0 && showProgressInside && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "gantt-tr-progressText", children: [
1198
+ progressWidth,
1199
+ "%"
1200
+ ] }),
1027
1201
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "gantt-tr-resizeHandle gantt-tr-resizeHandleRight" })
1028
1202
  ]
1029
1203
  }
@@ -1042,14 +1216,20 @@ var TaskRow = import_react3.default.memo(
1042
1216
  ] })
1043
1217
  }
1044
1218
  ),
1045
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1219
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1046
1220
  "div",
1047
1221
  {
1048
1222
  className: "gantt-tr-rightLabels",
1049
1223
  style: {
1050
1224
  left: `${displayLeft + displayWidth}px`
1051
1225
  },
1052
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gantt-tr-externalTaskName", children: task.name })
1226
+ children: [
1227
+ progressWidth > 0 && !showProgressInside && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "gantt-tr-externalProgress", children: [
1228
+ progressWidth,
1229
+ "%"
1230
+ ] }),
1231
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gantt-tr-externalTaskName", children: task.name })
1232
+ ]
1053
1233
  }
1054
1234
  )
1055
1235
  ] })
@@ -1198,6 +1378,62 @@ var DragGuideLines_default = DragGuideLines;
1198
1378
  // src/components/DependencyLines/DependencyLines.tsx
1199
1379
  var import_react6 = __toESM(require("react"));
1200
1380
  var import_jsx_runtime6 = require("react/jsx-runtime");
1381
+ function calculateEffectiveLag(edge, predPosition, succPosition, monthStart, dayWidth) {
1382
+ const predStartDate = pixelsToDate(predPosition.left, monthStart, dayWidth);
1383
+ const predEndDate = pixelsToDate(predPosition.right - dayWidth, monthStart, dayWidth);
1384
+ const succStartDate = pixelsToDate(succPosition.left, monthStart, dayWidth);
1385
+ const succEndDate = pixelsToDate(succPosition.right - dayWidth, monthStart, dayWidth);
1386
+ let lagMs = 0;
1387
+ switch (edge.type) {
1388
+ case "FS":
1389
+ lagMs = Date.UTC(
1390
+ succStartDate.getUTCFullYear(),
1391
+ succStartDate.getUTCMonth(),
1392
+ succStartDate.getUTCDate()
1393
+ ) - Date.UTC(
1394
+ predEndDate.getUTCFullYear(),
1395
+ predEndDate.getUTCMonth(),
1396
+ predEndDate.getUTCDate()
1397
+ ) - 24 * 60 * 60 * 1e3;
1398
+ break;
1399
+ case "SS":
1400
+ lagMs = Date.UTC(
1401
+ succStartDate.getUTCFullYear(),
1402
+ succStartDate.getUTCMonth(),
1403
+ succStartDate.getUTCDate()
1404
+ ) - Date.UTC(
1405
+ predStartDate.getUTCFullYear(),
1406
+ predStartDate.getUTCMonth(),
1407
+ predStartDate.getUTCDate()
1408
+ );
1409
+ break;
1410
+ case "FF":
1411
+ lagMs = Date.UTC(
1412
+ succEndDate.getUTCFullYear(),
1413
+ succEndDate.getUTCMonth(),
1414
+ succEndDate.getUTCDate()
1415
+ ) - Date.UTC(
1416
+ predEndDate.getUTCFullYear(),
1417
+ predEndDate.getUTCMonth(),
1418
+ predEndDate.getUTCDate()
1419
+ );
1420
+ break;
1421
+ case "SF":
1422
+ lagMs = Date.UTC(
1423
+ succEndDate.getUTCFullYear(),
1424
+ succEndDate.getUTCMonth(),
1425
+ succEndDate.getUTCDate()
1426
+ ) - Date.UTC(
1427
+ predStartDate.getUTCFullYear(),
1428
+ predStartDate.getUTCMonth(),
1429
+ predStartDate.getUTCDate()
1430
+ ) + 24 * 60 * 60 * 1e3;
1431
+ break;
1432
+ default:
1433
+ return 0;
1434
+ }
1435
+ return Math.round(lagMs / (24 * 60 * 60 * 1e3));
1436
+ }
1201
1437
  var DependencyLines = import_react6.default.memo(({
1202
1438
  tasks,
1203
1439
  monthStart,
@@ -1218,7 +1454,7 @@ var DependencyLines = import_react6.default.memo(({
1218
1454
  const resolvedWidth = override?.width ?? computed.width;
1219
1455
  indices.set(task.id, index);
1220
1456
  positions.set(task.id, {
1221
- left: resolvedLeft + 10,
1457
+ left: resolvedLeft,
1222
1458
  right: resolvedLeft + resolvedWidth,
1223
1459
  rowTop: index * rowHeight
1224
1460
  });
@@ -1251,18 +1487,27 @@ var DependencyLines = import_react6.default.memo(({
1251
1487
  fromY = predecessor.rowTop + rowHeight - 10;
1252
1488
  toY = successor.rowTop + 6;
1253
1489
  }
1254
- const from = { x: predecessor.right, y: fromY };
1255
- const to = { x: successor.left, y: toY };
1256
- const path = calculateOrthogonalPath(from, to);
1490
+ const fromX = edge.type === "SS" || edge.type === "SF" ? predecessor.left : predecessor.right;
1491
+ const toX = edge.type === "FF" || edge.type === "SF" ? successor.right : successor.left;
1492
+ const arrivesFromRight = edge.type === "FF" || edge.type === "SF";
1493
+ const from = { x: fromX, y: fromY };
1494
+ const to = { x: toX, y: toY };
1495
+ const path = calculateDependencyPath(from, to, arrivesFromRight);
1257
1496
  const hasCycle = cycleInfo.has(edge.predecessorId) || cycleInfo.has(edge.successorId);
1497
+ const lag = calculateEffectiveLag(edge, predecessor, successor, monthStart, dayWidth);
1258
1498
  lines2.push({
1259
- id: `${edge.predecessorId}-${edge.successorId}`,
1499
+ id: `${edge.predecessorId}-${edge.successorId}-${edge.type}`,
1260
1500
  path,
1261
- hasCycle
1501
+ hasCycle,
1502
+ lag,
1503
+ fromX,
1504
+ toX,
1505
+ fromY,
1506
+ reverseOrder
1262
1507
  });
1263
1508
  }
1264
1509
  return lines2;
1265
- }, [tasks, taskPositions, taskIndices, cycleInfo]);
1510
+ }, [tasks, taskPositions, taskIndices, cycleInfo, monthStart, dayWidth, dragOverrides]);
1266
1511
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1267
1512
  "svg",
1268
1513
  {
@@ -1311,15 +1556,28 @@ var DependencyLines = import_react6.default.memo(({
1311
1556
  }
1312
1557
  )
1313
1558
  ] }),
1314
- lines.map(({ id, path, hasCycle }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1315
- "path",
1316
- {
1317
- d: path,
1318
- className: hasCycle ? "gantt-dependency-path gantt-dependency-cycle" : "gantt-dependency-path",
1319
- markerEnd: hasCycle ? "url(#arrowhead-cycle)" : "url(#arrowhead)"
1320
- },
1321
- id
1322
- ))
1559
+ lines.map(({ id, path, hasCycle, lag, fromX, toX, fromY, reverseOrder }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react6.default.Fragment, { children: [
1560
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1561
+ "path",
1562
+ {
1563
+ d: path,
1564
+ className: hasCycle ? "gantt-dependency-path gantt-dependency-cycle" : "gantt-dependency-path",
1565
+ markerEnd: hasCycle ? "url(#arrowhead-cycle)" : "url(#arrowhead)"
1566
+ }
1567
+ ),
1568
+ lag !== 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1569
+ "text",
1570
+ {
1571
+ className: "gantt-dependency-lag-label",
1572
+ x: lag < 0 ? toX + 14 : toX - 14,
1573
+ y: reverseOrder ? fromY - 4 : fromY + 12,
1574
+ textAnchor: "middle",
1575
+ fontSize: "10",
1576
+ fill: hasCycle ? "var(--gantt-dependency-cycle-color, #ef4444)" : "var(--gantt-dependency-line-color, #666666)",
1577
+ children: lag > 0 ? `+${lag}` : `${lag}`
1578
+ }
1579
+ )
1580
+ ] }, id))
1323
1581
  ]
1324
1582
  }
1325
1583
  );
@@ -1537,6 +1795,7 @@ var GanttChart = ({
1537
1795
  TodayIndicator,
1538
1796
  buildAdjacencyList,
1539
1797
  calculateBezierPath,
1798
+ calculateDependencyPath,
1540
1799
  calculateGridLines,
1541
1800
  calculateGridWidth,
1542
1801
  calculateOrthogonalPath,