gantt-lib 0.1.2 → 0.3.1

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
@@ -55,6 +55,7 @@ __export(index_exports, {
55
55
  calculateTaskBar: () => calculateTaskBar,
56
56
  calculateWeekendBlocks: () => calculateWeekendBlocks,
57
57
  cascadeByLinks: () => cascadeByLinks,
58
+ computeLagFromDates: () => computeLagFromDates,
58
59
  detectCycles: () => detectCycles,
59
60
  detectEdgeZone: () => detectEdgeZone,
60
61
  formatDateLabel: () => formatDateLabel,
@@ -271,11 +272,35 @@ function detectCycles(tasks) {
271
272
  }
272
273
  return { hasCycle: false };
273
274
  }
275
+ function computeLagFromDates(linkType, predStart, predEnd, succStart, succEnd) {
276
+ const DAY_MS = 24 * 60 * 60 * 1e3;
277
+ const pS = Date.UTC(predStart.getUTCFullYear(), predStart.getUTCMonth(), predStart.getUTCDate());
278
+ const pE = Date.UTC(predEnd.getUTCFullYear(), predEnd.getUTCMonth(), predEnd.getUTCDate());
279
+ const sS = Date.UTC(succStart.getUTCFullYear(), succStart.getUTCMonth(), succStart.getUTCDate());
280
+ const sE = Date.UTC(succEnd.getUTCFullYear(), succEnd.getUTCMonth(), succEnd.getUTCDate());
281
+ switch (linkType) {
282
+ case "FS":
283
+ return Math.round((sS - pE) / DAY_MS) - 1;
284
+ case "SS":
285
+ return Math.round((sS - pS) / DAY_MS);
286
+ case "FF":
287
+ return Math.round((sE - pE) / DAY_MS);
288
+ case "SF":
289
+ return Math.round((sE - pS) / DAY_MS) + 1;
290
+ }
291
+ }
274
292
  function calculateSuccessorDate(predecessorStart, predecessorEnd, linkType, lag = 0) {
275
- const baseDate = linkType.startsWith("F") ? predecessorEnd : predecessorStart;
276
- const lagMs = lag * 24 * 60 * 60 * 1e3;
277
- const resultDate = new Date(baseDate.getTime() + lagMs);
278
- return resultDate;
293
+ const DAY_MS = 24 * 60 * 60 * 1e3;
294
+ switch (linkType) {
295
+ case "FS":
296
+ return new Date(predecessorEnd.getTime() + (lag + 1) * DAY_MS);
297
+ case "SS":
298
+ return new Date(predecessorStart.getTime() + lag * DAY_MS);
299
+ case "FF":
300
+ return new Date(predecessorEnd.getTime() + lag * DAY_MS);
301
+ case "SF":
302
+ return new Date(predecessorStart.getTime() + (lag - 1) * DAY_MS);
303
+ }
279
304
  }
280
305
  function validateDependencies(tasks) {
281
306
  const errors = [];
@@ -422,35 +447,10 @@ function recalculateIncomingLags(task, newStartDate, newEndDate, allTasks) {
422
447
  return task.dependencies.map((dep) => {
423
448
  const predecessor = taskById.get(dep.taskId);
424
449
  if (!predecessor) return dep;
425
- if (dep.type === "FS") {
426
- const predEnd = new Date(predecessor.endDate);
427
- const lagDays = Math.round(
428
- (Date.UTC(newStartDate.getUTCFullYear(), newStartDate.getUTCMonth(), newStartDate.getUTCDate()) - Date.UTC(predEnd.getUTCFullYear(), predEnd.getUTCMonth(), predEnd.getUTCDate())) / (24 * 60 * 60 * 1e3)
429
- );
430
- return { ...dep, lag: lagDays };
431
- }
432
- if (dep.type === "SS") {
433
- const predStart = new Date(predecessor.startDate);
434
- const lagDays = Math.max(0, Math.round(
435
- (Date.UTC(newStartDate.getUTCFullYear(), newStartDate.getUTCMonth(), newStartDate.getUTCDate()) - Date.UTC(predStart.getUTCFullYear(), predStart.getUTCMonth(), predStart.getUTCDate())) / (24 * 60 * 60 * 1e3)
436
- ));
437
- return { ...dep, lag: lagDays };
438
- }
439
- if (dep.type === "FF") {
440
- const predEnd = new Date(predecessor.endDate);
441
- const lagDays = Math.round(
442
- (Date.UTC(newEndDate.getUTCFullYear(), newEndDate.getUTCMonth(), newEndDate.getUTCDate()) - Date.UTC(predEnd.getUTCFullYear(), predEnd.getUTCMonth(), predEnd.getUTCDate())) / (24 * 60 * 60 * 1e3)
443
- );
444
- return { ...dep, lag: lagDays };
445
- }
446
- if (dep.type === "SF") {
447
- const predStart = new Date(predecessor.startDate);
448
- const lagDays = Math.min(0, Math.round(
449
- (Date.UTC(newEndDate.getUTCFullYear(), newEndDate.getUTCMonth(), newEndDate.getUTCDate()) - Date.UTC(predStart.getUTCFullYear(), predStart.getUTCMonth(), predStart.getUTCDate()) + 24 * 60 * 60 * 1e3) / (24 * 60 * 60 * 1e3)
450
- ));
451
- return { ...dep, lag: lagDays };
452
- }
453
- return dep;
450
+ const predStart = new Date(predecessor.startDate);
451
+ const predEnd = new Date(predecessor.endDate);
452
+ const lagDays = computeLagFromDates(dep.type, predStart, predEnd, newStartDate, newEndDate);
453
+ return { ...dep, lag: lagDays };
454
454
  });
455
455
  }
456
456
  function getAllDependencyEdges(tasks) {
@@ -1169,29 +1169,51 @@ var useTaskDrag = (options) => {
1169
1169
  // src/components/TaskRow/TaskRow.tsx
1170
1170
  var import_jsx_runtime2 = require("react/jsx-runtime");
1171
1171
  var arePropsEqual = (prevProps, nextProps) => {
1172
- 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.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;
1172
+ 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.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;
1173
1173
  };
1174
1174
  var TaskRow = import_react3.default.memo(
1175
- ({ task, monthStart, dayWidth, rowHeight, onChange, onDragStateChange, rowIndex, allTasks, enableAutoSchedule, disableConstraints, overridePosition, onCascadeProgress, onCascade, divider }) => {
1175
+ ({ task, monthStart, dayWidth, rowHeight, onChange, onDragStateChange, rowIndex, allTasks, enableAutoSchedule, disableConstraints, overridePosition, onCascadeProgress, onCascade, divider, highlightExpiredTasks }) => {
1176
1176
  const { divider: taskDivider } = task;
1177
1177
  const taskStartDate = (0, import_react3.useMemo)(() => parseUTCDate(task.startDate), [task.startDate]);
1178
1178
  const taskEndDate = (0, import_react3.useMemo)(() => parseUTCDate(task.endDate), [task.endDate]);
1179
+ const isExpired = (0, import_react3.useMemo)(() => {
1180
+ if (!highlightExpiredTasks) return false;
1181
+ const now = /* @__PURE__ */ new Date();
1182
+ const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
1183
+ const tomorrow = new Date(Date.UTC(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate() + 1));
1184
+ const taskStart = parseUTCDate(task.startDate);
1185
+ const taskEnd = parseUTCDate(task.endDate);
1186
+ const actualProgress = task.progress ?? 0;
1187
+ if (actualProgress >= 100) {
1188
+ return false;
1189
+ }
1190
+ const msPerDay = 1e3 * 60 * 60 * 24;
1191
+ const taskDuration = taskEnd.getTime() - taskStart.getTime() + msPerDay;
1192
+ const isTaskEndingTodayOrTomorrow = today.getUTCFullYear() === taskEnd.getUTCFullYear() && today.getUTCMonth() === taskEnd.getUTCMonth() && today.getUTCDate() === taskEnd.getUTCDate() || tomorrow.getUTCFullYear() === taskEnd.getUTCFullYear() && tomorrow.getUTCMonth() === taskEnd.getUTCMonth() && tomorrow.getUTCDate() === taskEnd.getUTCDate();
1193
+ const elapsedCutoff = isTaskEndingTodayOrTomorrow ? new Date(today.getTime() - msPerDay) : today;
1194
+ const daysFromStart = elapsedCutoff.getTime() - taskStart.getTime();
1195
+ const todayPosition = Math.min(100, Math.max(0, daysFromStart / taskDuration * 100));
1196
+ return actualProgress < todayPosition;
1197
+ }, [task.startDate, task.endDate, task.progress, highlightExpiredTasks]);
1179
1198
  const { left, width } = (0, import_react3.useMemo)(
1180
1199
  () => calculateTaskBar(taskStartDate, taskEndDate, monthStart, dayWidth),
1181
1200
  [taskStartDate, taskEndDate, monthStart, dayWidth]
1182
1201
  );
1183
- const barColor = task.color || "var(--gantt-task-bar-default-color)";
1202
+ const barColor = isExpired ? "var(--gantt-expired-color)" : task.color || "var(--gantt-task-bar-default-color)";
1184
1203
  const progressWidth = (0, import_react3.useMemo)(() => {
1185
1204
  if (task.progress === void 0 || task.progress <= 0) return 0;
1186
1205
  return Math.min(100, Math.max(0, Math.round(task.progress)));
1187
1206
  }, [task.progress]);
1188
1207
  const progressColor = (0, import_react3.useMemo)(() => {
1208
+ if (isExpired) {
1209
+ return "color-mix(in srgb, var(--gantt-expired-color) 40%, black)";
1210
+ }
1189
1211
  if (progressWidth === 100) {
1190
1212
  return task.accepted ? "var(--gantt-progress-accepted, #22c55e)" : "var(--gantt-progress-completed, #fbbf24)";
1191
1213
  }
1192
1214
  const baseColor = task.color || "var(--gantt-task-bar-default-color)";
1193
1215
  return `color-mix(in srgb, ${baseColor} 40%, black)`;
1194
- }, [progressWidth, task.accepted, task.color]);
1216
+ }, [isExpired, progressWidth, task.accepted, task.color]);
1195
1217
  const handleDragEnd = (result) => {
1196
1218
  const updatedTask = {
1197
1219
  ...task,
@@ -1477,60 +1499,11 @@ var DragGuideLines_default = DragGuideLines;
1477
1499
  var import_react6 = __toESM(require("react"));
1478
1500
  var import_jsx_runtime6 = require("react/jsx-runtime");
1479
1501
  function calculateEffectiveLag(edge, predPosition, succPosition, monthStart, dayWidth) {
1480
- const predStartDate = pixelsToDate(predPosition.left, monthStart, dayWidth);
1481
- const predEndDate = pixelsToDate(predPosition.right - dayWidth, monthStart, dayWidth);
1482
- const succStartDate = pixelsToDate(succPosition.left, monthStart, dayWidth);
1483
- const succEndDate = pixelsToDate(succPosition.right - dayWidth, monthStart, dayWidth);
1484
- let lagMs = 0;
1485
- switch (edge.type) {
1486
- case "FS":
1487
- lagMs = Date.UTC(
1488
- succStartDate.getUTCFullYear(),
1489
- succStartDate.getUTCMonth(),
1490
- succStartDate.getUTCDate()
1491
- ) - Date.UTC(
1492
- predEndDate.getUTCFullYear(),
1493
- predEndDate.getUTCMonth(),
1494
- predEndDate.getUTCDate()
1495
- ) - 24 * 60 * 60 * 1e3;
1496
- break;
1497
- case "SS":
1498
- lagMs = Date.UTC(
1499
- succStartDate.getUTCFullYear(),
1500
- succStartDate.getUTCMonth(),
1501
- succStartDate.getUTCDate()
1502
- ) - Date.UTC(
1503
- predStartDate.getUTCFullYear(),
1504
- predStartDate.getUTCMonth(),
1505
- predStartDate.getUTCDate()
1506
- );
1507
- break;
1508
- case "FF":
1509
- lagMs = Date.UTC(
1510
- succEndDate.getUTCFullYear(),
1511
- succEndDate.getUTCMonth(),
1512
- succEndDate.getUTCDate()
1513
- ) - Date.UTC(
1514
- predEndDate.getUTCFullYear(),
1515
- predEndDate.getUTCMonth(),
1516
- predEndDate.getUTCDate()
1517
- );
1518
- break;
1519
- case "SF":
1520
- lagMs = Date.UTC(
1521
- succEndDate.getUTCFullYear(),
1522
- succEndDate.getUTCMonth(),
1523
- succEndDate.getUTCDate()
1524
- ) - Date.UTC(
1525
- predStartDate.getUTCFullYear(),
1526
- predStartDate.getUTCMonth(),
1527
- predStartDate.getUTCDate()
1528
- ) + 24 * 60 * 60 * 1e3;
1529
- break;
1530
- default:
1531
- return 0;
1532
- }
1533
- return Math.round(lagMs / (24 * 60 * 60 * 1e3));
1502
+ const predStart = pixelsToDate(predPosition.left, monthStart, dayWidth);
1503
+ const predEnd = pixelsToDate(predPosition.right - dayWidth, monthStart, dayWidth);
1504
+ const succStart = pixelsToDate(succPosition.left, monthStart, dayWidth);
1505
+ const succEnd = pixelsToDate(succPosition.right - dayWidth, monthStart, dayWidth);
1506
+ return computeLagFromDates(edge.type, predStart, predEnd, succStart, succEnd);
1534
1507
  }
1535
1508
  var DependencyLines = import_react6.default.memo(({
1536
1509
  tasks,
@@ -1538,7 +1511,8 @@ var DependencyLines = import_react6.default.memo(({
1538
1511
  dayWidth,
1539
1512
  rowHeight,
1540
1513
  gridWidth,
1541
- dragOverrides
1514
+ dragOverrides,
1515
+ selectedDep
1542
1516
  }) => {
1543
1517
  const { taskPositions, taskIndices } = (0, import_react6.useMemo)(() => {
1544
1518
  const positions = /* @__PURE__ */ new Map();
@@ -1652,30 +1626,60 @@ var DependencyLines = import_react6.default.memo(({
1652
1626
  }
1653
1627
  )
1654
1628
  }
1655
- )
1656
- ] }),
1657
- lines.map(({ id, path, hasCycle, lag, fromX, toX, fromY, reverseOrder }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react6.default.Fragment, { children: [
1658
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1659
- "path",
1660
- {
1661
- d: path,
1662
- className: hasCycle ? "gantt-dependency-path gantt-dependency-cycle" : "gantt-dependency-path",
1663
- markerEnd: hasCycle ? "url(#arrowhead-cycle)" : "url(#arrowhead)"
1664
- }
1665
1629
  ),
1666
- lag !== 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1667
- "text",
1630
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1631
+ "marker",
1668
1632
  {
1669
- className: "gantt-dependency-lag-label",
1670
- x: lag < 0 ? toX + 14 : toX - 14,
1671
- y: reverseOrder ? fromY - 4 : fromY + 12,
1672
- textAnchor: "middle",
1673
- fontSize: "10",
1674
- fill: hasCycle ? "var(--gantt-dependency-cycle-color, #ef4444)" : "var(--gantt-dependency-line-color, #666666)",
1675
- children: lag > 0 ? `+${lag}` : `${lag}`
1633
+ id: "arrowhead-selected",
1634
+ markerWidth: "8",
1635
+ markerHeight: "6",
1636
+ markerUnits: "userSpaceOnUse",
1637
+ refX: "7",
1638
+ refY: "3",
1639
+ orient: "auto",
1640
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1641
+ "polygon",
1642
+ {
1643
+ points: "0 0, 8 3, 0 6",
1644
+ fill: "#ef4444"
1645
+ }
1646
+ )
1676
1647
  }
1677
1648
  )
1678
- ] }, id))
1649
+ ] }),
1650
+ lines.map(({ id, path, hasCycle, lag, fromX, toX, fromY, reverseOrder }) => {
1651
+ const isSelected = selectedDep != null && id === `${selectedDep.predecessorId}-${selectedDep.successorId}-${selectedDep.linkType}`;
1652
+ let pathClassName = "gantt-dependency-path";
1653
+ if (isSelected) pathClassName += " gantt-dependency-selected";
1654
+ else if (hasCycle) pathClassName += " gantt-dependency-cycle";
1655
+ let markerEnd;
1656
+ if (isSelected) markerEnd = "url(#arrowhead-selected)";
1657
+ else if (hasCycle) markerEnd = "url(#arrowhead-cycle)";
1658
+ else markerEnd = "url(#arrowhead)";
1659
+ const lagColor = isSelected ? "#ef4444" : hasCycle ? "var(--gantt-dependency-cycle-color, #ef4444)" : "var(--gantt-dependency-line-color, #666666)";
1660
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react6.default.Fragment, { children: [
1661
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1662
+ "path",
1663
+ {
1664
+ d: path,
1665
+ className: pathClassName,
1666
+ markerEnd
1667
+ }
1668
+ ),
1669
+ lag !== 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1670
+ "text",
1671
+ {
1672
+ className: "gantt-dependency-lag-label",
1673
+ x: lag < 0 ? toX + 14 : toX - 14,
1674
+ y: reverseOrder ? fromY - 4 : fromY + 12,
1675
+ textAnchor: "middle",
1676
+ fontSize: "10",
1677
+ fill: lagColor,
1678
+ children: lag > 0 ? `+${lag}` : `${lag}`
1679
+ }
1680
+ )
1681
+ ] }, id);
1682
+ })
1679
1683
  ]
