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.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  // src/components/GanttChart/GanttChart.tsx
4
- import { useMemo as useMemo8, useCallback as useCallback6, useRef as useRef4, useState as useState5, useEffect as useEffect4, useImperativeHandle, forwardRef } from "react";
4
+ import { useMemo as useMemo9, useCallback as useCallback6, useRef as useRef5, useState as useState6, useEffect as useEffect5, useImperativeHandle, forwardRef } from "react";
5
5
 
6
6
  // src/utils/dateUtils.ts
7
7
  var parseUTCDate = (date) => {
@@ -195,11 +195,35 @@ function detectCycles(tasks) {
195
195
  }
196
196
  return { hasCycle: false };
197
197
  }
198
+ function computeLagFromDates(linkType, predStart, predEnd, succStart, succEnd) {
199
+ const DAY_MS = 24 * 60 * 60 * 1e3;
200
+ const pS = Date.UTC(predStart.getUTCFullYear(), predStart.getUTCMonth(), predStart.getUTCDate());
201
+ const pE = Date.UTC(predEnd.getUTCFullYear(), predEnd.getUTCMonth(), predEnd.getUTCDate());
202
+ const sS = Date.UTC(succStart.getUTCFullYear(), succStart.getUTCMonth(), succStart.getUTCDate());
203
+ const sE = Date.UTC(succEnd.getUTCFullYear(), succEnd.getUTCMonth(), succEnd.getUTCDate());
204
+ switch (linkType) {
205
+ case "FS":
206
+ return Math.round((sS - pE) / DAY_MS) - 1;
207
+ case "SS":
208
+ return Math.round((sS - pS) / DAY_MS);
209
+ case "FF":
210
+ return Math.round((sE - pE) / DAY_MS);
211
+ case "SF":
212
+ return Math.round((sE - pS) / DAY_MS) + 1;
213
+ }
214
+ }
198
215
  function calculateSuccessorDate(predecessorStart, predecessorEnd, linkType, lag = 0) {
199
- const baseDate = linkType.startsWith("F") ? predecessorEnd : predecessorStart;
200
- const lagMs = lag * 24 * 60 * 60 * 1e3;
201
- const resultDate = new Date(baseDate.getTime() + lagMs);
202
- return resultDate;
216
+ const DAY_MS = 24 * 60 * 60 * 1e3;
217
+ switch (linkType) {
218
+ case "FS":
219
+ return new Date(predecessorEnd.getTime() + (lag + 1) * DAY_MS);
220
+ case "SS":
221
+ return new Date(predecessorStart.getTime() + lag * DAY_MS);
222
+ case "FF":
223
+ return new Date(predecessorEnd.getTime() + lag * DAY_MS);
224
+ case "SF":
225
+ return new Date(predecessorStart.getTime() + (lag - 1) * DAY_MS);
226
+ }
203
227
  }
