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.mjs CHANGED
@@ -231,7 +231,7 @@ function validateDependencies(tasks) {
231
231
  errors
232
232
  };
233
233
  }
234
- function getSuccessorChain(draggedTaskId, allTasks) {
234
+ function getSuccessorChain(draggedTaskId, allTasks, linkTypes = ["FS"]) {
235
235
  const successorMap = /* @__PURE__ */ new Map();
236
236
  for (const task of allTasks) {
237
237
  successorMap.set(task.id, []);
@@ -239,7 +239,7 @@ function getSuccessorChain(draggedTaskId, allTasks) {
239
239
  for (const task of allTasks) {
240
240
  if (!task.dependencies) continue;
241
241
  for (const dep of task.dependencies) {
242
- if (dep.type === "FS") {
242
+ if (linkTypes.includes(dep.type)) {
243
243
  const list = successorMap.get(dep.taskId) ?? [];
244
244
  list.push(task.id);
245
245
  successorMap.set(dep.taskId, list);
@@ -461,6 +461,43 @@ var calculateBezierPath = (from, to) => {
461
461
  const cp2y = to.y - (to.y > from.y ? cpOffset : -cpOffset);
462
462
  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)}`;
463
463
  };
464
+ var calculateDependencyPath = (from, to, arrivesFromRight) => {
465
+ const fx = Math.round(from.x);
466
+ const fy = Math.round(from.y);
467
+ const tx = Math.round(to.x);
468
+ const ty = Math.round(to.y);
469
+ if (fy === ty) {
470
+ return `M ${fx} ${fy} H ${tx}`;
471
+ }
472
+ const C = 2;
473
+ const goingDown = ty > fy;
474
+ const dirY = goingDown ? 1 : -1;
475
+ if (arrivesFromRight) {
476
+ const goingRight = tx >= fx;
477
+ const dirX = goingRight ? 1 : -1;
478
+ if (Math.abs(ty - fy) >= C && Math.abs(tx - fx) >= C) {
479
+ return [
480
+ `M ${fx} ${fy}`,
481
+ `H ${tx - dirX * C}`,
482
+ `L ${tx} ${fy + dirY * C}`,
483
+ `V ${ty}`
484
+ ].join(" ");
485
+ }
486
+ return `M ${fx} ${fy} H ${tx} V ${ty}`;
487
+ } else {
488
+ const goingRight = tx >= fx;
489
+ const dirX = goingRight ? 1 : -1;
490
+ if (Math.abs(ty - fy) >= C && Math.abs(tx - fx) >= C) {
491
+ return [
492
+ `M ${fx} ${fy}`,
493
+ `H ${tx - dirX * C}`,
494
+ `L ${tx} ${fy + dirY * C}`,
495
+ `V ${ty}`
496
+ ].join(" ");
497
+ }
498
+ return `M ${fx} ${fy} H ${tx} V ${ty}`;
499
+ }
500
+ };
464
501
  var calculateOrthogonalPath = (from, to) => {
465
502
  const fx = Math.round(from.x);
466
503
  const fy = Math.round(from.y);
@@ -487,6 +524,36 @@ var calculateOrthogonalPath = (from, to) => {
487
524
 
488
525
  // src/hooks/useTaskDrag.ts
489
526
  import { useEffect, useRef, useState, useCallback } from "react";
527
+ function getTransitiveCascadeChain(draggedTaskId, allTasks, firstLevelLinkTypes) {
528
+ const allTypesSuccessorMap = /* @__PURE__ */ new Map();
529
+ for (const task of allTasks) {
530
+ allTypesSuccessorMap.set(task.id, []);
531
+ }
532
+ for (const task of allTasks) {
533
+ if (!task.dependencies) continue;
534
+ for (const dep of task.dependencies) {
535
+ const list = allTypesSuccessorMap.get(dep.taskId) ?? [];
536
+ list.push(task);
537
+ allTypesSuccessorMap.set(dep.taskId, list);
538
+ }
539
+ }
540
+ const directSuccessors = getSuccessorChain(draggedTaskId, allTasks, firstLevelLinkTypes);
541
+ const chain = [...directSuccessors];
542
+ const visited = /* @__PURE__ */ new Set([draggedTaskId, ...directSuccessors.map((t) => t.id)]);
543
+ const queue = [...directSuccessors];
544
+ while (queue.length > 0) {
545
+ const current = queue.shift();
546
+ const successors = allTypesSuccessorMap.get(current.id) ?? [];
547
+ for (const successor of successors) {
548
+ if (!visited.has(successor.id)) {
549
+ visited.add(successor.id);
550
+ chain.push(successor);
551
+ queue.push(successor);
552
+ }
553
+ }
554
+ }
555
+ return chain;
556
+ }
490
557
  var globalActiveDrag = null;
491
558
  var globalRafId = null;
492
559
  function completeDrag() {
@@ -515,25 +582,43 @@ function cancelDrag() {
515
582
  function snapToGrid(pixels, dayWidth) {
516
583
  return Math.round(pixels / dayWidth) * dayWidth;
517
584
  }
518
- function recalculateIncomingLags(task, newStartDate, allTasks) {
585
+ function recalculateIncomingLags(task, newStartDate, newEndDate, allTasks) {
519
586
  if (!task.dependencies) return [];
520
587
  const taskById = new Map(allTasks.map((t) => [t.id, t]));
521
588
  return task.dependencies.map((dep) => {
522
- if (dep.type !== "FS") return dep;
523
- const predecessor = taskById.get(dep.taskId);
524
- if (!predecessor) return dep;
525
- const predEnd = new Date(predecessor.endDate);
526
- const lagMs = Date.UTC(
527
- newStartDate.getUTCFullYear(),
528
- newStartDate.getUTCMonth(),
529
- newStartDate.getUTCDate()
530
- ) - Date.UTC(
531
- predEnd.getUTCFullYear(),
532
- predEnd.getUTCMonth(),
533
- predEnd.getUTCDate()
534
- );
535
- const lagDays = Math.round(lagMs / (24 * 60 * 60 * 1e3));
536
- return { ...dep, lag: lagDays };
589
+ if (dep.type === "FS") {
590
+ const predecessor = taskById.get(dep.taskId);
591
+ if (!predecessor) return dep;
592
+ const predEnd = new Date(predecessor.endDate);
593
+ const lagMs = Date.UTC(newStartDate.getUTCFullYear(), newStartDate.getUTCMonth(), newStartDate.getUTCDate()) - Date.UTC(predEnd.getUTCFullYear(), predEnd.getUTCMonth(), predEnd.getUTCDate());
594
+ const lagDays = Math.round(lagMs / (24 * 60 * 60 * 1e3));
595
+ return { ...dep, lag: lagDays };
596
+ }
597
+ if (dep.type === "SS") {
598
+ const predecessor = taskById.get(dep.taskId);
599
+ if (!predecessor) return dep;
600
+ const predStart = new Date(predecessor.startDate);
601
+ const lagMs = Date.UTC(newStartDate.getUTCFullYear(), newStartDate.getUTCMonth(), newStartDate.getUTCDate()) - Date.UTC(predStart.getUTCFullYear(), predStart.getUTCMonth(), predStart.getUTCDate());
602
+ const lagDays = Math.max(0, Math.round(lagMs / (24 * 60 * 60 * 1e3)));
603
+ return { ...dep, lag: lagDays };
604
+ }
605
+ if (dep.type === "FF") {
606
+ const predecessor = taskById.get(dep.taskId);
607
+ if (!predecessor) return dep;
608
+ const predEnd = new Date(predecessor.endDate);
609
+ const lagMs = Date.UTC(newEndDate.getUTCFullYear(), newEndDate.getUTCMonth(), newEndDate.getUTCDate()) - Date.UTC(predEnd.getUTCFullYear(), predEnd.getUTCMonth(), predEnd.getUTCDate());
610
+ const lagDays = Math.round(lagMs / (24 * 60 * 60 * 1e3));
611
+ return { ...dep, lag: lagDays };
612
+ }
613
+ if (dep.type === "SF") {
614
+ const predecessor = taskById.get(dep.taskId);
615
+ if (!predecessor) return dep;
616
+ const predStart = new Date(predecessor.startDate);
617
+ const lagMs = Date.UTC(newEndDate.getUTCFullYear(), newEndDate.getUTCMonth(), newEndDate.getUTCDate()) - Date.UTC(predStart.getUTCFullYear(), predStart.getUTCMonth(), predStart.getUTCDate()) + 24 * 60 * 60 * 1e3;
618
+ const lagDays = Math.min(0, Math.round(lagMs / (24 * 60 * 60 * 1e3)));
619
+ return { ...dep, lag: lagDays };
620
+ }
621
+ return dep;
537
622
  });
538
623
  }
539
624
  function handleGlobalMouseMove(e) {
@@ -564,12 +649,12 @@ function handleGlobalMouseMove(e) {
564
649
  newWidth = Math.max(dayWidth, snappedWidth);
565
650
  break;
566
651
  }
567
- if (mode === "move" && allTasks.length > 0 && !globalActiveDrag.disableConstraints) {
652
+ if ((mode === "move" || mode === "resize-left") && allTasks.length > 0 && !globalActiveDrag.disableConstraints) {
568
653
  const currentTask = allTasks.find((t) => t.id === globalActiveDrag?.taskId);
569
654
  if (currentTask && currentTask.dependencies && currentTask.dependencies.length > 0) {
570
655
  let minAllowedLeft = 0;
571
656
  for (const dep of currentTask.dependencies) {
572
- if (dep.type !== "FS") continue;
657
+ if (dep.type !== "FS" && dep.type !== "SS") continue;
573
658
  const predecessor = globalActiveDrag.allTasks.find((t) => t.id === dep.taskId);
574
659
  if (!predecessor) continue;
575
660
  const predStart = new Date(predecessor.startDate);
@@ -585,25 +670,91 @@ function handleGlobalMouseMove(e) {
585
670
  }
586
671
  newLeft = Math.max(minAllowedLeft, newLeft);
587
672
  }
673
+ if (mode === "resize-left") {
674
+ const rightEdge = globalActiveDrag.initialLeft + globalActiveDrag.initialWidth;
675
+ newWidth = Math.max(globalActiveDrag.dayWidth, rightEdge - newLeft);
676
+ }
677
+ }
678
+ if ((mode === "move" || mode === "resize-right") && allTasks.length > 0 && !globalActiveDrag.disableConstraints) {
679
+ const currentTask = allTasks.find((t) => t.id === globalActiveDrag?.taskId);
680
+ if (currentTask && currentTask.dependencies && currentTask.dependencies.length > 0) {
681
+ for (const dep of currentTask.dependencies) {
682
+ if (dep.type !== "SF") continue;
683
+ const predecessor = globalActiveDrag.allTasks.find((t) => t.id === dep.taskId);
684
+ if (!predecessor) continue;
685
+ const predStart = new Date(predecessor.startDate);
686
+ const predStartOffset = Math.round(
687
+ (Date.UTC(predStart.getUTCFullYear(), predStart.getUTCMonth(), predStart.getUTCDate()) - Date.UTC(globalActiveDrag.monthStart.getUTCFullYear(), globalActiveDrag.monthStart.getUTCDate(), globalActiveDrag.monthStart.getUTCDate())) / (24 * 60 * 60 * 1e3)
688
+ );
689
+ const predStartLeft = Math.round(predStartOffset * globalActiveDrag.dayWidth);
690
+ const sfBoundaryRight = predStartLeft;
691
+ if (mode === "move") {
692
+ const proposedEndRight = newLeft + globalActiveDrag.initialWidth;
693
+ if (proposedEndRight > sfBoundaryRight) {
694
+ newLeft = Math.max(globalActiveDrag.initialLeft, sfBoundaryRight - globalActiveDrag.initialWidth);
695
+ }
696
+ } else {
697
+ const currentEndRight = newLeft + newWidth;
698
+ if (currentEndRight > sfBoundaryRight) {
699
+ newWidth = Math.max(globalActiveDrag.dayWidth, sfBoundaryRight - newLeft);
700
+ }
701
+ }
702
+ }
703
+ }
588
704
  }
589
- if ((mode === "move" || mode === "resize-right") && !globalActiveDrag.disableConstraints && globalActiveDrag.cascadeChain.length > 0 && globalActiveDrag.onCascadeProgress) {
705
+ const activeChain = mode === "resize-right" ? globalActiveDrag.cascadeChainEnd : (
706
+ // FS + FF
707
+ mode === "resize-left" ? globalActiveDrag.cascadeChainStart : (
708
+ // SS + SF
709
+ /* move */
710
+ globalActiveDrag.cascadeChain
711
+ )
712
+ );
713
+ if ((mode === "move" || mode === "resize-right" || mode === "resize-left" && globalActiveDrag.cascadeChainStart.length > 0) && !globalActiveDrag.disableConstraints && activeChain.length > 0 && globalActiveDrag.onCascadeProgress) {
590
714
  const deltaDays = mode === "resize-right" ? Math.round((newWidth - globalActiveDrag.initialWidth) / globalActiveDrag.dayWidth) : Math.round((newLeft - globalActiveDrag.initialLeft) / globalActiveDrag.dayWidth);
591
715
  const overrides = /* @__PURE__ */ new Map();
592
- for (const chainTask of globalActiveDrag.cascadeChain) {
716
+ const draggedTaskId = globalActiveDrag.taskId;
717
+ const dayWidth2 = globalActiveDrag.dayWidth;
718
+ const monthStart = globalActiveDrag.monthStart;
719
+ for (const chainTask of activeChain) {
593
720
  const chainStart = new Date(chainTask.startDate);
594
721
  const chainEnd = new Date(chainTask.endDate);
595
722
  const chainStartOffset = Math.round(
596
723
  (Date.UTC(chainStart.getUTCFullYear(), chainStart.getUTCMonth(), chainStart.getUTCDate()) - Date.UTC(
597
- globalActiveDrag.monthStart.getUTCFullYear(),
598
- globalActiveDrag.monthStart.getUTCMonth(),
599
- globalActiveDrag.monthStart.getUTCDate()
724
+ monthStart.getUTCFullYear(),
725
+ monthStart.getUTCMonth(),
726
+ monthStart.getUTCDate()
727
+ )) / (24 * 60 * 60 * 1e3)
728
+ );
729
+ const chainEndOffset = Math.round(
730
+ (Date.UTC(chainEnd.getUTCFullYear(), chainEnd.getUTCMonth(), chainEnd.getUTCDate()) - Date.UTC(
731
+ monthStart.getUTCFullYear(),
732
+ monthStart.getUTCMonth(),
733
+ monthStart.getUTCDate()
600
734
  )) / (24 * 60 * 60 * 1e3)
601
735
  );
602
736
  const chainDuration = Math.round(
603
737
  (Date.UTC(chainEnd.getUTCFullYear(), chainEnd.getUTCMonth(), chainEnd.getUTCDate()) - Date.UTC(chainStart.getUTCFullYear(), chainStart.getUTCMonth(), chainStart.getUTCDate())) / (24 * 60 * 60 * 1e3)
604
738
  );
605
- const chainLeft = Math.round((chainStartOffset + deltaDays) * globalActiveDrag.dayWidth);
606
- const chainWidth = Math.round((chainDuration + 1) * globalActiveDrag.dayWidth);
739
+ const hasFFDepOnDragged = chainTask.dependencies?.some(
740
+ (dep) => dep.taskId === draggedTaskId && dep.type === "FF"
741
+ );
742
+ const hasSFDepOnDragged = chainTask.dependencies?.some(
743
+ (dep) => dep.taskId === draggedTaskId && dep.type === "SF"
744
+ );
745
+ let chainLeft;
746
+ if (hasFFDepOnDragged || hasSFDepOnDragged) {
747
+ chainLeft = Math.round((chainEndOffset + deltaDays - chainDuration) * dayWidth2);
748
+ } else {
749
+ chainLeft = Math.round((chainStartOffset + deltaDays) * dayWidth2);
750
+ }
751
+ const chainWidth = Math.round((chainDuration + 1) * dayWidth2);
752
+ const hasSSDepOnDragged = chainTask.dependencies?.some(
753
+ (dep) => dep.taskId === draggedTaskId && dep.type === "SS"
754
+ );
755
+ if (hasSSDepOnDragged && (mode === "move" || mode === "resize-left")) {
756
+ chainLeft = Math.max(chainLeft, newLeft);
757
+ }
607
758
  overrides.set(chainTask.id, { left: chainLeft, width: chainWidth });
608
759
  }
609
760
  globalActiveDrag.onCascadeProgress(overrides);
@@ -714,19 +865,32 @@ var useTaskDrag = (options) => {
714
865
  }
715
866
  if (wasOwner) {
716
867
  if (!disableConstraints && onCascade && allTasks.length > 0) {
717
- const chain = getSuccessorChain(taskId, allTasks);
718
- if (chain.length > 0) {
719
- const origEndMs = Date.UTC(
720
- initialEndDate.getUTCFullYear(),
721
- initialEndDate.getUTCMonth(),
722
- initialEndDate.getUTCDate()
723
- );
724
- const newEndMs = Date.UTC(
725
- newEndDate.getUTCFullYear(),
726
- newEndDate.getUTCMonth(),
727
- newEndDate.getUTCDate()
728
- );
729
- const deltaDays = Math.round((newEndMs - origEndMs) / (24 * 60 * 60 * 1e3));
868
+ const origStartMs = Date.UTC(
869
+ initialStartDate.getUTCFullYear(),
870
+ initialStartDate.getUTCMonth(),
871
+ initialStartDate.getUTCDate()
872
+ );
873
+ const newStartMs = Date.UTC(
874
+ newStartDate.getUTCFullYear(),
875
+ newStartDate.getUTCMonth(),
876
+ newStartDate.getUTCDate()
877
+ );
878
+ const deltaFromStart = Math.round((newStartMs - origStartMs) / (24 * 60 * 60 * 1e3));
879
+ const origEndMs = Date.UTC(
880
+ initialEndDate.getUTCFullYear(),
881
+ initialEndDate.getUTCMonth(),
882
+ initialEndDate.getUTCDate()
883
+ );
884
+ const newEndMs = Date.UTC(
885
+ newEndDate.getUTCFullYear(),
886
+ newEndDate.getUTCMonth(),
887
+ newEndDate.getUTCDate()
888
+ );
889
+ const deltaFromEnd = Math.round((newEndMs - origEndMs) / (24 * 60 * 60 * 1e3));
890
+ const deltaDays = deltaFromStart === 0 ? deltaFromEnd : deltaFromStart;
891
+ const isResizeLeft = deltaFromStart !== 0 && deltaFromEnd === 0;
892
+ const chainForCompletion = deltaFromStart === 0 ? getTransitiveCascadeChain(taskId, allTasks, ["FS", "FF"]) : isResizeLeft ? getTransitiveCascadeChain(taskId, allTasks, ["SS", "SF"]) : getTransitiveCascadeChain(taskId, allTasks, ["FS", "SS", "FF", "SF"]);
893
+ if (chainForCompletion.length > 0) {
730
894
  const draggedTaskData = allTasks.find((t) => t.id === taskId);
731
895
  const cascadedTasks = [
732
896
  {
@@ -734,10 +898,10 @@ var useTaskDrag = (options) => {
734
898
  startDate: newStartDate.toISOString(),
735
899
  endDate: newEndDate.toISOString(),
736
900
  ...draggedTaskData?.dependencies && {
737
- dependencies: recalculateIncomingLags(draggedTaskData, newStartDate, allTasks)
901
+ dependencies: recalculateIncomingLags(draggedTaskData, newStartDate, newEndDate, allTasks)
738
902
  }
739
903
  },
740
- ...chain.map((chainTask) => {
904
+ ...chainForCompletion.map((chainTask) => {
741
905
  const origStart = new Date(chainTask.startDate);
742
906
  const origEnd = new Date(chainTask.endDate);
743
907
  const newStart = new Date(Date.UTC(
@@ -759,7 +923,7 @@ var useTaskDrag = (options) => {
759
923
  }
760
924
  if (allTasks.length > 0 && onDragEnd) {
761
925
  const currentTaskData = allTasks.find((t) => t.id === taskId);
762
- const updatedDependencies = currentTaskData?.dependencies ? recalculateIncomingLags(currentTaskData, newStartDate, allTasks) : void 0;
926
+ const updatedDependencies = currentTaskData?.dependencies ? recalculateIncomingLags(currentTaskData, newStartDate, newEndDate, allTasks) : void 0;
763
927
  onDragEnd({ id: taskId, startDate: newStartDate, endDate: newEndDate, updatedDependencies });
764
928
  } else if (onDragEnd) {
765
929
  onDragEnd({ id: taskId, startDate: newStartDate, endDate: newEndDate });
@@ -835,7 +999,10 @@ var useTaskDrag = (options) => {
835
999
  onCancel: handleCancel,
836
1000
  allTasks,
837
1001
  disableConstraints,
838
- cascadeChain: (mode === "move" || mode === "resize-right") && !disableConstraints ? getSuccessorChain(taskId, allTasks) : [],
1002
+ cascadeChain: !disableConstraints ? getTransitiveCascadeChain(taskId, allTasks, ["FS", "SS", "FF", "SF"]) : [],
1003
+ cascadeChainFS: !disableConstraints ? getTransitiveCascadeChain(taskId, allTasks, ["FS"]) : [],
1004
+ cascadeChainStart: !disableConstraints ? getTransitiveCascadeChain(taskId, allTasks, ["SS", "SF"]) : [],
1005
+ cascadeChainEnd: !disableConstraints ? getTransitiveCascadeChain(taskId, allTasks, ["FS", "FF"]) : [],
839
1006
  onCascadeProgress
840
1007
  };
841
1008
  }, [edgeZoneWidth, currentLeft, currentWidth, dayWidth, monthStart, taskId, onDragStateChange, handleProgress, handleComplete, handleCancel, allTasks, disableConstraints, onCascadeProgress, onCascade]);
@@ -924,6 +1091,8 @@ var TaskRow = React2.memo(
924
1091
  const durationDays = Math.round(
925
1092
  (currentEndDate.getTime() - currentStartDate.getTime()) / (1e3 * 60 * 60 * 24)
926
1093
  ) + 1;
1094
+ const estimatedTextWidth = durationDays >= 10 ? 76 : 62;
1095
+ const showProgressInside = progressWidth > 0 && displayWidth > estimatedTextWidth;
927
1096
  return /* @__PURE__ */ jsx2(
928
1097
  "div",
929
1098
  {
@@ -960,6 +1129,10 @@ var TaskRow = React2.memo(
960
1129
  durationDays,
961
1130
  " \u0434"
962
1131
  ] }),
1132
+ progressWidth > 0 && showProgressInside && /* @__PURE__ */ jsxs2("span", { className: "gantt-tr-progressText", children: [
1133
+ progressWidth,
1134
+ "%"
1135
+ ] }),
963
1136
  /* @__PURE__ */ jsx2("div", { className: "gantt-tr-resizeHandle gantt-tr-resizeHandleRight" })
964
1137
  ]
965
1138
  }
@@ -978,14 +1151,20 @@ var TaskRow = React2.memo(
978
1151
  ] })
979
1152
  }
980
1153
  ),
981
- /* @__PURE__ */ jsx2(
1154
+ /* @__PURE__ */ jsxs2(
982
1155
  "div",
983
1156
  {
984
1157
  className: "gantt-tr-rightLabels",
985
1158
  style: {
986
1159
  left: `${displayLeft + displayWidth}px`
987
1160
  },
988
- children: /* @__PURE__ */ jsx2("span", { className: "gantt-tr-externalTaskName", children: task.name })
1161
+ children: [
1162
+ progressWidth > 0 && !showProgressInside && /* @__PURE__ */ jsxs2("span", { className: "gantt-tr-externalProgress", children: [
1163
+ progressWidth,
1164
+ "%"
1165
+ ] }),
1166
+ /* @__PURE__ */ jsx2("span", { className: "gantt-tr-externalTaskName", children: task.name })
1167
+ ]
989
1168
  }
990
1169
  )
991
1170
  ] })
@@ -1134,6 +1313,62 @@ var DragGuideLines_default = DragGuideLines;
1134
1313
  // src/components/DependencyLines/DependencyLines.tsx
1135
1314
  import React5, { useMemo as useMemo5 } from "react";
1136
1315
  import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1316
+ function calculateEffectiveLag(edge, predPosition, succPosition, monthStart, dayWidth) {
1317
+ const predStartDate = pixelsToDate(predPosition.left, monthStart, dayWidth);
1318
+ const predEndDate = pixelsToDate(predPosition.right - dayWidth, monthStart, dayWidth);
1319
+ const succStartDate = pixelsToDate(succPosition.left, monthStart, dayWidth);
1320
+ const succEndDate = pixelsToDate(succPosition.right - dayWidth, monthStart, dayWidth);
1321
+ let lagMs = 0;
1322
+ switch (edge.type) {
1323
+ case "FS":
1324
+ lagMs = Date.UTC(
1325
+ succStartDate.getUTCFullYear(),
1326
+ succStartDate.getUTCMonth(),
1327
+ succStartDate.getUTCDate()
1328
+ ) - Date.UTC(
1329
+ predEndDate.getUTCFullYear(),
1330
+ predEndDate.getUTCMonth(),
1331
+ predEndDate.getUTCDate()
1332
+ ) - 24 * 60 * 60 * 1e3;
1333
+ break;
1334
+ case "SS":
1335
+ lagMs = Date.UTC(
1336
+ succStartDate.getUTCFullYear(),
1337
+ succStartDate.getUTCMonth(),
1338
+ succStartDate.getUTCDate()
1339
+ ) - Date.UTC(
1340
+ predStartDate.getUTCFullYear(),
1341
+ predStartDate.getUTCMonth(),
1342
+ predStartDate.getUTCDate()
1343
+ );
1344
+ break;
1345
+ case "FF":
1346
+ lagMs = Date.UTC(
1347
+ succEndDate.getUTCFullYear(),
1348
+ succEndDate.getUTCMonth(),
1349
+ succEndDate.getUTCDate()
1350
+ ) - Date.UTC(
1351
+ predEndDate.getUTCFullYear(),
1352
+ predEndDate.getUTCMonth(),
1353
+ predEndDate.getUTCDate()
1354
+ );
1355
+ break;
1356
+ case "SF":
1357
+ lagMs = Date.UTC(
1358
+ succEndDate.getUTCFullYear(),
1359
+ succEndDate.getUTCMonth(),
1360
+ succEndDate.getUTCDate()
1361
+ ) - Date.UTC(
1362
+ predStartDate.getUTCFullYear(),
1363
+ predStartDate.getUTCMonth(),
1364
+ predStartDate.getUTCDate()
1365
+ ) + 24 * 60 * 60 * 1e3;
1366
+ break;
1367
+ default:
1368
+ return 0;
1369
+ }
1370
+ return Math.round(lagMs / (24 * 60 * 60 * 1e3));
1371
+ }
1137
1372
  var DependencyLines = React5.memo(({
1138
1373
  tasks,
1139
1374
  monthStart,
@@ -1154,7 +1389,7 @@ var DependencyLines = React5.memo(({
1154
1389
  const resolvedWidth = override?.width ?? computed.width;
1155
1390
  indices.set(task.id, index);
1156
1391
  positions.set(task.id, {
1157
- left: resolvedLeft + 10,
1392
+ left: resolvedLeft,
1158
1393
  right: resolvedLeft + resolvedWidth,
1159
1394
  rowTop: index * rowHeight
1160
1395
  });
@@ -1187,18 +1422,27 @@ var DependencyLines = React5.memo(({
1187
1422
  fromY = predecessor.rowTop + rowHeight - 10;
1188
1423
  toY = successor.rowTop + 6;
1189
1424
  }
1190
- const from = { x: predecessor.right, y: fromY };
1191
- const to = { x: successor.left, y: toY };
1192
- const path = calculateOrthogonalPath(from, to);
1425
+ const fromX = edge.type === "SS" || edge.type === "SF" ? predecessor.left : predecessor.right;
1426
+ const toX = edge.type === "FF" || edge.type === "SF" ? successor.right : successor.left;
1427
+ const arrivesFromRight = edge.type === "FF" || edge.type === "SF";
1428
+ const from = { x: fromX, y: fromY };
1429
+ const to = { x: toX, y: toY };
1430
+ const path = calculateDependencyPath(from, to, arrivesFromRight);
1193
1431
  const hasCycle = cycleInfo.has(edge.predecessorId) || cycleInfo.has(edge.successorId);
1432
+ const lag = calculateEffectiveLag(edge, predecessor, successor, monthStart, dayWidth);
1194
1433
  lines2.push({
1195
- id: `${edge.predecessorId}-${edge.successorId}`,
1434
+ id: `${edge.predecessorId}-${edge.successorId}-${edge.type}`,
1196
1435
  path,
1197
- hasCycle
1436
+ hasCycle,
1437
+ lag,
1438
+ fromX,
1439
+ toX,
1440
+ fromY,
1441
+ reverseOrder
1198
1442
  });
1199
1443
  }
1200
1444
  return lines2;
1201
- }, [tasks, taskPositions, taskIndices, cycleInfo]);
1445
+ }, [tasks, taskPositions, taskIndices, cycleInfo, monthStart, dayWidth, dragOverrides]);
1202
1446
  return /* @__PURE__ */ jsxs5(
1203
1447
  "svg",
1204
1448
  {
@@ -1247,15 +1491,28 @@ var DependencyLines = React5.memo(({
1247
1491
  }
1248
1492
  )
1249
1493
  ] }),
1250
- lines.map(({ id, path, hasCycle }) => /* @__PURE__ */ jsx6(
1251
- "path",
1252
- {
1253
- d: path,
1254
- className: hasCycle ? "gantt-dependency-path gantt-dependency-cycle" : "gantt-dependency-path",
1255
- markerEnd: hasCycle ? "url(#arrowhead-cycle)" : "url(#arrowhead)"
1256
- },
1257
- id
1258
- ))
1494
+ lines.map(({ id, path, hasCycle, lag, fromX, toX, fromY, reverseOrder }) => /* @__PURE__ */ jsxs5(React5.Fragment, { children: [
1495
+ /* @__PURE__ */ jsx6(
1496
+ "path",
1497
+ {
1498
+ d: path,
1499
+ className: hasCycle ? "gantt-dependency-path gantt-dependency-cycle" : "gantt-dependency-path",
1500
+ markerEnd: hasCycle ? "url(#arrowhead-cycle)" : "url(#arrowhead)"
1501
+ }
1502
+ ),
1503
+ lag !== 0 && /* @__PURE__ */ jsx6(
1504
+ "text",
1505
+ {
1506
+ className: "gantt-dependency-lag-label",
1507
+ x: lag < 0 ? toX + 14 : toX - 14,
1508
+ y: reverseOrder ? fromY - 4 : fromY + 12,
1509
+ textAnchor: "middle",
1510
+ fontSize: "10",
1511
+ fill: hasCycle ? "var(--gantt-dependency-cycle-color, #ef4444)" : "var(--gantt-dependency-line-color, #666666)",
1512
+ children: lag > 0 ? `+${lag}` : `${lag}`
1513
+ }
1514
+ )
1515
+ ] }, id))
1259
1516
  ]
1260
1517
  }
1261
1518
  );
@@ -1472,6 +1729,7 @@ export {
1472
1729
  TodayIndicator_default as TodayIndicator,
1473
1730
  buildAdjacencyList,
1474
1731
  calculateBezierPath,
1732
+ calculateDependencyPath,
1475
1733
  calculateGridLines,
1476
1734
  calculateGridWidth,
1477
1735
  calculateOrthogonalPath,