1680
1684
  }
1681
1685
  );
@@ -1684,17 +1688,51 @@ DependencyLines.displayName = "DependencyLines";
1684
1688
  var DependencyLines_default = DependencyLines;
1685
1689
 
1686
1690
  // src/components/TaskList/TaskList.tsx
1687
- var import_react11 = require("react");
1691
+ var import_react11 = __toESM(require("react"));
1692
+
1693
+ // src/components/ui/Popover.tsx
1694
+ var RadixPopover = __toESM(require("@radix-ui/react-popover"));
1695
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1696
+ var Popover = ({ open, onOpenChange, children }) => {
1697
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(RadixPopover.Root, { open, onOpenChange, children });
1698
+ };
1699
+ var PopoverTrigger = RadixPopover.Trigger;
1700
+ var PopoverContent = ({
1701
+ children,
1702
+ className,
1703
+ align = "start",
1704
+ side = "bottom",
1705
+ portal = true,
1706
+ collisionPadding = 8,
1707
+ onInteractOutside
1708
+ }) => {
1709
+ const content = /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1710
+ RadixPopover.Content,
1711
+ {
1712
+ className: `gantt-popover${className ? ` ${className}` : ""}`,
1713
+ align,
1714
+ side,
1715
+ collisionPadding,
1716
+ sideOffset: 4,
1717
+ onInteractOutside,
1718
+ children
1719
+ }
1720
+ );
1721
+ if (portal) {
1722
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(RadixPopover.Portal, { children: content });
1723
+ }
1724
+ return content;
1725
+ };
1688
1726
 