204
228
  function validateDependencies(tasks) {
205
229
  const errors = [];
@@ -346,35 +370,10 @@ function recalculateIncomingLags(task, newStartDate, newEndDate, allTasks) {
346
370
  return task.dependencies.map((dep) => {
347
371
  const predecessor = taskById.get(dep.taskId);
348
372
  if (!predecessor) return dep;
349
- if (dep.type === "FS") {
350
- const predEnd = new Date(predecessor.endDate);
351
- const lagDays = Math.round(
352
- (Date.UTC(newStartDate.getUTCFullYear(), newStartDate.getUTCMonth(), newStartDate.getUTCDate()) - Date.UTC(predEnd.getUTCFullYear(), predEnd.getUTCMonth(), predEnd.getUTCDate())) / (24 * 60 * 60 * 1e3)
353
- );
354
- return { ...dep, lag: lagDays };
355
- }
356
- if (dep.type === "SS") {
357
- const predStart = new Date(predecessor.startDate);
358
- const lagDays = Math.max(0, Math.round(
359
- (Date.UTC(newStartDate.getUTCFullYear(), newStartDate.getUTCMonth(), newStartDate.getUTCDate()) - Date.UTC(predStart.getUTCFullYear(), predStart.getUTCMonth(), predStart.getUTCDate())) / (24 * 60 * 60 * 1e3)
360
- ));
361
- return { ...dep, lag: lagDays };
362
- }
363
- if (dep.type === "FF") {
364
- const predEnd = new Date(predecessor.endDate);
365
- const lagDays = Math.round(
366
- (Date.UTC(newEndDate.getUTCFullYear(), newEndDate.getUTCMonth(), newEndDate.getUTCDate()) - Date.UTC(predEnd.getUTCFullYear(), predEnd.getUTCMonth(), predEnd.getUTCDate())) / (24 * 60 * 60 * 1e3)
367
- );
368
- return { ...dep, lag: lagDays };
369
- }
370
- if (dep.type === "SF") {
371
- const predStart = new Date(predecessor.startDate);
372
- const lagDays = Math.min(0, Math.round(
373
- (Date.UTC(newEndDate.getUTCFullYear(), newEndDate.getUTCMonth(), newEndDate.getUTCDate()) - Date.UTC(predStart.getUTCFullYear(), predStart.getUTCMonth(), predStart.getUTCDate()) + 24 * 60 * 60 * 1e3) / (24 * 60 * 60 * 1e3)
374
- ));
375
- return { ...dep, lag: lagDays };
376
- }
377
- return dep;
373
+ const predStart = new Date(predecessor.startDate);
374
+ const predEnd = new Date(predecessor.endDate);
375
+ const lagDays = computeLagFromDates(dep.type, predStart, predEnd, newStartDate, newEndDate);
376
+ return { ...dep, lag: lagDays };
378
377
  });
379
378
  }
380
379
  function getAllDependencyEdges(tasks) {
@@ -1093,29 +1092,51 @@ var useTaskDrag = (options) => {
1093
1092
  // src/components/TaskRow/TaskRow.tsx
1094
1093
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
1095
1094
  var arePropsEqual = (prevProps, nextProps) => {
1096
- 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;
1095
+ 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;
1097
1096
  };
1098
1097
  var TaskRow = React2.memo(
1099
- ({ task, monthStart, dayWidth, rowHeight, onChange, onDragStateChange, rowIndex, allTasks, enableAutoSchedule, disableConstraints, overridePosition, onCascadeProgress, onCascade, divider }) => {
1098
+ ({ task, monthStart, dayWidth, rowHeight, onChange, onDragStateChange, rowIndex, allTasks, enableAutoSchedule, disableConstraints, overridePosition, onCascadeProgress, onCascade, divider, highlightExpiredTasks }) => {
1100
1099
  const { divider: taskDivider } = task;
1101
1100
  const taskStartDate = useMemo2(() => parseUTCDate(task.startDate), [task.startDate]);
1102
1101
  const taskEndDate = useMemo2(() => parseUTCDate(task.endDate), [task.endDate]);
1102
+ const isExpired = useMemo2(() => {
1103
+ if (!highlightExpiredTasks) return false;
1104
+ const now = /* @__PURE__ */ new Date();
1105
+ const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
1106
+ const tomorrow = new Date(Date.UTC(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate() + 1));
1107
+ const taskStart = parseUTCDate(task.startDate);
1108
+ const taskEnd = parseUTCDate(task.endDate);
1109
+ const actualProgress = task.progress ?? 0;
1110
+ if (actualProgress >= 100) {
1111
+ return false;
1112
+ }
1113
+ const msPerDay = 1e3 * 60 * 60 * 24;
1114
+ const taskDuration = taskEnd.getTime() - taskStart.getTime() + msPerDay;
1115
+ 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();
1116
+ const elapsedCutoff = isTaskEndingTodayOrTomorrow ? new Date(today.getTime() - msPerDay) : today;
1117
+ const daysFromStart = elapsedCutoff.getTime() - taskStart.getTime();
1118
+ const todayPosition = Math.min(100, Math.max(0, daysFromStart / taskDuration * 100));
1119
+ return actualProgress < todayPosition;
1120
+ }, [task.startDate, task.endDate, task.progress, highlightExpiredTasks]);
1103
1121
  const { left, width } = useMemo2(
1104
1122
  () => calculateTaskBar(taskStartDate, taskEndDate, monthStart, dayWidth),
1105
1123
  [taskStartDate, taskEndDate, monthStart, dayWidth]
1106
1124
  );
1107
- const barColor = task.color || "var(--gantt-task-bar-default-color)";
1125
+ const barColor = isExpired ? "var(--gantt-expired-color)" : task.color || "var(--gantt-task-bar-default-color)";
1108
1126
  const progressWidth = useMemo2(() => {
1109
1127
  if (task.progress === void 0 || task.progress <= 0) return 0;
1110
1128
  return Math.min(100, Math.max(0, Math.round(task.progress)));
1111
1129
  }, [task.progress]);
1112
1130
  const progressColor = useMemo2(() => {
1131
+ if (isExpired) {
1132
+ return "color-mix(in srgb, var(--gantt-expired-color) 40%, black)";
1133
+ }
1113
1134
  if (progressWidth === 100) {
1114
1135
  return task.accepted ? "var(--gantt-progress-accepted, #22c55e)" : "var(--gantt-progress-completed, #fbbf24)";
1115
1136
  }
1116
1137
  const baseColor = task.color || "var(--gantt-task-bar-default-color)";
1117
1138
  return `color-mix(in srgb, ${baseColor} 40%, black)`;
1118
- }, [progressWidth, task.accepted, task.color]);
1139
+ }, [isExpired, progressWidth, task.accepted, task.color]);
1119
1140
  const handleDragEnd = (result) => {
1120
1141
  const updatedTask = {
1121
1142
  ...task,
@@ -1401,60 +1422,11 @@ var DragGuideLines_default = DragGuideLines;
1401
1422
  import React5, { useMemo as useMemo5 } from "react";
1402
1423
  import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1403
1424
  function calculateEffectiveLag(edge, predPosition, succPosition, monthStart, dayWidth) {
1404
- const predStartDate = pixelsToDate(predPosition.left, monthStart, dayWidth);
1405
- const predEndDate = pixelsToDate(predPosition.right - dayWidth, monthStart, dayWidth);
1406
- const succStartDate = pixelsToDate(succPosition.left, monthStart, dayWidth);
1407
- const succEndDate = pixelsToDate(succPosition.right - dayWidth, monthStart, dayWidth);
1408
- let lagMs = 0;
1409
- switch (edge.type) {
1410
- case "FS":
1411
- lagMs = Date.UTC(
1412
- succStartDate.getUTCFullYear(),
1413
- succStartDate.getUTCMonth(),
1414
- succStartDate.getUTCDate()
1415
- ) - Date.UTC(
1416
- predEndDate.getUTCFullYear(),
1417
- predEndDate.getUTCMonth(),
1418
- predEndDate.getUTCDate()
1419
- ) - 24 * 60 * 60 * 1e3;
1420
- break;
1421
- case "SS":
1422
- lagMs = Date.UTC(
1423
- succStartDate.getUTCFullYear(),
1424
- succStartDate.getUTCMonth(),
1425
- succStartDate.getUTCDate()
1426
- ) - Date.UTC(
1427
- predStartDate.getUTCFullYear(),
1428
- predStartDate.getUTCMonth(),
1429
- predStartDate.getUTCDate()
1430
- );
1431
- break;
1432
- case "FF":
1433
- lagMs = Date.UTC(
1434
- succEndDate.getUTCFullYear(),
1435
- succEndDate.getUTCMonth(),
1436
- succEndDate.getUTCDate()
1437
- ) - Date.UTC(
1438
- predEndDate.getUTCFullYear(),
1439
- predEndDate.getUTCMonth(),
1440
- predEndDate.getUTCDate()
1441
- );
1442
- break;
1443
- case "SF":
1444
- lagMs = Date.UTC(
1445
- succEndDate.getUTCFullYear(),
1446
- succEndDate.getUTCMonth(),
1447
- succEndDate.getUTCDate()
1448
- ) - Date.UTC(
1449
- predStartDate.getUTCFullYear(),
1450
- predStartDate.getUTCMonth(),
1451
- predStartDate.getUTCDate()
1452
- ) + 24 * 60 * 60 * 1e3;
1453
- break;
1454
- default:
1455
- return 0;
1456
- }
1457
- return Math.round(lagMs / (24 * 60 * 60 * 1e3));
1425
+ const predStart = pixelsToDate(predPosition.left, monthStart, dayWidth);
1426
+ const predEnd = pixelsToDate(predPosition.right - dayWidth, monthStart, dayWidth);
1427
+ const succStart = pixelsToDate(succPosition.left, monthStart, dayWidth);
1428
+ const succEnd = pixelsToDate(succPosition.right - dayWidth, monthStart, dayWidth);
1429
+ return computeLagFromDates(edge.type, predStart, predEnd, succStart, succEnd);
1458
1430
  }
1459
1431
  var DependencyLines = React5.memo(({
1460
1432
  tasks,
@@ -1462,7 +1434,8 @@ var DependencyLines = React5.memo(({
1462
1434
  dayWidth,
1463
1435
  rowHeight,
1464
1436
  gridWidth,
1465
- dragOverrides
1437
+ dragOverrides,
1438
+ selectedDep
1466
1439
  }) => {
1467
1440
  const { taskPositions, taskIndices } = useMemo5(() => {
1468
1441
  const positions = /* @__PURE__ */ new Map();
@@ -1576,30 +1549,60 @@ var DependencyLines = React5.memo(({
1576
1549
  }
1577
1550
  )
1578
1551
  }
1579
- )
1580
- ] }),
1581
- lines.map(({ id, path, hasCycle, lag, fromX, toX, fromY, reverseOrder }) => /* @__PURE__ */ jsxs5(React5.Fragment, { children: [
1582
- /* @__PURE__ */ jsx6(
1583
- "path",
1584
- {
1585
- d: path,
1586
- className: hasCycle ? "gantt-dependency-path gantt-dependency-cycle" : "gantt-dependency-path",
1587
- markerEnd: hasCycle ? "url(#arrowhead-cycle)" : "url(#arrowhead)"
1588
- }
1589
1552
  ),
1590
- lag !== 0 && /* @__PURE__ */ jsx6(
1591
- "text",
1553
+ /* @__PURE__ */ jsx6(
1554
+ "marker",
1592
1555
  {
1593
- className: "gantt-dependency-lag-label",
1594
- x: lag < 0 ? toX + 14 : toX - 14,
1595
- y: reverseOrder ? fromY - 4 : fromY + 12,
1596
- textAnchor: "middle",
1597
- fontSize: "10",
1598
- fill: hasCycle ? "var(--gantt-dependency-cycle-color, #ef4444)" : "var(--gantt-dependency-line-color, #666666)",
1599
- children: lag > 0 ? `+${lag}` : `${lag}`
1556
+ id: "arrowhead-selected",
1557
+ markerWidth: "8",
1558
+ markerHeight: "6",
1559
+ markerUnits: "userSpaceOnUse",
1560
+ refX: "7",
1561
+ refY: "3",
1562
+ orient: "auto",
1563
+ children: /* @__PURE__ */ jsx6(
1564
+ "polygon",
1565
+ {
1566
+ points: "0 0, 8 3, 0 6",
1567
+ fill: "#ef4444"
1568
+ }
1569
+ )
1600
1570
  }
1601
1571
  )
1602
- ] }, id))
1572
+ ] }),
1573
+ lines.map(({ id, path, hasCycle, lag, fromX, toX, fromY, reverseOrder }) => {
1574
+ const isSelected = selectedDep != null && id === `${selectedDep.predecessorId}-${selectedDep.successorId}-${selectedDep.linkType}`;
1575
+ let pathClassName = "gantt-dependency-path";
1576
+ if (isSelected) pathClassName += " gantt-dependency-selected";
1577
+ else if (hasCycle) pathClassName += " gantt-dependency-cycle";
1578
+ let markerEnd;
1579
+ if (isSelected) markerEnd = "url(#arrowhead-selected)";
1580
+ else if (hasCycle) markerEnd = "url(#arrowhead-cycle)";
1581
+ else markerEnd = "url(#arrowhead)";
1582
+ const lagColor = isSelected ? "#ef4444" : hasCycle ? "var(--gantt-dependency-cycle-color, #ef4444)" : "var(--gantt-dependency-line-color, #666666)";
1583
+ return /* @__PURE__ */ jsxs5(React5.Fragment, { children: [
1584
+ /* @__PURE__ */ jsx6(
1585
+ "path",
1586
+ {
1587
+ d: path,
1588
+ className: pathClassName,
1589
+ markerEnd
1590
+ }
1591
+ ),
1592
+ lag !== 0 && /* @__PURE__ */ jsx6(
1593
+ "text",
1594
+ {
1595
+ className: "gantt-dependency-lag-label",
1596
+ x: lag < 0 ? toX + 14 : toX - 14,
1597
+ y: reverseOrder ? fromY - 4 : fromY + 12,
1598
+ textAnchor: "middle",
1599
+ fontSize: "10",
1600
+ fill: lagColor,
1601
+ children: lag > 0 ? `+${lag}` : `${lag}`
1602
+ }
1603
+ )
1604
+ ] }, id);
1605
+ })
1603
1606
  ]
1604
1607
  }
1605
1608
  );
@@ -1608,17 +1611,51 @@ DependencyLines.displayName = "DependencyLines";
1608
1611
  var DependencyLines_default = DependencyLines;
1609
1612
 
1610
1613
  // src/components/TaskList/TaskList.tsx
1611
- import { useMemo as useMemo7, useCallback as useCallback5 } from "react";
1614
+ import React10, { useMemo as useMemo8, useCallback as useCallback5, useState as useState5, useEffect as useEffect4, useRef as useRef4 } from "react";
1615
+
1616
+ // src/components/ui/Popover.tsx
1617
+ import * as RadixPopover from "@radix-ui/react-popover";
1618
+ import { jsx as jsx7 } from "react/jsx-runtime";
1619
+ var Popover = ({ open, onOpenChange, children }) => {
1620
+ return /* @__PURE__ */ jsx7(RadixPopover.Root, { open, onOpenChange, children });
1621
+ };
1622
+ var PopoverTrigger = RadixPopover.Trigger;
1623
+ var PopoverContent = ({
1624
+ children,
1625
+ className,
1626
+ align = "start",
1627
+ side = "bottom",
1628
+ portal = true,
1629
+ collisionPadding = 8,
1630
+ onInteractOutside
1631
+ }) => {
1632
+ const content = /* @__PURE__ */ jsx7(
1633
+ RadixPopover.Content,
1634
+ {
1635
+ className: `gantt-popover${className ? ` ${className}` : ""}`,
1636
+ align,
1637
+ side,
1638
+ collisionPadding,
1639
+ sideOffset: 4,
1640
+ onInteractOutside,
1641
+ children
1642
+ }
1643
+ );
1644
+ if (portal) {
1645
+ return /* @__PURE__ */ jsx7(RadixPopover.Portal, { children: content });
1646
+ }
1647
+ return content;
1648
+ };
1612
1649
 
1613
1650
  // src/components/TaskList/TaskListRow.tsx
1614
- import React9, { useState as useState4, useRef as useRef3, useEffect as useEffect3, useCallback as useCallback4 } from "react";
1651
+ import React9, { useState as useState4, useRef as useRef3, useEffect as useEffect3, useCallback as useCallback4, useMemo as useMemo7 } from "react";
1615
1652
 
1616
1653
  // src/components/ui/Input.tsx
1617
1654
  import React6 from "react";
1618
- import { jsx as jsx7 } from "react/jsx-runtime";
1655
+ import { jsx as jsx8 } from "react/jsx-runtime";
1619
1656
  var Input = React6.forwardRef(
1620
1657
  ({ className, ...props }, ref) => {
1621
- return /* @__PURE__ */ jsx7(
1658
+ return /* @__PURE__ */ jsx8(
1622
1659
  "input",
1623
1660
  {
1624
1661
  ref,
@@ -1656,7 +1693,7 @@ import {
1656
1693
  startOfDay
1657
1694
  } from "date-fns";
1658
1695
  import { ru as ru2 } from "date-fns/locale";
1659
- import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
1696
+ import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
1660
1697
  function getDayClassName(day, selected) {
1661
1698
  const classes = ["gantt-day-btn"];
1662
1699
  if (selected && isSameDay(day, selected)) classes.push("selected");
@@ -1726,12 +1763,12 @@ var Calendar = ({
1726
1763
  const emptyDays = (getDay(firstDay) + 6) % 7;
1727
1764
  const monthKey = format2(month, "yyyy-MM");
1728
1765
  const monthLabel = format2(month, "LLLL yyyy", { locale: ru2 });
1729
- const emptyCells = Array.from({ length: emptyDays }, (_, i) => /* @__PURE__ */ jsx8("div", { className: "gantt-cal-empty-day" }, `e-${i}`));
1766
+ const emptyCells = Array.from({ length: emptyDays }, (_, i) => /* @__PURE__ */ jsx9("div", { className: "gantt-cal-empty-day" }, `e-${i}`));
1730
1767
  const dayCells = Array.from({ length: totalDays }, (_, i) => {
1731
1768
  const dayNum = i + 1;
1732
1769
  const day = new Date(month.getFullYear(), month.getMonth(), dayNum);
1733
1770
  const className = getDayClassName(day, selected);
1734
- return /* @__PURE__ */ jsx8(
1771
+ return /* @__PURE__ */ jsx9(
1735
1772
  "button",
1736
1773
  {
1737
1774
  type: "button",
@@ -1748,7 +1785,7 @@ var Calendar = ({
1748
1785
  );
1749
1786
  });
1750
1787
  return /* @__PURE__ */ jsxs6("div", { className: "gantt-cal-month", "data-month": monthKey, children: [
1751
- /* @__PURE__ */ jsx8("div", { className: "gantt-cal-month-header", children: monthLabel }),
1788
+ /* @__PURE__ */ jsx9("div", { className: "gantt-cal-month-header", children: monthLabel }),
1752
1789
  /* @__PURE__ */ jsxs6("div", { className: "gantt-cal-month-days", children: [
1753
1790
  emptyCells,
1754
1791
  dayCells
@@ -1761,42 +1798,10 @@ var Calendar = ({
1761
1798
  () => months.map(renderMonth),
1762
1799
  [months, renderMonth]
1763
1800
  );
1764
- return /* @__PURE__ */ jsx8("div", { ref: scrollRef, className: "gantt-cal-container", children: renderedMonths });
1801
+ return /* @__PURE__ */ jsx9("div", { ref: scrollRef, className: "gantt-cal-container", children: renderedMonths });
1765
1802
  };
1766
1803
  Calendar.displayName = "Calendar";
1767
1804
 
1768
- // src/components/ui/Popover.tsx
1769
- import * as RadixPopover from "@radix-ui/react-popover";
1770
- import { jsx as jsx9 } from "react/jsx-runtime";
1771
- var Popover = ({ open, onOpenChange, children }) => {
1772
- return /* @__PURE__ */ jsx9(RadixPopover.Root, { open, onOpenChange, children });
1773
- };
1774
- var PopoverTrigger = RadixPopover.Trigger;
1775
- var PopoverContent = ({
1776
- children,
1777
- className,
1778
- align = "start",
1779
- side = "bottom",
1780
- portal = true,
1781
- collisionPadding = 8
1782
- }) => {
1783
- const content = /* @__PURE__ */ jsx9(
1784
- RadixPopover.Content,
1785
- {
1786
- className: `gantt-popover${className ? ` ${className}` : ""}`,
1787
- align,
1788
- side,
1789
- collisionPadding,
1790
- sideOffset: 4,
1791
- children
1792
- }
1793
- );
1794
- if (portal) {
1795
- return /* @__PURE__ */ jsx9(RadixPopover.Portal, { children: content });
1796
- }
1797
- return content;
1798
- };
1799
-
1800
1805
  // src/components/ui/DatePicker.tsx
1801
1806
  import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
1802
1807
  var DatePicker = ({
@@ -1861,19 +1866,198 @@ var DatePicker = ({
1861
1866
  };
1862
1867
  DatePicker.displayName = "DatePicker";
1863
1868
 
1864
- // src/components/TaskList/TaskListRow.tsx
1869
+ // src/components/TaskList/DepIcons.tsx
1865
1870
  import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
1871
+ var DepIconFS = () => /* @__PURE__ */ jsxs8("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: [
1872
+ /* @__PURE__ */ jsx11("path", { d: "m10 15 5 5 5-5" }),
1873
+ /* @__PURE__ */ jsx11("path", { d: "M4 4h7a4 4 0 0 1 4 4v12" })
1874
+ ] });
1875
+ var DepIconSS = () => /* @__PURE__ */ jsxs8("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: [
1876
+ /* @__PURE__ */ jsx11("path", { d: "M3 5v14" }),
1877
+ /* @__PURE__ */ jsx11("path", { d: "M21 12H7" }),
1878
+ /* @__PURE__ */ jsx11("path", { d: "m15 18 6-6-6-6" })
1879
+ ] });
1880
+ var DepIconFF = () => /* @__PURE__ */ jsxs8("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: [
1881
+ /* @__PURE__ */ jsx11("path", { d: "M17 12H3" }),
1882
+ /* @__PURE__ */ jsx11("path", { d: "m11 18 6-6-6-6" }),
1883
+ /* @__PURE__ */ jsx11("path", { d: "M21 5v14" })
1884
+ ] });
1885
+ var DepIconSF = () => /* @__PURE__ */ jsxs8("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: [
1886
+ /* @__PURE__ */ jsx11("path", { d: "m14 15-5 5-5-5" }),
1887
+ /* @__PURE__ */ jsx11("path", { d: "M20 4h-7a4 4 0 0 0-4 4v12" })
1888
+ ] });
1889
+ var LINK_TYPE_ICONS = {
1890
+ FS: DepIconFS,
1891
+ SS: DepIconSS,
1892
+ FF: DepIconFF,
1893
+ SF: DepIconSF
1894
+ };
1895
+ var LINK_TYPE_LABELS = {
1896
+ FS: "\u041E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u0435-\u043D\u0430\u0447\u0430\u043B\u043E",
1897
+ SS: "\u041D\u0430\u0447\u0430\u043B\u043E-\u043D\u0430\u0447\u0430\u043B\u043E",
1898
+ FF: "\u041E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u0435-\u043E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u0435",
1899
+ SF: "\u041D\u0430\u0447\u0430\u043B\u043E-\u043E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u0435"
1900
+ };
1901
+
1902
+ // src/components/TaskList/TaskListRow.tsx
1903
+ import { Fragment as Fragment2, jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
1904
+ var TrashIcon = () => /* @__PURE__ */ jsxs9("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: [
1905
+ /* @__PURE__ */ jsx12("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6" }),
1906
+ /* @__PURE__ */ jsx12("path", { d: "M3 6h18" }),
1907
+ /* @__PURE__ */ jsx12("path", { d: "M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })
1908
+ ] });
1909
+ function formatDepDescription(type, lag) {
1910
+ const effectiveLag = lag ?? 0;
1911
+ if (type === "FS") {
1912
+ 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`;
1913
+ 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`;
1914
+ 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`;
1915
+ }
1916
+ if (type === "FF") {
1917
+ 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`;
1918
+ 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`;
1919
+ return `\u0417\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044C \u043F\u043E\u0441\u043B\u0435 \u043E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u044F`;
1920
+ }
1921
+ if (type === "SS") {
1922
+ 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`;
1923
+ 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`;
1924
+ return `\u041D\u0430\u0447\u0430\u0442\u044C \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 \u043D\u0430\u0447\u0430\u043B\u043E\u043C`;
1925
+ }
1926
+ if (type === "SF") {
1927
+ 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`;
1928
+ 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`;
1929
+ return `\u0417\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044C \u0434\u043E \u043D\u0430\u0447\u0430\u043B\u0430`;
1930
+ }
1931
+ return "";
1932
+ }
1933
+ var DepChip = ({
1934
+ lag,
1935
+ dep,
1936
+ taskId,
1937
+ predecessorName,
1938
+ selectedChip,
1939
+ disableDependencyEditing,
1940
+ onChipSelect,
1941
+ onRowClick,
1942
+ onScrollToTask,
1943
+ onRemoveDependency,
1944
+ onChipSelectClear
1945
+ }) => {
1946
+ const isSelected = selectedChip?.successorId === taskId && selectedChip?.predecessorId === dep.taskId && selectedChip?.linkType === dep.type;
1947
+ const handleClick = (e) => {
1948
+ e.stopPropagation();
1949
+ if (disableDependencyEditing) return;
1950
+ onChipSelect?.(isSelected ? null : { successorId: taskId, predecessorId: dep.taskId, linkType: dep.type });
1951
+ if (!isSelected) {
1952
+ onRowClick?.(taskId);
1953
+ onScrollToTask?.(taskId);
1954
+ }
1955
+ };
1956
+ const handleTrashClick = (e) => {
1957
+ e.stopPropagation();
1958
+ onRemoveDependency?.(taskId, dep.taskId, dep.type);
1959
+ onChipSelectClear();
1960
+ };
1961
+ const Icon = LINK_TYPE_ICONS[dep.type];
1962
+ const depPrefix = formatDepDescription(dep.type, lag);
1963
+ const depName = predecessorName ?? dep.taskId;
1964
+ return /* @__PURE__ */ jsxs9(Popover, { open: isSelected, onOpenChange: (open) => {
1965
+ }, children: [
1966
+ /* @__PURE__ */ jsx12(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs9("span", { className: "gantt-tl-dep-chip-wrapper", children: [
1967
+ /* @__PURE__ */ jsx12(
1968
+ "span",
1969
+ {
1970
+ className: `gantt-tl-dep-chip${isSelected ? " gantt-tl-dep-chip-selected" : ""}`,
1971
+ onClick: handleClick,
1972
+ children: /* @__PURE__ */ jsxs9(Fragment2, { children: [
1973
+ /* @__PURE__ */ jsx12(Icon, {}),
1974
+ lag != null && lag !== 0 ? lag > 0 ? `+${lag}` : `${lag}` : ""
1975
+ ] })
1976
+ }
1977
+ ),
1978
+ !disableDependencyEditing && /* @__PURE__ */ jsx12(
1979
+ "button",
1980
+ {
1981
+ type: "button",
1982
+ className: "gantt-tl-dep-chip-trash",
1983
+ "aria-label": "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u0432\u044F\u0437\u044C",
1984
+ onClick: handleTrashClick,
1985
+ children: /* @__PURE__ */ jsx12(TrashIcon, {})
1986
+ }
1987
+ )
1988
+ ] }) }),
1989
+ /* @__PURE__ */ jsxs9(
1990
+ PopoverContent,
1991
+ {
1992
+ portal: true,
1993
+ side: "bottom",
1994
+ align: "start",
1995
+ className: "gantt-tl-dep-info-popover",
1996
+ onInteractOutside: (event) => {
1997
+ const target = event.target;
1998
+ if (target?.closest?.(".gantt-tl-dep-chip") || target?.closest?.(".gantt-tl-dep-delete-label") || target?.closest?.(".gantt-tl-dep-chip-trash")) {
1999
+ event.preventDefault();
2000
+ } else {
2001
+ onChipSelectClear();
2002
+ }
2003
+ },
2004
+ children: [
2005
+ /* @__PURE__ */ jsx12("span", { className: "gantt-tl-dep-info-prefix", children: depPrefix }),
2006
+ /* @__PURE__ */ jsx12("span", { className: "gantt-tl-dep-info-name", children: depName })
2007
+ ]
2008
+ }
2009
+ )
2010
+ ] });
2011
+ };
1866
2012
  var toISODate = (value) => {
1867
2013
  if (value instanceof Date) return value.toISOString().split("T")[0];
1868
2014
  if (typeof value === "string" && value.includes("T")) return value.split("T")[0];
1869
2015
  return value;
1870
2016
  };
1871
2017
  var TaskListRow = React9.memo(
1872
- ({ task, rowIndex, rowHeight, onTaskChange, selectedTaskId, onRowClick, disableTaskNameEditing = false }) => {
2018
+ ({
2019
+ task,
2020
+ rowIndex,
2021
+ rowHeight,
2022
+ onTaskChange,
2023
+ selectedTaskId,
2024
+ onRowClick,
2025
+ disableTaskNameEditing = false,
2026
+ disableDependencyEditing = false,
2027
+ allTasks = [],
2028
+ activeLinkType,
2029
+ selectingPredecessorFor,
2030
+ onSetSelectingPredecessorFor,
2031
+ onAddDependency,
2032
+ onRemoveDependency,
2033
+ selectedChip,
2034
+ onChipSelect,
2035
+ onScrollToTask
2036
+ }) => {
1873
2037
  const [editingName, setEditingName] = useState4(false);
1874
2038
  const [nameValue, setNameValue] = useState4("");
1875
2039
  const nameInputRef = useRef3(null);
2040
+ const [overflowOpen, setOverflowOpen] = useState4(false);
1876
2041
  const isSelected = selectedTaskId === task.id;
2042
+ const isPicking = selectingPredecessorFor != null;
2043
+ const isSourceRow = isPicking && selectingPredecessorFor === task.id;
2044
+ const chips = useMemo7(() => {
2045
+ const succStart = new Date(task.startDate);
2046
+ const succEnd = new Date(task.endDate);
2047
+ const taskById = new Map((allTasks ?? []).map((t) => [t.id, t]));
2048
+ return (task.dependencies ?? []).map((dep) => {
2049
+ const pred = taskById.get(dep.taskId);
2050
+ const lag = pred ? computeLagFromDates(
2051
+ dep.type,
2052
+ new Date(pred.startDate),
2053
+ new Date(pred.endDate),
2054
+ succStart,
2055
+ succEnd
2056
+ ) : dep.lag ?? 0;
2057
+ return { dep, lag, predecessorName: pred?.name ?? dep.taskId };
2058
+ });
2059
+ }, [task.dependencies, task.startDate, task.endDate, allTasks]);
2060
+ const linkWord = chips.length <= 4 ? "\u0441\u0432\u044F\u0437\u0438" : "\u0441\u0432\u044F\u0437\u0435\u0439";
1877
2061
  useEffect3(() => {
1878
2062
  if (editingName && nameInputRef.current) {
1879
2063
  nameInputRef.current.focus();
@@ -1919,18 +2103,60 @@ var TaskListRow = React9.memo(
1919
2103
  const handleRowClickInternal = useCallback4(() => {
1920
2104
  onRowClick?.(task.id);
1921
2105
  }, [task.id, onRowClick]);
2106
+ const handleNumberClick = useCallback4((e) => {
2107
+ e.stopPropagation();
2108
+ onRowClick?.(task.id);
2109
+ onScrollToTask?.(task.id);
2110
+ }, [task.id, onRowClick, onScrollToTask]);
2111
+ const handleAddClick = useCallback4((e) => {
2112
+ e.stopPropagation();
2113
+ onSetSelectingPredecessorFor?.(task.id);
2114
+ }, [task.id, onSetSelectingPredecessorFor]);
2115
+ const handlePredecessorPick = useCallback4((e) => {
2116
+ e.stopPropagation();
2117
+ if (!isPicking || isSourceRow) return;
2118
+ if (!selectingPredecessorFor || !activeLinkType) return;
2119
+ onAddDependency?.(task.id, selectingPredecessorFor, activeLinkType);
2120
+ }, [isPicking, isSourceRow, selectingPredecessorFor, task.id, activeLinkType, onAddDependency]);
2121
+ const isSelectedPredecessor = selectedChip != null && selectedChip.predecessorId === task.id;
2122
+ const handleDeleteSelected = useCallback4((e) => {
2123
+ e.stopPropagation();
2124
+ if (!selectedChip) return;
2125
+ onRemoveDependency?.(selectedChip.successorId, selectedChip.predecessorId, selectedChip.linkType);
2126
+ onChipSelect?.(null);
2127
+ }, [selectedChip, onRemoveDependency, onChipSelect]);
1922
2128
  const startDateISO = toISODate(task.startDate);
1923
2129
  const endDateISO = toISODate(task.endDate);
1924
- return /* @__PURE__ */ jsxs8(
2130
+ return /* @__PURE__ */ jsxs9(
1925
2131
  "div",
1926
2132
  {
1927
- className: `gantt-tl-row ${isSelected ? "gantt-tl-row-selected" : ""}`,
2133
+ className: [
2134
+ "gantt-tl-row",
2135
+ isSelected ? "gantt-tl-row-selected" : "",
2136
+ isPicking && !isSourceRow ? "gantt-tl-row-picking" : "",
2137
+ isSourceRow ? "gantt-tl-row-picking-self" : ""
2138
+ ].filter(Boolean).join(" "),
1928
2139
  style: { minHeight: `${rowHeight}px` },
1929
2140
  onClick: handleRowClickInternal,
1930
2141
  children: [
1931
- /* @__PURE__ */ jsx11("div", { className: "gantt-tl-cell gantt-tl-cell-number", children: rowIndex + 1 }),
1932
- /* @__PURE__ */ jsxs8("div", { className: "gantt-tl-cell gantt-tl-cell-name", children: [
1933
- editingName && /* @__PURE__ */ jsx11(
2142
+ /* @__PURE__ */ jsxs9(
2143
+ "div",
2144
+ {
2145
+ className: "gantt-tl-cell gantt-tl-cell-number",
2146
+ onClick: handleNumberClick,
2147
+ title: "\u041F\u0435\u0440\u0435\u0439\u0442\u0438 \u043A \u0440\u0430\u0431\u043E\u0442\u0435",
2148
+ children: [
2149
+ /* @__PURE__ */ jsx12("span", { className: "gantt-tl-num-label", children: rowIndex + 1 }),
2150
+ /* @__PURE__ */ jsxs9("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: [
2151
+ /* @__PURE__ */ jsx12("path", { d: "M17 12H3" }),
2152
+ /* @__PURE__ */ jsx12("path", { d: "m11 18 6-6-6-6" }),
2153
+ /* @__PURE__ */ jsx12("path", { d: "M21 5v14" })
2154
+ ] })
2155
+ ]
2156
+ }
2157
+ ),
2158
+ /* @__PURE__ */ jsxs9("div", { className: "gantt-tl-cell gantt-tl-cell-name", children: [
2159
+ editingName && /* @__PURE__ */ jsx12(
1934
2160
  Input,
1935
2161
  {
1936
2162
  ref: nameInputRef,
@@ -1943,7 +2169,7 @@ var TaskListRow = React9.memo(
1943
2169
  onClick: (e) => e.stopPropagation()
1944
2170
  }
1945
2171
  ),
1946
- /* @__PURE__ */ jsx11(
2172
+ /* @__PURE__ */ jsx12(
1947
2173
  "button",
1948
2174
  {
1949
2175
  type: "button",
@@ -1954,7 +2180,7 @@ var TaskListRow = React9.memo(
1954
2180
  }
1955
2181
  )
1956
2182
  ] }),
1957
- /* @__PURE__ */ jsx11("div", { className: "gantt-tl-cell gantt-tl-cell-date", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx11(
2183
+ /* @__PURE__ */ jsx12("div", { className: "gantt-tl-cell gantt-tl-cell-date", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx12(
1958
2184
  DatePicker,
1959
2185
  {
1960
2186
  value: startDateISO,
@@ -1964,7 +2190,7 @@ var TaskListRow = React9.memo(
1964
2190
  disabled: task.locked
1965
2191
  }
1966
2192
  ) }),
1967
- /* @__PURE__ */ jsx11("div", { className: "gantt-tl-cell gantt-tl-cell-date", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx11(
2193
+ /* @__PURE__ */ jsx12("div", { className: "gantt-tl-cell gantt-tl-cell-date", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx12(
1968
2194
  DatePicker,
1969
2195
  {
1970
2196
  value: endDateISO,
@@ -1973,7 +2199,97 @@ var TaskListRow = React9.memo(
1973
2199
  portal: true,
1974
2200
  disabled: task.locked
1975
2201
  }
1976
- ) })
2202
+ ) }),
2203
+ /* @__PURE__ */ jsx12(
2204
+ "div",
2205
+ {
2206
+ className: "gantt-tl-cell gantt-tl-cell-deps",
2207
+ onClick: isPicking && !isSourceRow ? handlePredecessorPick : void 0,
2208
+ children: isSourceRow ? /* @__PURE__ */ jsx12("span", { className: "gantt-tl-dep-source-hint", children: "\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0437\u0430\u0434\u0430\u0447\u0443" }) : isSelectedPredecessor && !disableDependencyEditing ? (
2209
+ /* Full-replacement: "Зависит от [name]" → hover → "Удалить" */
2210
+ /* @__PURE__ */ jsxs9(
2211
+ "button",
2212
+ {
2213
+ type: "button",
2214
+ className: "gantt-tl-dep-delete-label",
2215
+ onClick: handleDeleteSelected,
2216
+ "aria-label": "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u0432\u044F\u0437\u044C",
2217
+ children: [
2218
+ /* @__PURE__ */ jsx12("span", { className: "gantt-tl-dep-delete-label-default", children: "\u0421\u0432\u044F\u0437\u0430\u043D\u043E \u0441" }),
2219
+ /* @__PURE__ */ jsx12("span", { className: "gantt-tl-dep-delete-label-hover", children: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u0432\u044F\u0437\u044C" })
2220
+ ]
2221
+ }
2222
+ )
2223
+ ) : /* @__PURE__ */ jsxs9(Fragment2, { children: [
2224
+ chips.length >= 2 ? (
2225
+ /* 2+ deps — show only "N связей" summary chip that opens a popover */
2226
+ /* @__PURE__ */ jsxs9(Popover, { open: overflowOpen, onOpenChange: setOverflowOpen, children: [
2227
+ /* @__PURE__ */ jsx12(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs9(
2228
+ "button",
2229
+ {
2230
+ type: "button",
2231
+ className: "gantt-tl-dep-summary-chip",
2232
+ onClick: (e) => {
2233
+ e.stopPropagation();
2234
+ setOverflowOpen((v) => !v);
2235
+ },
2236
+ children: [
2237
+ chips.length,
2238
+ " ",
2239
+ linkWord
2240
+ ]
2241
+ }
2242
+ ) }),
2243
+ /* @__PURE__ */ jsx12(PopoverContent, { portal: true, align: "start", children: /* @__PURE__ */ jsx12("div", { className: "gantt-tl-dep-overflow-list", onClick: (e) => e.stopPropagation(), children: chips.map(({ dep, lag, predecessorName }) => /* @__PURE__ */ jsx12(
2244
+ DepChip,
2245
+ {
2246
+ lag,
2247
+ dep,
2248
+ taskId: task.id,
2249
+ predecessorName,
2250
+ selectedChip,
2251
+ disableDependencyEditing,
2252
+ onChipSelect,
2253
+ onRowClick,
2254
+ onScrollToTask,
2255
+ onRemoveDependency,
2256
+ onChipSelectClear: () => onChipSelect?.(null)
2257
+ },
2258
+ `${dep.taskId}-${dep.type}`
2259
+ )) }) })
2260
+ ] })
2261
+ ) : chips.length === 1 ? (
2262
+ /* Single chip — unified DepChip */
2263
+ /* @__PURE__ */ jsx12(
2264
+ DepChip,
2265
+ {
2266
+ lag: chips[0].lag,
2267
+ dep: chips[0].dep,
2268
+ taskId: task.id,
2269
+ predecessorName: chips[0].predecessorName,
2270
+ selectedChip,
2271
+ disableDependencyEditing,
2272
+ onChipSelect,
2273
+ onRowClick,
2274
+ onScrollToTask,
2275
+ onRemoveDependency,
2276
+ onChipSelectClear: () => onChipSelect?.(null)
2277
+ }
2278
+ )
2279
+ ) : null,
2280
+ !disableDependencyEditing && !isPicking && /* @__PURE__ */ jsx12(
2281
+ "button",
2282
+ {
2283
+ type: "button",
2284
+ className: "gantt-tl-dep-add",
2285
+ onClick: handleAddClick,
2286
+ "aria-label": "\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0441\u0432\u044F\u0437\u044C",
2287
+ children: "+"
2288
+ }
2289
+ )
2290
+ ] })
2291
+ }
2292
+ )
1977
2293
  ]
1978
2294
  }
1979
2295
  );
@@ -1982,7 +2298,8 @@ var TaskListRow = React9.memo(
1982
2298
  TaskListRow.displayName = "TaskListRow";
1983
2299
 
1984
2300
  // src/components/TaskList/TaskList.tsx
1985
- import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
2301
+ import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
2302
+ var LINK_TYPE_ORDER = ["FS", "SS", "FF", "SF"];
1986
2303
  var TaskList = ({
1987
2304
  tasks,
1988
2305
  rowHeight,
@@ -1992,28 +2309,156 @@ var TaskList = ({
1992
2309
  selectedTaskId,
1993
2310
  onTaskSelect,
1994
2311
  show = true,
1995
- disableTaskNameEditing = false
2312
+ disableTaskNameEditing = false,
2313
+ disableDependencyEditing = false,
2314
+ onScrollToTask,
2315
+ onSelectedChipChange
1996
2316
  }) => {
1997
- const totalHeight = useMemo7(
2317
+ const totalHeight = useMemo8(
1998
2318
  () => tasks.length * rowHeight,
1999
2319
  [tasks.length, rowHeight]
2000
2320
  );
2001
2321
  const handleRowClick = useCallback5((taskId) => {
2002
2322
  onTaskSelect?.(taskId);
2003
2323
  }, [onTaskSelect]);
2004
- return /* @__PURE__ */ jsx12(
2324
+ const [activeLinkType, setActiveLinkType] = useState5("FS");
2325
+ const [selectingPredecessorFor, setSelectingPredecessorFor] = useState5(null);
2326
+ const [typeMenuOpen, setTypeMenuOpen] = useState5(false);
2327
+ const [cycleError, setCycleError] = useState5(false);
2328
+ const overlayRef = useRef4(null);
2329
+ const [selectedChip, setSelectedChip] = useState5(null);
2330
+ const handleChipSelect = useCallback5((chip) => {
2331
+ setSelectedChip(chip);
2332
+ onSelectedChipChange?.(chip);
2333
+ }, [onSelectedChipChange]);
2334
+ useEffect4(() => {
2335
+ if (!selectingPredecessorFor && !selectedChip) return;
2336
+ const handleKeyDown = (e) => {
2337
+ if (e.key === "Escape") {
2338
+ setSelectingPredecessorFor(null);
2339
+ setSelectedChip(null);
2340
+ onSelectedChipChange?.(null);
2341
+ }
2342
+ };
2343
+ const handleMouseDown = (e) => {
2344
+ const target = e.target;
2345
+ if (overlayRef.current?.contains(target)) return;
2346
+ if (target.closest?.(".gantt-popover")) return;
2347
+ setSelectingPredecessorFor(null);
2348
+ setSelectedChip(null);
2349
+ onSelectedChipChange?.(null);
2350
+ };
2351
+ document.addEventListener("keydown", handleKeyDown);
2352
+ document.addEventListener("mousedown", handleMouseDown, true);
2353
+ return () => {
2354
+ document.removeEventListener("keydown", handleKeyDown);
2355
+ document.removeEventListener("mousedown", handleMouseDown, true);
2356
+ };
2357
+ }, [selectingPredecessorFor, selectedChip, onSelectedChipChange]);
2358
+ const handleAddDependency = useCallback5((successorTaskId, predecessorTaskId, linkType) => {
2359
+ if (successorTaskId === predecessorTaskId) return;
2360
+ const successor = tasks.find((t) => t.id === successorTaskId);
2361
+ if (!successor) return;
2362
+ const alreadyExists = (successor.dependencies ?? []).some(
2363
+ (d) => d.taskId === predecessorTaskId && d.type === linkType
2364
+ );
2365
+ if (alreadyExists) {
2366
+ setSelectingPredecessorFor(null);
2367
+ return;
2368
+ }
2369
+ const newDep = { taskId: predecessorTaskId, type: linkType, lag: 0 };
2370
+ const hypothetical = tasks.map(
2371
+ (t) => t.id === successorTaskId ? { ...t, dependencies: [...t.dependencies ?? [], newDep] } : t
2372
+ );
2373
+ const validation = validateDependencies(hypothetical);
2374
+ if (!validation.isValid) {
2375
+ setCycleError(true);
2376
+ setTimeout(() => setCycleError(false), 3e3);
2377
+ return;
2378
+ }
2379
+ const updatedTask = hypothetical.find((t) => t.id === successorTaskId);
2380
+ const predecessor = tasks.find((t) => t.id === predecessorTaskId);
2381
+ if (predecessor) {
2382
+ const predStart = new Date(predecessor.startDate);
2383
+ const predEnd = new Date(predecessor.endDate);
2384
+ const constraintDate = calculateSuccessorDate(predStart, predEnd, linkType, 0);
2385
+ const origSuccessor = tasks.find((t) => t.id === successorTaskId);
2386
+ const durationMs = new Date(origSuccessor.endDate).getTime() - new Date(origSuccessor.startDate).getTime();
2387
+ let newStart;
2388
+ let newEnd;
2389
+ if (linkType === "FS" || linkType === "SS") {
2390
+ newStart = constraintDate;
2391
+ newEnd = new Date(constraintDate.getTime() + durationMs);
2392
+ } else {
2393
+ newEnd = constraintDate;
2394
+ newStart = new Date(constraintDate.getTime() - durationMs);
2395
+ }
2396
+ const snappedTask = {
2397
+ ...updatedTask,
2398
+ startDate: newStart.toISOString().split("T")[0],
2399
+ endDate: newEnd.toISOString().split("T")[0]
2400
+ };
2401
+ onTaskChange?.(snappedTask);
2402
+ } else {
2403
+ onTaskChange?.(updatedTask);
2404
+ }
2405
+ setSelectingPredecessorFor(null);
2406
+ }, [tasks, onTaskChange]);
2407
+ const handleRemoveDependency = useCallback5((taskId, predecessorTaskId, linkType) => {
2408
+ const task = tasks.find((t) => t.id === taskId);
2409
+ if (!task) return;
2410
+ const updatedDeps = (task.dependencies ?? []).filter(
2411
+ (d) => !(d.taskId === predecessorTaskId && d.type === linkType)
2412
+ );
2413
+ onTaskChange?.({ ...task, dependencies: updatedDeps });
2414
+ }, [tasks, onTaskChange]);
2415
+ return /* @__PURE__ */ jsx13(
2005
2416
  "div",
2006
2417
  {
2418
+ ref: overlayRef,
2007
2419
  className: `gantt-tl-overlay${show ? "" : " gantt-tl-hidden"}`,
2008
2420
  style: { width: `${taskListWidth}px` },
2009
- children: /* @__PURE__ */ jsxs9("div", { className: "gantt-tl-table", children: [
2010
- /* @__PURE__ */ jsxs9("div", { className: "gantt-tl-header", style: { height: `${headerHeight + 0.5}px` }, children: [
2011
- /* @__PURE__ */ jsx12("div", { className: "gantt-tl-headerCell gantt-tl-cell-number", children: "\u2116" }),
2012
- /* @__PURE__ */ jsx12("div", { className: "gantt-tl-headerCell gantt-tl-cell-name", children: "\u0418\u043C\u044F" }),
2013
- /* @__PURE__ */ jsx12("div", { className: "gantt-tl-headerCell gantt-tl-cell-date", children: "\u041D\u0430\u0447\u0430\u043B\u043E" }),
2014
- /* @__PURE__ */ jsx12("div", { className: "gantt-tl-headerCell gantt-tl-cell-date", children: "\u041E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u0435" })
2421
+ children: /* @__PURE__ */ jsxs10("div", { className: "gantt-tl-table", children: [
2422
+ /* @__PURE__ */ jsxs10("div", { className: "gantt-tl-header", style: { height: `${headerHeight + 0.5}px` }, children: [
2423
+ /* @__PURE__ */ jsx13("div", { className: "gantt-tl-headerCell gantt-tl-cell-number", children: "\u2116" }),
2424
+ /* @__PURE__ */ jsx13("div", { className: "gantt-tl-headerCell gantt-tl-cell-name", children: "\u0418\u043C\u044F" }),
2425
+ /* @__PURE__ */ jsx13("div", { className: "gantt-tl-headerCell gantt-tl-cell-date", children: "\u041D\u0430\u0447\u0430\u043B\u043E" }),
2426
+ /* @__PURE__ */ jsx13("div", { className: "gantt-tl-headerCell gantt-tl-cell-date", children: "\u041E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u0435" }),
2427
+ /* @__PURE__ */ jsxs10("div", { className: "gantt-tl-headerCell gantt-tl-cell-deps", style: { position: "relative" }, children: [
2428
+ /* @__PURE__ */ jsxs10(Popover, { open: typeMenuOpen, onOpenChange: setTypeMenuOpen, children: [
2429
+ /* @__PURE__ */ jsx13(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs10(
2430
+ "button",
2431
+ {
2432
+ className: "gantt-tl-dep-type-trigger",
2433
+ disabled: disableDependencyEditing,
2434
+ onClick: (e) => e.stopPropagation(),
2435
+ children: [
2436
+ "\u0421\u0432\u044F\u0437\u0438 ",
2437
+ React10.createElement(LINK_TYPE_ICONS[activeLinkType]),
2438
+ " \u25BE"
2439
+ ]
2440
+ }
2441
+ ) }),
2442
+ /* @__PURE__ */ jsx13(PopoverContent, { portal: true, align: "start", children: /* @__PURE__ */ jsx13("div", { className: "gantt-tl-dep-type-menu", children: LINK_TYPE_ORDER.map((lt) => /* @__PURE__ */ jsxs10(
2443
+ "button",
2444
+ {
2445
+ className: `gantt-tl-dep-type-option${activeLinkType === lt ? " active" : ""}`,
2446
+ onClick: () => {
2447
+ setActiveLinkType(lt);
2448
+ setTypeMenuOpen(false);
2449
+ },
2450
+ children: [
2451
+ React10.createElement(LINK_TYPE_ICONS[lt]),
2452
+ /* @__PURE__ */ jsx13("span", { children: LINK_TYPE_LABELS[lt] })
2453
+ ]
2454
+ },
2455
+ lt
2456
+ )) }) })
2457
+ ] }),
2458
+ cycleError && /* @__PURE__ */ jsx13("div", { className: "gantt-tl-dep-error", children: "\u0426\u0438\u043A\u043B \u0437\u0430\u0432\u0438\u0441\u0438\u043C\u043E\u0441\u0442\u0435\u0439!" })
2459
+ ] })
2015
2460
  ] }),
2016
- /* @__PURE__ */ jsx12("div", { className: "gantt-tl-body", style: { height: `${totalHeight}px` }, children: tasks.map((task, index) => /* @__PURE__ */ jsx12(
2461
+ /* @__PURE__ */ jsx13("div", { className: "gantt-tl-body", style: { height: `${totalHeight}px` }, children: tasks.map((task, index) => /* @__PURE__ */ jsx13(
2017
2462
  TaskListRow,
2018
2463
  {
2019
2464
  task,
@@ -2022,7 +2467,17 @@ var TaskList = ({
2022
2467
  onTaskChange,
2023
2468
  selectedTaskId,
2024
2469
  onRowClick: handleRowClick,
2025
- disableTaskNameEditing
2470
+ disableTaskNameEditing,
2471
+ disableDependencyEditing,
2472
+ allTasks: tasks,
2473
+ activeLinkType,
2474
+ selectingPredecessorFor,
2475
+ onSetSelectingPredecessorFor: setSelectingPredecessorFor,
2476
+ onAddDependency: handleAddDependency,
2477
+ onRemoveDependency: handleRemoveDependency,
2478
+ selectedChip,
2479
+ onChipSelect: handleChipSelect,
2480
+ onScrollToTask
2026
2481
  },
2027
2482
  task.id
2028
2483
  )) })
@@ -2032,7 +2487,7 @@ var TaskList = ({
2032
2487
  };
2033
2488
 
2034
2489
  // src/components/GanttChart/GanttChart.tsx
2035
- import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
2490
+ import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
2036
2491
  var GanttChart = forwardRef(({
2037
2492
  tasks,
2038
2493
  dayWidth = 40,
@@ -2046,34 +2501,37 @@ var GanttChart = forwardRef(({
2046
2501
  onCascade,
2047
2502
  showTaskList = false,
2048
2503
  taskListWidth = 520,
2049
- disableTaskNameEditing = false
2504
+ disableTaskNameEditing = false,
2505
+ disableDependencyEditing = false,
2506
+ highlightExpiredTasks = false
2050
2507
  }, ref) => {
2051
- const scrollContainerRef = useRef4(null);
2052
- const [selectedTaskId, setSelectedTaskId] = useState5(null);
2053
- const dateRange = useMemo8(() => getMultiMonthDays(tasks), [tasks]);
2054
- const [validationResult, setValidationResult] = useState5(null);
2055
- const [cascadeOverrides, setCascadeOverrides] = useState5(/* @__PURE__ */ new Map());
2056
- const gridWidth = useMemo8(
2508
+ const scrollContainerRef = useRef5(null);
2509
+ const [selectedTaskId, setSelectedTaskId] = useState6(null);
2510
+ const [selectedChip, setSelectedChip] = useState6(null);
2511
+ const dateRange = useMemo9(() => getMultiMonthDays(tasks), [tasks]);
2512
+ const [validationResult, setValidationResult] = useState6(null);
2513
+ const [cascadeOverrides, setCascadeOverrides] = useState6(/* @__PURE__ */ new Map());
2514
+ const gridWidth = useMemo9(
2057
2515
  () => Math.round(dateRange.length * dayWidth),
2058
2516
  [dateRange.length, dayWidth]
2059
2517
  );
2060
- const totalGridHeight = useMemo8(
2518
+ const totalGridHeight = useMemo9(
2061
2519
  () => tasks.length * rowHeight,
2062
2520
  [tasks.length, rowHeight]
2063
2521
  );
2064
- const monthStart = useMemo8(() => {
2522
+ const monthStart = useMemo9(() => {
2065
2523
  if (dateRange.length === 0) {
2066
2524
  return new Date(Date.UTC((/* @__PURE__ */ new Date()).getUTCFullYear(), (/* @__PURE__ */ new Date()).getUTCMonth(), 1));
2067
2525
  }
2068
2526
  const firstDay = dateRange[0];
2069
2527
  return new Date(Date.UTC(firstDay.getUTCFullYear(), firstDay.getUTCMonth(), 1));
2070
2528
  }, [dateRange]);
2071
- const todayInRange = useMemo8(() => {
2529
+ const todayInRange = useMemo9(() => {
2072
2530
  const now = /* @__PURE__ */ new Date();
2073
2531
  const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
2074
2532
  return dateRange.some((day) => day.getTime() === today.getTime());
2075
2533
  }, [dateRange]);
2076
- useEffect4(() => {
2534
+ useEffect5(() => {
2077
2535
  const container = scrollContainerRef.current;
2078
2536
  if (!container || dateRange.length === 0) return;
2079
2537
  const now = /* @__PURE__ */ new Date();
@@ -2097,16 +2555,34 @@ var GanttChart = forwardRef(({
2097
2555
  const scrollLeft = Math.round(todayOffset - containerWidth / 2 + dayWidth / 2);
2098
2556
  container.scrollLeft = Math.max(0, scrollLeft);
2099
2557
  }, [dateRange, dayWidth]);
2558
+ const scrollToTask = useCallback6((taskId) => {
2559
+ const container = scrollContainerRef.current;
2560
+ if (!container || dateRange.length === 0) return;
2561
+ const task = tasks.find((t) => t.id === taskId);
2562
+ if (!task) return;
2563
+ const taskStart = new Date(task.startDate);
2564
+ const taskStartUTC = new Date(Date.UTC(
2565
+ taskStart.getUTCFullYear(),
2566
+ taskStart.getUTCMonth(),
2567
+ taskStart.getUTCDate()
2568
+ ));
2569
+ const taskIndex = dateRange.findIndex((day) => day.getTime() === taskStartUTC.getTime());
2570
+ if (taskIndex === -1) return;
2571
+ const taskOffset = taskIndex * dayWidth;
2572
+ const scrollLeft = Math.round(taskOffset - dayWidth * 2);
2573
+ container.scrollLeft = Math.max(0, scrollLeft);
2574
+ }, [tasks, dateRange, dayWidth]);
2100
2575
  useImperativeHandle(
2101
2576
  ref,
2102
2577
  () => ({
2103
- scrollToToday
2578
+ scrollToToday,
2579
+ scrollToTask
2104
2580
  }),
2105
- [scrollToToday]
2581
+ [scrollToToday, scrollToTask]
2106
2582
  );
2107
- const [dragGuideLines, setDragGuideLines] = useState5(null);
2108
- const [draggedTaskOverride, setDraggedTaskOverride] = useState5(null);
2109
- useEffect4(() => {
2583
+ const [dragGuideLines, setDragGuideLines] = useState6(null);
2584
+ const [draggedTaskOverride, setDraggedTaskOverride] = useState6(null);
2585
+ useEffect5(() => {
2110
2586
  const result = validateDependencies(tasks);
2111
2587
  setValidationResult(result);
2112
2588
  onValidateDependencies?.(result);
@@ -2135,7 +2611,7 @@ var GanttChart = forwardRef(({
2135
2611
  });
2136
2612
  onCascade?.(allCascaded);
2137
2613
  }, [tasks, onChange, disableConstraints, onCascade]);
2138
- const dependencyOverrides = useMemo8(() => {
2614
+ const dependencyOverrides = useMemo9(() => {
2139
2615
  const map = new Map(cascadeOverrides);
2140
2616
  if (draggedTaskOverride) {
2141
2617
  map.set(draggedTaskOverride.taskId, {
@@ -2158,7 +2634,7 @@ var GanttChart = forwardRef(({
2158
2634
  const handleTaskSelect = useCallback6((taskId) => {
2159
2635
  setSelectedTaskId(taskId);
2160
2636
  }, []);
2161
- const panStateRef = useRef4(null);
2637
+ const panStateRef = useRef5(null);
2162
2638
  const handlePanStart = useCallback6((e) => {
2163
2639
  if (e.button !== 0) return;
2164
2640
  const target = e.target;
@@ -2180,7 +2656,7 @@ var GanttChart = forwardRef(({
2180
2656
  container.style.cursor = "grabbing";
2181
2657
  e.preventDefault();
2182
2658
  }, []);
2183
- useEffect4(() => {
2659
+ useEffect5(() => {
2184
2660
  const handlePanMove = (e) => {
2185
2661
  const pan = panStateRef.current;
2186
2662
  if (!pan?.active) return;
@@ -2202,15 +2678,15 @@ var GanttChart = forwardRef(({
2202
2678
  window.removeEventListener("mouseup", handlePanEnd);
2203
2679
  };
2204
2680
  }, []);
2205
- return /* @__PURE__ */ jsx13("div", { className: "gantt-container", children: /* @__PURE__ */ jsx13(
2681
+ return /* @__PURE__ */ jsx14("div", { className: "gantt-container", children: /* @__PURE__ */ jsx14(
2206
2682
  "div",
2207
2683
  {
2208
2684
  ref: scrollContainerRef,
2209
2685
  className: "gantt-scrollContainer",
2210
2686
  style: { height: containerHeight ?? "auto", cursor: "grab" },
2211
2687
  onMouseDown: handlePanStart,
2212
- children: /* @__PURE__ */ jsxs10("div", { className: "gantt-scrollContent", children: [
2213
- /* @__PURE__ */ jsx13(
2688
+ children: /* @__PURE__ */ jsxs11("div", { className: "gantt-scrollContent", children: [
2689
+ /* @__PURE__ */ jsx14(
2214
2690
  TaskList,
2215
2691
  {
2216
2692
  tasks,
@@ -2221,11 +2697,14 @@ var GanttChart = forwardRef(({
2221
2697
  selectedTaskId: selectedTaskId ?? void 0,
2222
2698
  onTaskSelect: handleTaskSelect,
2223
2699
  show: showTaskList,
2224
- disableTaskNameEditing
2700
+ disableTaskNameEditing,
2701
+ disableDependencyEditing,
2702
+ onScrollToTask: scrollToTask,
2703
+ onSelectedChipChange: setSelectedChip
2225
2704
  }
2226
2705
  ),
2227
- /* @__PURE__ */ jsxs10("div", { style: { minWidth: `${gridWidth}px`, flex: 1 }, children: [
2228
- /* @__PURE__ */ jsx13("div", { className: "gantt-stickyHeader", style: { width: `${gridWidth}px` }, children: /* @__PURE__ */ jsx13(
2706
+ /* @__PURE__ */ jsxs11("div", { style: { minWidth: `${gridWidth}px`, flex: 1 }, children: [
2707
+ /* @__PURE__ */ jsx14("div", { className: "gantt-stickyHeader", style: { width: `${gridWidth}px` }, children: /* @__PURE__ */ jsx14(
2229
2708
  TimeScaleHeader_default,
2230
2709
  {
2231
2710
  days: dateRange,
@@ -2233,7 +2712,7 @@ var GanttChart = forwardRef(({
2233
2712
  headerHeight
2234
2713
  }
2235
2714
  ) }),
2236
- /* @__PURE__ */ jsxs10(
2715
+ /* @__PURE__ */ jsxs11(
2237
2716
  "div",
2238
2717
  {
2239
2718
  className: "gantt-taskArea",
@@ -2242,7 +2721,7 @@ var GanttChart = forwardRef(({
2242
2721
  width: `${gridWidth}px`
2243
2722
  },
2244
2723
  children: [
2245
- /* @__PURE__ */ jsx13(
2724
+ /* @__PURE__ */ jsx14(
2246
2725
  GridBackground_default,
2247
2726
  {
2248
2727
  dateRange,
@@ -2250,8 +2729,8 @@ var GanttChart = forwardRef(({
2250
2729
  totalHeight: totalGridHeight
2251
2730
  }
2252
2731
  ),
2253
- todayInRange && /* @__PURE__ */ jsx13(TodayIndicator_default, { monthStart, dayWidth }),
2254
- /* @__PURE__ */ jsx13(
2732
+ todayInRange && /* @__PURE__ */ jsx14(TodayIndicator_default, { monthStart, dayWidth }),
2733
+ /* @__PURE__ */ jsx14(
2255
2734
  DependencyLines_default,
2256
2735
  {
2257
2736
  tasks,
@@ -2259,10 +2738,11 @@ var GanttChart = forwardRef(({
2259
2738
  dayWidth,
2260
2739
  rowHeight,
2261
2740
  gridWidth,
2262
- dragOverrides: dependencyOverrides
2741
+ dragOverrides: dependencyOverrides,
2742
+ selectedDep: selectedChip
2263
2743
  }
2264
2744
  ),
2265
- dragGuideLines && /* @__PURE__ */ jsx13(
2745
+ dragGuideLines && /* @__PURE__ */ jsx14(
2266
2746
  DragGuideLines_default,
2267
2747
  {
2268
2748
  isDragging: dragGuideLines.isDragging,
@@ -2272,7 +2752,7 @@ var GanttChart = forwardRef(({
2272
2752
  totalHeight: totalGridHeight
2273
2753
  }
2274
2754
  ),
2275
- tasks.map((task, index) => /* @__PURE__ */ jsx13(
2755
+ tasks.map((task, index) => /* @__PURE__ */ jsx14(
2276
2756
  TaskRow_default,
2277
2757
  {
2278
2758
  task,
@@ -2295,7 +2775,8 @@ var GanttChart = forwardRef(({
2295
2775
  disableConstraints: disableConstraints ?? false,
2296
2776
  overridePosition: cascadeOverrides.get(task.id),
2297
2777
  onCascadeProgress: handleCascadeProgress,
2298
- onCascade: handleCascade
2778
+ onCascade: handleCascade,
2779
+ highlightExpiredTasks
2299
2780
  },
2300
2781
  task.id
2301
2782
  ))
@@ -2311,7 +2792,7 @@ GanttChart.displayName = "GanttChart";
2311
2792
 
2312
2793
  // src/components/ui/Button.tsx
2313
2794
  import React12 from "react";
2314
- import { jsx as jsx14 } from "react/jsx-runtime";
2795
+ import { jsx as jsx15 } from "react/jsx-runtime";
2315
2796
  var Button = React12.forwardRef(
2316
2797
  ({ className, variant = "default", size = "default", children, ...props }, ref) => {
2317
2798
  const classes = [
@@ -2320,7 +2801,7 @@ var Button = React12.forwardRef(
2320
2801
  size !== "default" ? `gantt-btn-${size}` : "",
2321
2802
  className || ""
2322
2803
  ].filter(Boolean).join(" ");
2323
- return /* @__PURE__ */ jsx14("button", { ref, className: classes, ...props, children });
2804
+ return /* @__PURE__ */ jsx15("button", { ref, className: classes, ...props, children });
2324
2805
  }
2325
2806
  );
2326
2807
  Button.displayName = "Button";
@@ -2349,6 +2830,7 @@ export {
2349
2830
  calculateTaskBar,
2350
2831
  calculateWeekendBlocks,
2351
2832
  cascadeByLinks,
2833
+ computeLagFromDates,
2352
2834
  detectCycles,
2353
2835
  detectEdgeZone,
2354
2836
  formatDateLabel,