gantt-lib 0.135.9 → 0.136.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -0
- package/dist/core/scheduling/index.d.mts +1 -1
- package/dist/core/scheduling/index.d.ts +1 -1
- package/dist/{index-DR8Q6-de.d.mts → index-D99kbU4p.d.mts} +5 -0
- package/dist/{index-DR8Q6-de.d.ts → index-D99kbU4p.d.ts} +5 -0
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +15 -2
- package/dist/index.d.ts +15 -2
- package/dist/index.js +440 -117
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +636 -313
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +219 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3306,6 +3306,7 @@ var TimeScaleHeader_default = TimeScaleHeader;
|
|
|
3306
3306
|
|
|
3307
3307
|
// src/components/TaskRow/TaskRow.tsx
|
|
3308
3308
|
var import_react3 = __toESM(require("react"));
|
|
3309
|
+
var import_react_dom = require("react-dom");
|
|
3309
3310
|
|
|
3310
3311
|
// src/utils/geometry.ts
|
|
3311
3312
|
var getUTCDayDifference = (date1, date2) => {
|
|
@@ -4413,12 +4414,35 @@ var useTaskDrag = (options) => {
|
|
|
4413
4414
|
|
|
4414
4415
|
// src/components/TaskRow/TaskRow.tsx
|
|
4415
4416
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
4417
|
+
var formatCompositePreviewDate = (date) => {
|
|
4418
|
+
const month = new Intl.DateTimeFormat("ru-RU", { month: "short", timeZone: "UTC" }).format(date).replace(/\.$/, "");
|
|
4419
|
+
const yearSuffix = date.getUTCFullYear() === (/* @__PURE__ */ new Date()).getFullYear() ? "" : ` ${String(date.getUTCFullYear()).slice(-2)}`;
|
|
4420
|
+
return `${date.getUTCDate()} ${month}${yearSuffix}`;
|
|
4421
|
+
};
|
|
4416
4422
|
var arePropsEqual = (prevProps, nextProps) => {
|
|
4417
|
-
return prevProps.task.id === nextProps.task.id && prevProps.task.name === nextProps.task.name && prevProps.task.startDate === nextProps.task.startDate && prevProps.task.endDate === nextProps.task.endDate && prevProps.task.baselineStartDate === nextProps.task.baselineStartDate && prevProps.task.baselineEndDate === nextProps.task.baselineEndDate && prevProps.task.type === nextProps.task.type && prevProps.task.color === nextProps.task.color && prevProps.task.progress === nextProps.task.progress && prevProps.task.accepted === nextProps.task.accepted && prevProps.monthStart.getTime() === nextProps.monthStart.getTime() && prevProps.dayWidth === nextProps.dayWidth && prevProps.rowHeight === nextProps.rowHeight && prevProps.overridePosition?.left === nextProps.overridePosition?.left && prevProps.overridePosition?.width === nextProps.overridePosition?.width && prevProps.previewPositionStore === nextProps.previewPositionStore && prevProps.allTasks === nextProps.allTasks && prevProps.disableConstraints === nextProps.disableConstraints && prevProps.deferCascadePreview === nextProps.deferCascadePreview && prevProps.task.locked === nextProps.task.locked && prevProps.task.synced === nextProps.task.synced && prevProps.task.divider === nextProps.task.divider && prevProps.highlightExpiredTasks === nextProps.highlightExpiredTasks && prevProps.isCritical === nextProps.isCritical && prevProps.showBaseline === nextProps.showBaseline && prevProps.isFilterMatch === nextProps.isFilterMatch && prevProps.businessDays === nextProps.businessDays && prevProps.customDays === nextProps.customDays && prevProps.isWeekend === nextProps.isWeekend && prevProps.disableTaskDrag === nextProps.disableTaskDrag && prevProps.disableDependencyEditing === nextProps.disableDependencyEditing && prevProps.isDependencyDragActive === nextProps.isDependencyDragActive && prevProps.viewMode === nextProps.viewMode && prevProps.showTaskDateLabels === nextProps.showTaskDateLabels && prevProps.showTaskNames === nextProps.showTaskNames;
|
|
4423
|
+
return prevProps.task.id === nextProps.task.id && prevProps.task.name === nextProps.task.name && prevProps.task.startDate === nextProps.task.startDate && prevProps.task.endDate === nextProps.task.endDate && prevProps.task.baselineStartDate === nextProps.task.baselineStartDate && prevProps.task.baselineEndDate === nextProps.task.baselineEndDate && prevProps.task.type === nextProps.task.type && prevProps.task.color === nextProps.task.color && prevProps.task.progress === nextProps.task.progress && prevProps.task.accepted === nextProps.task.accepted && prevProps.monthStart.getTime() === nextProps.monthStart.getTime() && prevProps.dayWidth === nextProps.dayWidth && prevProps.rowHeight === nextProps.rowHeight && prevProps.overridePosition?.left === nextProps.overridePosition?.left && prevProps.overridePosition?.width === nextProps.overridePosition?.width && prevProps.previewPositionStore === nextProps.previewPositionStore && prevProps.allTasks === nextProps.allTasks && prevProps.disableConstraints === nextProps.disableConstraints && prevProps.deferCascadePreview === nextProps.deferCascadePreview && prevProps.task.locked === nextProps.task.locked && prevProps.task.synced === nextProps.task.synced && prevProps.task.divider === nextProps.task.divider && prevProps.highlightExpiredTasks === nextProps.highlightExpiredTasks && prevProps.isCritical === nextProps.isCritical && prevProps.showBaseline === nextProps.showBaseline && prevProps.onCompositeToggle === nextProps.onCompositeToggle && prevProps.compactDetail === nextProps.compactDetail && prevProps.compositeParentColor === nextProps.compositeParentColor && prevProps.compositeExpanded === nextProps.compositeExpanded && prevProps.isFilterMatch === nextProps.isFilterMatch && prevProps.businessDays === nextProps.businessDays && prevProps.customDays === nextProps.customDays && prevProps.isWeekend === nextProps.isWeekend && prevProps.disableTaskDrag === nextProps.disableTaskDrag && prevProps.disableDependencyEditing === nextProps.disableDependencyEditing && prevProps.isDependencyDragActive === nextProps.isDependencyDragActive && prevProps.viewMode === nextProps.viewMode && prevProps.showTaskDateLabels === nextProps.showTaskDateLabels && prevProps.showTaskNames === nextProps.showTaskNames;
|
|
4418
4424
|
};
|
|
4419
4425
|
var TaskRow = import_react3.default.memo(
|
|
4420
|
-
({ task, monthStart, dayWidth, rowHeight, onTasksChange, onScheduleIntent, onDragStateChange, rowIndex, allTasks, enableAutoSchedule, disableConstraints, deferCascadePreview = false, overridePosition, previewPositionStore, onCascadeProgress, onCascade, divider, highlightExpiredTasks, isCritical = false, showBaseline = false, isFilterMatch = false, businessDays, customDays, isWeekend: isWeekend3, disableTaskDrag = false, disableDependencyEditing = false, onDependencyPortPointerDown, isDependencyDragActive = false, viewMode = "day", showTaskDateLabels = true, showTaskNames = true }) => {
|
|
4426
|
+
({ task, monthStart, dayWidth, rowHeight, onTasksChange, onScheduleIntent, onDragStateChange, rowIndex, allTasks, enableAutoSchedule, disableConstraints, deferCascadePreview = false, overridePosition, previewPositionStore, onCascadeProgress, onCascade, divider, highlightExpiredTasks, isCritical = false, showBaseline = false, isFilterMatch = false, businessDays, customDays, isWeekend: isWeekend3, disableTaskDrag = false, disableDependencyEditing = false, onDependencyPortPointerDown, isDependencyDragActive = false, viewMode = "day", showTaskDateLabels = true, showTaskNames = true, onCompositeToggle, compactDetail = false, compositeParentColor, compositeExpanded = false }) => {
|
|
4421
4427
|
const defaultParentBarColor = "#782FC4";
|
|
4428
|
+
const [showCompositePreview, setShowCompositePreview] = (0, import_react3.useState)(false);
|
|
4429
|
+
const [compositePreviewPosition, setCompositePreviewPosition] = (0, import_react3.useState)(null);
|
|
4430
|
+
const pointerStart = (0, import_react3.useRef)(null);
|
|
4431
|
+
const suppressCompositeClick = (0, import_react3.useRef)(false);
|
|
4432
|
+
const compositeChildren = (0, import_react3.useMemo)(
|
|
4433
|
+
() => task.composite ? (allTasks ?? []).filter((child) => child.parentId === task.id) : [],
|
|
4434
|
+
[allTasks, task.composite, task.id]
|
|
4435
|
+
);
|
|
4436
|
+
(0, import_react3.useEffect)(() => {
|
|
4437
|
+
if (!showCompositePreview) return;
|
|
4438
|
+
const hide = () => setShowCompositePreview(false);
|
|
4439
|
+
window.addEventListener("scroll", hide, true);
|
|
4440
|
+
window.addEventListener("resize", hide);
|
|
4441
|
+
return () => {
|
|
4442
|
+
window.removeEventListener("scroll", hide, true);
|
|
4443
|
+
window.removeEventListener("resize", hide);
|
|
4444
|
+
};
|
|
4445
|
+
}, [showCompositePreview]);
|
|
4422
4446
|
const { divider: taskDivider } = task;
|
|
4423
4447
|
const normalizedTask = (0, import_react3.useMemo)(() => normalizeTaskDatesForType(task), [task]);
|
|
4424
4448
|
const milestone = (0, import_react3.useMemo)(() => isMilestoneTask(normalizedTask), [normalizedTask]);
|
|
@@ -4435,6 +4459,7 @@ var TaskRow = import_react3.default.memo(
|
|
|
4435
4459
|
const isParent = (0, import_react3.useMemo)(() => {
|
|
4436
4460
|
return allTasks ? isTaskParent(task.id, allTasks) : false;
|
|
4437
4461
|
}, [allTasks, task.id]);
|
|
4462
|
+
const isVisualParent = isParent && !task.composite;
|
|
4438
4463
|
const childCount = (0, import_react3.useMemo)(() => {
|
|
4439
4464
|
return allTasks ? getChildren(task.id, allTasks).length : 0;
|
|
4440
4465
|
}, [allTasks, task.id]);
|
|
@@ -4480,19 +4505,19 @@ var TaskRow = import_react3.default.memo(
|
|
|
4480
4505
|
if (isExpired) {
|
|
4481
4506
|
return "color-mix(in srgb, var(--gantt-expired-color) 40%, black)";
|
|
4482
4507
|
}
|
|
4483
|
-
const baseColor =
|
|
4508
|
+
const baseColor = isVisualParent ? task.color || defaultParentBarColor : task.color || "var(--gantt-task-bar-default-color)";
|
|
4484
4509
|
return `color-mix(in srgb, ${baseColor} 40%, black)`;
|
|
4485
|
-
}, [defaultParentBarColor, isCritical, isExpired,
|
|
4510
|
+
}, [defaultParentBarColor, isCritical, isExpired, isVisualParent, task.color]);
|
|
4486
4511
|
const barStyle = (0, import_react3.useMemo)(() => {
|
|
4487
4512
|
const parentBarColor = task.color || defaultParentBarColor;
|
|
4488
4513
|
if (isCritical && !isExpired) {
|
|
4489
4514
|
const c = criticalBarColor;
|
|
4490
|
-
if (
|
|
4515
|
+
if (isVisualParent) {
|
|
4491
4516
|
return { backgroundColor: c, "--gantt-parent-bar-color": c };
|
|
4492
4517
|
}
|
|
4493
4518
|
return { backgroundColor: c };
|
|
4494
4519
|
}
|
|
4495
|
-
if (
|
|
4520
|
+
if (isVisualParent) {
|
|
4496
4521
|
if (progressWidth >= 100) {
|
|
4497
4522
|
const c = isExpired ? "color-mix(in srgb, var(--gantt-expired-color) 40%, black)" : `color-mix(in srgb, ${parentBarColor} 40%, black)`;
|
|
4498
4523
|
return { backgroundColor: c, "--gantt-parent-bar-color": c };
|
|
@@ -4503,7 +4528,7 @@ var TaskRow = import_react3.default.memo(
|
|
|
4503
4528
|
return { backgroundColor: progressColor };
|
|
4504
4529
|
}
|
|
4505
4530
|
return { backgroundColor: barColor };
|
|
4506
|
-
}, [isCritical, defaultParentBarColor, isExpired,
|
|
4531
|
+
}, [isCritical, defaultParentBarColor, isExpired, isVisualParent, progressWidth, barColor, progressColor, task.color]);
|
|
4507
4532
|
const handleDragEnd = (result) => {
|
|
4508
4533
|
const updatedTask = {
|
|
4509
4534
|
...normalizedTask,
|
|
@@ -4577,6 +4602,25 @@ var TaskRow = import_react3.default.memo(
|
|
|
4577
4602
|
}, [displayLeft, dayWidth, milestoneGeometry.size]);
|
|
4578
4603
|
const visualLeft = milestone ? displayMilestoneGeometry.left : displayLeft;
|
|
4579
4604
|
const visualWidth = milestone ? displayMilestoneGeometry.size : displayWidth;
|
|
4605
|
+
const compositeSegments = (0, import_react3.useMemo)(() => {
|
|
4606
|
+
if (!task.composite || width <= 0) return [];
|
|
4607
|
+
const laneEnds = [];
|
|
4608
|
+
return compositeChildren.map((child) => {
|
|
4609
|
+
const segment = calculateTaskBar(parseUTCDate(child.startDate), parseUTCDate(child.endDate), monthStart, dayWidth);
|
|
4610
|
+
let lane = laneEnds.findIndex((end) => end <= segment.left);
|
|
4611
|
+
if (lane < 0) lane = laneEnds.length;
|
|
4612
|
+
laneEnds[lane] = segment.left + segment.width;
|
|
4613
|
+
return {
|
|
4614
|
+
id: child.id,
|
|
4615
|
+
name: child.name,
|
|
4616
|
+
left: (segment.left - left) / width * 100,
|
|
4617
|
+
width: segment.width / width * 100,
|
|
4618
|
+
lane
|
|
4619
|
+
};
|
|
4620
|
+
});
|
|
4621
|
+
}, [task.composite, compositeChildren, monthStart, dayWidth, left, width, displayLeft]);
|
|
4622
|
+
const compositeLaneCount = Math.max(1, ...compositeSegments.map((segment) => segment.lane + 1));
|
|
4623
|
+
const showCompositeSegments = task.composite && compositeSegments.length > 0 && visualWidth / compositeSegments.length >= 22;
|
|
4580
4624
|
const shouldRenderBaseline = showBaseline && baselineGeometry !== null;
|
|
4581
4625
|
const hasPreviewPosition = isDragging || effectiveOverridePosition !== void 0;
|
|
4582
4626
|
const currentStartDate = hasPreviewPosition ? pixelsToDate(displayLeft, monthStart, dayWidth) : taskStartDate;
|
|
@@ -4594,17 +4638,20 @@ var TaskRow = import_react3.default.memo(
|
|
|
4594
4638
|
if (lastDigit >= 2 && lastDigit <= 4) return `${count} \u0440\u0430\u0431\u043E\u0442\u044B`;
|
|
4595
4639
|
return `${count} \u0440\u0430\u0431\u043E\u0442`;
|
|
4596
4640
|
};
|
|
4597
|
-
const estimatedTextWidth =
|
|
4598
|
-
const showProgressInside = !milestone && progressWidth > 0 && displayWidth > estimatedTextWidth;
|
|
4599
|
-
const MIN_DURATION_WIDTH =
|
|
4600
|
-
const showDurationInside = !milestone && durationDays >= 2 && displayWidth > MIN_DURATION_WIDTH;
|
|
4641
|
+
const estimatedTextWidth = isVisualParent ? 120 : durationDays >= 10 ? 76 : 62;
|
|
4642
|
+
const showProgressInside = !milestone && progressWidth > 0 && displayWidth > (compactDetail ? 28 : estimatedTextWidth);
|
|
4643
|
+
const MIN_DURATION_WIDTH = isVisualParent ? 80 : task.composite ? 92 : 50;
|
|
4644
|
+
const showDurationInside = !compactDetail && !milestone && durationDays >= 2 && displayWidth > MIN_DURATION_WIDTH;
|
|
4601
4645
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
4602
4646
|
"div",
|
|
4603
4647
|
{
|
|
4604
4648
|
"data-filter-match": isFilterMatch ? "true" : "false",
|
|
4605
4649
|
"data-gantt-task-row-id": task.id,
|
|
4606
|
-
className: `gantt-tr-row ${isFilterMatch ? "gantt-tr-row-filter-match" : ""}`,
|
|
4607
|
-
style: {
|
|
4650
|
+
className: `gantt-tr-row ${compactDetail ? "gantt-tr-row-compositeDetail" : ""} ${isFilterMatch ? "gantt-tr-row-filter-match" : ""}`,
|
|
4651
|
+
style: {
|
|
4652
|
+
height: `${rowHeight}px`,
|
|
4653
|
+
"--gantt-tr-composite-detail-color": compositeParentColor ?? "var(--gantt-task-bar-default-color, #8b5cf6)"
|
|
4654
|
+
},
|
|
4608
4655
|
children: [
|
|
4609
4656
|
taskDivider === "top" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "gantt-tr-divider gantt-tr-divider-top" }),
|
|
4610
4657
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "gantt-tr-taskContainer", children: [
|
|
@@ -4622,7 +4669,11 @@ var TaskRow = import_react3.default.memo(
|
|
|
4622
4669
|
"div",
|
|
4623
4670
|
{
|
|
4624
4671
|
"data-taskbar": true,
|
|
4625
|
-
|
|
4672
|
+
role: task.composite ? "button" : void 0,
|
|
4673
|
+
tabIndex: task.composite ? 0 : void 0,
|
|
4674
|
+
"aria-label": task.composite ? `${task.name}: ${compositeExpanded ? "\u0441\u0432\u0435\u0440\u043D\u0443\u0442\u044C" : "\u0440\u0430\u0441\u043A\u0440\u044B\u0442\u044C"} \u0434\u0435\u0442\u0430\u043B\u0438` : void 0,
|
|
4675
|
+
"aria-expanded": task.composite ? compositeExpanded : void 0,
|
|
4676
|
+
className: `gantt-tr-taskBar ${isDragging ? "gantt-tr-dragging" : ""} ${task.locked ? "gantt-tr-locked" : ""} ${task.synced === false ? "gantt-tr-unsynced" : ""} ${isVisualParent ? "gantt-tr-parentBar" : ""} ${task.composite ? "gantt-tr-compositeBar" : ""} ${milestone ? "gantt-tr-milestone" : ""} ${isCritical ? "gantt-tr-critical" : ""}`,
|
|
4626
4677
|
style: {
|
|
4627
4678
|
left: `${visualLeft}px`,
|
|
4628
4679
|
...barStyle,
|
|
@@ -4632,14 +4683,57 @@ var TaskRow = import_react3.default.memo(
|
|
|
4632
4683
|
padding: 0
|
|
4633
4684
|
} : {
|
|
4634
4685
|
width: `${visualWidth}px`,
|
|
4635
|
-
height:
|
|
4686
|
+
height: compactDetail ? "18px" : isVisualParent ? "var(--gantt-parent-bar-height, 14px)" : "var(--gantt-task-bar-height)"
|
|
4636
4687
|
},
|
|
4637
4688
|
cursor: dragHandleProps.style.cursor,
|
|
4638
4689
|
userSelect: dragHandleProps.style.userSelect
|
|
4639
4690
|
},
|
|
4640
4691
|
onMouseDown: dragHandleProps.onMouseDown,
|
|
4641
4692
|
onMouseMove: dragHandleProps.onMouseMove,
|
|
4642
|
-
onMouseLeave:
|
|
4693
|
+
onMouseLeave: () => {
|
|
4694
|
+
dragHandleProps.onMouseLeave();
|
|
4695
|
+
setShowCompositePreview(false);
|
|
4696
|
+
},
|
|
4697
|
+
onMouseEnter: task.composite ? (event) => {
|
|
4698
|
+
const rect = event.currentTarget.getBoundingClientRect();
|
|
4699
|
+
const previewWidth = 220;
|
|
4700
|
+
const previewHeight = Math.min(340, 68 + Math.min(compositeChildren.length, 12) * 20);
|
|
4701
|
+
setCompositePreviewPosition({
|
|
4702
|
+
left: Math.max(8, Math.min(rect.left, window.innerWidth - previewWidth - 8)),
|
|
4703
|
+
top: rect.bottom + previewHeight + 8 < window.innerHeight ? rect.bottom + 6 : Math.max(8, rect.top - previewHeight - 6)
|
|
4704
|
+
});
|
|
4705
|
+
setShowCompositePreview(true);
|
|
4706
|
+
} : void 0,
|
|
4707
|
+
onMouseDownCapture: task.composite ? (event) => {
|
|
4708
|
+
suppressCompositeClick.current = Boolean(event.target.closest(".gantt-tr-resizeHandle"));
|
|
4709
|
+
pointerStart.current = { x: event.clientX, y: event.clientY };
|
|
4710
|
+
} : void 0,
|
|
4711
|
+
onMouseMoveCapture: task.composite ? (event) => {
|
|
4712
|
+
const start = pointerStart.current;
|
|
4713
|
+
if (start && Math.hypot(event.clientX - start.x, event.clientY - start.y) >= 4) {
|
|
4714
|
+
suppressCompositeClick.current = true;
|
|
4715
|
+
}
|
|
4716
|
+
} : void 0,
|
|
4717
|
+
onMouseUpCapture: task.composite ? (event) => {
|
|
4718
|
+
const start = pointerStart.current;
|
|
4719
|
+
if (start && Math.hypot(event.clientX - start.x, event.clientY - start.y) >= 4) {
|
|
4720
|
+
suppressCompositeClick.current = true;
|
|
4721
|
+
}
|
|
4722
|
+
pointerStart.current = null;
|
|
4723
|
+
} : void 0,
|
|
4724
|
+
onClick: task.composite ? () => {
|
|
4725
|
+
if (!isDragging && !suppressCompositeClick.current) {
|
|
4726
|
+
setShowCompositePreview(false);
|
|
4727
|
+
onCompositeToggle?.("click");
|
|
4728
|
+
}
|
|
4729
|
+
suppressCompositeClick.current = false;
|
|
4730
|
+
} : void 0,
|
|
4731
|
+
onKeyDown: task.composite ? (event) => {
|
|
4732
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
4733
|
+
event.preventDefault();
|
|
4734
|
+
onCompositeToggle?.("keyboard");
|
|
4735
|
+
}
|
|
4736
|
+
} : void 0,
|
|
4643
4737
|
children: [
|
|
4644
4738
|
!milestone && progressWidth > 0 && progressWidth < 100 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
4645
4739
|
"div",
|
|
@@ -4648,14 +4742,28 @@ var TaskRow = import_react3.default.memo(
|
|
|
4648
4742
|
style: {
|
|
4649
4743
|
width: `${progressWidth}%`,
|
|
4650
4744
|
backgroundColor: progressColor,
|
|
4651
|
-
...
|
|
4745
|
+
...isVisualParent && {
|
|
4652
4746
|
borderRadius: "var(--gantt-parent-bar-radius, 8px) 0 0 0"
|
|
4653
4747
|
}
|
|
4654
4748
|
}
|
|
4655
4749
|
}
|
|
4656
4750
|
),
|
|
4657
4751
|
!milestone && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "gantt-tr-resizeHandle gantt-tr-resizeHandleLeft" }),
|
|
4658
|
-
|
|
4752
|
+
showCompositeSegments && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gantt-tr-compositeSegments", "aria-hidden": "true", children: compositeSegments.map((segment) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
4753
|
+
"span",
|
|
4754
|
+
{
|
|
4755
|
+
className: "gantt-tr-compositeSegment",
|
|
4756
|
+
style: {
|
|
4757
|
+
left: `${segment.left}%`,
|
|
4758
|
+
width: `${segment.width}%`,
|
|
4759
|
+
top: `${segment.lane / compositeLaneCount * 100}%`,
|
|
4760
|
+
height: `${100 / compositeLaneCount}%`
|
|
4761
|
+
}
|
|
4762
|
+
},
|
|
4763
|
+
segment.id
|
|
4764
|
+
)) }),
|
|
4765
|
+
task.composite && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gantt-tr-compositeHoverChevron", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { className: `gantt-tr-compositeChevron${compositeExpanded ? " gantt-tr-compositeChevron-open" : ""}`, viewBox: "0 0 20 20", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m7 4 6 6-6 6", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }),
|
|
4766
|
+
showDurationInside && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gantt-tr-taskDuration", children: isVisualParent ? getChildCountLabel(childCount) : `${durationDays} \u0434` }),
|
|
4659
4767
|
progressWidth > 0 && showProgressInside && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "gantt-tr-progressText", children: [
|
|
4660
4768
|
progressWidth,
|
|
4661
4769
|
"%"
|
|
@@ -4664,6 +4772,41 @@ var TaskRow = import_react3.default.memo(
|
|
|
4664
4772
|
]
|
|
4665
4773
|
}
|
|
4666
4774
|
),
|
|
4775
|
+
task.composite && showCompositePreview && compositePreviewPosition && compositeChildren.length > 0 && !isDragging && typeof document !== "undefined" && (0, import_react_dom.createPortal)(
|
|
4776
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
4777
|
+
"div",
|
|
4778
|
+
{
|
|
4779
|
+
className: "gantt-tr-compositePreview",
|
|
4780
|
+
style: { left: `${compositePreviewPosition.left}px`, top: `${compositePreviewPosition.top}px` },
|
|
4781
|
+
role: "tooltip",
|
|
4782
|
+
children: [
|
|
4783
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "gantt-tr-compositePreviewAxis", children: [
|
|
4784
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: formatCompositePreviewDate(currentStartDate) }),
|
|
4785
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: formatCompositePreviewDate(currentEndDate) })
|
|
4786
|
+
] }),
|
|
4787
|
+
compositeChildren.slice(0, 12).map((child) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "gantt-tr-compositePreviewRow", children: [
|
|
4788
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: child.name }),
|
|
4789
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gantt-tr-compositePreviewTrack", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
4790
|
+
"span",
|
|
4791
|
+
{
|
|
4792
|
+
className: "gantt-tr-compositePreviewBar",
|
|
4793
|
+
style: {
|
|
4794
|
+
left: `${Math.max(0, (parseUTCDate(child.startDate).getTime() - taskStartDate.getTime()) / (taskEndDate.getTime() - taskStartDate.getTime() + 864e5) * 100)}%`,
|
|
4795
|
+
width: `${Math.max(2, (parseUTCDate(child.endDate).getTime() - parseUTCDate(child.startDate).getTime() + 864e5) / (taskEndDate.getTime() - taskStartDate.getTime() + 864e5) * 100)}%`,
|
|
4796
|
+
backgroundColor: barColor
|
|
4797
|
+
}
|
|
4798
|
+
}
|
|
4799
|
+
) })
|
|
4800
|
+
] }, child.id)),
|
|
4801
|
+
compositeChildren.length > 12 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
4802
|
+
"+",
|
|
4803
|
+
compositeChildren.length - 12
|
|
4804
|
+
] })
|
|
4805
|
+
]
|
|
4806
|
+
}
|
|
4807
|
+
),
|
|
4808
|
+
document.body
|
|
4809
|
+
),
|
|
4667
4810
|
!disableDependencyEditing && onDependencyPortPointerDown && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
4668
4811
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
4669
4812
|
"button",
|
|
@@ -4672,7 +4815,7 @@ var TaskRow = import_react3.default.memo(
|
|
|
4672
4815
|
"data-gantt-dependency-port": true,
|
|
4673
4816
|
"data-task-id": task.id,
|
|
4674
4817
|
"data-port-side": "left",
|
|
4675
|
-
className: `gantt-tr-dependencyPort gantt-tr-dependencyPortLeft ${milestone ? "gantt-tr-dependencyPortMilestone" : ""} ${
|
|
4818
|
+
className: `gantt-tr-dependencyPort gantt-tr-dependencyPortLeft ${milestone ? "gantt-tr-dependencyPortMilestone" : ""} ${isVisualParent ? "gantt-tr-dependencyPortParent" : ""} ${isDependencyDragActive ? "gantt-tr-dependencyPortDragActive" : ""}`,
|
|
4676
4819
|
style: { left: `${visualLeft - 24}px` },
|
|
4677
4820
|
"aria-label": `\u041D\u0430\u0447\u0430\u0442\u044C \u0441\u0432\u044F\u0437\u044C \u043E\u0442 \u043B\u0435\u0432\u043E\u0433\u043E \u043A\u0440\u0430\u044F: ${task.name}`,
|
|
4678
4821
|
title: "\u041F\u043E\u0442\u044F\u043D\u0438\u0442\u0435 \u043A \u043A\u0440\u0430\u044E \u0434\u0440\u0443\u0433\u043E\u0439 \u043F\u043E\u043B\u043E\u0441\u044B, \u0447\u0442\u043E\u0431\u044B \u0441\u043E\u0437\u0434\u0430\u0442\u044C \u0441\u0432\u044F\u0437\u044C",
|
|
@@ -4686,7 +4829,7 @@ var TaskRow = import_react3.default.memo(
|
|
|
4686
4829
|
"data-gantt-dependency-port": true,
|
|
4687
4830
|
"data-task-id": task.id,
|
|
4688
4831
|
"data-port-side": "right",
|
|
4689
|
-
className: `gantt-tr-dependencyPort gantt-tr-dependencyPortRight ${milestone ? "gantt-tr-dependencyPortMilestone" : ""} ${
|
|
4832
|
+
className: `gantt-tr-dependencyPort gantt-tr-dependencyPortRight ${milestone ? "gantt-tr-dependencyPortMilestone" : ""} ${isVisualParent ? "gantt-tr-dependencyPortParent" : ""} ${isDependencyDragActive ? "gantt-tr-dependencyPortDragActive" : ""}`,
|
|
4690
4833
|
style: { left: `${visualLeft + visualWidth}px` },
|
|
4691
4834
|
"aria-label": `\u041D\u0430\u0447\u0430\u0442\u044C \u0441\u0432\u044F\u0437\u044C \u043E\u0442 \u043F\u0440\u0430\u0432\u043E\u0433\u043E \u043A\u0440\u0430\u044F: ${task.name}`,
|
|
4692
4835
|
title: "\u041F\u043E\u0442\u044F\u043D\u0438\u0442\u0435 \u043A \u043A\u0440\u0430\u044E \u0434\u0440\u0443\u0433\u043E\u0439 \u043F\u043E\u043B\u043E\u0441\u044B, \u0447\u0442\u043E\u0431\u044B \u0441\u043E\u0437\u0434\u0430\u0442\u044C \u0441\u0432\u044F\u0437\u044C",
|
|
@@ -4725,6 +4868,14 @@ var TaskRow = import_react3.default.memo(
|
|
|
4725
4868
|
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zM12 17c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z" })
|
|
4726
4869
|
}
|
|
4727
4870
|
),
|
|
4871
|
+
!showDurationInside && !milestone && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
4872
|
+
"span",
|
|
4873
|
+
{
|
|
4874
|
+
className: `gantt-tr-externalDuration gantt-tr-durationBeforeBar${compactDetail ? " gantt-tr-compositeDuration" : ""}`,
|
|
4875
|
+
style: { left: `${visualLeft - 46}px`, color: isParent ? task.color || defaultParentBarColor : barColor },
|
|
4876
|
+
children: isVisualParent ? getChildCountLabel(childCount) : `${durationDays} \u0434`
|
|
4877
|
+
}
|
|
4878
|
+
),
|
|
4728
4879
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
4729
4880
|
"div",
|
|
4730
4881
|
{
|
|
@@ -4734,7 +4885,6 @@ var TaskRow = import_react3.default.memo(
|
|
|
4734
4885
|
color: isParent ? task.color || defaultParentBarColor : barColor
|
|
4735
4886
|
},
|
|
4736
4887
|
children: [
|
|
4737
|
-
!showDurationInside && !milestone && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gantt-tr-externalDuration", children: isParent ? getChildCountLabel(childCount) : `${durationDays} \u0434` }),
|
|
4738
4888
|
progressWidth > 0 && !showProgressInside && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "gantt-tr-externalProgress", children: [
|
|
4739
4889
|
progressWidth,
|
|
4740
4890
|
"%"
|
|
@@ -5038,6 +5188,8 @@ var DependencyLines = import_react7.default.memo(({
|
|
|
5038
5188
|
gridWidth,
|
|
5039
5189
|
totalHeight,
|
|
5040
5190
|
rowIndexByTaskId,
|
|
5191
|
+
rowTops,
|
|
5192
|
+
rowHeights,
|
|
5041
5193
|
dragOverrides,
|
|
5042
5194
|
selectedDep,
|
|
5043
5195
|
criticalTaskIds,
|
|
@@ -5061,7 +5213,8 @@ var DependencyLines = import_react7.default.memo(({
|
|
|
5061
5213
|
left: computed.left,
|
|
5062
5214
|
right: computed.right,
|
|
5063
5215
|
centerX: computed.centerX,
|
|
5064
|
-
rowTop: rowIndex * rowHeight,
|
|
5216
|
+
rowTop: rowTops?.[rowIndex] ?? rowIndex * rowHeight,
|
|
5217
|
+
rowHeight: rowHeights?.[rowIndex] ?? rowHeight,
|
|
5065
5218
|
isVirtual: false
|
|
5066
5219
|
});
|
|
5067
5220
|
});
|
|
@@ -5081,6 +5234,7 @@ var DependencyLines = import_react7.default.memo(({
|
|
|
5081
5234
|
right: computed.right,
|
|
5082
5235
|
centerX: computed.centerX,
|
|
5083
5236
|
rowTop: ancestorPosition.rowTop,
|
|
5237
|
+
rowHeight: ancestorPosition.rowHeight,
|
|
5084
5238
|
isVirtual: true
|
|
5085
5239
|
});
|
|
5086
5240
|
}
|
|
@@ -5094,18 +5248,19 @@ var DependencyLines = import_react7.default.memo(({
|
|
|
5094
5248
|
const override = dragOverrides?.get(task.id);
|
|
5095
5249
|
const computed = resolveTaskHorizontalGeometry(task, monthStart, dayWidth, override);
|
|
5096
5250
|
const rowIndex = rowIndexByTaskId?.get(task.id);
|
|
5097
|
-
const rowTop = rowIndex !== void 0 ? rowIndex * rowHeight : 0;
|
|
5251
|
+
const rowTop = rowIndex !== void 0 ? rowTops?.[rowIndex] ?? rowIndex * rowHeight : 0;
|
|
5098
5252
|
positions.set(task.id, {
|
|
5099
5253
|
left: computed.left,
|
|
5100
5254
|
right: computed.right,
|
|
5101
5255
|
centerX: computed.centerX,
|
|
5102
5256
|
rowTop,
|
|
5257
|
+
rowHeight: rowIndex !== void 0 ? rowHeights?.[rowIndex] ?? rowHeight : rowHeight,
|
|
5103
5258
|
isVirtual: false
|
|
5104
5259
|
});
|
|
5105
5260
|
}
|
|
5106
5261
|
}
|
|
5107
5262
|
return { taskPositions: positions, taskIndices: indices, hiddenTaskIds: hidden };
|
|
5108
|
-
}, [tasks, tasksForPositions, allTasks, collapsedParentIds, monthStart, dayWidth, rowHeight, dragOverrides, rowIndexByTaskId]);
|
|
5263
|
+
}, [tasks, tasksForPositions, allTasks, collapsedParentIds, monthStart, dayWidth, rowHeight, rowTops, rowHeights, dragOverrides, rowIndexByTaskId]);
|
|
5109
5264
|
const tasksForCycleDetection = allTasks ?? tasks;
|
|
5110
5265
|
const cycleInfo = (0, import_react7.useMemo)(() => {
|
|
5111
5266
|
const result = detectCycles(tasksForCycleDetection);
|
|
@@ -5147,7 +5302,9 @@ var DependencyLines = import_react7.default.memo(({
|
|
|
5147
5302
|
continue;
|
|
5148
5303
|
}
|
|
5149
5304
|
}
|
|
5150
|
-
|
|
5305
|
+
const predecessorVisibleId = predecessor.isVirtual ? findVisibleAncestor(taskMap.get(edge.predecessorId), collapsedParentIds, taskMap)?.id : edge.predecessorId;
|
|
5306
|
+
const successorVisibleId = successor.isVirtual ? findVisibleAncestor(taskMap.get(edge.successorId), collapsedParentIds, taskMap)?.id : edge.successorId;
|
|
5307
|
+
if (!renderedTaskIdSet.has(predecessorVisibleId ?? "") && !renderedTaskIdSet.has(successorVisibleId ?? "")) {
|
|
5151
5308
|
continue;
|
|
5152
5309
|
}
|
|
5153
5310
|
const isVirtual = predecessor.isVirtual || successor.isVirtual;
|
|
@@ -5161,9 +5318,9 @@ var DependencyLines = import_react7.default.memo(({
|
|
|
5161
5318
|
let toY;
|
|
5162
5319
|
if (reverseOrder) {
|
|
5163
5320
|
fromY = predecessor.rowTop + 10;
|
|
5164
|
-
toY = successor.rowTop + rowHeight - 6;
|
|
5321
|
+
toY = successor.rowTop + successor.rowHeight - 6;
|
|
5165
5322
|
} else {
|
|
5166
|
-
fromY = predecessor.rowTop + rowHeight - 10;
|
|
5323
|
+
fromY = predecessor.rowTop + predecessor.rowHeight - 10;
|
|
5167
5324
|
toY = successor.rowTop + 6;
|
|
5168
5325
|
}
|
|
5169
5326
|
let fromX = predecessorTask && isMilestoneTask(predecessorTask) ? predecessor.centerX : edge.type === "SS" || edge.type === "SF" ? predecessor.left : predecessor.right;
|
|
@@ -6841,6 +6998,7 @@ var TaskListRow = import_react11.default.memo(
|
|
|
6841
6998
|
taskListMenuCommands = [],
|
|
6842
6999
|
hideTaskListRowActions = false,
|
|
6843
7000
|
rowClassName,
|
|
7001
|
+
compositeParentColor,
|
|
6844
7002
|
getTaskListNamePrefixIcon,
|
|
6845
7003
|
taskDateChangeMode = "preserve-duration",
|
|
6846
7004
|
onTaskDateChangeModeChange,
|
|
@@ -6925,6 +7083,35 @@ var TaskListRow = import_react11.default.memo(
|
|
|
6925
7083
|
[businessDays, weekendPredicate]
|
|
6926
7084
|
);
|
|
6927
7085
|
const isCollapsed = collapsedParentIds.has(task.id);
|
|
7086
|
+
const [compositeIconMode, setCompositeIconMode] = (0, import_react11.useState)(
|
|
7087
|
+
() => isCollapsed ? "composite" : "down"
|
|
7088
|
+
);
|
|
7089
|
+
const compositeIconModeRef = (0, import_react11.useRef)(compositeIconMode);
|
|
7090
|
+
const [compositeIconAnimation, setCompositeIconAnimation] = (0, import_react11.useState)(null);
|
|
7091
|
+
const [compositeIconAnimationPhase, setCompositeIconAnimationPhase] = (0, import_react11.useState)(null);
|
|
7092
|
+
(0, import_react11.useEffect)(() => {
|
|
7093
|
+
const nextMode = isCollapsed ? "composite" : "down";
|
|
7094
|
+
if (nextMode === compositeIconModeRef.current) {
|
|
7095
|
+
setCompositeIconAnimation(null);
|
|
7096
|
+
setCompositeIconAnimationPhase(null);
|
|
7097
|
+
return;
|
|
7098
|
+
}
|
|
7099
|
+
setCompositeIconAnimation(isCollapsed ? "closing" : "opening");
|
|
7100
|
+
setCompositeIconAnimationPhase("outgoing");
|
|
7101
|
+
const swapTimeoutId = window.setTimeout(() => {
|
|
7102
|
+
compositeIconModeRef.current = nextMode;
|
|
7103
|
+
setCompositeIconMode(nextMode);
|
|
7104
|
+
setCompositeIconAnimationPhase("incoming");
|
|
7105
|
+
}, 120);
|
|
7106
|
+
const finishTimeoutId = window.setTimeout(() => {
|
|
7107
|
+
setCompositeIconAnimation(null);
|
|
7108
|
+
setCompositeIconAnimationPhase(null);
|
|
7109
|
+
}, 240);
|
|
7110
|
+
return () => {
|
|
7111
|
+
window.clearTimeout(swapTimeoutId);
|
|
7112
|
+
window.clearTimeout(finishTimeoutId);
|
|
7113
|
+
};
|
|
7114
|
+
}, [isCollapsed]);
|
|
6928
7115
|
const getHierarchyLineColor = (0, import_react11.useCallback)((columnDepth) => {
|
|
6929
7116
|
return columnDepth % 2 === 0 ? "#93c5fd" : "var(--gantt-hierarchy-line-color)";
|
|
6930
7117
|
}, []);
|
|
@@ -7033,6 +7220,7 @@ var TaskListRow = import_react11.default.memo(
|
|
|
7033
7220
|
);
|
|
7034
7221
|
const handleNameDoubleClick = (0, import_react11.useCallback)(
|
|
7035
7222
|
(e) => {
|
|
7223
|
+
if (task.composite) return;
|
|
7036
7224
|
if (disableTaskNameEditing) return;
|
|
7037
7225
|
e.stopPropagation();
|
|
7038
7226
|
nameConfirmedRef.current = false;
|
|
@@ -7040,7 +7228,7 @@ var TaskListRow = import_react11.default.memo(
|
|
|
7040
7228
|
setNameValue(task.name);
|
|
7041
7229
|
setEditingColumnId("name");
|
|
7042
7230
|
},
|
|
7043
|
-
[task.name, disableTaskNameEditing]
|
|
7231
|
+
[task.name, task.composite, disableTaskNameEditing]
|
|
7044
7232
|
);
|
|
7045
7233
|
const handleRowKeyDown = (0, import_react11.useCallback)(
|
|
7046
7234
|
(e) => {
|
|
@@ -7689,7 +7877,7 @@ var TaskListRow = import_react11.default.memo(
|
|
|
7689
7877
|
]
|
|
7690
7878
|
}
|
|
7691
7879
|
);
|
|
7692
|
-
const nameTriggerPaddingLeft = isParent ? `${nestingDepth * 20 + 28}px` : nestingDepth > 0 ? `${nestingDepth * 20 + 8}px` : void 0;
|
|
7880
|
+
const nameTriggerPaddingLeft = isParent && !task.composite ? `${nestingDepth * 20 + 28}px` : nestingDepth > 0 ? `${nestingDepth * 20 + 8}px` : void 0;
|
|
7693
7881
|
const nameInputPaddingLeft = nestingDepth > 0 ? `${nestingDepth * 20 + 8}px` : void 0;
|
|
7694
7882
|
const nestedDropIndicatorLeft = (() => {
|
|
7695
7883
|
const numberColumnWidth = resolvedColumns?.find((col) => col.id === "number")?.width ?? 40;
|
|
@@ -7787,36 +7975,35 @@ var TaskListRow = import_react11.default.memo(
|
|
|
7787
7975
|
}
|
|
7788
7976
|
)
|
|
7789
7977
|
] }),
|
|
7790
|
-
|
|
7791
|
-
|
|
7792
|
-
|
|
7793
|
-
|
|
7794
|
-
|
|
7795
|
-
|
|
7796
|
-
|
|
7797
|
-
|
|
7798
|
-
|
|
7799
|
-
|
|
7800
|
-
|
|
7801
|
-
|
|
7802
|
-
|
|
7803
|
-
}
|
|
7804
|
-
}
|
|
7805
|
-
),
|
|
7806
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
7807
|
-
"button",
|
|
7808
|
-
{
|
|
7809
|
-
type: "button",
|
|
7810
|
-
className: `gantt-tl-collapse-btn ${isCollapsed ? "gantt-tl-collapse-btn-collapsed" : ""}`,
|
|
7811
|
-
onClick: handleToggleCollapse,
|
|
7812
|
-
style: { left: `${nestingDepth * 20 + 1}px` },
|
|
7813
|
-
"aria-label": isCollapsed ? "Expand children" : "Collapse children",
|
|
7814
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ChevronRightIcon, {})
|
|
7978
|
+
task.composite && !isFilterHideMode && !isCollapsed && !editingName && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
7979
|
+
"span",
|
|
7980
|
+
{
|
|
7981
|
+
"data-testid": "gantt-tl-parent-connector-tail",
|
|
7982
|
+
style: {
|
|
7983
|
+
position: "absolute",
|
|
7984
|
+
left: `${nestingDepth * 20 + 9}px`,
|
|
7985
|
+
top: `${rowHeight / 2 + 7}px`,
|
|
7986
|
+
height: `${rowHeight / 2 - 7}px`,
|
|
7987
|
+
width: "1.5px",
|
|
7988
|
+
background: getHierarchyLineColor(nestingDepth),
|
|
7989
|
+
borderRadius: "1px",
|
|
7990
|
+
pointerEvents: "none"
|
|
7815
7991
|
}
|
|
7816
|
-
|
|
7817
|
-
|
|
7992
|
+
}
|
|
7993
|
+
),
|
|
7994
|
+
isParent && !task.composite && !editingName && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_jsx_runtime14.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
7995
|
+
"button",
|
|
7996
|
+
{
|
|
7997
|
+
type: "button",
|
|
7998
|
+
className: `gantt-tl-collapse-btn ${isCollapsed ? "gantt-tl-collapse-btn-collapsed" : ""}`,
|
|
7999
|
+
onClick: handleToggleCollapse,
|
|
8000
|
+
style: { left: `${nestingDepth * 20 - 2}px` },
|
|
8001
|
+
"aria-label": isCollapsed ? "Expand children" : "Collapse children",
|
|
8002
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ChevronRightIcon, {})
|
|
8003
|
+
}
|
|
8004
|
+
) })
|
|
7818
8005
|
] }),
|
|
7819
|
-
!isChild && isParent && !editingName && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
8006
|
+
!isChild && isParent && !task.composite && !editingName && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
7820
8007
|
!isFilterHideMode && !isCollapsed && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
7821
8008
|
"span",
|
|
7822
8009
|
{
|
|
@@ -7839,7 +8026,7 @@ var TaskListRow = import_react11.default.memo(
|
|
|
7839
8026
|
type: "button",
|
|
7840
8027
|
className: `gantt-tl-collapse-btn ${isCollapsed ? "gantt-tl-collapse-btn-collapsed" : ""}`,
|
|
7841
8028
|
onClick: handleToggleCollapse,
|
|
7842
|
-
style: { left: `${nestingDepth * 20
|
|
8029
|
+
style: { left: `${nestingDepth * 20 - 2}px` },
|
|
7843
8030
|
"aria-label": isCollapsed ? "Expand children" : "Collapse children",
|
|
7844
8031
|
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ChevronRightIcon, {})
|
|
7845
8032
|
}
|
|
@@ -7858,27 +8045,57 @@ var TaskListRow = import_react11.default.memo(
|
|
|
7858
8045
|
style: { paddingLeft: nameInputPaddingLeft },
|
|
7859
8046
|
onClick: (e) => e.stopPropagation()
|
|
7860
8047
|
}
|
|
7861
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
7862
|
-
|
|
7863
|
-
|
|
7864
|
-
|
|
7865
|
-
|
|
7866
|
-
"gantt-tl-
|
|
7867
|
-
|
|
7868
|
-
|
|
7869
|
-
|
|
7870
|
-
|
|
7871
|
-
|
|
7872
|
-
|
|
7873
|
-
|
|
7874
|
-
|
|
7875
|
-
|
|
7876
|
-
|
|
7877
|
-
|
|
7878
|
-
|
|
7879
|
-
|
|
7880
|
-
|
|
7881
|
-
|
|
8048
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
8049
|
+
task.composite && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
8050
|
+
"button",
|
|
8051
|
+
{
|
|
8052
|
+
type: "button",
|
|
8053
|
+
className: "gantt-tl-compositeToggle",
|
|
8054
|
+
onClick: handleToggleCollapse,
|
|
8055
|
+
style: { left: `${nestingDepth * 20 - 3}px` },
|
|
8056
|
+
"aria-label": isCollapsed ? `\u0420\u0430\u0441\u043A\u0440\u044B\u0442\u044C ${task.name}` : `\u0421\u0432\u0435\u0440\u043D\u0443\u0442\u044C ${task.name}`,
|
|
8057
|
+
"aria-expanded": !isCollapsed,
|
|
8058
|
+
title: isCollapsed ? "\u0420\u0430\u0441\u043A\u0440\u044B\u0442\u044C \u044D\u0442\u0430\u0436\u0438" : "\u0421\u0432\u0435\u0440\u043D\u0443\u0442\u044C \u044D\u0442\u0430\u0436\u0438",
|
|
8059
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
8060
|
+
"svg",
|
|
8061
|
+
{
|
|
8062
|
+
className: compositeIconAnimation && compositeIconAnimationPhase ? `gantt-tl-compositeGlyph-${compositeIconMode}-${compositeIconAnimation}-${compositeIconAnimationPhase}` : void 0,
|
|
8063
|
+
viewBox: "0 0 24 24",
|
|
8064
|
+
fill: "none",
|
|
8065
|
+
stroke: "currentColor",
|
|
8066
|
+
strokeWidth: "2",
|
|
8067
|
+
strokeLinecap: "round",
|
|
8068
|
+
strokeLinejoin: "round",
|
|
8069
|
+
"aria-hidden": "true",
|
|
8070
|
+
children: compositeIconMode === "composite" ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
8071
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("path", { d: "M21 5H11" }),
|
|
8072
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("path", { d: "M21 12H11" }),
|
|
8073
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("path", { d: "M21 19H11" }),
|
|
8074
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("path", { d: "m3 8 4 4-4 4" })
|
|
8075
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("path", { d: "m6 9 6 6 6-6" })
|
|
8076
|
+
}
|
|
8077
|
+
)
|
|
8078
|
+
}
|
|
8079
|
+
),
|
|
8080
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
8081
|
+
"button",
|
|
8082
|
+
{
|
|
8083
|
+
type: "button",
|
|
8084
|
+
className: `gantt-tl-name-trigger${disableTaskNameEditing ? " gantt-tl-name-locked" : ""}`,
|
|
8085
|
+
title: task.name,
|
|
8086
|
+
onClick: handleNameClick,
|
|
8087
|
+
onDoubleClick: handleNameDoubleClick,
|
|
8088
|
+
style: {
|
|
8089
|
+
paddingLeft: task.composite ? `${nestingDepth * 20 + 30}px` : nameTriggerPaddingLeft,
|
|
8090
|
+
paddingRight: task.color ? "20px" : void 0
|
|
8091
|
+
},
|
|
8092
|
+
children: [
|
|
8093
|
+
taskListNamePrefixIcon ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "gantt-tl-name-trigger-icon", "aria-hidden": "true", children: taskListNamePrefixIcon }) : null,
|
|
8094
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "gantt-tl-name-trigger-text", children: task.name })
|
|
8095
|
+
]
|
|
8096
|
+
}
|
|
8097
|
+
)
|
|
8098
|
+
] }),
|
|
7882
8099
|
!editingName && task.color && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
7883
8100
|
"span",
|
|
7884
8101
|
{
|
|
@@ -8495,8 +8712,9 @@ var TaskListRow = import_react11.default.memo(
|
|
|
8495
8712
|
isDragOver && isNestedDropTarget ? "gantt-tl-row-drag-over-nested" : "",
|
|
8496
8713
|
isDragOver && isDirectChildDropTarget ? "gantt-tl-row-drag-over-direct-child" : "",
|
|
8497
8714
|
isChild ? "gantt-tl-row-child" : "",
|
|
8498
|
-
isParent ? "gantt-tl-row-parent" : "",
|
|
8499
|
-
|
|
8715
|
+
isParent && !task.composite ? "gantt-tl-row-parent" : "",
|
|
8716
|
+
task.composite ? "gantt-tl-row-composite" : "",
|
|
8717
|
+
isParent && !task.composite && fillParentRow ? "gantt-tl-row-parent-filled" : "",
|
|
8500
8718
|
`gantt-tl-row-level-${rowFillLevel}`,
|
|
8501
8719
|
isTotalRow ? "gantt-tl-row-total" : "",
|
|
8502
8720
|
rowClassName ?? ""
|
|
@@ -8504,6 +8722,7 @@ var TaskListRow = import_react11.default.memo(
|
|
|
8504
8722
|
style: {
|
|
8505
8723
|
height: `${rowHeight}px`,
|
|
8506
8724
|
position: "relative",
|
|
8725
|
+
"--gantt-tl-composite-detail-color": compositeParentColor ?? "var(--gantt-task-bar-default-color, #8b5cf6)",
|
|
8507
8726
|
"--gantt-tl-nested-drop-left": nestedDropIndicatorLeft,
|
|
8508
8727
|
"--gantt-tl-nested-inside-drop-left": nestedInsideDropIndicatorLeft
|
|
8509
8728
|
},
|
|
@@ -8729,6 +8948,7 @@ var GenerationSkeletonRows = ({
|
|
|
8729
8948
|
rowHeight,
|
|
8730
8949
|
variant,
|
|
8731
8950
|
startIndex = 0,
|
|
8951
|
+
startTop,
|
|
8732
8952
|
taskListLayout,
|
|
8733
8953
|
chartDayWidth = 40,
|
|
8734
8954
|
chartStartDayOffset = 0,
|
|
@@ -8769,7 +8989,7 @@ var GenerationSkeletonRows = ({
|
|
|
8769
8989
|
"div",
|
|
8770
8990
|
{
|
|
8771
8991
|
className: "gantt-generation-skeleton-row",
|
|
8772
|
-
style: { top: `${
|
|
8992
|
+
style: { top: `${(startTop ?? startIndex * rowHeight) + index * rowHeight}px`, height: `${rowHeight}px` },
|
|
8773
8993
|
children: variant === "task-list" ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: `gantt-generation-skeleton-label ${shortShape ? "gantt-generation-skeleton-label-short" : ""} ${mediumShape ? "gantt-generation-skeleton-label-medium" : ""}` }) }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: `gantt-generation-skeleton-bar ${parentShape ? "gantt-generation-skeleton-bar-parent" : ""} ${shortShape ? "gantt-generation-skeleton-bar-short" : ""}`, style: chartBarStyle })
|
|
8774
8994
|
},
|
|
8775
8995
|
rowIndex
|
|
@@ -9029,6 +9249,8 @@ var SelectAllCheckbox = ({
|
|
|
9029
9249
|
var TaskList = ({
|
|
9030
9250
|
tasks,
|
|
9031
9251
|
rowHeight,
|
|
9252
|
+
rowTops,
|
|
9253
|
+
rowHeights,
|
|
9032
9254
|
headerHeight,
|
|
9033
9255
|
taskListWidth,
|
|
9034
9256
|
onTasksChange,
|
|
@@ -9156,14 +9378,22 @@ var TaskList = ({
|
|
|
9156
9378
|
return tasks2;
|
|
9157
9379
|
}, [orderedTasks, collapsedParentIds, filterMode, filteredTaskIds, isFilterActive, criticalPathMode, criticalTaskIds]);
|
|
9158
9380
|
const totalHeight = (0, import_react14.useMemo)(
|
|
9159
|
-
() => (visibleTasks.length + Math.max(0, Math.floor(skeletonRowCount))
|
|
9160
|
-
[rowHeight, skeletonRowCount, visibleTasks.length]
|
|
9381
|
+
() => (rowTops && rowHeights && visibleTasks.length > 0 ? rowTops[visibleTasks.length - 1] + rowHeights[visibleTasks.length - 1] : visibleTasks.length * rowHeight) + Math.max(0, Math.floor(skeletonRowCount)) * rowHeight,
|
|
9382
|
+
[rowHeight, rowTops, rowHeights, skeletonRowCount, visibleTasks.length]
|
|
9161
9383
|
);
|
|
9162
9384
|
const visibleTaskNumberMap = (0, import_react14.useMemo)(
|
|
9163
9385
|
() => Object.fromEntries(buildTaskNumberMap(visibleTasks)),
|
|
9164
9386
|
[visibleTasks]
|
|
9165
9387
|
);
|
|
9166
9388
|
const visibleTaskIds = (0, import_react14.useMemo)(() => visibleTasks.map((task) => task.id), [visibleTasks]);
|
|
9389
|
+
const compositeParentIds = (0, import_react14.useMemo)(
|
|
9390
|
+
() => new Set(tasks.filter((task) => task.composite).map((task) => task.id)),
|
|
9391
|
+
[tasks]
|
|
9392
|
+
);
|
|
9393
|
+
const compositeParentsById = (0, import_react14.useMemo)(
|
|
9394
|
+
() => new Map(tasks.filter((task) => task.composite).map((task) => [task.id, task])),
|
|
9395
|
+
[tasks]
|
|
9396
|
+
);
|
|
9167
9397
|
const renderedVisibleRowIndices = (0, import_react14.useMemo)(
|
|
9168
9398
|
() => visibleRowIndices ?? visibleTasks.map((_, index) => index),
|
|
9169
9399
|
[visibleRowIndices, visibleTasks]
|
|
@@ -10155,7 +10385,7 @@ var TaskList = ({
|
|
|
10155
10385
|
renderedVisibleTasks.map(({ task, index }) => {
|
|
10156
10386
|
const previousVisibleTask = index > 0 ? visibleTasks[index - 1] : void 0;
|
|
10157
10387
|
const canDemoteTask = index === 0 || !task.parentId || previousVisibleTask?.id !== task.parentId;
|
|
10158
|
-
const topOffset = index * rowHeight + (hasVisiblePendingInsert && index > pendingInsertRowIndex ? rowHeight : 0);
|
|
10388
|
+
const topOffset = (rowTops?.[index] ?? index * rowHeight) + (hasVisiblePendingInsert && index > pendingInsertRowIndex ? rowHeight : 0);
|
|
10159
10389
|
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
10160
10390
|
"div",
|
|
10161
10391
|
{
|
|
@@ -10172,7 +10402,7 @@ var TaskList = ({
|
|
|
10172
10402
|
rowIndex: index,
|
|
10173
10403
|
taskNumber: originalTaskNumberMap[task.id] || "",
|
|
10174
10404
|
taskNumberMap: originalTaskNumberMap,
|
|
10175
|
-
rowHeight,
|
|
10405
|
+
rowHeight: rowHeights?.[index] ?? rowHeight,
|
|
10176
10406
|
onTasksChange,
|
|
10177
10407
|
onDurationChange,
|
|
10178
10408
|
selectedTaskId,
|
|
@@ -10229,7 +10459,8 @@ var TaskList = ({
|
|
|
10229
10459
|
onActiveCustomCellChange: setActiveCustomCell,
|
|
10230
10460
|
taskListMenuCommands,
|
|
10231
10461
|
hideTaskListRowActions,
|
|
10232
|
-
rowClassName: getTaskListRowClassName?.(task),
|
|
10462
|
+
rowClassName: [task.parentId && compositeParentIds.has(task.parentId) ? "gantt-tl-row-composite-detail" : "", getTaskListRowClassName?.(task)].filter(Boolean).join(" "),
|
|
10463
|
+
compositeParentColor: task.parentId ? compositeParentsById.get(task.parentId)?.color : void 0,
|
|
10233
10464
|
getTaskListNamePrefixIcon,
|
|
10234
10465
|
taskDateChangeMode,
|
|
10235
10466
|
onTaskDateChangeModeChange,
|
|
@@ -10245,7 +10476,7 @@ var TaskList = ({
|
|
|
10245
10476
|
{
|
|
10246
10477
|
style: {
|
|
10247
10478
|
position: "absolute",
|
|
10248
|
-
top: `${(pendingInsertRowIndex + 1) * rowHeight}px`,
|
|
10479
|
+
top: `${rowTops?.[pendingInsertRowIndex + 1] ?? (pendingInsertRowIndex + 1) * rowHeight}px`,
|
|
10249
10480
|
left: 0,
|
|
10250
10481
|
right: 0
|
|
10251
10482
|
},
|
|
@@ -10267,6 +10498,7 @@ var TaskList = ({
|
|
|
10267
10498
|
rowHeight,
|
|
10268
10499
|
variant: "task-list",
|
|
10269
10500
|
startIndex: visibleTasks.length,
|
|
10501
|
+
startTop: totalHeight - Math.max(0, Math.floor(skeletonRowCount)) * rowHeight,
|
|
10270
10502
|
taskListLayout: generationSkeletonTaskListLayout
|
|
10271
10503
|
}
|
|
10272
10504
|
)
|
|
@@ -14451,7 +14683,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
14451
14683
|
}, [dependencyLineMenu, onTasksChange, tasks]);
|
|
14452
14684
|
const [activeTimelineTooltip, setActiveTimelineTooltip] = (0, import_react19.useState)(null);
|
|
14453
14685
|
const [internalCollapsedParentIds, setInternalCollapsedParentIds] = (0, import_react19.useState)(/* @__PURE__ */ new Set());
|
|
14454
|
-
const
|
|
14686
|
+
const [expandedCompositeIds, setExpandedCompositeIds] = (0, import_react19.useState)(/* @__PURE__ */ new Set());
|
|
14455
14687
|
const [editingTaskId, setEditingTaskId] = (0, import_react19.useState)(null);
|
|
14456
14688
|
const taskDateChangeMode = externalTaskDateChangeMode ?? internalTaskDateChangeMode;
|
|
14457
14689
|
const handleTaskDateChangeMode = externalOnTaskDateChangeModeChange ?? setInternalTaskDateChangeMode;
|
|
@@ -14461,7 +14693,36 @@ function TaskGanttChartInner(props, ref) {
|
|
|
14461
14693
|
() => Math.max(rowHeight, 10 + resolvedRowContentLines * 18),
|
|
14462
14694
|
[resolvedRowContentLines, rowHeight]
|
|
14463
14695
|
);
|
|
14464
|
-
const normalizedTasks = (0, import_react19.useMemo)(() =>
|
|
14696
|
+
const normalizedTasks = (0, import_react19.useMemo)(() => {
|
|
14697
|
+
const ordered = normalizeHierarchyTasks(tasks);
|
|
14698
|
+
const ranges = /* @__PURE__ */ new Map();
|
|
14699
|
+
for (const task of ordered) {
|
|
14700
|
+
if (!task.parentId) continue;
|
|
14701
|
+
const start = parseUTCDate(task.startDate).getTime();
|
|
14702
|
+
const end = parseUTCDate(task.endDate).getTime();
|
|
14703
|
+
const range = ranges.get(task.parentId);
|
|
14704
|
+
ranges.set(task.parentId, {
|
|
14705
|
+
start: Math.min(range?.start ?? start, start),
|
|
14706
|
+
end: Math.max(range?.end ?? end, end)
|
|
14707
|
+
});
|
|
14708
|
+
}
|
|
14709
|
+
return ordered.map((task) => {
|
|
14710
|
+
const range = task.composite ? ranges.get(task.id) : void 0;
|
|
14711
|
+
return range ? {
|
|
14712
|
+
...task,
|
|
14713
|
+
startDate: new Date(range.start).toISOString().slice(0, 10),
|
|
14714
|
+
endDate: new Date(range.end).toISOString().slice(0, 10)
|
|
14715
|
+
} : task;
|
|
14716
|
+
});
|
|
14717
|
+
}, [tasks]);
|
|
14718
|
+
const collapsedParentIds = (0, import_react19.useMemo)(() => {
|
|
14719
|
+
if (externalCollapsedParentIds) return externalCollapsedParentIds;
|
|
14720
|
+
const ids = new Set(internalCollapsedParentIds);
|
|
14721
|
+
for (const task of normalizedTasks) {
|
|
14722
|
+
if (task.composite && !expandedCompositeIds.has(task.id)) ids.add(task.id);
|
|
14723
|
+
}
|
|
14724
|
+
return ids;
|
|
14725
|
+
}, [externalCollapsedParentIds, internalCollapsedParentIds, normalizedTasks, expandedCompositeIds]);
|
|
14465
14726
|
const controlledScheduleIdentity = (0, import_react19.useMemo)(
|
|
14466
14727
|
() => buildControlledScheduleIdentity(normalizedTasks),
|
|
14467
14728
|
[normalizedTasks]
|
|
@@ -14541,6 +14802,23 @@ function TaskGanttChartInner(props, ref) {
|
|
|
14541
14802
|
}
|
|
14542
14803
|
return tasks2;
|
|
14543
14804
|
}, [normalizedTasks, collapsedParentIds, filterMode, taskFilter, criticalPathMode, criticalTaskIds]);
|
|
14805
|
+
const compositeRowLayout = (0, import_react19.useMemo)(() => {
|
|
14806
|
+
const compositeIds = new Set(normalizedTasks.filter((task) => task.composite).map((task) => task.id));
|
|
14807
|
+
const tops = [];
|
|
14808
|
+
const heights = [];
|
|
14809
|
+
let top = 0;
|
|
14810
|
+
for (const task of visibleTasks) {
|
|
14811
|
+
tops.push(top);
|
|
14812
|
+
const height = task.parentId && compositeIds.has(task.parentId) ? Math.min(effectiveRowHeight, 22) : effectiveRowHeight;
|
|
14813
|
+
heights.push(height);
|
|
14814
|
+
top += height;
|
|
14815
|
+
}
|
|
14816
|
+
return { tops, heights, totalHeight: top };
|
|
14817
|
+
}, [normalizedTasks, visibleTasks, effectiveRowHeight]);
|
|
14818
|
+
const compositeParentsById = (0, import_react19.useMemo)(
|
|
14819
|
+
() => new Map(normalizedTasks.filter((task) => task.composite).map((task) => [task.id, task])),
|
|
14820
|
+
[normalizedTasks]
|
|
14821
|
+
);
|
|
14544
14822
|
const matchedTaskIds = (0, import_react19.useMemo)(() => {
|
|
14545
14823
|
if (!taskFilter) return /* @__PURE__ */ new Set();
|
|
14546
14824
|
return new Set(visibleTasks.filter(taskFilter).map((task) => task.id));
|
|
@@ -14562,8 +14840,8 @@ function TaskGanttChartInner(props, ref) {
|
|
|
14562
14840
|
return mergedHighlightedTaskIds;
|
|
14563
14841
|
}, [filterMode, highlightedTaskIds, matchedTaskIds, criticalPathMode, criticalTaskIds]);
|
|
14564
14842
|
const totalGridHeight = (0, import_react19.useMemo)(
|
|
14565
|
-
() =>
|
|
14566
|
-
[effectiveRowHeight, skeletonRowCount
|
|
14843
|
+
() => compositeRowLayout.totalHeight + Math.max(0, Math.floor(skeletonRowCount)) * effectiveRowHeight,
|
|
14844
|
+
[compositeRowLayout.totalHeight, effectiveRowHeight, skeletonRowCount]
|
|
14567
14845
|
);
|
|
14568
14846
|
const timelineHeaderHeight = headerHeight + 1;
|
|
14569
14847
|
const tableBodyMinHeight = (0, import_react19.useMemo)(() => {
|
|
@@ -14690,7 +14968,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
14690
14968
|
const rowIndex = visibleTasks.findIndex((visibleTask) => visibleTask.id === taskId);
|
|
14691
14969
|
if (rowIndex === -1) return;
|
|
14692
14970
|
const paddedRowIndex = Math.max(0, rowIndex - SCROLL_TO_ROW_CONTEXT_ROWS);
|
|
14693
|
-
container2.scrollTo({ top: Math.max(0,
|
|
14971
|
+
container2.scrollTo({ top: Math.max(0, compositeRowLayout.tops[paddedRowIndex] ?? 0), behavior: "smooth" });
|
|
14694
14972
|
setSelectedTaskId(taskId);
|
|
14695
14973
|
return;
|
|
14696
14974
|
}
|
|
@@ -14709,7 +14987,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
14709
14987
|
const taskOffset = taskIndex * dayWidth;
|
|
14710
14988
|
const scrollLeft = Math.round(taskOffset - dayWidth * 2);
|
|
14711
14989
|
container.scrollTo({ left: Math.max(0, scrollLeft), behavior: "smooth" });
|
|
14712
|
-
}, [dateRange, dayWidth, effectiveRowHeight, isTableMatrixMode, tasks, visibleTasks]);
|
|
14990
|
+
}, [dateRange, dayWidth, effectiveRowHeight, compositeRowLayout, isTableMatrixMode, tasks, visibleTasks]);
|
|
14713
14991
|
const scrollToRow = (0, import_react19.useCallback)((taskId, options = {}) => {
|
|
14714
14992
|
const container = scrollContainerRef.current;
|
|
14715
14993
|
if (!container) return;
|
|
@@ -14718,7 +14996,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
14718
14996
|
const rowIndex = visibleTasks.findIndex((visibleTask) => visibleTask.id === task.id);
|
|
14719
14997
|
if (rowIndex === -1) return;
|
|
14720
14998
|
const paddedRowIndex = Math.max(0, rowIndex - SCROLL_TO_ROW_CONTEXT_ROWS);
|
|
14721
|
-
const scrollTop = Math.max(0,
|
|
14999
|
+
const scrollTop = Math.max(0, compositeRowLayout.tops[paddedRowIndex] ?? 0);
|
|
14722
15000
|
const {
|
|
14723
15001
|
select = true,
|
|
14724
15002
|
behavior = "smooth",
|
|
@@ -14738,7 +15016,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
14738
15016
|
}
|
|
14739
15017
|
}
|
|
14740
15018
|
container.scrollTo({ top: scrollTop, behavior });
|
|
14741
|
-
}, [effectiveRowHeight, tasks, visibleTasks]);
|
|
15019
|
+
}, [effectiveRowHeight, compositeRowLayout, tasks, visibleTasks]);
|
|
14742
15020
|
const [dragGuideLines, setDragGuideLines] = (0, import_react19.useState)(null);
|
|
14743
15021
|
const [draggedTaskOverride, setDraggedTaskOverride] = (0, import_react19.useState)(null);
|
|
14744
15022
|
(0, import_react19.useEffect)(() => {
|
|
@@ -14765,9 +15043,9 @@ function TaskGanttChartInner(props, ref) {
|
|
|
14765
15043
|
previewPositionStore.clear();
|
|
14766
15044
|
}, [previewPositionStore]);
|
|
14767
15045
|
const handleTaskChange = (0, import_react19.useCallback)((updatedTasks, durationEdit) => {
|
|
14768
|
-
|
|
15046
|
+
let updatedTask = updatedTasks[0];
|
|
14769
15047
|
if (!updatedTask) return;
|
|
14770
|
-
const originalTask =
|
|
15048
|
+
const originalTask = normalizedTasks.find((t) => t.id === updatedTask.id);
|
|
14771
15049
|
if (!originalTask) {
|
|
14772
15050
|
onTasksChange?.(updatedTasks);
|
|
14773
15051
|
if (editingTaskId === updatedTask.id) {
|
|
@@ -14780,6 +15058,8 @@ function TaskGanttChartInner(props, ref) {
|
|
|
14780
15058
|
const newStart = new Date(updatedTask.startDate);
|
|
14781
15059
|
const newEnd = new Date(updatedTask.endDate);
|
|
14782
15060
|
const datesChanged = origStart.getTime() !== newStart.getTime() || origEnd.getTime() !== newEnd.getTime();
|
|
15061
|
+
const isCompositeDetail = datesChanged && tasks.some((task) => task.id === updatedTask.parentId && task.composite);
|
|
15062
|
+
if (isCompositeDetail) updatedTask = { ...updatedTask, synced: false };
|
|
14783
15063
|
if (!datesChanged) {
|
|
14784
15064
|
if (updatedTasks.length > 1) {
|
|
14785
15065
|
onTasksChange?.(updatedTasks);
|
|
@@ -14841,7 +15121,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
14841
15121
|
}
|
|
14842
15122
|
return;
|
|
14843
15123
|
}
|
|
14844
|
-
const movedParentCascade = disableConstraints ? [updatedTask] : universalCascade(updatedTask, newStart, newEnd,
|
|
15124
|
+
const movedParentCascade = disableConstraints && !originalTask.composite ? [updatedTask] : universalCascade(updatedTask, newStart, newEnd, normalizedTasks, businessDays, isCustomWeekend);
|
|
14845
15125
|
if (onScheduleIntent) {
|
|
14846
15126
|
onScheduleIntent({
|
|
14847
15127
|
type: "move_task",
|
|
@@ -14865,7 +15145,8 @@ function TaskGanttChartInner(props, ref) {
|
|
|
14865
15145
|
taskId: updatedTask.id,
|
|
14866
15146
|
duration: durationEdit.duration,
|
|
14867
15147
|
anchor: durationEdit.anchor,
|
|
14868
|
-
taskType: updatedTask.type ?? "task"
|
|
15148
|
+
taskType: updatedTask.type ?? "task",
|
|
15149
|
+
...isCompositeDetail ? { localOverride: true } : {}
|
|
14869
15150
|
});
|
|
14870
15151
|
} else {
|
|
14871
15152
|
onTasksChange?.(cascadedTasks);
|
|
@@ -14877,7 +15158,8 @@ function TaskGanttChartInner(props, ref) {
|
|
|
14877
15158
|
onScheduleIntent({
|
|
14878
15159
|
type: "move_task",
|
|
14879
15160
|
taskId: updatedTask.id,
|
|
14880
|
-
startDate: newStart.toISOString().split("T")[0]
|
|
15161
|
+
startDate: newStart.toISOString().split("T")[0],
|
|
15162
|
+
...isCompositeDetail ? { localOverride: true } : {}
|
|
14881
15163
|
});
|
|
14882
15164
|
} else {
|
|
14883
15165
|
const anchor = startChanged ? "end" : "start";
|
|
@@ -14885,13 +15167,14 @@ function TaskGanttChartInner(props, ref) {
|
|
|
14885
15167
|
type: "resize_task",
|
|
14886
15168
|
taskId: updatedTask.id,
|
|
14887
15169
|
anchor,
|
|
14888
|
-
date: (startChanged ? newStart : newEnd).toISOString().split("T")[0]
|
|
15170
|
+
date: (startChanged ? newStart : newEnd).toISOString().split("T")[0],
|
|
15171
|
+
...isCompositeDetail ? { localOverride: true } : {}
|
|
14889
15172
|
});
|
|
14890
15173
|
}
|
|
14891
15174
|
} else {
|
|
14892
15175
|
onTasksChange?.(cascadedTasks);
|
|
14893
15176
|
}
|
|
14894
|
-
}, [tasks, onTasksChange, onScheduleIntent, disableConstraints, editingTaskId, businessDays, isCustomWeekend, onSubtreeScaleResult]);
|
|
15177
|
+
}, [tasks, normalizedTasks, onTasksChange, onScheduleIntent, disableConstraints, editingTaskId, businessDays, isCustomWeekend, onSubtreeScaleResult]);
|
|
14895
15178
|
const handleTaskDurationChange = (0, import_react19.useCallback)((task, duration) => {
|
|
14896
15179
|
const updatedTask = {
|
|
14897
15180
|
...task,
|
|
@@ -15005,12 +15288,25 @@ function TaskGanttChartInner(props, ref) {
|
|
|
15005
15288
|
if (scrollViewport.viewportHeight <= 0) {
|
|
15006
15289
|
return Array.from({ length: totalTasks }, (_, index) => index);
|
|
15007
15290
|
}
|
|
15008
|
-
|
|
15009
|
-
|
|
15010
|
-
|
|
15011
|
-
|
|
15012
|
-
|
|
15013
|
-
|
|
15291
|
+
let low = 0;
|
|
15292
|
+
let high = totalTasks;
|
|
15293
|
+
while (low < high) {
|
|
15294
|
+
const middle = low + high >>> 1;
|
|
15295
|
+
if (compositeRowLayout.tops[middle] + compositeRowLayout.heights[middle] < scrollViewport.scrollTop) low = middle + 1;
|
|
15296
|
+
else high = middle;
|
|
15297
|
+
}
|
|
15298
|
+
const first = Math.min(low, totalTasks - 1);
|
|
15299
|
+
const viewportBottom = scrollViewport.scrollTop + scrollViewport.viewportHeight;
|
|
15300
|
+
low = first;
|
|
15301
|
+
high = totalTasks;
|
|
15302
|
+
while (low < high) {
|
|
15303
|
+
const middle = low + high >>> 1;
|
|
15304
|
+
if (compositeRowLayout.tops[middle] < viewportBottom) low = middle + 1;
|
|
15305
|
+
else high = middle;
|
|
15306
|
+
}
|
|
15307
|
+
const last = Math.min(low, totalTasks - 1);
|
|
15308
|
+
const rangeStart = Math.max(0, first - TASK_ROW_OVERSCAN);
|
|
15309
|
+
const rangeEnd = Math.min(totalTasks - 1, last + TASK_ROW_OVERSCAN);
|
|
15014
15310
|
const indices = /* @__PURE__ */ new Set();
|
|
15015
15311
|
for (let index = rangeStart; index <= rangeEnd; index += 1) {
|
|
15016
15312
|
indices.add(index);
|
|
@@ -15022,7 +15318,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
15022
15318
|
}
|
|
15023
15319
|
}
|
|
15024
15320
|
return Array.from(indices).sort((left, right) => left - right);
|
|
15025
|
-
}, [
|
|
15321
|
+
}, [compositeRowLayout, forceFullRenderForPrint, forcedRenderedTaskIds, scrollViewport, visibleTaskIndexMap, visibleTasks.length]);
|
|
15026
15322
|
const visiblePlanFactDateIndices = (0, import_react19.useMemo)(() => {
|
|
15027
15323
|
if (forceFullRenderForPrint) {
|
|
15028
15324
|
return void 0;
|
|
@@ -15099,7 +15395,16 @@ function TaskGanttChartInner(props, ref) {
|
|
|
15099
15395
|
}
|
|
15100
15396
|
applyHoveredRows(taskId);
|
|
15101
15397
|
}, [applyHoveredRows]);
|
|
15102
|
-
const handleToggleCollapse = externalOnToggleCollapse ?? (
|
|
15398
|
+
const handleToggleCollapse = externalOnToggleCollapse ?? ((parentId) => {
|
|
15399
|
+
if (normalizedTasks.some((task) => task.id === parentId && task.composite)) {
|
|
15400
|
+
setExpandedCompositeIds((prev) => {
|
|
15401
|
+
const next = new Set(prev);
|
|
15402
|
+
if (next.has(parentId)) next.delete(parentId);
|
|
15403
|
+
else next.add(parentId);
|
|
15404
|
+
return next;
|
|
15405
|
+
});
|
|
15406
|
+
return;
|
|
15407
|
+
}
|
|
15103
15408
|
setInternalCollapsedParentIds((prev) => {
|
|
15104
15409
|
const next = new Set(prev);
|
|
15105
15410
|
if (next.has(parentId)) {
|
|
@@ -15109,7 +15414,14 @@ function TaskGanttChartInner(props, ref) {
|
|
|
15109
15414
|
}
|
|
15110
15415
|
return next;
|
|
15111
15416
|
});
|
|
15112
|
-
}
|
|
15417
|
+
});
|
|
15418
|
+
const lastCompositeBarToggleRef = (0, import_react19.useRef)(null);
|
|
15419
|
+
const handleCompositeBarToggle = (taskId, source) => {
|
|
15420
|
+
const now = Date.now();
|
|
15421
|
+
if (source === "click" && lastCompositeBarToggleRef.current?.source === "release" && lastCompositeBarToggleRef.current.id === taskId && now - lastCompositeBarToggleRef.current.time < 150) return;
|
|
15422
|
+
lastCompositeBarToggleRef.current = { id: taskId, time: now, source };
|
|
15423
|
+
handleToggleCollapse(taskId);
|
|
15424
|
+
};
|
|
15113
15425
|
const allParentIds = (0, import_react19.useMemo)(() => {
|
|
15114
15426
|
const taskIds = new Set(normalizedTasks.map((task) => task.id));
|
|
15115
15427
|
return new Set(normalizedTasks.map((task) => task.parentId).filter((parentId) => Boolean(parentId && taskIds.has(parentId))));
|
|
@@ -15117,11 +15429,13 @@ function TaskGanttChartInner(props, ref) {
|
|
|
15117
15429
|
const handleCollapseAll = (0, import_react19.useCallback)(() => {
|
|
15118
15430
|
if (externalCollapsedParentIds) return;
|
|
15119
15431
|
setInternalCollapsedParentIds(allParentIds);
|
|
15432
|
+
setExpandedCompositeIds(/* @__PURE__ */ new Set());
|
|
15120
15433
|
}, [allParentIds, externalCollapsedParentIds]);
|
|
15121
15434
|
const handleExpandAll = (0, import_react19.useCallback)(() => {
|
|
15122
15435
|
if (externalCollapsedParentIds) return;
|
|
15123
15436
|
setInternalCollapsedParentIds(/* @__PURE__ */ new Set());
|
|
15124
|
-
|
|
15437
|
+
setExpandedCompositeIds(new Set(normalizedTasks.filter((task) => task.composite).map((task) => task.id)));
|
|
15438
|
+
}, [externalCollapsedParentIds, normalizedTasks]);
|
|
15125
15439
|
const exportToPdf = (0, import_react19.useCallback)(async (options) => {
|
|
15126
15440
|
const sourceContainer = containerRef.current;
|
|
15127
15441
|
if (!sourceContainer || typeof window === "undefined" || typeof document === "undefined") {
|
|
@@ -15386,6 +15700,8 @@ function TaskGanttChartInner(props, ref) {
|
|
|
15386
15700
|
{
|
|
15387
15701
|
tasks: normalizedTasks,
|
|
15388
15702
|
rowHeight: effectiveRowHeight,
|
|
15703
|
+
rowTops: compositeRowLayout.tops,
|
|
15704
|
+
rowHeights: compositeRowLayout.heights,
|
|
15389
15705
|
headerHeight,
|
|
15390
15706
|
taskListWidth,
|
|
15391
15707
|
onTasksChange: handleTaskChange,
|
|
@@ -15580,6 +15896,8 @@ function TaskGanttChartInner(props, ref) {
|
|
|
15580
15896
|
gridWidth: renderGridWidth,
|
|
15581
15897
|
totalHeight: totalGridHeight,
|
|
15582
15898
|
rowIndexByTaskId: visibleTaskIndexMap,
|
|
15899
|
+
rowTops: compositeRowLayout.tops,
|
|
15900
|
+
rowHeights: compositeRowLayout.heights,
|
|
15583
15901
|
dragOverrides: dependencyOverrides,
|
|
15584
15902
|
selectedDep: selectedChip,
|
|
15585
15903
|
businessDays,
|
|
@@ -15666,10 +15984,10 @@ function TaskGanttChartInner(props, ref) {
|
|
|
15666
15984
|
{
|
|
15667
15985
|
style: {
|
|
15668
15986
|
position: "absolute",
|
|
15669
|
-
top: `${index
|
|
15987
|
+
top: `${compositeRowLayout.tops[index]}px`,
|
|
15670
15988
|
left: 0,
|
|
15671
15989
|
right: 0,
|
|
15672
|
-
height: `${
|
|
15990
|
+
height: `${compositeRowLayout.heights[index]}px`
|
|
15673
15991
|
},
|
|
15674
15992
|
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
15675
15993
|
TaskRow_default,
|
|
@@ -15677,7 +15995,9 @@ function TaskGanttChartInner(props, ref) {
|
|
|
15677
15995
|
task,
|
|
15678
15996
|
monthStart,
|
|
15679
15997
|
dayWidth,
|
|
15680
|
-
rowHeight:
|
|
15998
|
+
rowHeight: compositeRowLayout.heights[index],
|
|
15999
|
+
compactDetail: compositeRowLayout.heights[index] < effectiveRowHeight,
|
|
16000
|
+
compositeParentColor: task.parentId ? compositeParentsById.get(task.parentId)?.color : void 0,
|
|
15681
16001
|
onTasksChange: handleTaskChange,
|
|
15682
16002
|
onDragStateChange: (state) => {
|
|
15683
16003
|
if (state.isDragging) {
|
|
@@ -15714,7 +16034,9 @@ function TaskGanttChartInner(props, ref) {
|
|
|
15714
16034
|
isDependencyDragActive: dependencyCreationDrag !== null,
|
|
15715
16035
|
viewMode,
|
|
15716
16036
|
showTaskDateLabels,
|
|
15717
|
-
showTaskNames
|
|
16037
|
+
showTaskNames,
|
|
16038
|
+
onCompositeToggle: task.composite ? (source) => handleCompositeBarToggle(task.id, source) : void 0,
|
|
16039
|
+
compositeExpanded: task.composite ? !collapsedParentIds.has(task.id) : void 0
|
|
15718
16040
|
}
|
|
15719
16041
|
)
|
|
15720
16042
|
},
|
|
@@ -15727,6 +16049,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
15727
16049
|
rowHeight: effectiveRowHeight,
|
|
15728
16050
|
variant: "chart",
|
|
15729
16051
|
startIndex: visibleTasks.length,
|
|
16052
|
+
startTop: compositeRowLayout.totalHeight,
|
|
15730
16053
|
chartDayWidth: dayWidth,
|
|
15731
16054
|
chartStartDayOffset: todayInRange ? Math.max(0, todayIndex + Math.floor(Number.isFinite(skeletonStartOffsetDays) ? skeletonStartOffsetDays : 0)) : 0,
|
|
15732
16055
|
chartStartJitterDays: skeletonStartJitterDays
|