1689
1727
  // src/components/TaskList/TaskListRow.tsx
1690
1728
  var import_react10 = __toESM(require("react"));
1691
1729
 
1692
1730
  // src/components/ui/Input.tsx
1693
1731
  var import_react7 = __toESM(require("react"));
1694
- var import_jsx_runtime7 = require("react/jsx-runtime");
1732
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1695
1733
  var Input = import_react7.default.forwardRef(
1696
1734
  ({ className, ...props }, ref) => {
1697
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1735
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1698
1736
  "input",
1699
1737
  {
1700
1738
  ref,
@@ -1714,7 +1752,7 @@ var import_date_fns3 = require("date-fns");
1714
1752
  var import_react8 = require("react");
1715
1753
  var import_date_fns2 = require("date-fns");
1716
1754
  var import_locale2 = require("date-fns/locale");
1717
- var import_jsx_runtime8 = require("react/jsx-runtime");
1755
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1718
1756
  function getDayClassName(day, selected) {
1719
1757
  const classes = ["gantt-day-btn"];
1720
1758
  if (selected && (0, import_date_fns2.isSameDay)(day, selected)) classes.push("selected");
@@ -1784,12 +1822,12 @@ var Calendar = ({
1784
1822
  const emptyDays = ((0, import_date_fns2.getDay)(firstDay) + 6) % 7;
1785
1823
  const monthKey = (0, import_date_fns2.format)(month, "yyyy-MM");
1786
1824
  const monthLabel = (0, import_date_fns2.format)(month, "LLLL yyyy", { locale: import_locale2.ru });
1787
- const emptyCells = Array.from({ length: emptyDays }, (_, i) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "gantt-cal-empty-day" }, `e-${i}`));
1825
+ const emptyCells = Array.from({ length: emptyDays }, (_, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "gantt-cal-empty-day" }, `e-${i}`));
1788
1826
  const dayCells = Array.from({ length: totalDays }, (_, i) => {
1789
1827
  const dayNum = i + 1;
1790
1828
  const day = new Date(month.getFullYear(), month.getMonth(), dayNum);
1791
1829
  const className = getDayClassName(day, selected);
1792
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1830
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1793
1831
  "button",
1794
1832
  {
1795
1833
  type: "button",
@@ -1805,9 +1843,9 @@ var Calendar = ({
1805
1843
  dayNum
1806
1844
  );
1807
1845
  });
1808
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "gantt-cal-month", "data-month": monthKey, children: [
1809
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "gantt-cal-month-header", children: monthLabel }),
1810
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "gantt-cal-month-days", children: [
1846
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "gantt-cal-month", "data-month": monthKey, children: [
1847
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "gantt-cal-month-header", children: monthLabel }),
1848
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "gantt-cal-month-days", children: [
1811
1849
  emptyCells,
1812
1850
  dayCells
1813
1851
  ] })
@@ -1819,42 +1857,10 @@ var Calendar = ({
1819
1857
  () => months.map(renderMonth),
1820
1858
  [months, renderMonth]
1821
1859
  );
1822
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { ref: scrollRef, className: "gantt-cal-container", children: renderedMonths });
1860
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { ref: scrollRef, className: "gantt-cal-container", children: renderedMonths });
1823
1861
  };
1824
1862
  Calendar.displayName = "Calendar";
1825
1863
 
1826
- // src/components/ui/Popover.tsx
1827
- var RadixPopover = __toESM(require("@radix-ui/react-popover"));
1828
- var import_jsx_runtime9 = require("react/jsx-runtime");
1829
- var Popover = ({ open, onOpenChange, children }) => {
1830
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(RadixPopover.Root, { open, onOpenChange, children });
1831
- };
1832
- var PopoverTrigger = RadixPopover.Trigger;
1833
- var PopoverContent = ({
1834
- children,
1835
- className,
1836
- align = "start",
1837
- side = "bottom",
1838
- portal = true,
1839
- collisionPadding = 8
1840
- }) => {
1841
- const content = /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1842
- RadixPopover.Content,
1843
- {
1844
- className: `gantt-popover${className ? ` ${className}` : ""}`,
1845
- align,
1846
- side,
1847
- collisionPadding,
1848
- sideOffset: 4,
1849
- children
1850
- }
1851
- );
1852
- if (portal) {
1853
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(RadixPopover.Portal, { children: content });
1854
- }
1855
- return content;
1856
- };
1857
-
1858
1864
  // src/components/ui/DatePicker.tsx
1859
1865
  var import_jsx_runtime10 = require("react/jsx-runtime");
1860
1866
  var DatePicker = ({
@@ -1919,19 +1925,198 @@ var DatePicker = ({
1919
1925
  };
1920
1926
  DatePicker.displayName = "DatePicker";
1921
1927
 
1922
- // src/components/TaskList/TaskListRow.tsx
1928
+ // src/components/TaskList/DepIcons.tsx
1923
1929
  var import_jsx_runtime11 = require("react/jsx-runtime");
1930
+ var DepIconFS = () => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1931
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "m10 15 5 5 5-5" }),
1932
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M4 4h7a4 4 0 0 1 4 4v12" })
1933
+ ] });
1934
+ var DepIconSS = () => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1935
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M3 5v14" }),
1936
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M21 12H7" }),
1937
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "m15 18 6-6-6-6" })
1938
+ ] });
1939
+ var DepIconFF = () => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1940
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M17 12H3" }),
1941
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "m11 18 6-6-6-6" }),
1942
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M21 5v14" })
1943
+ ] });
1944
+ var DepIconSF = () => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1945
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "m14 15-5 5-5-5" }),
1946
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M20 4h-7a4 4 0 0 0-4 4v12" })
1947
+ ] });
1948
+ var LINK_TYPE_ICONS = {
1949
+ FS: DepIconFS,
1950
+ SS: DepIconSS,
1951
+ FF: DepIconFF,
1952
+ SF: DepIconSF
1953
+ };
1954
+ var LINK_TYPE_LABELS = {
1955
+ FS: "\u041E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u0435-\u043D\u0430\u0447\u0430\u043B\u043E",
1956
+ SS: "\u041D\u0430\u0447\u0430\u043B\u043E-\u043D\u0430\u0447\u0430\u043B\u043E",
1957
+ FF: "\u041E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u0435-\u043E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u0435",
1958
+ SF: "\u041D\u0430\u0447\u0430\u043B\u043E-\u043E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u0435"
1959
+ };
1960
+
1961
+ // src/components/TaskList/TaskListRow.tsx
1962
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1963
+ var TrashIcon = () => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1964
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6" }),
1965
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M3 6h18" }),
1966
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })
1967
+ ] });
1968
+ function formatDepDescription(type, lag) {
1969
+ const effectiveLag = lag ?? 0;
1970
+ if (type === "FS") {
1971
+ if (effectiveLag > 0) return `\u041D\u0430\u0447\u0430\u0442\u044C \u0447\u0435\u0440\u0435\u0437 ${effectiveLag} \u0434\u043D. \u043F\u043E\u0441\u043B\u0435 \u043E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u044F`;
1972
+ if (effectiveLag < 0) return `\u041D\u0430\u0447\u0430\u0442\u044C \u0437\u0430 ${Math.abs(effectiveLag)} \u0434\u043D. \u0434\u043E \u043E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u044F`;
1973
+ return `\u041D\u0430\u0447\u0430\u0442\u044C \u0441\u0440\u0430\u0437\u0443 \u043F\u043E\u0441\u043B\u0435 \u043E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u044F`;
1974
+ }
1975
+ if (type === "FF") {
1976
+ if (effectiveLag > 0) return `\u0417\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044C \u0447\u0435\u0440\u0435\u0437 ${effectiveLag} \u0434\u043D. \u043F\u043E\u0441\u043B\u0435 \u043E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u044F`;
1977
+ if (effectiveLag < 0) return `\u0417\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044C \u0437\u0430 ${Math.abs(effectiveLag)} \u0434\u043D. \u0434\u043E \u043E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u044F`;
1978
+ return `\u0417\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044C \u043F\u043E\u0441\u043B\u0435 \u043E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u044F`;
1979
+ }
1980
+ if (type === "SS") {
1981
+ if (effectiveLag > 0) return `\u041D\u0430\u0447\u0430\u0442\u044C \u0447\u0435\u0440\u0435\u0437 ${effectiveLag} \u0434\u043D. \u043F\u043E\u0441\u043B\u0435 \u043D\u0430\u0447\u0430\u043B\u0430`;
1982
+ if (effectiveLag < 0) return `\u041D\u0430\u0447\u0430\u0442\u044C \u0437\u0430 ${Math.abs(effectiveLag)} \u0434\u043D. \u0434\u043E \u043D\u0430\u0447\u0430\u043B\u0430`;
1983
+ return `\u041D\u0430\u0447\u0430\u0442\u044C \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 \u043D\u0430\u0447\u0430\u043B\u043E\u043C`;
1984
+ }
1985
+ if (type === "SF") {
1986
+ if (effectiveLag > 0) return `\u0417\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044C \u0447\u0435\u0440\u0435\u0437 ${effectiveLag} \u0434\u043D. \u043F\u043E\u0441\u043B\u0435 \u043D\u0430\u0447\u0430\u043B\u0430`;
1987
+ if (effectiveLag < 0) return `\u0417\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044C \u0437\u0430 ${Math.abs(effectiveLag)} \u0434\u043D. \u0434\u043E \u043D\u0430\u0447\u0430\u043B\u0430`;
1988
+ return `\u0417\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044C \u0434\u043E \u043D\u0430\u0447\u0430\u043B\u0430`;
1989
+ }
1990
+ return "";
1991
+ }
1992
+ var DepChip = ({
1993
+ lag,
1994
+ dep,
1995
+ taskId,
1996
+ predecessorName,
1997
+ selectedChip,
1998
+ disableDependencyEditing,
1999
+ onChipSelect,
2000
+ onRowClick,
2001
+ onScrollToTask,
2002
+ onRemoveDependency,
2003
+ onChipSelectClear
2004
+ }) => {
2005
+ const isSelected = selectedChip?.successorId === taskId && selectedChip?.predecessorId === dep.taskId && selectedChip?.linkType === dep.type;
2006
+ const handleClick = (e) => {
2007
+ e.stopPropagation();
2008
+ if (disableDependencyEditing) return;
2009
+ onChipSelect?.(isSelected ? null : { successorId: taskId, predecessorId: dep.taskId, linkType: dep.type });
2010
+ if (!isSelected) {
2011
+ onRowClick?.(taskId);
2012
+ onScrollToTask?.(taskId);
2013
+ }
2014
+ };
2015
+ const handleTrashClick = (e) => {
2016
+ e.stopPropagation();
2017
+ onRemoveDependency?.(taskId, dep.taskId, dep.type);
2018
+ onChipSelectClear();
2019
+ };
2020
+ const Icon = LINK_TYPE_ICONS[dep.type];
2021
+ const depPrefix = formatDepDescription(dep.type, lag);
2022
+ const depName = predecessorName ?? dep.taskId;
2023
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Popover, { open: isSelected, onOpenChange: (open) => {
2024
+ }, children: [
2025
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "gantt-tl-dep-chip-wrapper", children: [
2026
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2027
+ "span",
2028
+ {
2029
+ className: `gantt-tl-dep-chip${isSelected ? " gantt-tl-dep-chip-selected" : ""}`,
2030
+ onClick: handleClick,
2031
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
2032
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Icon, {}),
2033
+ lag != null && lag !== 0 ? lag > 0 ? `+${lag}` : `${lag}` : ""
2034
+ ] })
2035
+ }
2036
+ ),
2037
+ !disableDependencyEditing && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2038
+ "button",
2039
+ {
2040
+ type: "button",
2041
+ className: "gantt-tl-dep-chip-trash",
2042
+ "aria-label": "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u0432\u044F\u0437\u044C",
2043
+ onClick: handleTrashClick,
2044
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TrashIcon, {})
2045
+ }
2046
+ )
2047
+ ] }) }),
2048
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2049
+ PopoverContent,
2050
+ {
2051
+ portal: true,
2052
+ side: "bottom",
2053
+ align: "start",
2054
+ className: "gantt-tl-dep-info-popover",
2055
+ onInteractOutside: (event) => {
2056
+ const target = event.target;
2057
+ if (target?.closest?.(".gantt-tl-dep-chip") || target?.closest?.(".gantt-tl-dep-delete-label") || target?.closest?.(".gantt-tl-dep-chip-trash")) {
2058
+ event.preventDefault();
2059
+ } else {
2060
+ onChipSelectClear();
2061
+ }
2062
+ },
2063
+ children: [
2064
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "gantt-tl-dep-info-prefix", children: depPrefix }),
2065
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "gantt-tl-dep-info-name", children: depName })
2066
+ ]
2067
+ }
2068
+ )
2069
+ ] });
2070
+ };
1924
2071
  var toISODate = (value) => {
1925
2072
  if (value instanceof Date) return value.toISOString().split("T")[0];
1926
2073
  if (typeof value === "string" && value.includes("T")) return value.split("T")[0];
1927
2074
  return value;
1928
2075
  };
1929
2076
  var TaskListRow = import_react10.default.memo(
1930
- ({ task, rowIndex, rowHeight, onTaskChange, selectedTaskId, onRowClick, disableTaskNameEditing = false }) => {
2077
+ ({
2078
+ task,
2079
+ rowIndex,
2080
+ rowHeight,
2081
+ onTaskChange,
2082
+ selectedTaskId,
2083
+ onRowClick,
2084
+ disableTaskNameEditing = false,
2085
+ disableDependencyEditing = false,
2086
+ allTasks = [],
2087
+ activeLinkType,
2088
+ selectingPredecessorFor,
2089
+ onSetSelectingPredecessorFor,
2090
+ onAddDependency,
2091
+ onRemoveDependency,
2092
+ selectedChip,
2093
+ onChipSelect,
2094
+ onScrollToTask
2095
+ }) => {
1931
2096
  const [editingName, setEditingName] = (0, import_react10.useState)(false);
1932
2097
  const [nameValue, setNameValue] = (0, import_react10.useState)("");
1933
2098
  const nameInputRef = (0, import_react10.useRef)(null);
2099
+ const [overflowOpen, setOverflowOpen] = (0, import_react10.useState)(false);
1934
2100
  const isSelected = selectedTaskId === task.id;
2101
+ const isPicking = selectingPredecessorFor != null;
2102
+ const isSourceRow = isPicking && selectingPredecessorFor === task.id;
2103
+ const chips = (0, import_react10.useMemo)(() => {
2104
+ const succStart = new Date(task.startDate);
2105
+ const succEnd = new Date(task.endDate);
2106
+ const taskById = new Map((allTasks ?? []).map((t) => [t.id, t]));
2107
+ return (task.dependencies ?? []).map((dep) => {
2108
+ const pred = taskById.get(dep.taskId);
2109
+ const lag = pred ? computeLagFromDates(
2110
+ dep.type,
2111
+ new Date(pred.startDate),
2112
+ new Date(pred.endDate),
2113
+ succStart,
2114
+ succEnd
2115
+ ) : dep.lag ?? 0;
2116
+ return { dep, lag, predecessorName: pred?.name ?? dep.taskId };
2117
+ });
2118
+ }, [task.dependencies, task.startDate, task.endDate, allTasks]);
2119
+ const linkWord = chips.length <= 4 ? "\u0441\u0432\u044F\u0437\u0438" : "\u0441\u0432\u044F\u0437\u0435\u0439";
1935
2120
  (0, import_react10.useEffect)(() => {
1936
2121
  if (editingName && nameInputRef.current) {
1937
2122
  nameInputRef.current.focus();
@@ -1977,18 +2162,60 @@ var TaskListRow = import_react10.default.memo(
1977
2162
  const handleRowClickInternal = (0, import_react10.useCallback)(() => {
1978
2163
  onRowClick?.(task.id);
1979
2164
  }, [task.id, onRowClick]);
2165
+ const handleNumberClick = (0, import_react10.useCallback)((e) => {
2166
+ e.stopPropagation();
2167
+ onRowClick?.(task.id);
2168
+ onScrollToTask?.(task.id);
2169
+ }, [task.id, onRowClick, onScrollToTask]);
2170
+ const handleAddClick = (0, import_react10.useCallback)((e) => {
2171
+ e.stopPropagation();
2172
+ onSetSelectingPredecessorFor?.(task.id);
2173
+ }, [task.id, onSetSelectingPredecessorFor]);
2174
+ const handlePredecessorPick = (0, import_react10.useCallback)((e) => {
2175
+ e.stopPropagation();
2176
+ if (!isPicking || isSourceRow) return;
2177
+ if (!selectingPredecessorFor || !activeLinkType) return;
2178
+ onAddDependency?.(task.id, selectingPredecessorFor, activeLinkType);
2179
+ }, [isPicking, isSourceRow, selectingPredecessorFor, task.id, activeLinkType, onAddDependency]);
2180
+ const isSelectedPredecessor = selectedChip != null && selectedChip.predecessorId === task.id;
2181
+ const handleDeleteSelected = (0, import_react10.useCallback)((e) => {
2182
+ e.stopPropagation();
2183
+ if (!selectedChip) return;
2184
+ onRemoveDependency?.(selectedChip.successorId, selectedChip.predecessorId, selectedChip.linkType);
2185
+ onChipSelect?.(null);
2186
+ }, [selectedChip, onRemoveDependency, onChipSelect]);
1980
2187
  const startDateISO = toISODate(task.startDate);
1981
2188
  const endDateISO = toISODate(task.endDate);
1982
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
2189
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1983
2190
  "div",
1984
2191
  {
1985
- className: `gantt-tl-row ${isSelected ? "gantt-tl-row-selected" : ""}`,
2192
+ className: [
2193
+ "gantt-tl-row",
2194
+ isSelected ? "gantt-tl-row-selected" : "",
2195
+ isPicking && !isSourceRow ? "gantt-tl-row-picking" : "",
2196
+ isSourceRow ? "gantt-tl-row-picking-self" : ""
2197
+ ].filter(Boolean).join(" "),
1986
2198
  style: { minHeight: `${rowHeight}px` },
1987
2199
  onClick: handleRowClickInternal,
1988
2200
  children: [
1989
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "gantt-tl-cell gantt-tl-cell-number", children: rowIndex + 1 }),
1990
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "gantt-tl-cell gantt-tl-cell-name", children: [
1991
- editingName && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2201
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2202
+ "div",
2203
+ {
2204
+ className: "gantt-tl-cell gantt-tl-cell-number",
2205
+ onClick: handleNumberClick,
2206
+ title: "\u041F\u0435\u0440\u0435\u0439\u0442\u0438 \u043A \u0440\u0430\u0431\u043E\u0442\u0435",
2207
+ children: [
2208
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "gantt-tl-num-label", children: rowIndex + 1 }),
2209
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("svg", { className: "gantt-tl-num-icon", xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
2210
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M17 12H3" }),
2211
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "m11 18 6-6-6-6" }),
2212
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M21 5v14" })
2213
+ ] })
2214
+ ]
2215
+ }
2216
+ ),
2217
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-cell gantt-tl-cell-name", children: [
2218
+ editingName && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1992
2219
  Input,
1993
2220
  {
1994
2221
  ref: nameInputRef,
@@ -2001,7 +2228,7 @@ var TaskListRow = import_react10.default.memo(
2001
2228
  onClick: (e) => e.stopPropagation()
2002
2229
  }
2003
2230
  ),
2004
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2231
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2005
2232
  "button",
2006
2233
  {
2007
2234
  type: "button",
@@ -2012,7 +2239,7 @@ var TaskListRow = import_react10.default.memo(
2012
2239
  }
2013
2240
  )
2014
2241
  ] }),
2015
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "gantt-tl-cell gantt-tl-cell-date", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2242
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "gantt-tl-cell gantt-tl-cell-date", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2016
2243
  DatePicker,
2017
2244
  {
2018
2245
  value: startDateISO,
@@ -2022,7 +2249,7 @@ var TaskListRow = import_react10.default.memo(
2022
2249
  disabled: task.locked
2023
2250
  }
2024
2251
  ) }),
2025
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "gantt-tl-cell gantt-tl-cell-date", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2252
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "gantt-tl-cell gantt-tl-cell-date", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2026
2253
  DatePicker,
2027
2254
  {
2028
2255
  value: endDateISO,
@@ -2031,7 +2258,97 @@ var TaskListRow = import_react10.default.memo(
2031
2258
  portal: true,
2032
2259
  disabled: task.locked
2033
2260
  }
2034
- ) })
2261
+ ) }),
2262
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2263
+ "div",
2264
+ {
2265
+ className: "gantt-tl-cell gantt-tl-cell-deps",
2266
+ onClick: isPicking && !isSourceRow ? handlePredecessorPick : void 0,
2267
+ children: isSourceRow ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "gantt-tl-dep-source-hint", children: "\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0437\u0430\u0434\u0430\u0447\u0443" }) : isSelectedPredecessor && !disableDependencyEditing ? (
2268
+ /* Full-replacement: "Зависит от [name]" → hover → "Удалить" */
2269
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2270
+ "button",
2271
+ {
2272
+ type: "button",
2273
+ className: "gantt-tl-dep-delete-label",
2274
+ onClick: handleDeleteSelected,
2275
+ "aria-label": "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u0432\u044F\u0437\u044C",
2276
+ children: [
2277
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "gantt-tl-dep-delete-label-default", children: "\u0421\u0432\u044F\u0437\u0430\u043D\u043E \u0441" }),
2278
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "gantt-tl-dep-delete-label-hover", children: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u0432\u044F\u0437\u044C" })
2279
+ ]
2280
+ }
2281
+ )
2282
+ ) : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
2283
+ chips.length >= 2 ? (
2284
+ /* 2+ deps — show only "N связей" summary chip that opens a popover */
2285
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Popover, { open: overflowOpen, onOpenChange: setOverflowOpen, children: [
2286
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2287
+ "button",
2288
+ {
2289
+ type: "button",
2290
+ className: "gantt-tl-dep-summary-chip",
2291
+ onClick: (e) => {
2292
+ e.stopPropagation();
2293
+ setOverflowOpen((v) => !v);
2294
+ },
2295
+ children: [
2296
+ chips.length,
2297
+ " ",
2298
+ linkWord
2299
+ ]
2300
+ }
2301
+ ) }),
2302
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PopoverContent, { portal: true, align: "start", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "gantt-tl-dep-overflow-list", onClick: (e) => e.stopPropagation(), children: chips.map(({ dep, lag, predecessorName }) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2303
+ DepChip,
2304
+ {
2305
+ lag,
2306
+ dep,
2307
+ taskId: task.id,
2308
+ predecessorName,
2309
+ selectedChip,
2310
+ disableDependencyEditing,
2311
+ onChipSelect,
2312
+ onRowClick,
2313
+ onScrollToTask,
2314
+ onRemoveDependency,
2315
+ onChipSelectClear: () => onChipSelect?.(null)
2316
+ },
2317
+ `${dep.taskId}-${dep.type}`
2318
+ )) }) })
2319
+ ] })
2320
+ ) : chips.length === 1 ? (
2321
+ /* Single chip — unified DepChip */
2322
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2323
+ DepChip,
2324
+ {
2325
+ lag: chips[0].lag,
2326
+ dep: chips[0].dep,
2327
+ taskId: task.id,
2328
+ predecessorName: chips[0].predecessorName,
2329
+ selectedChip,
2330
+ disableDependencyEditing,
2331
+ onChipSelect,
2332
+ onRowClick,
2333
+ onScrollToTask,
2334
+ onRemoveDependency,
2335
+ onChipSelectClear: () => onChipSelect?.(null)
2336
+ }
2337
+ )
2338
+ ) : null,
2339
+ !disableDependencyEditing && !isPicking && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2340
+ "button",
2341
+ {
2342
+ type: "button",
2343
+ className: "gantt-tl-dep-add",
2344
+ onClick: handleAddClick,
2345
+ "aria-label": "\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0441\u0432\u044F\u0437\u044C",
2346
+ children: "+"
2347
+ }
2348
+ )
2349
+ ] })
2350
+ }
2351
+ )
2035
2352
  ]
2036
2353
  }
2037
2354
  );
@@ -2040,7 +2357,8 @@ var TaskListRow = import_react10.default.memo(
2040
2357
  TaskListRow.displayName = "TaskListRow";
2041
2358
 
2042
2359
  // src/components/TaskList/TaskList.tsx
2043
- var import_jsx_runtime12 = require("react/jsx-runtime");
2360
+ var import_jsx_runtime13 = require("react/jsx-runtime");
2361
+ var LINK_TYPE_ORDER = ["FS", "SS", "FF", "SF"];
2044
2362
  var TaskList = ({
2045
2363
  tasks,
2046
2364
  rowHeight,
@@ -2050,7 +2368,10 @@ var TaskList = ({
2050
2368
  selectedTaskId,
2051
2369
  onTaskSelect,
2052
2370
  show = true,
2053
- disableTaskNameEditing = false
2371
+ disableTaskNameEditing = false,
2372
+ disableDependencyEditing = false,
2373
+ onScrollToTask,
2374
+ onSelectedChipChange
2054
2375
  }) => {
2055
2376
  const totalHeight = (0, import_react11.useMemo)(
2056
2377
  () => tasks.length * rowHeight,
@@ -2059,19 +2380,144 @@ var TaskList = ({
2059
2380
  const handleRowClick = (0, import_react11.useCallback)((taskId) => {
2060
2381
  onTaskSelect?.(taskId);
2061
2382
  }, [onTaskSelect]);
2062
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2383
+ const [activeLinkType, setActiveLinkType] = (0, import_react11.useState)("FS");
2384
+ const [selectingPredecessorFor, setSelectingPredecessorFor] = (0, import_react11.useState)(null);
2385
+ const [typeMenuOpen, setTypeMenuOpen] = (0, import_react11.useState)(false);
2386
+ const [cycleError, setCycleError] = (0, import_react11.useState)(false);
2387
+ const overlayRef = (0, import_react11.useRef)(null);
2388
+ const [selectedChip, setSelectedChip] = (0, import_react11.useState)(null);
2389
+ const handleChipSelect = (0, import_react11.useCallback)((chip) => {
2390
+ setSelectedChip(chip);
2391
+ onSelectedChipChange?.(chip);
2392
+ }, [onSelectedChipChange]);
2393
+ (0, import_react11.useEffect)(() => {
2394
+ if (!selectingPredecessorFor && !selectedChip) return;
2395
+ const handleKeyDown = (e) => {
2396
+ if (e.key === "Escape") {
2397
+ setSelectingPredecessorFor(null);
2398
+ setSelectedChip(null);
2399
+ onSelectedChipChange?.(null);
2400
+ }
2401
+ };
2402
+ const handleMouseDown = (e) => {
2403
+ const target = e.target;
2404
+ if (overlayRef.current?.contains(target)) return;
2405
+ if (target.closest?.(".gantt-popover")) return;
2406
+ setSelectingPredecessorFor(null);
2407
+ setSelectedChip(null);
2408
+ onSelectedChipChange?.(null);
2409
+ };
2410
+ document.addEventListener("keydown", handleKeyDown);
2411
+ document.addEventListener("mousedown", handleMouseDown, true);
2412
+ return () => {
2413
+ document.removeEventListener("keydown", handleKeyDown);
2414
+ document.removeEventListener("mousedown", handleMouseDown, true);
2415
+ };
2416
+ }, [selectingPredecessorFor, selectedChip, onSelectedChipChange]);
2417
+ const handleAddDependency = (0, import_react11.useCallback)((successorTaskId, predecessorTaskId, linkType) => {
2418
+ if (successorTaskId === predecessorTaskId) return;
2419
+ const successor = tasks.find((t) => t.id === successorTaskId);
2420
+ if (!successor) return;
2421
+ const alreadyExists = (successor.dependencies ?? []).some(
2422
+ (d) => d.taskId === predecessorTaskId && d.type === linkType
2423
+ );
2424
+ if (alreadyExists) {
2425
+ setSelectingPredecessorFor(null);
2426
+ return;
2427
+ }
2428
+ const newDep = { taskId: predecessorTaskId, type: linkType, lag: 0 };
2429
+ const hypothetical = tasks.map(
2430
+ (t) => t.id === successorTaskId ? { ...t, dependencies: [...t.dependencies ?? [], newDep] } : t
2431
+ );
2432
+ const validation = validateDependencies(hypothetical);
2433
+ if (!validation.isValid) {
2434
+ setCycleError(true);
2435
+ setTimeout(() => setCycleError(false), 3e3);
2436
+ return;
2437
+ }
2438
+ const updatedTask = hypothetical.find((t) => t.id === successorTaskId);
2439
+ const predecessor = tasks.find((t) => t.id === predecessorTaskId);
2440
+ if (predecessor) {
2441
+ const predStart = new Date(predecessor.startDate);
2442
+ const predEnd = new Date(predecessor.endDate);
2443
+ const constraintDate = calculateSuccessorDate(predStart, predEnd, linkType, 0);
2444
+ const origSuccessor = tasks.find((t) => t.id === successorTaskId);
2445
+ const durationMs = new Date(origSuccessor.endDate).getTime() - new Date(origSuccessor.startDate).getTime();
2446
+ let newStart;
2447
+ let newEnd;
2448
+ if (linkType === "FS" || linkType === "SS") {
2449
+ newStart = constraintDate;
2450
+ newEnd = new Date(constraintDate.getTime() + durationMs);
2451
+ } else {
2452
+ newEnd = constraintDate;
2453
+ newStart = new Date(constraintDate.getTime() - durationMs);
2454
+ }
2455
+ const snappedTask = {
2456
+ ...updatedTask,
2457
+ startDate: newStart.toISOString().split("T")[0],
2458
+ endDate: newEnd.toISOString().split("T")[0]
2459
+ };
2460
+ onTaskChange?.(snappedTask);
2461
+ } else {
2462
+ onTaskChange?.(updatedTask);
2463
+ }
2464
+ setSelectingPredecessorFor(null);
2465
+ }, [tasks, onTaskChange]);
2466
+ const handleRemoveDependency = (0, import_react11.useCallback)((taskId, predecessorTaskId, linkType) => {
2467
+ const task = tasks.find((t) => t.id === taskId);
2468
+ if (!task) return;
2469
+ const updatedDeps = (task.dependencies ?? []).filter(
2470
+ (d) => !(d.taskId === predecessorTaskId && d.type === linkType)
2471
+ );
2472
+ onTaskChange?.({ ...task, dependencies: updatedDeps });
2473
+ }, [tasks, onTaskChange]);
2474
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2063
2475
  "div",
2064
2476
  {
2477
+ ref: overlayRef,
2065
2478
  className: `gantt-tl-overlay${show ? "" : " gantt-tl-hidden"}`,
2066
2479
  style: { width: `${taskListWidth}px` },
2067
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-table", children: [
2068
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-header", style: { height: `${headerHeight + 0.5}px` }, children: [
2069
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "gantt-tl-headerCell gantt-tl-cell-number", children: "\u2116" }),
2070
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "gantt-tl-headerCell gantt-tl-cell-name", children: "\u0418\u043C\u044F" }),
2071
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "gantt-tl-headerCell gantt-tl-cell-date", children: "\u041D\u0430\u0447\u0430\u043B\u043E" }),
2072
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "gantt-tl-headerCell gantt-tl-cell-date", children: "\u041E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u0435" })
2480
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "gantt-tl-table", children: [
2481
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "gantt-tl-header", style: { height: `${headerHeight + 0.5}px` }, children: [
2482
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "gantt-tl-headerCell gantt-tl-cell-number", children: "\u2116" }),
2483
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "gantt-tl-headerCell gantt-tl-cell-name", children: "\u0418\u043C\u044F" }),
2484
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "gantt-tl-headerCell gantt-tl-cell-date", children: "\u041D\u0430\u0447\u0430\u043B\u043E" }),
2485
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "gantt-tl-headerCell gantt-tl-cell-date", children: "\u041E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u0435" }),
2486
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "gantt-tl-headerCell gantt-tl-cell-deps", style: { position: "relative" }, children: [
2487
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Popover, { open: typeMenuOpen, onOpenChange: setTypeMenuOpen, children: [
2488
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2489
+ "button",
2490
+ {
2491
+ className: "gantt-tl-dep-type-trigger",
2492
+ disabled: disableDependencyEditing,
2493
+ onClick: (e) => e.stopPropagation(),
2494
+ children: [
2495
+ "\u0421\u0432\u044F\u0437\u0438 ",
2496
+ import_react11.default.createElement(LINK_TYPE_ICONS[activeLinkType]),
2497
+ " \u25BE"
2498
+ ]
2499
+ }
2500
+ ) }),
2501
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PopoverContent, { portal: true, align: "start", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "gantt-tl-dep-type-menu", children: LINK_TYPE_ORDER.map((lt) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2502
+ "button",
2503
+ {
2504
+ className: `gantt-tl-dep-type-option${activeLinkType === lt ? " active" : ""}`,
2505
+ onClick: () => {
2506
+ setActiveLinkType(lt);
2507
+ setTypeMenuOpen(false);
2508
+ },
2509
+ children: [
2510
+ import_react11.default.createElement(LINK_TYPE_ICONS[lt]),
2511
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: LINK_TYPE_LABELS[lt] })
2512
+ ]
2513
+ },
2514
+ lt
2515
+ )) }) })
2516
+ ] }),
2517
+ cycleError && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "gantt-tl-dep-error", children: "\u0426\u0438\u043A\u043B \u0437\u0430\u0432\u0438\u0441\u0438\u043C\u043E\u0441\u0442\u0435\u0439!" })
2518
+ ] })
2073
2519
  ] }),
2074
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "gantt-tl-body", style: { height: `${totalHeight}px` }, children: tasks.map((task, index) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2520
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "gantt-tl-body", style: { height: `${totalHeight}px` }, children: tasks.map((task, index) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2075
2521
  TaskListRow,
2076
2522
  {
2077
2523
  task,
@@ -2080,7 +2526,17 @@ var TaskList = ({
2080
2526
  onTaskChange,
2081
2527
  selectedTaskId,
2082
2528
  onRowClick: handleRowClick,
2083
- disableTaskNameEditing
2529
+ disableTaskNameEditing,
2530
+ disableDependencyEditing,
2531
+ allTasks: tasks,
2532
+ activeLinkType,
2533
+ selectingPredecessorFor,
2534
+ onSetSelectingPredecessorFor: setSelectingPredecessorFor,
2535
+ onAddDependency: handleAddDependency,
2536
+ onRemoveDependency: handleRemoveDependency,
2537
+ selectedChip,
2538
+ onChipSelect: handleChipSelect,
2539
+ onScrollToTask
2084
2540
  },
2085
2541
  task.id
2086
2542
  )) })
@@ -2090,7 +2546,7 @@ var TaskList = ({
2090
2546
  };
2091
2547
 
2092
2548
  // src/components/GanttChart/GanttChart.tsx
2093
- var import_jsx_runtime13 = require("react/jsx-runtime");
2549
+ var import_jsx_runtime14 = require("react/jsx-runtime");
2094
2550
  var GanttChart = (0, import_react12.forwardRef)(({
2095
2551
  tasks,
2096
2552
  dayWidth = 40,
@@ -2104,10 +2560,13 @@ var GanttChart = (0, import_react12.forwardRef)(({
2104
2560
  onCascade,
2105
2561
  showTaskList = false,
2106
2562
  taskListWidth = 520,
2107
- disableTaskNameEditing = false
2563
+ disableTaskNameEditing = false,
2564
+ disableDependencyEditing = false,
2565
+ highlightExpiredTasks = false
2108
2566
  }, ref) => {
2109
2567
  const scrollContainerRef = (0, import_react12.useRef)(null);
2110
2568
  const [selectedTaskId, setSelectedTaskId] = (0, import_react12.useState)(null);
2569
+ const [selectedChip, setSelectedChip] = (0, import_react12.useState)(null);
2111
2570
  const dateRange = (0, import_react12.useMemo)(() => getMultiMonthDays(tasks), [tasks]);
2112
2571
  const [validationResult, setValidationResult] = (0, import_react12.useState)(null);
2113
2572
  const [cascadeOverrides, setCascadeOverrides] = (0, import_react12.useState)(/* @__PURE__ */ new Map());
@@ -2155,12 +2614,30 @@ var GanttChart = (0, import_react12.forwardRef)(({
2155
2614
  const scrollLeft = Math.round(todayOffset - containerWidth / 2 + dayWidth / 2);
2156
2615
  container.scrollLeft = Math.max(0, scrollLeft);
2157
2616
  }, [dateRange, dayWidth]);
2617
+ const scrollToTask = (0, import_react12.useCallback)((taskId) => {
2618
+ const container = scrollContainerRef.current;
2619
+ if (!container || dateRange.length === 0) return;
2620
+ const task = tasks.find((t) => t.id === taskId);
2621
+ if (!task) return;
2622
+ const taskStart = new Date(task.startDate);
2623
+ const taskStartUTC = new Date(Date.UTC(
2624
+ taskStart.getUTCFullYear(),
2625
+ taskStart.getUTCMonth(),
2626
+ taskStart.getUTCDate()
2627
+ ));
2628
+ const taskIndex = dateRange.findIndex((day) => day.getTime() === taskStartUTC.getTime());
2629
+ if (taskIndex === -1) return;
2630
+ const taskOffset = taskIndex * dayWidth;
2631
+ const scrollLeft = Math.round(taskOffset - dayWidth * 2);
2632
+ container.scrollLeft = Math.max(0, scrollLeft);
2633
+ }, [tasks, dateRange, dayWidth]);
2158
2634
  (0, import_react12.useImperativeHandle)(
2159
2635
  ref,
2160
2636
  () => ({
2161
- scrollToToday
2637
+ scrollToToday,
2638
+ scrollToTask
2162
2639
  }),
2163
- [scrollToToday]
2640
+ [scrollToToday, scrollToTask]
2164
2641
  );
2165
2642
  const [dragGuideLines, setDragGuideLines] = (0, import_react12.useState)(null);
2166
2643
  const [draggedTaskOverride, setDraggedTaskOverride] = (0, import_react12.useState)(null);
@@ -2260,15 +2737,15 @@ var GanttChart = (0, import_react12.forwardRef)(({
2260
2737
  window.removeEventListener("mouseup", handlePanEnd);
2261
2738
  };
2262
2739
  }, []);
2263
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "gantt-container", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2740
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "gantt-container", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2264
2741
  "div",
2265
2742
  {
2266
2743
  ref: scrollContainerRef,
2267
2744
  className: "gantt-scrollContainer",
2268
2745
  style: { height: containerHeight ?? "auto", cursor: "grab" },
2269
2746
  onMouseDown: handlePanStart,
2270
- children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "gantt-scrollContent", children: [
2271
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2747
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "gantt-scrollContent", children: [
2748
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2272
2749
  TaskList,
2273
2750
  {
2274
2751
  tasks,
@@ -2279,11 +2756,14 @@ var GanttChart = (0, import_react12.forwardRef)(({
2279
2756
  selectedTaskId: selectedTaskId ?? void 0,
2280
2757
  onTaskSelect: handleTaskSelect,
2281
2758
  show: showTaskList,
2282
- disableTaskNameEditing
2759
+ disableTaskNameEditing,
2760
+ disableDependencyEditing,
2761
+ onScrollToTask: scrollToTask,
2762
+ onSelectedChipChange: setSelectedChip
2283
2763
  }
2284
2764
  ),
2285
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { minWidth: `${gridWidth}px`, flex: 1 }, children: [
2286
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "gantt-stickyHeader", style: { width: `${gridWidth}px` }, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2765
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { minWidth: `${gridWidth}px`, flex: 1 }, children: [
2766
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "gantt-stickyHeader", style: { width: `${gridWidth}px` }, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2287
2767
  TimeScaleHeader_default,
2288
2768
  {
2289
2769
  days: dateRange,
@@ -2291,7 +2771,7 @@ var GanttChart = (0, import_react12.forwardRef)(({
2291
2771
  headerHeight
2292
2772
  }
2293
2773
  ) }),
2294
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2774
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
2295
2775
  "div",
2296
2776
  {
2297
2777
  className: "gantt-taskArea",
@@ -2300,7 +2780,7 @@ var GanttChart = (0, import_react12.forwardRef)(({
2300
2780
  width: `${gridWidth}px`
2301
2781
  },
2302
2782
  children: [
2303
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2783
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2304
2784
  GridBackground_default,
2305
2785
  {
2306
2786
  dateRange,
@@ -2308,8 +2788,8 @@ var GanttChart = (0, import_react12.forwardRef)(({
2308
2788
  totalHeight: totalGridHeight
2309
2789
  }
2310
2790
  ),
2311
- todayInRange && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TodayIndicator_default, { monthStart, dayWidth }),
2312
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2791
+ todayInRange && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(TodayIndicator_default, { monthStart, dayWidth }),
2792
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2313
2793
  DependencyLines_default,
2314
2794
  {
2315
2795
  tasks,
@@ -2317,10 +2797,11 @@ var GanttChart = (0, import_react12.forwardRef)(({
2317
2797
  dayWidth,
2318
2798
  rowHeight,
2319
2799
  gridWidth,
2320
- dragOverrides: dependencyOverrides
2800
+ dragOverrides: dependencyOverrides,
2801
+ selectedDep: selectedChip
2321
2802
  }
2322
2803
  ),
2323
- dragGuideLines && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2804
+ dragGuideLines && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2324
2805
  DragGuideLines_default,
2325
2806
  {
2326
2807
  isDragging: dragGuideLines.isDragging,
@@ -2330,7 +2811,7 @@ var GanttChart = (0, import_react12.forwardRef)(({
2330
2811
  totalHeight: totalGridHeight
2331
2812
  }
2332
2813
  ),
2333
- tasks.map((task, index) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2814
+ tasks.map((task, index) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2334
2815
  TaskRow_default,
2335
2816
  {
2336
2817
  task,
@@ -2353,7 +2834,8 @@ var GanttChart = (0, import_react12.forwardRef)(({
2353
2834
  disableConstraints: disableConstraints ?? false,
2354
2835
  overridePosition: cascadeOverrides.get(task.id),
2355
2836
  onCascadeProgress: handleCascadeProgress,
2356
- onCascade: handleCascade
2837
+ onCascade: handleCascade,
2838
+ highlightExpiredTasks
2357
2839
  },
2358
2840
  task.id
2359
2841
  ))
@@ -2369,7 +2851,7 @@ GanttChart.displayName = "GanttChart";
2369
2851
 
2370
2852
  // src/components/ui/Button.tsx
2371
2853
  var import_react13 = __toESM(require("react"));
2372
- var import_jsx_runtime14 = require("react/jsx-runtime");
2854
+ var import_jsx_runtime15 = require("react/jsx-runtime");
2373
2855
  var Button = import_react13.default.forwardRef(
2374
2856
  ({ className, variant = "default", size = "default", children, ...props }, ref) => {
2375
2857
  const classes = [
@@ -2378,7 +2860,7 @@ var Button = import_react13.default.forwardRef(
2378
2860
  size !== "default" ? `gantt-btn-${size}` : "",
2379
2861
  className || ""
2380
2862
  ].filter(Boolean).join(" ");
2381
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { ref, className: classes, ...props, children });
2863
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { ref, className: classes, ...props, children });
2382
2864
  }
2383
2865
  );
2384
2866
  Button.displayName = "Button";
@@ -2408,6 +2890,7 @@ Button.displayName = "Button";
2408
2890
  calculateTaskBar,
2409
2891
  calculateWeekendBlocks,
2410
2892
  cascadeByLinks,
2893
+ computeLagFromDates,
2411
2894
  detectCycles,
2412
2895
  detectEdgeZone,
2413
2896
  formatDateLabel,