gantt-lib 0.111.0 → 0.113.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/dist/core/scheduling/index.d.mts +1 -1
- package/dist/core/scheduling/index.d.ts +1 -1
- package/dist/{index-CQSAjkhV.d.mts → index-D1s_8MxS.d.mts} +5 -1
- package/dist/{index-CQSAjkhV.d.ts → index-D1s_8MxS.d.ts} +5 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +43 -4
- package/dist/index.d.ts +43 -4
- package/dist/index.js +1270 -136
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1266 -133
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +282 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -41,6 +41,7 @@ __export(index_exports, {
|
|
|
41
41
|
GanttChart: () => GanttChart,
|
|
42
42
|
GridBackground: () => GridBackground_default,
|
|
43
43
|
Input: () => Input,
|
|
44
|
+
PlanFactMatrix: () => PlanFactMatrix,
|
|
44
45
|
Popover: () => Popover,
|
|
45
46
|
PopoverContent: () => PopoverContent,
|
|
46
47
|
PopoverTrigger: () => PopoverTrigger,
|
|
@@ -144,7 +145,7 @@ __export(index_exports, {
|
|
|
144
145
|
module.exports = __toCommonJS(index_exports);
|
|
145
146
|
|
|
146
147
|
// src/components/GanttChart/GanttChart.tsx
|
|
147
|
-
var
|
|
148
|
+
var import_react18 = require("react");
|
|
148
149
|
|
|
149
150
|
// src/core/scheduling/dateMath.ts
|
|
150
151
|
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -698,10 +699,10 @@ function buildTaskRangeFromStart(startDate, duration, businessDays = false, week
|
|
|
698
699
|
end: parseDateOnly(addBusinessDays(normalizedStart, duration, weekendPredicate))
|
|
699
700
|
};
|
|
700
701
|
}
|
|
701
|
-
const
|
|
702
|
+
const DAY_MS6 = 24 * 60 * 60 * 1e3;
|
|
702
703
|
return {
|
|
703
704
|
start: normalizedStart,
|
|
704
|
-
end: new Date(normalizedStart.getTime() + (Math.max(1, duration) - 1) *
|
|
705
|
+
end: new Date(normalizedStart.getTime() + (Math.max(1, duration) - 1) * DAY_MS6)
|
|
705
706
|
};
|
|
706
707
|
}
|
|
707
708
|
function buildTaskRangeFromEnd(endDate, duration, businessDays = false, weekendPredicate, snapDirection = -1) {
|
|
@@ -712,9 +713,9 @@ function buildTaskRangeFromEnd(endDate, duration, businessDays = false, weekendP
|
|
|
712
713
|
end: normalizedEnd
|
|
713
714
|
};
|
|
714
715
|
}
|
|
715
|
-
const
|
|
716
|
+
const DAY_MS6 = 24 * 60 * 60 * 1e3;
|
|
716
717
|
return {
|
|
717
|
-
start: new Date(normalizedEnd.getTime() - (Math.max(1, duration) - 1) *
|
|
718
|
+
start: new Date(normalizedEnd.getTime() - (Math.max(1, duration) - 1) * DAY_MS6),
|
|
718
719
|
end: normalizedEnd
|
|
719
720
|
};
|
|
720
721
|
}
|
|
@@ -1129,13 +1130,13 @@ function computeParentProgress(parentId, tasks) {
|
|
|
1129
1130
|
if (children.length === 0) {
|
|
1130
1131
|
return 0;
|
|
1131
1132
|
}
|
|
1132
|
-
const
|
|
1133
|
+
const DAY_MS6 = 24 * 60 * 60 * 1e3;
|
|
1133
1134
|
let totalWeight = 0;
|
|
1134
1135
|
let weightedSum = 0;
|
|
1135
1136
|
for (const child of children) {
|
|
1136
1137
|
const start = new Date(child.startDate).getTime();
|
|
1137
1138
|
const end = new Date(child.endDate).getTime();
|
|
1138
|
-
const duration = (end - start +
|
|
1139
|
+
const duration = (end - start + DAY_MS6) / DAY_MS6;
|
|
1139
1140
|
const progress = child.progress ?? 0;
|
|
1140
1141
|
totalWeight += duration;
|
|
1141
1142
|
weightedSum += duration * progress;
|
|
@@ -10564,6 +10565,1001 @@ function TableMatrix({
|
|
|
10564
10565
|
] });
|
|
10565
10566
|
}
|
|
10566
10567
|
|
|
10568
|
+
// src/components/PlanFactMatrix/PlanFactMatrix.tsx
|
|
10569
|
+
var import_react17 = __toESM(require("react"));
|
|
10570
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
10571
|
+
var DAY_MS5 = 24 * 60 * 60 * 1e3;
|
|
10572
|
+
function joinClasses2(...values) {
|
|
10573
|
+
return values.filter(Boolean).join(" ");
|
|
10574
|
+
}
|
|
10575
|
+
function formatDateKey(date) {
|
|
10576
|
+
const year = date.getUTCFullYear();
|
|
10577
|
+
const month = String(date.getUTCMonth() + 1).padStart(2, "0");
|
|
10578
|
+
const day = String(date.getUTCDate()).padStart(2, "0");
|
|
10579
|
+
return `${year}-${month}-${day}`;
|
|
10580
|
+
}
|
|
10581
|
+
function escapeAttributeValue(value) {
|
|
10582
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
10583
|
+
}
|
|
10584
|
+
function parseNumberInput(value) {
|
|
10585
|
+
const trimmed = value.trim();
|
|
10586
|
+
if (trimmed === "") return void 0;
|
|
10587
|
+
const normalized = trimmed.replace(/\s+/g, "").replace(",", ".");
|
|
10588
|
+
const parsed = Number(normalized);
|
|
10589
|
+
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
10590
|
+
return null;
|
|
10591
|
+
}
|
|
10592
|
+
return parsed;
|
|
10593
|
+
}
|
|
10594
|
+
function getDateOnlyMs(date) {
|
|
10595
|
+
return Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate());
|
|
10596
|
+
}
|
|
10597
|
+
function getPlannedIndexRange(task, rangeStartMs, rangeLength) {
|
|
10598
|
+
if (rangeLength <= 0) return null;
|
|
10599
|
+
const start = parseUTCDate(task.startDate);
|
|
10600
|
+
const end = parseUTCDate(task.endDate);
|
|
10601
|
+
const startIndex = Math.ceil((getDateOnlyMs(start) - rangeStartMs) / DAY_MS5);
|
|
10602
|
+
const endIndex = Math.floor((getDateOnlyMs(end) - rangeStartMs) / DAY_MS5);
|
|
10603
|
+
const clampedStartIndex = Math.max(0, startIndex);
|
|
10604
|
+
const clampedEndIndex = Math.min(rangeLength - 1, endIndex);
|
|
10605
|
+
if (clampedStartIndex > clampedEndIndex) return null;
|
|
10606
|
+
return {
|
|
10607
|
+
startIndex: clampedStartIndex,
|
|
10608
|
+
endIndex: clampedEndIndex
|
|
10609
|
+
};
|
|
10610
|
+
}
|
|
10611
|
+
function isDateIndexWithinPlannedRange(dateIndex, range) {
|
|
10612
|
+
return !!range && range.startIndex <= dateIndex && dateIndex <= range.endIndex;
|
|
10613
|
+
}
|
|
10614
|
+
function formatValue(value) {
|
|
10615
|
+
if (value === void 0) return "";
|
|
10616
|
+
const absoluteValue = Math.abs(value);
|
|
10617
|
+
if (absoluteValue >= 1e6) {
|
|
10618
|
+
const compactValue = value / 1e6;
|
|
10619
|
+
const fractionDigits = absoluteValue >= 1e7 ? 0 : 1;
|
|
10620
|
+
return `${compactValue.toLocaleString("ru-RU", {
|
|
10621
|
+
minimumFractionDigits: 0,
|
|
10622
|
+
maximumFractionDigits: fractionDigits,
|
|
10623
|
+
useGrouping: false
|
|
10624
|
+
})}m`;
|
|
10625
|
+
}
|
|
10626
|
+
if (absoluteValue >= 1e4) {
|
|
10627
|
+
const compactValue = value / 1e3;
|
|
10628
|
+
const fractionDigits = absoluteValue >= 1e5 ? 0 : 1;
|
|
10629
|
+
return `${compactValue.toLocaleString("ru-RU", {
|
|
10630
|
+
minimumFractionDigits: 0,
|
|
10631
|
+
maximumFractionDigits: fractionDigits,
|
|
10632
|
+
useGrouping: false
|
|
10633
|
+
})}k`;
|
|
10634
|
+
}
|
|
10635
|
+
return Number.isInteger(value) ? String(value) : String(value).replace(".", ",");
|
|
10636
|
+
}
|
|
10637
|
+
function formatTooltipValue(value) {
|
|
10638
|
+
if (value === void 0) return "";
|
|
10639
|
+
return value.toLocaleString("ru-RU", { maximumFractionDigits: 20 });
|
|
10640
|
+
}
|
|
10641
|
+
function getSubrowIndex(taskIndex, kind) {
|
|
10642
|
+
return taskIndex * 2 + (kind === "plan" ? 0 : 1);
|
|
10643
|
+
}
|
|
10644
|
+
function findEditableTaskIndex(tasks, parentTaskIds, startIndex, step) {
|
|
10645
|
+
let index = startIndex;
|
|
10646
|
+
while (index >= 0 && index < tasks.length) {
|
|
10647
|
+
if (!parentTaskIds.has(tasks[index].id)) {
|
|
10648
|
+
return index;
|
|
10649
|
+
}
|
|
10650
|
+
index += step;
|
|
10651
|
+
}
|
|
10652
|
+
return null;
|
|
10653
|
+
}
|
|
10654
|
+
function PlanFactCellEditor({
|
|
10655
|
+
value,
|
|
10656
|
+
startValue,
|
|
10657
|
+
onCommit,
|
|
10658
|
+
onCommitRange,
|
|
10659
|
+
onCancel
|
|
10660
|
+
}) {
|
|
10661
|
+
const [draft, setDraft] = (0, import_react17.useState)(startValue ?? (value === void 0 ? "" : String(value)));
|
|
10662
|
+
const inputRef = (0, import_react17.useRef)(null);
|
|
10663
|
+
(0, import_react17.useEffect)(() => {
|
|
10664
|
+
inputRef.current?.focus();
|
|
10665
|
+
if (startValue === void 0) {
|
|
10666
|
+
inputRef.current?.select();
|
|
10667
|
+
} else {
|
|
10668
|
+
inputRef.current?.setSelectionRange(startValue.length, startValue.length);
|
|
10669
|
+
}
|
|
10670
|
+
}, [startValue]);
|
|
10671
|
+
const commit = (0, import_react17.useCallback)(() => {
|
|
10672
|
+
const parsed = parseNumberInput(draft);
|
|
10673
|
+
if (parsed === null) {
|
|
10674
|
+
onCancel();
|
|
10675
|
+
return;
|
|
10676
|
+
}
|
|
10677
|
+
onCommit(parsed);
|
|
10678
|
+
}, [draft, onCancel, onCommit]);
|
|
10679
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
10680
|
+
"input",
|
|
10681
|
+
{
|
|
10682
|
+
ref: inputRef,
|
|
10683
|
+
value: draft,
|
|
10684
|
+
className: "gantt-pf-editor",
|
|
10685
|
+
inputMode: "decimal",
|
|
10686
|
+
onChange: (event) => setDraft(event.target.value),
|
|
10687
|
+
onBlur: commit,
|
|
10688
|
+
onKeyDown: (event) => {
|
|
10689
|
+
if (event.key === "Escape") {
|
|
10690
|
+
event.preventDefault();
|
|
10691
|
+
onCancel();
|
|
10692
|
+
return;
|
|
10693
|
+
}
|
|
10694
|
+
if (event.key === "Enter") {
|
|
10695
|
+
event.preventDefault();
|
|
10696
|
+
if (event.ctrlKey || event.metaKey) {
|
|
10697
|
+
const parsed = parseNumberInput(draft);
|
|
10698
|
+
if (parsed === null) {
|
|
10699
|
+
onCancel();
|
|
10700
|
+
return;
|
|
10701
|
+
}
|
|
10702
|
+
onCommitRange?.(parsed);
|
|
10703
|
+
} else {
|
|
10704
|
+
commit();
|
|
10705
|
+
}
|
|
10706
|
+
}
|
|
10707
|
+
}
|
|
10708
|
+
}
|
|
10709
|
+
);
|
|
10710
|
+
}
|
|
10711
|
+
function getCellSignatureForTask(cell, taskId) {
|
|
10712
|
+
return cell?.taskId === taskId ? `${cell.dateIndex}:${cell.kind}` : "";
|
|
10713
|
+
}
|
|
10714
|
+
function getEditingCellSignatureForTask(cell, taskId) {
|
|
10715
|
+
return cell?.taskId === taskId ? `${cell.dateIndex}:${cell.kind}:${cell.startValue ?? ""}` : "";
|
|
10716
|
+
}
|
|
10717
|
+
function getRangeAnchorSignatureForTask(range, taskId) {
|
|
10718
|
+
return range?.anchor.taskId === taskId ? `${range.anchor.dateIndex}:${range.anchor.kind}` : "";
|
|
10719
|
+
}
|
|
10720
|
+
function doesRangeTouchRow(bounds, rowIndex) {
|
|
10721
|
+
if (!bounds) return false;
|
|
10722
|
+
const firstSubrowIndex = rowIndex * 2;
|
|
10723
|
+
const lastSubrowIndex = firstSubrowIndex + 1;
|
|
10724
|
+
return bounds.fromSubrowIndex <= lastSubrowIndex && bounds.toSubrowIndex >= firstSubrowIndex;
|
|
10725
|
+
}
|
|
10726
|
+
function areRangeBoundsEqual(left, right) {
|
|
10727
|
+
if (left === right) return true;
|
|
10728
|
+
if (!left || !right) return false;
|
|
10729
|
+
return left.fromDateIndex === right.fromDateIndex && left.toDateIndex === right.toDateIndex && left.fromSubrowIndex === right.fromSubrowIndex && left.toSubrowIndex === right.toSubrowIndex;
|
|
10730
|
+
}
|
|
10731
|
+
function PlanFactRowInner({
|
|
10732
|
+
task,
|
|
10733
|
+
rowIndex,
|
|
10734
|
+
dateRange,
|
|
10735
|
+
dateKeys,
|
|
10736
|
+
renderedDateIndices,
|
|
10737
|
+
rowHeight,
|
|
10738
|
+
subrowHeight,
|
|
10739
|
+
dayWidth,
|
|
10740
|
+
plannedRange,
|
|
10741
|
+
todayDateIndex,
|
|
10742
|
+
isParent,
|
|
10743
|
+
isHighlighted,
|
|
10744
|
+
selectedTaskId,
|
|
10745
|
+
activeCell,
|
|
10746
|
+
editingCell,
|
|
10747
|
+
selectedRange,
|
|
10748
|
+
renderedRangeBounds,
|
|
10749
|
+
didDragSelectRef,
|
|
10750
|
+
isSelectingRef,
|
|
10751
|
+
isFillDraggingRef,
|
|
10752
|
+
onTaskSelect,
|
|
10753
|
+
selectSingleCell,
|
|
10754
|
+
queueHoverCellUpdate,
|
|
10755
|
+
setActiveCell,
|
|
10756
|
+
setEditingCell,
|
|
10757
|
+
setFillRange,
|
|
10758
|
+
clearSelectedCells,
|
|
10759
|
+
commitCell,
|
|
10760
|
+
commitSelectedCells,
|
|
10761
|
+
moveActiveCell,
|
|
10762
|
+
extendSelectedRange,
|
|
10763
|
+
focusCell,
|
|
10764
|
+
showOverflowTooltip,
|
|
10765
|
+
hideOverflowTooltip
|
|
10766
|
+
}) {
|
|
10767
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
10768
|
+
"div",
|
|
10769
|
+
{
|
|
10770
|
+
"data-gantt-task-row-id": task.id,
|
|
10771
|
+
className: joinClasses2(
|
|
10772
|
+
"gantt-pf-row",
|
|
10773
|
+
isParent && "gantt-pf-row-parent",
|
|
10774
|
+
selectedTaskId === task.id && "gantt-pf-row-selected",
|
|
10775
|
+
isHighlighted && "gantt-pf-row-highlighted"
|
|
10776
|
+
),
|
|
10777
|
+
style: {
|
|
10778
|
+
top: `${rowIndex * rowHeight}px`,
|
|
10779
|
+
height: `${rowHeight}px`,
|
|
10780
|
+
gridTemplateColumns: `repeat(${dateRange.length}, ${dayWidth}px)`,
|
|
10781
|
+
["--gantt-pf-today-left"]: todayDateIndex !== void 0 && todayDateIndex >= 0 ? `${todayDateIndex * dayWidth}px` : void 0
|
|
10782
|
+
},
|
|
10783
|
+
onClick: () => onTaskSelect?.(task.id),
|
|
10784
|
+
children: renderedDateIndices.map((dateIndex) => {
|
|
10785
|
+
const dateKey = dateKeys[dateIndex];
|
|
10786
|
+
if (dateKey === void 0) return null;
|
|
10787
|
+
const planned = isDateIndexWithinPlannedRange(dateIndex, plannedRange);
|
|
10788
|
+
return ["plan", "fact"].map((kind) => {
|
|
10789
|
+
const subrowIndex = getSubrowIndex(rowIndex, kind);
|
|
10790
|
+
const isInRenderedRange = !!renderedRangeBounds && dateIndex >= renderedRangeBounds.fromDateIndex && dateIndex <= renderedRangeBounds.toDateIndex && subrowIndex >= renderedRangeBounds.fromSubrowIndex && subrowIndex <= renderedRangeBounds.toSubrowIndex;
|
|
10791
|
+
const planValue = task.planByDate?.[dateKey];
|
|
10792
|
+
const factValue = task.factByDate?.[dateKey];
|
|
10793
|
+
const value = kind === "plan" ? planValue : factValue;
|
|
10794
|
+
const factStatus = factValue === void 0 || planValue === void 0 ? null : factValue >= planValue ? "success" : "warning";
|
|
10795
|
+
const isActive = activeCell?.taskId === task.id && activeCell.dateIndex === dateIndex && activeCell.kind === kind;
|
|
10796
|
+
const isEditing = editingCell?.taskId === task.id && editingCell.dateIndex === dateIndex && editingCell.kind === kind;
|
|
10797
|
+
const currentCell = { taskId: task.id, dateIndex, kind };
|
|
10798
|
+
const isSelected = !isParent && isInRenderedRange;
|
|
10799
|
+
const showFillHandle = !isParent && !isEditing && isInRenderedRange && renderedRangeBounds !== null && dateIndex === renderedRangeBounds.toDateIndex && subrowIndex === renderedRangeBounds.toSubrowIndex;
|
|
10800
|
+
const isRangeAnchor = !showFillHandle && !isParent && selectedRange?.anchor.taskId === task.id && selectedRange.anchor.dateIndex === dateIndex && selectedRange.anchor.kind === kind;
|
|
10801
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
10802
|
+
"div",
|
|
10803
|
+
{
|
|
10804
|
+
"data-plan-fact-task-id": task.id,
|
|
10805
|
+
"data-plan-fact-date-index": dateIndex,
|
|
10806
|
+
"data-plan-fact-kind": kind,
|
|
10807
|
+
className: joinClasses2(
|
|
10808
|
+
"gantt-pf-cell",
|
|
10809
|
+
`gantt-pf-cell-${kind}`,
|
|
10810
|
+
planned && kind === "plan" && "gantt-pf-cell-planned",
|
|
10811
|
+
value !== void 0 && "gantt-pf-cell-hasValue",
|
|
10812
|
+
kind === "fact" && factStatus === "success" && "gantt-pf-cell-factSuccess",
|
|
10813
|
+
kind === "fact" && factStatus === "warning" && "gantt-pf-cell-factWarning",
|
|
10814
|
+
isSelected && "gantt-pf-cell-selected",
|
|
10815
|
+
isInRenderedRange && renderedRangeBounds !== null && dateIndex === renderedRangeBounds.fromDateIndex && "gantt-pf-cell-rangeLeft",
|
|
10816
|
+
isInRenderedRange && renderedRangeBounds !== null && dateIndex === renderedRangeBounds.toDateIndex && "gantt-pf-cell-rangeRight",
|
|
10817
|
+
isInRenderedRange && renderedRangeBounds !== null && subrowIndex === renderedRangeBounds.fromSubrowIndex && "gantt-pf-cell-rangeTop",
|
|
10818
|
+
isInRenderedRange && renderedRangeBounds !== null && subrowIndex === renderedRangeBounds.toSubrowIndex && "gantt-pf-cell-rangeBottom",
|
|
10819
|
+
isRangeAnchor && "gantt-pf-cell-rangeAnchor",
|
|
10820
|
+
isActive && "gantt-pf-cell-active",
|
|
10821
|
+
isEditing && "gantt-pf-cell-editing",
|
|
10822
|
+
isParent && "gantt-pf-cell-readonly"
|
|
10823
|
+
),
|
|
10824
|
+
style: {
|
|
10825
|
+
gridColumn: dateIndex + 1,
|
|
10826
|
+
gridRow: kind === "plan" ? 1 : 2,
|
|
10827
|
+
height: `${subrowHeight}px`
|
|
10828
|
+
},
|
|
10829
|
+
tabIndex: isParent ? -1 : 0,
|
|
10830
|
+
onMouseDown: (event) => {
|
|
10831
|
+
if (isParent) return;
|
|
10832
|
+
event.preventDefault();
|
|
10833
|
+
event.stopPropagation();
|
|
10834
|
+
didDragSelectRef.current = false;
|
|
10835
|
+
isSelectingRef.current = true;
|
|
10836
|
+
selectSingleCell(currentCell);
|
|
10837
|
+
onTaskSelect?.(task.id);
|
|
10838
|
+
event.currentTarget.focus();
|
|
10839
|
+
},
|
|
10840
|
+
onMouseEnter: () => {
|
|
10841
|
+
if (isParent) return;
|
|
10842
|
+
if (!isFillDraggingRef.current && !isSelectingRef.current) return;
|
|
10843
|
+
queueHoverCellUpdate(currentCell);
|
|
10844
|
+
},
|
|
10845
|
+
onFocus: () => {
|
|
10846
|
+
if (isParent) return;
|
|
10847
|
+
setActiveCell({ taskId: task.id, dateIndex, kind });
|
|
10848
|
+
},
|
|
10849
|
+
onClick: (event) => {
|
|
10850
|
+
event.stopPropagation();
|
|
10851
|
+
if (didDragSelectRef.current) {
|
|
10852
|
+
didDragSelectRef.current = false;
|
|
10853
|
+
return;
|
|
10854
|
+
}
|
|
10855
|
+
onTaskSelect?.(task.id);
|
|
10856
|
+
if (isParent) return;
|
|
10857
|
+
selectSingleCell(currentCell);
|
|
10858
|
+
event.currentTarget.focus();
|
|
10859
|
+
},
|
|
10860
|
+
onDoubleClick: (event) => {
|
|
10861
|
+
event.stopPropagation();
|
|
10862
|
+
if (isParent) return;
|
|
10863
|
+
setEditingCell({ taskId: task.id, dateIndex, kind });
|
|
10864
|
+
},
|
|
10865
|
+
onKeyDown: (event) => {
|
|
10866
|
+
if (isParent || isEditing) return;
|
|
10867
|
+
if (event.key === "ArrowLeft" || event.key === "ArrowRight" || event.key === "ArrowUp" || event.key === "ArrowDown") {
|
|
10868
|
+
event.preventDefault();
|
|
10869
|
+
event.stopPropagation();
|
|
10870
|
+
const direction = event.key.replace("Arrow", "").toLowerCase();
|
|
10871
|
+
if (event.shiftKey) {
|
|
10872
|
+
extendSelectedRange(selectedRange?.focus ?? currentCell, direction);
|
|
10873
|
+
} else {
|
|
10874
|
+
moveActiveCell(currentCell, direction);
|
|
10875
|
+
}
|
|
10876
|
+
return;
|
|
10877
|
+
}
|
|
10878
|
+
if (event.key === "Enter" || event.key === "F2") {
|
|
10879
|
+
event.preventDefault();
|
|
10880
|
+
event.stopPropagation();
|
|
10881
|
+
setEditingCell(selectedRange?.anchor ?? currentCell);
|
|
10882
|
+
return;
|
|
10883
|
+
}
|
|
10884
|
+
if (event.key === "Backspace" || event.key === "Delete") {
|
|
10885
|
+
event.preventDefault();
|
|
10886
|
+
event.stopPropagation();
|
|
10887
|
+
clearSelectedCells();
|
|
10888
|
+
return;
|
|
10889
|
+
}
|
|
10890
|
+
if (event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {
|
|
10891
|
+
event.preventDefault();
|
|
10892
|
+
event.stopPropagation();
|
|
10893
|
+
setEditingCell({ ...currentCell, startValue: event.key });
|
|
10894
|
+
}
|
|
10895
|
+
},
|
|
10896
|
+
children: [
|
|
10897
|
+
isEditing ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
10898
|
+
PlanFactCellEditor,
|
|
10899
|
+
{
|
|
10900
|
+
value,
|
|
10901
|
+
startValue: editingCell.startValue,
|
|
10902
|
+
onCommit: (nextValue) => {
|
|
10903
|
+
commitCell(task, dateIndex, kind, nextValue);
|
|
10904
|
+
setEditingCell(null);
|
|
10905
|
+
const nextActiveCell = { taskId: task.id, dateIndex, kind };
|
|
10906
|
+
selectSingleCell(nextActiveCell);
|
|
10907
|
+
focusCell(nextActiveCell);
|
|
10908
|
+
},
|
|
10909
|
+
onCommitRange: (nextValue) => {
|
|
10910
|
+
commitSelectedCells(nextValue);
|
|
10911
|
+
setEditingCell(null);
|
|
10912
|
+
const nextActiveCell = { taskId: task.id, dateIndex, kind };
|
|
10913
|
+
selectSingleCell(nextActiveCell);
|
|
10914
|
+
focusCell(nextActiveCell);
|
|
10915
|
+
},
|
|
10916
|
+
onCancel: () => {
|
|
10917
|
+
setEditingCell(null);
|
|
10918
|
+
const nextActiveCell = { taskId: task.id, dateIndex, kind };
|
|
10919
|
+
selectSingleCell(nextActiveCell);
|
|
10920
|
+
focusCell(nextActiveCell);
|
|
10921
|
+
}
|
|
10922
|
+
}
|
|
10923
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
10924
|
+
"span",
|
|
10925
|
+
{
|
|
10926
|
+
className: "gantt-pf-cellValue",
|
|
10927
|
+
onMouseEnter: (event) => {
|
|
10928
|
+
if (isParent || value === void 0) return;
|
|
10929
|
+
const compactValue = formatValue(value);
|
|
10930
|
+
const fullValue = formatTooltipValue(value);
|
|
10931
|
+
showOverflowTooltip(event.currentTarget, fullValue, compactValue !== fullValue);
|
|
10932
|
+
},
|
|
10933
|
+
onMouseLeave: hideOverflowTooltip,
|
|
10934
|
+
children: isParent ? "" : formatValue(value)
|
|
10935
|
+
}
|
|
10936
|
+
),
|
|
10937
|
+
showFillHandle && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
10938
|
+
"span",
|
|
10939
|
+
{
|
|
10940
|
+
className: "gantt-pf-fillHandle",
|
|
10941
|
+
"aria-hidden": "true",
|
|
10942
|
+
onMouseDown: (event) => {
|
|
10943
|
+
event.preventDefault();
|
|
10944
|
+
event.stopPropagation();
|
|
10945
|
+
isSelectingRef.current = false;
|
|
10946
|
+
isFillDraggingRef.current = true;
|
|
10947
|
+
setFillRange(selectedRange);
|
|
10948
|
+
}
|
|
10949
|
+
}
|
|
10950
|
+
)
|
|
10951
|
+
]
|
|
10952
|
+
},
|
|
10953
|
+
`${task.id}:${dateKey}:${kind}`
|
|
10954
|
+
);
|
|
10955
|
+
});
|
|
10956
|
+
})
|
|
10957
|
+
}
|
|
10958
|
+
);
|
|
10959
|
+
}
|
|
10960
|
+
function arePlanFactRowsEqual(previous, next) {
|
|
10961
|
+
const previousRangeTouchesRow = doesRangeTouchRow(previous.renderedRangeBounds, previous.rowIndex);
|
|
10962
|
+
const nextRangeTouchesRow = doesRangeTouchRow(next.renderedRangeBounds, next.rowIndex);
|
|
10963
|
+
return previous.task === next.task && previous.rowIndex === next.rowIndex && previous.dateRange === next.dateRange && previous.dateKeys === next.dateKeys && previous.renderedDateIndices === next.renderedDateIndices && previous.rowHeight === next.rowHeight && previous.subrowHeight === next.subrowHeight && previous.dayWidth === next.dayWidth && previous.plannedRange === next.plannedRange && previous.todayDateIndex === next.todayDateIndex && previous.isParent === next.isParent && previous.isHighlighted === next.isHighlighted && previous.selectedTaskId === previous.task.id === (next.selectedTaskId === next.task.id) && getCellSignatureForTask(previous.activeCell, previous.task.id) === getCellSignatureForTask(next.activeCell, next.task.id) && getEditingCellSignatureForTask(previous.editingCell, previous.task.id) === getEditingCellSignatureForTask(next.editingCell, next.task.id) && getRangeAnchorSignatureForTask(previous.selectedRange, previous.task.id) === getRangeAnchorSignatureForTask(next.selectedRange, next.task.id) && previousRangeTouchesRow === nextRangeTouchesRow && (!nextRangeTouchesRow || areRangeBoundsEqual(previous.renderedRangeBounds, next.renderedRangeBounds));
|
|
10964
|
+
}
|
|
10965
|
+
var PlanFactRow = import_react17.default.memo(PlanFactRowInner, arePlanFactRowsEqual);
|
|
10966
|
+
function PlanFactMatrix({
|
|
10967
|
+
tasks,
|
|
10968
|
+
allTasks = tasks,
|
|
10969
|
+
dateRange,
|
|
10970
|
+
dayWidth,
|
|
10971
|
+
rowHeight,
|
|
10972
|
+
headerHeight,
|
|
10973
|
+
bodyMinHeight,
|
|
10974
|
+
selectedTaskId,
|
|
10975
|
+
onTaskSelect,
|
|
10976
|
+
onTasksChange,
|
|
10977
|
+
onCellCommit,
|
|
10978
|
+
highlightedTaskIds,
|
|
10979
|
+
filterMode = "highlight",
|
|
10980
|
+
visibleRowIndices,
|
|
10981
|
+
visibleDateIndices,
|
|
10982
|
+
todayDateIndex
|
|
10983
|
+
}) {
|
|
10984
|
+
const [activeCell, setActiveCell] = (0, import_react17.useState)(null);
|
|
10985
|
+
const [editingCell, setEditingCell] = (0, import_react17.useState)(null);
|
|
10986
|
+
const [selectedRange, setSelectedRange] = (0, import_react17.useState)(null);
|
|
10987
|
+
const [fillRange, setFillRange] = (0, import_react17.useState)(null);
|
|
10988
|
+
const [overflowTooltip, setOverflowTooltip] = (0, import_react17.useState)(null);
|
|
10989
|
+
const isSelectingRef = (0, import_react17.useRef)(false);
|
|
10990
|
+
const isFillDraggingRef = (0, import_react17.useRef)(false);
|
|
10991
|
+
const didDragSelectRef = (0, import_react17.useRef)(false);
|
|
10992
|
+
const pendingHoverCellRef = (0, import_react17.useRef)(null);
|
|
10993
|
+
const hoverFrameRef = (0, import_react17.useRef)(null);
|
|
10994
|
+
const rootRef = (0, import_react17.useRef)(null);
|
|
10995
|
+
const bodyRef = (0, import_react17.useRef)(null);
|
|
10996
|
+
const totalWidth = dateRange.length * dayWidth;
|
|
10997
|
+
const subrowHeight = rowHeight / 2;
|
|
10998
|
+
const renderedRowIndices = (0, import_react17.useMemo)(
|
|
10999
|
+
() => visibleRowIndices ?? tasks.map((_, index) => index),
|
|
11000
|
+
[tasks, visibleRowIndices]
|
|
11001
|
+
);
|
|
11002
|
+
const renderedDateIndices = (0, import_react17.useMemo)(
|
|
11003
|
+
() => visibleDateIndices ?? dateRange.map((_, index) => index),
|
|
11004
|
+
[dateRange, visibleDateIndices]
|
|
11005
|
+
);
|
|
11006
|
+
const parentTaskIds = (0, import_react17.useMemo)(() => {
|
|
11007
|
+
const ids = /* @__PURE__ */ new Set();
|
|
11008
|
+
for (const task of allTasks) {
|
|
11009
|
+
if (task.parentId) ids.add(task.parentId);
|
|
11010
|
+
}
|
|
11011
|
+
return ids;
|
|
11012
|
+
}, [allTasks]);
|
|
11013
|
+
const dateKeys = (0, import_react17.useMemo)(() => dateRange.map(formatDateKey), [dateRange]);
|
|
11014
|
+
const dateRangeStartMs = dateRange[0] ? getDateOnlyMs(dateRange[0]) : 0;
|
|
11015
|
+
const taskIndexById = (0, import_react17.useMemo)(() => {
|
|
11016
|
+
const indexById = /* @__PURE__ */ new Map();
|
|
11017
|
+
tasks.forEach((task, index) => indexById.set(task.id, index));
|
|
11018
|
+
return indexById;
|
|
11019
|
+
}, [tasks]);
|
|
11020
|
+
const taskById = (0, import_react17.useMemo)(
|
|
11021
|
+
() => new Map(tasks.map((task) => [task.id, task])),
|
|
11022
|
+
[tasks]
|
|
11023
|
+
);
|
|
11024
|
+
const monthSeparatorIndices = (0, import_react17.useMemo)(() => {
|
|
11025
|
+
const indices = [];
|
|
11026
|
+
for (let index = 1; index < dateRange.length; index += 1) {
|
|
11027
|
+
if (dateRange[index].getUTCDate() === 1) {
|
|
11028
|
+
indices.push(index);
|
|
11029
|
+
}
|
|
11030
|
+
}
|
|
11031
|
+
return indices;
|
|
11032
|
+
}, [dateRange]);
|
|
11033
|
+
const plannedRangeByTaskId = (0, import_react17.useMemo)(() => {
|
|
11034
|
+
const rangeByTaskId = /* @__PURE__ */ new Map();
|
|
11035
|
+
for (const task of tasks) {
|
|
11036
|
+
rangeByTaskId.set(task.id, getPlannedIndexRange(task, dateRangeStartMs, dateRange.length));
|
|
11037
|
+
}
|
|
11038
|
+
return rangeByTaskId;
|
|
11039
|
+
}, [dateRange.length, dateRangeStartMs, tasks]);
|
|
11040
|
+
const focusCell = (0, import_react17.useCallback)((cell) => {
|
|
11041
|
+
window.requestAnimationFrame(() => {
|
|
11042
|
+
const selector = [
|
|
11043
|
+
`[data-plan-fact-task-id="${escapeAttributeValue(cell.taskId)}"]`,
|
|
11044
|
+
`[data-plan-fact-date-index="${cell.dateIndex}"]`,
|
|
11045
|
+
`[data-plan-fact-kind="${cell.kind}"]`
|
|
11046
|
+
].join("");
|
|
11047
|
+
bodyRef.current?.querySelector(selector)?.focus();
|
|
11048
|
+
});
|
|
11049
|
+
}, []);
|
|
11050
|
+
const clearSelection = (0, import_react17.useCallback)(() => {
|
|
11051
|
+
if (hoverFrameRef.current !== null) {
|
|
11052
|
+
window.cancelAnimationFrame(hoverFrameRef.current);
|
|
11053
|
+
hoverFrameRef.current = null;
|
|
11054
|
+
}
|
|
11055
|
+
pendingHoverCellRef.current = null;
|
|
11056
|
+
isSelectingRef.current = false;
|
|
11057
|
+
isFillDraggingRef.current = false;
|
|
11058
|
+
didDragSelectRef.current = false;
|
|
11059
|
+
setActiveCell(null);
|
|
11060
|
+
setEditingCell(null);
|
|
11061
|
+
setSelectedRange(null);
|
|
11062
|
+
setFillRange(null);
|
|
11063
|
+
setOverflowTooltip(null);
|
|
11064
|
+
}, []);
|
|
11065
|
+
const hideOverflowTooltip = (0, import_react17.useCallback)(() => {
|
|
11066
|
+
setOverflowTooltip(null);
|
|
11067
|
+
}, []);
|
|
11068
|
+
const flushPendingHoverCell = (0, import_react17.useCallback)(() => {
|
|
11069
|
+
hoverFrameRef.current = null;
|
|
11070
|
+
const currentCell = pendingHoverCellRef.current;
|
|
11071
|
+
if (!currentCell) return;
|
|
11072
|
+
if (isFillDraggingRef.current && selectedRange) {
|
|
11073
|
+
setFillRange({ anchor: selectedRange.anchor, focus: currentCell });
|
|
11074
|
+
setActiveCell(currentCell);
|
|
11075
|
+
onTaskSelect?.(currentCell.taskId);
|
|
11076
|
+
return;
|
|
11077
|
+
}
|
|
11078
|
+
if (!isSelectingRef.current) return;
|
|
11079
|
+
didDragSelectRef.current = true;
|
|
11080
|
+
setSelectedRange((currentRange) => ({
|
|
11081
|
+
anchor: currentRange?.anchor ?? currentCell,
|
|
11082
|
+
focus: currentCell
|
|
11083
|
+
}));
|
|
11084
|
+
onTaskSelect?.(currentCell.taskId);
|
|
11085
|
+
}, [onTaskSelect, selectedRange]);
|
|
11086
|
+
const queueHoverCellUpdate = (0, import_react17.useCallback)((cell) => {
|
|
11087
|
+
pendingHoverCellRef.current = cell;
|
|
11088
|
+
if (hoverFrameRef.current !== null) return;
|
|
11089
|
+
hoverFrameRef.current = window.requestAnimationFrame(flushPendingHoverCell);
|
|
11090
|
+
}, [flushPendingHoverCell]);
|
|
11091
|
+
const showOverflowTooltip = (0, import_react17.useCallback)((target, label, force = false) => {
|
|
11092
|
+
if (!rootRef.current || !label) return;
|
|
11093
|
+
if (!force && target.scrollWidth <= target.clientWidth) {
|
|
11094
|
+
setOverflowTooltip(null);
|
|
11095
|
+
return;
|
|
11096
|
+
}
|
|
11097
|
+
const rootRect = rootRef.current.getBoundingClientRect();
|
|
11098
|
+
const targetRect = target.getBoundingClientRect();
|
|
11099
|
+
setOverflowTooltip({
|
|
11100
|
+
label,
|
|
11101
|
+
left: targetRect.left - rootRect.left + targetRect.width / 2,
|
|
11102
|
+
top: targetRect.top - rootRect.top
|
|
11103
|
+
});
|
|
11104
|
+
}, []);
|
|
11105
|
+
const selectSingleCell = (0, import_react17.useCallback)((cell) => {
|
|
11106
|
+
setActiveCell(cell);
|
|
11107
|
+
setSelectedRange({ anchor: cell, focus: cell });
|
|
11108
|
+
setFillRange(null);
|
|
11109
|
+
}, []);
|
|
11110
|
+
const getRangeBounds = (0, import_react17.useCallback)((range) => {
|
|
11111
|
+
const anchorTaskIndex = taskIndexById.get(range.anchor.taskId);
|
|
11112
|
+
const focusTaskIndex = taskIndexById.get(range.focus.taskId);
|
|
11113
|
+
if (anchorTaskIndex === void 0 || focusTaskIndex === void 0) {
|
|
11114
|
+
return null;
|
|
11115
|
+
}
|
|
11116
|
+
return {
|
|
11117
|
+
fromDateIndex: Math.min(range.anchor.dateIndex, range.focus.dateIndex),
|
|
11118
|
+
toDateIndex: Math.max(range.anchor.dateIndex, range.focus.dateIndex),
|
|
11119
|
+
fromSubrowIndex: Math.min(
|
|
11120
|
+
getSubrowIndex(anchorTaskIndex, range.anchor.kind),
|
|
11121
|
+
getSubrowIndex(focusTaskIndex, range.focus.kind)
|
|
11122
|
+
),
|
|
11123
|
+
toSubrowIndex: Math.max(
|
|
11124
|
+
getSubrowIndex(anchorTaskIndex, range.anchor.kind),
|
|
11125
|
+
getSubrowIndex(focusTaskIndex, range.focus.kind)
|
|
11126
|
+
)
|
|
11127
|
+
};
|
|
11128
|
+
}, [taskIndexById]);
|
|
11129
|
+
const renderedRange = fillRange ?? selectedRange;
|
|
11130
|
+
const renderedRangeBounds = (0, import_react17.useMemo)(
|
|
11131
|
+
() => renderedRange ? getRangeBounds(renderedRange) : null,
|
|
11132
|
+
[getRangeBounds, renderedRange]
|
|
11133
|
+
);
|
|
11134
|
+
const getCellFromPosition = (0, import_react17.useCallback)((subrowIndex, dateIndex) => {
|
|
11135
|
+
const task = tasks[Math.floor(subrowIndex / 2)];
|
|
11136
|
+
if (!task) return null;
|
|
11137
|
+
return {
|
|
11138
|
+
taskId: task.id,
|
|
11139
|
+
dateIndex,
|
|
11140
|
+
kind: subrowIndex % 2 === 0 ? "plan" : "fact"
|
|
11141
|
+
};
|
|
11142
|
+
}, [tasks]);
|
|
11143
|
+
const isCellInRange = (0, import_react17.useCallback)((cell, range) => {
|
|
11144
|
+
const bounds = getRangeBounds(range);
|
|
11145
|
+
if (!bounds) return false;
|
|
11146
|
+
const cellTaskIndex = taskIndexById.get(cell.taskId);
|
|
11147
|
+
if (cellTaskIndex === void 0) {
|
|
11148
|
+
return false;
|
|
11149
|
+
}
|
|
11150
|
+
const cellSubrowIndex = getSubrowIndex(cellTaskIndex, cell.kind);
|
|
11151
|
+
return cell.dateIndex >= bounds.fromDateIndex && cell.dateIndex <= bounds.toDateIndex && cellSubrowIndex >= bounds.fromSubrowIndex && cellSubrowIndex <= bounds.toSubrowIndex;
|
|
11152
|
+
}, [getRangeBounds, taskIndexById]);
|
|
11153
|
+
const commitCell = (0, import_react17.useCallback)((task, dateIndex, kind, value) => {
|
|
11154
|
+
const dateKey = dateKeys[dateIndex];
|
|
11155
|
+
const source = kind === "plan" ? task.planByDate : task.factByDate;
|
|
11156
|
+
const nextValues = { ...source ?? {} };
|
|
11157
|
+
if (value === void 0) {
|
|
11158
|
+
delete nextValues[dateKey];
|
|
11159
|
+
} else {
|
|
11160
|
+
nextValues[dateKey] = value;
|
|
11161
|
+
}
|
|
11162
|
+
const changedTask = {
|
|
11163
|
+
...task,
|
|
11164
|
+
[kind === "plan" ? "planByDate" : "factByDate"]: nextValues
|
|
11165
|
+
};
|
|
11166
|
+
onTasksChange?.([changedTask]);
|
|
11167
|
+
onCellCommit?.({
|
|
11168
|
+
task,
|
|
11169
|
+
date: dateRange[dateIndex],
|
|
11170
|
+
dateKey,
|
|
11171
|
+
kind,
|
|
11172
|
+
value
|
|
11173
|
+
});
|
|
11174
|
+
}, [dateKeys, dateRange, onCellCommit, onTasksChange]);
|
|
11175
|
+
const commitRangeCells = (0, import_react17.useCallback)((bounds, value, mode) => {
|
|
11176
|
+
const changedTasksById = /* @__PURE__ */ new Map();
|
|
11177
|
+
for (let subrowIndex = bounds.fromSubrowIndex; subrowIndex <= bounds.toSubrowIndex; subrowIndex += 1) {
|
|
11178
|
+
const task = tasks[Math.floor(subrowIndex / 2)];
|
|
11179
|
+
if (!task || parentTaskIds.has(task.id)) continue;
|
|
11180
|
+
const kind = subrowIndex % 2 === 0 ? "plan" : "fact";
|
|
11181
|
+
const currentChangedTask = changedTasksById.get(task.id) ?? task;
|
|
11182
|
+
let nextPlanByDate = currentChangedTask.planByDate;
|
|
11183
|
+
let nextFactByDate = currentChangedTask.factByDate;
|
|
11184
|
+
let didChange = false;
|
|
11185
|
+
for (let dateIndex = bounds.fromDateIndex; dateIndex <= bounds.toDateIndex; dateIndex += 1) {
|
|
11186
|
+
const dateKey = dateKeys[dateIndex];
|
|
11187
|
+
if (dateKey === void 0) continue;
|
|
11188
|
+
const currentValues = kind === "plan" ? nextPlanByDate : nextFactByDate;
|
|
11189
|
+
const currentValue = currentValues?.[dateKey];
|
|
11190
|
+
const nextValue = mode === "clear" ? void 0 : value;
|
|
11191
|
+
if (currentValue === nextValue) continue;
|
|
11192
|
+
if (kind === "plan") {
|
|
11193
|
+
nextPlanByDate = { ...nextPlanByDate ?? {} };
|
|
11194
|
+
if (nextValue === void 0) {
|
|
11195
|
+
delete nextPlanByDate[dateKey];
|
|
11196
|
+
} else {
|
|
11197
|
+
nextPlanByDate[dateKey] = nextValue;
|
|
11198
|
+
}
|
|
11199
|
+
} else {
|
|
11200
|
+
nextFactByDate = { ...nextFactByDate ?? {} };
|
|
11201
|
+
if (nextValue === void 0) {
|
|
11202
|
+
delete nextFactByDate[dateKey];
|
|
11203
|
+
} else {
|
|
11204
|
+
nextFactByDate[dateKey] = nextValue;
|
|
11205
|
+
}
|
|
11206
|
+
}
|
|
11207
|
+
didChange = true;
|
|
11208
|
+
}
|
|
11209
|
+
if (didChange) {
|
|
11210
|
+
changedTasksById.set(task.id, {
|
|
11211
|
+
...currentChangedTask,
|
|
11212
|
+
...nextPlanByDate !== currentChangedTask.planByDate ? { planByDate: nextPlanByDate ?? {} } : {},
|
|
11213
|
+
...nextFactByDate !== currentChangedTask.factByDate ? { factByDate: nextFactByDate ?? {} } : {}
|
|
11214
|
+
});
|
|
11215
|
+
}
|
|
11216
|
+
}
|
|
11217
|
+
const changedTasks = Array.from(changedTasksById.values());
|
|
11218
|
+
if (changedTasks.length > 0) {
|
|
11219
|
+
onTasksChange?.(changedTasks);
|
|
11220
|
+
}
|
|
11221
|
+
}, [dateKeys, onTasksChange, parentTaskIds, tasks]);
|
|
11222
|
+
const clearSelectedCells = (0, import_react17.useCallback)(() => {
|
|
11223
|
+
const activeRange = fillRange ?? selectedRange;
|
|
11224
|
+
if (!activeRange) {
|
|
11225
|
+
if (!activeCell) return;
|
|
11226
|
+
const task = taskById.get(activeCell.taskId);
|
|
11227
|
+
if (!task || parentTaskIds.has(task.id)) return;
|
|
11228
|
+
commitCell(task, activeCell.dateIndex, activeCell.kind, void 0);
|
|
11229
|
+
return;
|
|
11230
|
+
}
|
|
11231
|
+
const bounds = getRangeBounds(activeRange);
|
|
11232
|
+
if (bounds) {
|
|
11233
|
+
commitRangeCells(bounds, void 0, "clear");
|
|
11234
|
+
}
|
|
11235
|
+
}, [activeCell, commitCell, commitRangeCells, fillRange, getRangeBounds, parentTaskIds, selectedRange, taskById]);
|
|
11236
|
+
const commitSelectedCells = (0, import_react17.useCallback)((value) => {
|
|
11237
|
+
const activeRange = fillRange ?? selectedRange;
|
|
11238
|
+
if (!activeRange) {
|
|
11239
|
+
if (!activeCell) return;
|
|
11240
|
+
const task = taskById.get(activeCell.taskId);
|
|
11241
|
+
if (!task || parentTaskIds.has(task.id)) return;
|
|
11242
|
+
commitCell(task, activeCell.dateIndex, activeCell.kind, value);
|
|
11243
|
+
return;
|
|
11244
|
+
}
|
|
11245
|
+
const bounds = getRangeBounds(activeRange);
|
|
11246
|
+
if (bounds) {
|
|
11247
|
+
commitRangeCells(bounds, value, "set");
|
|
11248
|
+
}
|
|
11249
|
+
}, [activeCell, commitCell, commitRangeCells, fillRange, getRangeBounds, parentTaskIds, selectedRange, taskById]);
|
|
11250
|
+
const getCellValue = (0, import_react17.useCallback)((cell) => {
|
|
11251
|
+
const task = taskById.get(cell.taskId);
|
|
11252
|
+
if (!task) return void 0;
|
|
11253
|
+
const dateKey = dateKeys[cell.dateIndex];
|
|
11254
|
+
return cell.kind === "plan" ? task.planByDate?.[dateKey] : task.factByDate?.[dateKey];
|
|
11255
|
+
}, [dateKeys, taskById]);
|
|
11256
|
+
const applyFillRange = (0, import_react17.useCallback)((nextFillRange) => {
|
|
11257
|
+
const targetRange = nextFillRange ?? fillRange;
|
|
11258
|
+
if (!selectedRange || !targetRange) return;
|
|
11259
|
+
const sourceBounds = getRangeBounds(selectedRange);
|
|
11260
|
+
const targetBounds = getRangeBounds(targetRange);
|
|
11261
|
+
if (!sourceBounds || !targetBounds) return;
|
|
11262
|
+
const sourceDateSpan = sourceBounds.toDateIndex - sourceBounds.fromDateIndex + 1;
|
|
11263
|
+
const sourceSubrowSpan = sourceBounds.toSubrowIndex - sourceBounds.fromSubrowIndex + 1;
|
|
11264
|
+
const changedTasksById = /* @__PURE__ */ new Map();
|
|
11265
|
+
for (let subrowIndex = targetBounds.fromSubrowIndex; subrowIndex <= targetBounds.toSubrowIndex; subrowIndex += 1) {
|
|
11266
|
+
const targetCellForRow = getCellFromPosition(subrowIndex, targetBounds.fromDateIndex);
|
|
11267
|
+
if (!targetCellForRow || parentTaskIds.has(targetCellForRow.taskId)) continue;
|
|
11268
|
+
const originalTask = taskById.get(targetCellForRow.taskId);
|
|
11269
|
+
if (!originalTask) continue;
|
|
11270
|
+
let changedTask = changedTasksById.get(originalTask.id) ?? originalTask;
|
|
11271
|
+
let nextPlanByDate = changedTask.planByDate;
|
|
11272
|
+
let nextFactByDate = changedTask.factByDate;
|
|
11273
|
+
let didChange = false;
|
|
11274
|
+
for (let dateIndex = targetBounds.fromDateIndex; dateIndex <= targetBounds.toDateIndex; dateIndex += 1) {
|
|
11275
|
+
const targetCell = getCellFromPosition(subrowIndex, dateIndex);
|
|
11276
|
+
if (!targetCell || isCellInRange(targetCell, selectedRange)) continue;
|
|
11277
|
+
const sourceSubrowIndex = sourceBounds.fromSubrowIndex + ((subrowIndex - sourceBounds.fromSubrowIndex) % sourceSubrowSpan + sourceSubrowSpan) % sourceSubrowSpan;
|
|
11278
|
+
const sourceDateIndex = sourceBounds.fromDateIndex + ((dateIndex - sourceBounds.fromDateIndex) % sourceDateSpan + sourceDateSpan) % sourceDateSpan;
|
|
11279
|
+
const sourceCell = getCellFromPosition(sourceSubrowIndex, sourceDateIndex);
|
|
11280
|
+
if (!sourceCell) continue;
|
|
11281
|
+
const nextValue = getCellValue(sourceCell);
|
|
11282
|
+
const dateKey = dateKeys[dateIndex];
|
|
11283
|
+
const currentValues = targetCell.kind === "plan" ? nextPlanByDate : nextFactByDate;
|
|
11284
|
+
if (currentValues?.[dateKey] === nextValue) continue;
|
|
11285
|
+
if (targetCell.kind === "plan") {
|
|
11286
|
+
nextPlanByDate = { ...nextPlanByDate ?? {} };
|
|
11287
|
+
if (nextValue === void 0) {
|
|
11288
|
+
delete nextPlanByDate[dateKey];
|
|
11289
|
+
} else {
|
|
11290
|
+
nextPlanByDate[dateKey] = nextValue;
|
|
11291
|
+
}
|
|
11292
|
+
} else {
|
|
11293
|
+
nextFactByDate = { ...nextFactByDate ?? {} };
|
|
11294
|
+
if (nextValue === void 0) {
|
|
11295
|
+
delete nextFactByDate[dateKey];
|
|
11296
|
+
} else {
|
|
11297
|
+
nextFactByDate[dateKey] = nextValue;
|
|
11298
|
+
}
|
|
11299
|
+
}
|
|
11300
|
+
didChange = true;
|
|
11301
|
+
}
|
|
11302
|
+
if (didChange) {
|
|
11303
|
+
changedTasksById.set(originalTask.id, {
|
|
11304
|
+
...changedTask,
|
|
11305
|
+
...nextPlanByDate !== changedTask.planByDate ? { planByDate: nextPlanByDate ?? {} } : {},
|
|
11306
|
+
...nextFactByDate !== changedTask.factByDate ? { factByDate: nextFactByDate ?? {} } : {}
|
|
11307
|
+
});
|
|
11308
|
+
}
|
|
11309
|
+
}
|
|
11310
|
+
const changedTasks = Array.from(changedTasksById.values());
|
|
11311
|
+
if (changedTasks.length > 0) {
|
|
11312
|
+
onTasksChange?.(changedTasks);
|
|
11313
|
+
}
|
|
11314
|
+
setSelectedRange(targetRange);
|
|
11315
|
+
setActiveCell(targetRange.anchor);
|
|
11316
|
+
setFillRange(null);
|
|
11317
|
+
}, [
|
|
11318
|
+
dateKeys,
|
|
11319
|
+
fillRange,
|
|
11320
|
+
getCellFromPosition,
|
|
11321
|
+
getCellValue,
|
|
11322
|
+
getRangeBounds,
|
|
11323
|
+
isCellInRange,
|
|
11324
|
+
onTasksChange,
|
|
11325
|
+
parentTaskIds,
|
|
11326
|
+
selectedRange,
|
|
11327
|
+
taskById
|
|
11328
|
+
]);
|
|
11329
|
+
const moveActiveCell = (0, import_react17.useCallback)((cell, direction) => {
|
|
11330
|
+
const taskIndex = tasks.findIndex((task) => task.id === cell.taskId);
|
|
11331
|
+
if (taskIndex < 0) return;
|
|
11332
|
+
let nextCell = { ...cell };
|
|
11333
|
+
if (direction === "left") {
|
|
11334
|
+
nextCell.dateIndex = Math.max(0, cell.dateIndex - 1);
|
|
11335
|
+
} else if (direction === "right") {
|
|
11336
|
+
nextCell.dateIndex = Math.min(dateRange.length - 1, cell.dateIndex + 1);
|
|
11337
|
+
} else if (direction === "up") {
|
|
11338
|
+
if (cell.kind === "fact") {
|
|
11339
|
+
nextCell.kind = "plan";
|
|
11340
|
+
} else {
|
|
11341
|
+
const previousEditableTaskIndex = findEditableTaskIndex(tasks, parentTaskIds, taskIndex - 1, -1);
|
|
11342
|
+
if (previousEditableTaskIndex === null) return;
|
|
11343
|
+
const previousTask = tasks[previousEditableTaskIndex];
|
|
11344
|
+
nextCell = { taskId: previousTask.id, dateIndex: cell.dateIndex, kind: "fact" };
|
|
11345
|
+
}
|
|
11346
|
+
} else if (direction === "down") {
|
|
11347
|
+
if (cell.kind === "plan") {
|
|
11348
|
+
nextCell.kind = "fact";
|
|
11349
|
+
} else {
|
|
11350
|
+
const nextEditableTaskIndex = findEditableTaskIndex(tasks, parentTaskIds, taskIndex + 1, 1);
|
|
11351
|
+
if (nextEditableTaskIndex === null) return;
|
|
11352
|
+
const nextTask = tasks[nextEditableTaskIndex];
|
|
11353
|
+
nextCell = { taskId: nextTask.id, dateIndex: cell.dateIndex, kind: "plan" };
|
|
11354
|
+
}
|
|
11355
|
+
}
|
|
11356
|
+
setActiveCell(nextCell);
|
|
11357
|
+
setSelectedRange({ anchor: nextCell, focus: nextCell });
|
|
11358
|
+
onTaskSelect?.(nextCell.taskId);
|
|
11359
|
+
focusCell(nextCell);
|
|
11360
|
+
}, [dateRange.length, focusCell, onTaskSelect, parentTaskIds, tasks]);
|
|
11361
|
+
const extendSelectedRange = (0, import_react17.useCallback)((cell, direction) => {
|
|
11362
|
+
const taskIndex = tasks.findIndex((task) => task.id === cell.taskId);
|
|
11363
|
+
if (taskIndex < 0) return;
|
|
11364
|
+
let nextCell = { ...cell };
|
|
11365
|
+
if (direction === "left") {
|
|
11366
|
+
nextCell.dateIndex = Math.max(0, cell.dateIndex - 1);
|
|
11367
|
+
} else if (direction === "right") {
|
|
11368
|
+
nextCell.dateIndex = Math.min(dateRange.length - 1, cell.dateIndex + 1);
|
|
11369
|
+
} else if (direction === "up") {
|
|
11370
|
+
if (cell.kind === "fact") {
|
|
11371
|
+
nextCell.kind = "plan";
|
|
11372
|
+
} else {
|
|
11373
|
+
const previousEditableTaskIndex = findEditableTaskIndex(tasks, parentTaskIds, taskIndex - 1, -1);
|
|
11374
|
+
if (previousEditableTaskIndex === null) return;
|
|
11375
|
+
const previousTask = tasks[previousEditableTaskIndex];
|
|
11376
|
+
nextCell = { taskId: previousTask.id, dateIndex: cell.dateIndex, kind: "fact" };
|
|
11377
|
+
}
|
|
11378
|
+
} else if (direction === "down") {
|
|
11379
|
+
if (cell.kind === "plan") {
|
|
11380
|
+
nextCell.kind = "fact";
|
|
11381
|
+
} else {
|
|
11382
|
+
const nextEditableTaskIndex = findEditableTaskIndex(tasks, parentTaskIds, taskIndex + 1, 1);
|
|
11383
|
+
if (nextEditableTaskIndex === null) return;
|
|
11384
|
+
const nextTask = tasks[nextEditableTaskIndex];
|
|
11385
|
+
nextCell = { taskId: nextTask.id, dateIndex: cell.dateIndex, kind: "plan" };
|
|
11386
|
+
}
|
|
11387
|
+
}
|
|
11388
|
+
setActiveCell((currentActiveCell) => currentActiveCell ?? cell);
|
|
11389
|
+
setFillRange(null);
|
|
11390
|
+
setSelectedRange((currentRange) => ({
|
|
11391
|
+
anchor: currentRange?.anchor ?? cell,
|
|
11392
|
+
focus: nextCell
|
|
11393
|
+
}));
|
|
11394
|
+
onTaskSelect?.(nextCell.taskId);
|
|
11395
|
+
focusCell(selectedRange?.anchor ?? cell);
|
|
11396
|
+
}, [dateRange.length, focusCell, onTaskSelect, parentTaskIds, selectedRange, tasks]);
|
|
11397
|
+
(0, import_react17.useEffect)(() => {
|
|
11398
|
+
const endSelection = () => {
|
|
11399
|
+
let pendingFillRange = null;
|
|
11400
|
+
if (hoverFrameRef.current !== null) {
|
|
11401
|
+
window.cancelAnimationFrame(hoverFrameRef.current);
|
|
11402
|
+
hoverFrameRef.current = null;
|
|
11403
|
+
const pendingCell = pendingHoverCellRef.current;
|
|
11404
|
+
if (pendingCell && isFillDraggingRef.current && selectedRange) {
|
|
11405
|
+
pendingFillRange = { anchor: selectedRange.anchor, focus: pendingCell };
|
|
11406
|
+
}
|
|
11407
|
+
flushPendingHoverCell();
|
|
11408
|
+
}
|
|
11409
|
+
if (isFillDraggingRef.current) {
|
|
11410
|
+
isFillDraggingRef.current = false;
|
|
11411
|
+
applyFillRange(pendingFillRange);
|
|
11412
|
+
}
|
|
11413
|
+
isSelectingRef.current = false;
|
|
11414
|
+
};
|
|
11415
|
+
window.addEventListener("mouseup", endSelection);
|
|
11416
|
+
return () => {
|
|
11417
|
+
window.removeEventListener("mouseup", endSelection);
|
|
11418
|
+
};
|
|
11419
|
+
}, [applyFillRange, flushPendingHoverCell]);
|
|
11420
|
+
(0, import_react17.useEffect)(() => () => {
|
|
11421
|
+
if (hoverFrameRef.current !== null) {
|
|
11422
|
+
window.cancelAnimationFrame(hoverFrameRef.current);
|
|
11423
|
+
}
|
|
11424
|
+
}, []);
|
|
11425
|
+
(0, import_react17.useEffect)(() => {
|
|
11426
|
+
const handleKeyDown = (event) => {
|
|
11427
|
+
if (event.key !== "Escape") return;
|
|
11428
|
+
clearSelection();
|
|
11429
|
+
};
|
|
11430
|
+
const handleMouseDown = (event) => {
|
|
11431
|
+
const target = event.target;
|
|
11432
|
+
if (target instanceof Node && rootRef.current?.contains(target)) {
|
|
11433
|
+
return;
|
|
11434
|
+
}
|
|
11435
|
+
clearSelection();
|
|
11436
|
+
};
|
|
11437
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
11438
|
+
document.addEventListener("mousedown", handleMouseDown);
|
|
11439
|
+
return () => {
|
|
11440
|
+
window.removeEventListener("keydown", handleKeyDown);
|
|
11441
|
+
document.removeEventListener("mousedown", handleMouseDown);
|
|
11442
|
+
};
|
|
11443
|
+
}, [clearSelection]);
|
|
11444
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
11445
|
+
"div",
|
|
11446
|
+
{
|
|
11447
|
+
ref: rootRef,
|
|
11448
|
+
className: "gantt-pf-root",
|
|
11449
|
+
style: {
|
|
11450
|
+
width: `${totalWidth}px`,
|
|
11451
|
+
["--gantt-pf-day-width"]: `${dayWidth}px`
|
|
11452
|
+
},
|
|
11453
|
+
children: [
|
|
11454
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "gantt-pf-header", style: { width: `${totalWidth}px`, height: `${headerHeight}px` }, children: [
|
|
11455
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
11456
|
+
TimeScaleHeader_default,
|
|
11457
|
+
{
|
|
11458
|
+
days: dateRange,
|
|
11459
|
+
dayWidth,
|
|
11460
|
+
headerHeight: headerHeight - 1,
|
|
11461
|
+
viewMode: "day"
|
|
11462
|
+
}
|
|
11463
|
+
),
|
|
11464
|
+
todayDateIndex !== void 0 && todayDateIndex >= 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
11465
|
+
"span",
|
|
11466
|
+
{
|
|
11467
|
+
className: "gantt-pf-headerTodayLine",
|
|
11468
|
+
"aria-hidden": "true",
|
|
11469
|
+
style: {
|
|
11470
|
+
left: `${todayDateIndex * dayWidth}px`,
|
|
11471
|
+
top: `${Math.max(0, headerHeight / 2)}px`
|
|
11472
|
+
}
|
|
11473
|
+
}
|
|
11474
|
+
)
|
|
11475
|
+
] }),
|
|
11476
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "gantt-pf-monthSeparatorLayer", "aria-hidden": "true", children: monthSeparatorIndices.map((dateIndex) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
11477
|
+
"span",
|
|
11478
|
+
{
|
|
11479
|
+
className: "gantt-pf-monthSeparator",
|
|
11480
|
+
style: {
|
|
11481
|
+
left: `${Math.round(dateIndex * dayWidth)}px`,
|
|
11482
|
+
top: `${Math.max(0, headerHeight / 2)}px`
|
|
11483
|
+
}
|
|
11484
|
+
},
|
|
11485
|
+
`month-separator-${dateIndex}`
|
|
11486
|
+
)) }),
|
|
11487
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
11488
|
+
"div",
|
|
11489
|
+
{
|
|
11490
|
+
ref: bodyRef,
|
|
11491
|
+
className: "gantt-pf-body",
|
|
11492
|
+
style: {
|
|
11493
|
+
height: `${tasks.length * rowHeight}px`,
|
|
11494
|
+
minHeight: bodyMinHeight,
|
|
11495
|
+
width: `${totalWidth}px`
|
|
11496
|
+
},
|
|
11497
|
+
children: renderedRowIndices.map((rowIndex) => {
|
|
11498
|
+
const task = tasks[rowIndex];
|
|
11499
|
+
if (!task) return null;
|
|
11500
|
+
const isParent = parentTaskIds.has(task.id);
|
|
11501
|
+
const isHighlighted = filterMode === "highlight" && !!highlightedTaskIds?.has(task.id);
|
|
11502
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
11503
|
+
PlanFactRow,
|
|
11504
|
+
{
|
|
11505
|
+
task,
|
|
11506
|
+
rowIndex,
|
|
11507
|
+
dateRange,
|
|
11508
|
+
dateKeys,
|
|
11509
|
+
renderedDateIndices,
|
|
11510
|
+
rowHeight,
|
|
11511
|
+
subrowHeight,
|
|
11512
|
+
dayWidth,
|
|
11513
|
+
plannedRange: plannedRangeByTaskId.get(task.id) ?? null,
|
|
11514
|
+
todayDateIndex,
|
|
11515
|
+
isParent,
|
|
11516
|
+
isHighlighted,
|
|
11517
|
+
selectedTaskId,
|
|
11518
|
+
activeCell,
|
|
11519
|
+
editingCell,
|
|
11520
|
+
selectedRange,
|
|
11521
|
+
renderedRangeBounds,
|
|
11522
|
+
didDragSelectRef,
|
|
11523
|
+
isSelectingRef,
|
|
11524
|
+
isFillDraggingRef,
|
|
11525
|
+
onTaskSelect,
|
|
11526
|
+
selectSingleCell,
|
|
11527
|
+
queueHoverCellUpdate,
|
|
11528
|
+
setActiveCell,
|
|
11529
|
+
setEditingCell,
|
|
11530
|
+
setFillRange,
|
|
11531
|
+
clearSelectedCells,
|
|
11532
|
+
commitCell,
|
|
11533
|
+
commitSelectedCells,
|
|
11534
|
+
moveActiveCell,
|
|
11535
|
+
extendSelectedRange,
|
|
11536
|
+
focusCell,
|
|
11537
|
+
showOverflowTooltip,
|
|
11538
|
+
hideOverflowTooltip
|
|
11539
|
+
},
|
|
11540
|
+
task.id
|
|
11541
|
+
);
|
|
11542
|
+
})
|
|
11543
|
+
}
|
|
11544
|
+
),
|
|
11545
|
+
overflowTooltip && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
11546
|
+
"div",
|
|
11547
|
+
{
|
|
11548
|
+
className: "gantt-pf-overflowTooltip",
|
|
11549
|
+
role: "tooltip",
|
|
11550
|
+
"aria-hidden": "true",
|
|
11551
|
+
style: {
|
|
11552
|
+
left: `${overflowTooltip.left}px`,
|
|
11553
|
+
top: `${overflowTooltip.top}px`
|
|
11554
|
+
},
|
|
11555
|
+
children: overflowTooltip.label
|
|
11556
|
+
}
|
|
11557
|
+
)
|
|
11558
|
+
]
|
|
11559
|
+
}
|
|
11560
|
+
);
|
|
11561
|
+
}
|
|
11562
|
+
|
|
10567
11563
|
// src/components/GanttChart/print.ts
|
|
10568
11564
|
function getPrintDocumentTitle({
|
|
10569
11565
|
header,
|
|
@@ -10972,9 +11968,60 @@ function createTaskPreviewPositionStore() {
|
|
|
10972
11968
|
}
|
|
10973
11969
|
|
|
10974
11970
|
// src/components/GanttChart/GanttChart.tsx
|
|
10975
|
-
var
|
|
11971
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
10976
11972
|
var SCROLL_TO_ROW_CONTEXT_ROWS = 2;
|
|
10977
11973
|
var TASK_ROW_OVERSCAN = 8;
|
|
11974
|
+
var PLAN_FACT_COLUMN_OVERSCAN = 24;
|
|
11975
|
+
var PLAN_FACT_COLUMN_WINDOW_STEP = 14;
|
|
11976
|
+
function getFullMonthDays(tasks) {
|
|
11977
|
+
if (!tasks || tasks.length === 0) {
|
|
11978
|
+
return getMultiMonthDays(tasks);
|
|
11979
|
+
}
|
|
11980
|
+
let minDate = null;
|
|
11981
|
+
let maxDate = null;
|
|
11982
|
+
for (const task of tasks) {
|
|
11983
|
+
const start = parseUTCDate(task.startDate);
|
|
11984
|
+
const end = parseUTCDate(task.endDate);
|
|
11985
|
+
if (!minDate || start.getTime() < minDate.getTime()) {
|
|
11986
|
+
minDate = start;
|
|
11987
|
+
}
|
|
11988
|
+
if (!maxDate || end.getTime() > maxDate.getTime()) {
|
|
11989
|
+
maxDate = end;
|
|
11990
|
+
}
|
|
11991
|
+
}
|
|
11992
|
+
if (!minDate || !maxDate) {
|
|
11993
|
+
return getMultiMonthDays(tasks);
|
|
11994
|
+
}
|
|
11995
|
+
const startOfMonth2 = new Date(Date.UTC(minDate.getUTCFullYear(), minDate.getUTCMonth(), 1));
|
|
11996
|
+
const endOfMonth = new Date(Date.UTC(maxDate.getUTCFullYear(), maxDate.getUTCMonth() + 1, 0));
|
|
11997
|
+
const days = [];
|
|
11998
|
+
const current = new Date(startOfMonth2);
|
|
11999
|
+
while (current.getTime() <= endOfMonth.getTime()) {
|
|
12000
|
+
days.push(new Date(Date.UTC(
|
|
12001
|
+
current.getUTCFullYear(),
|
|
12002
|
+
current.getUTCMonth(),
|
|
12003
|
+
current.getUTCDate()
|
|
12004
|
+
)));
|
|
12005
|
+
current.setUTCDate(current.getUTCDate() + 1);
|
|
12006
|
+
}
|
|
12007
|
+
return days;
|
|
12008
|
+
}
|
|
12009
|
+
function getPlanFactRangeTasks(tasks) {
|
|
12010
|
+
const rangeTasks = [];
|
|
12011
|
+
for (const task of tasks) {
|
|
12012
|
+
rangeTasks.push({ startDate: task.startDate, endDate: task.endDate });
|
|
12013
|
+
for (const dateKey of Object.keys(task.planByDate ?? {})) {
|
|
12014
|
+
rangeTasks.push({ startDate: dateKey, endDate: dateKey });
|
|
12015
|
+
}
|
|
12016
|
+
for (const dateKey of Object.keys(task.factByDate ?? {})) {
|
|
12017
|
+
rangeTasks.push({ startDate: dateKey, endDate: dateKey });
|
|
12018
|
+
}
|
|
12019
|
+
}
|
|
12020
|
+
return rangeTasks;
|
|
12021
|
+
}
|
|
12022
|
+
function clampScrollValue(value, max) {
|
|
12023
|
+
return Math.min(max, Math.max(0, value));
|
|
12024
|
+
}
|
|
10978
12025
|
function arePositionMapsEqual(left, right) {
|
|
10979
12026
|
if (left.size !== right.size) return false;
|
|
10980
12027
|
for (const [taskId, leftPosition] of left) {
|
|
@@ -11011,9 +12058,9 @@ function arePreviewTaskMapsEqual(left, right) {
|
|
|
11011
12058
|
}
|
|
11012
12059
|
function GanttChartInner(props, ref) {
|
|
11013
12060
|
if (props.mode === "resource-planner") {
|
|
11014
|
-
return /* @__PURE__ */ (0,
|
|
12061
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ResourceTimelineChart, { ...props });
|
|
11015
12062
|
}
|
|
11016
|
-
return /* @__PURE__ */ (0,
|
|
12063
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
11017
12064
|
TaskGanttChart,
|
|
11018
12065
|
{
|
|
11019
12066
|
...props,
|
|
@@ -11023,6 +12070,7 @@ function GanttChartInner(props, ref) {
|
|
|
11023
12070
|
}
|
|
11024
12071
|
function TaskGanttChartInner(props, ref) {
|
|
11025
12072
|
const isTableMatrixMode = props.mode === "table-matrix";
|
|
12073
|
+
const isPlanFactMode = props.mode === "plan-fact";
|
|
11026
12074
|
const {
|
|
11027
12075
|
tasks,
|
|
11028
12076
|
rowHeight = 40,
|
|
@@ -11072,47 +12120,52 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11072
12120
|
onTaskDateChangeModeChange: externalOnTaskDateChangeModeChange
|
|
11073
12121
|
} = props;
|
|
11074
12122
|
const dayWidth = !isTableMatrixMode ? props.dayWidth ?? 40 : 40;
|
|
11075
|
-
const viewMode = !isTableMatrixMode ? props.viewMode ?? "day" : "day";
|
|
11076
|
-
const customDays = !isTableMatrixMode ? props.customDays : void 0;
|
|
11077
|
-
const isWeekend3 = !isTableMatrixMode ? props.isWeekend : void 0;
|
|
11078
|
-
const businessDays = !isTableMatrixMode ? props.businessDays ?? true : true;
|
|
12123
|
+
const viewMode = !isTableMatrixMode && !isPlanFactMode ? props.viewMode ?? "day" : "day";
|
|
12124
|
+
const customDays = !isTableMatrixMode && !isPlanFactMode ? props.customDays : void 0;
|
|
12125
|
+
const isWeekend3 = !isTableMatrixMode && !isPlanFactMode ? props.isWeekend : void 0;
|
|
12126
|
+
const businessDays = !isTableMatrixMode && !isPlanFactMode ? props.businessDays ?? true : true;
|
|
11079
12127
|
const matrixColumns = isTableMatrixMode ? props.matrixColumns : [];
|
|
11080
12128
|
const matrixColumnGroups = isTableMatrixMode ? props.matrixColumnGroups : void 0;
|
|
11081
12129
|
const onMatrixCellClick = isTableMatrixMode ? props.onMatrixCellClick : void 0;
|
|
11082
12130
|
const matrixDateOverlay = isTableMatrixMode ? props.matrixDateOverlay : void 0;
|
|
11083
|
-
const
|
|
11084
|
-
const
|
|
11085
|
-
const
|
|
11086
|
-
const
|
|
11087
|
-
const
|
|
11088
|
-
const
|
|
11089
|
-
const
|
|
12131
|
+
const onPlanFactCellCommit = isPlanFactMode ? props.onPlanFactCellCommit : void 0;
|
|
12132
|
+
const containerRef = (0, import_react18.useRef)(null);
|
|
12133
|
+
const scrollContainerRef = (0, import_react18.useRef)(null);
|
|
12134
|
+
const scrollContentRef = (0, import_react18.useRef)(null);
|
|
12135
|
+
const clearSelectedTaskTimeoutRef = (0, import_react18.useRef)(null);
|
|
12136
|
+
const hasAutoScrolledToTodayRef = (0, import_react18.useRef)(false);
|
|
12137
|
+
const previewPositionStoreRef = (0, import_react18.useRef)(null);
|
|
12138
|
+
const renderedTaskIdsRef = (0, import_react18.useRef)(/* @__PURE__ */ new Set());
|
|
11090
12139
|
if (previewPositionStoreRef.current === null) {
|
|
11091
12140
|
previewPositionStoreRef.current = createTaskPreviewPositionStore();
|
|
11092
12141
|
}
|
|
11093
12142
|
const previewPositionStore = previewPositionStoreRef.current;
|
|
11094
|
-
const [selectedTaskId, setSelectedTaskId] = (0,
|
|
11095
|
-
const [taskListHasRightShadow, setTaskListHasRightShadow] = (0,
|
|
11096
|
-
const [internalTaskDateChangeMode, setInternalTaskDateChangeMode] = (0,
|
|
11097
|
-
const [scrollViewport, setScrollViewport] = (0,
|
|
11098
|
-
const [
|
|
11099
|
-
const [
|
|
11100
|
-
const [
|
|
12143
|
+
const [selectedTaskId, setSelectedTaskId] = (0, import_react18.useState)(null);
|
|
12144
|
+
const [taskListHasRightShadow, setTaskListHasRightShadow] = (0, import_react18.useState)(false);
|
|
12145
|
+
const [internalTaskDateChangeMode, setInternalTaskDateChangeMode] = (0, import_react18.useState)("preserve-duration");
|
|
12146
|
+
const [scrollViewport, setScrollViewport] = (0, import_react18.useState)({ scrollTop: 0, viewportHeight: 0 });
|
|
12147
|
+
const [planFactDateWindow, setPlanFactDateWindow] = (0, import_react18.useState)(null);
|
|
12148
|
+
const [selectedChip, setSelectedChip] = (0, import_react18.useState)(null);
|
|
12149
|
+
const [activeTimelineTooltip, setActiveTimelineTooltip] = (0, import_react18.useState)(null);
|
|
12150
|
+
const [internalCollapsedParentIds, setInternalCollapsedParentIds] = (0, import_react18.useState)(/* @__PURE__ */ new Set());
|
|
11101
12151
|
const collapsedParentIds = externalCollapsedParentIds ?? internalCollapsedParentIds;
|
|
11102
|
-
const [editingTaskId, setEditingTaskId] = (0,
|
|
12152
|
+
const [editingTaskId, setEditingTaskId] = (0, import_react18.useState)(null);
|
|
11103
12153
|
const taskDateChangeMode = externalTaskDateChangeMode ?? internalTaskDateChangeMode;
|
|
11104
12154
|
const handleTaskDateChangeMode = externalOnTaskDateChangeModeChange ?? setInternalTaskDateChangeMode;
|
|
11105
|
-
const resolvedRowContentLines = Math.max(1, Math.floor(rowContentLines));
|
|
11106
|
-
const effectiveRowHeight = (0,
|
|
12155
|
+
const resolvedRowContentLines = isPlanFactMode ? Math.max(2, Math.floor(rowContentLines)) : Math.max(1, Math.floor(rowContentLines));
|
|
12156
|
+
const effectiveRowHeight = (0, import_react18.useMemo)(
|
|
11107
12157
|
() => Math.max(rowHeight, 10 + resolvedRowContentLines * 18),
|
|
11108
12158
|
[resolvedRowContentLines, rowHeight]
|
|
11109
12159
|
);
|
|
11110
|
-
const normalizedTasks = (0,
|
|
11111
|
-
const isCustomWeekend = (0,
|
|
12160
|
+
const normalizedTasks = (0, import_react18.useMemo)(() => normalizeHierarchyTasks(tasks), [tasks]);
|
|
12161
|
+
const isCustomWeekend = (0, import_react18.useMemo)(
|
|
11112
12162
|
() => createCustomDayPredicate({ customDays, isWeekend: isWeekend3 }),
|
|
11113
12163
|
[customDays, isWeekend3]
|
|
11114
12164
|
);
|
|
11115
|
-
const dateRangeTasks = (0,
|
|
12165
|
+
const dateRangeTasks = (0, import_react18.useMemo)(() => {
|
|
12166
|
+
if (isPlanFactMode) {
|
|
12167
|
+
return getPlanFactRangeTasks(normalizedTasks);
|
|
12168
|
+
}
|
|
11116
12169
|
if (!showBaseline) {
|
|
11117
12170
|
return normalizedTasks;
|
|
11118
12171
|
}
|
|
@@ -11121,22 +12174,25 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11121
12174
|
startDate: task.baselineStartDate && parseUTCDate(task.baselineStartDate).getTime() < parseUTCDate(task.startDate).getTime() ? task.baselineStartDate : task.startDate,
|
|
11122
12175
|
endDate: task.baselineEndDate && parseUTCDate(task.baselineEndDate).getTime() > parseUTCDate(task.endDate).getTime() ? task.baselineEndDate : task.endDate
|
|
11123
12176
|
}));
|
|
11124
|
-
}, [normalizedTasks, showBaseline]);
|
|
11125
|
-
const dateRange = (0,
|
|
11126
|
-
|
|
11127
|
-
|
|
11128
|
-
|
|
12177
|
+
}, [isPlanFactMode, normalizedTasks, showBaseline]);
|
|
12178
|
+
const dateRange = (0, import_react18.useMemo)(
|
|
12179
|
+
() => isPlanFactMode ? getFullMonthDays(dateRangeTasks) : getMultiMonthDays(dateRangeTasks),
|
|
12180
|
+
[dateRangeTasks, isPlanFactMode]
|
|
12181
|
+
);
|
|
12182
|
+
const [validationResult, setValidationResult] = (0, import_react18.useState)(null);
|
|
12183
|
+
const [cascadeOverrides, setCascadeOverrides] = (0, import_react18.useState)(/* @__PURE__ */ new Map());
|
|
12184
|
+
const gridWidth = (0, import_react18.useMemo)(
|
|
11129
12185
|
() => Math.round(dateRange.length * dayWidth),
|
|
11130
12186
|
[dateRange.length, dayWidth]
|
|
11131
12187
|
);
|
|
11132
|
-
const matrixWidth = (0,
|
|
12188
|
+
const matrixWidth = (0, import_react18.useMemo)(
|
|
11133
12189
|
() => matrixColumns.reduce((sum, column) => {
|
|
11134
12190
|
if (typeof column.width !== "number") return void 0;
|
|
11135
12191
|
return sum !== void 0 ? sum + column.width : void 0;
|
|
11136
12192
|
}, 0),
|
|
11137
12193
|
[matrixColumns]
|
|
11138
12194
|
);
|
|
11139
|
-
const visibleTasks = (0,
|
|
12195
|
+
const visibleTasks = (0, import_react18.useMemo)(() => {
|
|
11140
12196
|
const parentMap = new Map(normalizedTasks.map((t) => [t.id, t.parentId]));
|
|
11141
12197
|
function isAnyAncestorCollapsed(parentId) {
|
|
11142
12198
|
let current = parentId;
|
|
@@ -11152,11 +12208,11 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11152
12208
|
}
|
|
11153
12209
|
return tasks2;
|
|
11154
12210
|
}, [normalizedTasks, collapsedParentIds, filterMode, taskFilter]);
|
|
11155
|
-
const matchedTaskIds = (0,
|
|
12211
|
+
const matchedTaskIds = (0, import_react18.useMemo)(() => {
|
|
11156
12212
|
if (!taskFilter) return /* @__PURE__ */ new Set();
|
|
11157
12213
|
return new Set(visibleTasks.filter(taskFilter).map((task) => task.id));
|
|
11158
12214
|
}, [visibleTasks, taskFilter]);
|
|
11159
|
-
const taskListHighlightedTaskIds = (0,
|
|
12215
|
+
const taskListHighlightedTaskIds = (0, import_react18.useMemo)(() => {
|
|
11160
12216
|
if (filterMode === "hide") {
|
|
11161
12217
|
return /* @__PURE__ */ new Set();
|
|
11162
12218
|
}
|
|
@@ -11167,33 +12223,34 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11167
12223
|
matchedTaskIds.forEach((taskId) => mergedHighlightedTaskIds.add(taskId));
|
|
11168
12224
|
return mergedHighlightedTaskIds;
|
|
11169
12225
|
}, [filterMode, highlightedTaskIds, matchedTaskIds]);
|
|
11170
|
-
const totalGridHeight = (0,
|
|
12226
|
+
const totalGridHeight = (0, import_react18.useMemo)(
|
|
11171
12227
|
() => visibleTasks.length * effectiveRowHeight,
|
|
11172
12228
|
[effectiveRowHeight, visibleTasks.length]
|
|
11173
12229
|
);
|
|
11174
12230
|
const timelineHeaderHeight = headerHeight + 1;
|
|
11175
|
-
const tableBodyMinHeight = (0,
|
|
11176
|
-
if (!isTableMatrixMode || containerHeight === void 0) {
|
|
12231
|
+
const tableBodyMinHeight = (0, import_react18.useMemo)(() => {
|
|
12232
|
+
if (!isTableMatrixMode && !isPlanFactMode || containerHeight === void 0) {
|
|
11177
12233
|
return void 0;
|
|
11178
12234
|
}
|
|
11179
12235
|
if (typeof containerHeight === "number") {
|
|
11180
12236
|
return Math.max(0, containerHeight - timelineHeaderHeight);
|
|
11181
12237
|
}
|
|
11182
12238
|
return `calc(${containerHeight} - ${timelineHeaderHeight}px)`;
|
|
11183
|
-
}, [containerHeight, isTableMatrixMode, timelineHeaderHeight]);
|
|
11184
|
-
const monthStart = (0,
|
|
12239
|
+
}, [containerHeight, isPlanFactMode, isTableMatrixMode, timelineHeaderHeight]);
|
|
12240
|
+
const monthStart = (0, import_react18.useMemo)(() => {
|
|
11185
12241
|
if (dateRange.length === 0) {
|
|
11186
12242
|
return new Date(Date.UTC((/* @__PURE__ */ new Date()).getUTCFullYear(), (/* @__PURE__ */ new Date()).getUTCMonth(), 1));
|
|
11187
12243
|
}
|
|
11188
12244
|
const firstDay = dateRange[0];
|
|
11189
12245
|
return new Date(Date.UTC(firstDay.getUTCFullYear(), firstDay.getUTCMonth(), 1));
|
|
11190
12246
|
}, [dateRange]);
|
|
11191
|
-
const
|
|
12247
|
+
const todayIndex = (0, import_react18.useMemo)(() => {
|
|
11192
12248
|
const now = /* @__PURE__ */ new Date();
|
|
11193
12249
|
const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
|
|
11194
|
-
return dateRange.
|
|
12250
|
+
return dateRange.findIndex((day) => day.getTime() === today.getTime());
|
|
11195
12251
|
}, [dateRange]);
|
|
11196
|
-
const
|
|
12252
|
+
const todayInRange = todayIndex !== -1;
|
|
12253
|
+
const visibleTimelineMarkers = (0, import_react18.useMemo)(() => {
|
|
11197
12254
|
if (isTableMatrixMode || !timelineMarkers || timelineMarkers.length === 0 || dateRange.length === 0) {
|
|
11198
12255
|
return [];
|
|
11199
12256
|
}
|
|
@@ -11204,22 +12261,22 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11204
12261
|
return markerDate >= rangeStartMs && markerDate <= rangeEndMs;
|
|
11205
12262
|
});
|
|
11206
12263
|
}, [dateRange, isTableMatrixMode, timelineMarkers]);
|
|
11207
|
-
(0,
|
|
12264
|
+
(0, import_react18.useEffect)(() => {
|
|
11208
12265
|
if (isTableMatrixMode) return;
|
|
11209
12266
|
if (hasAutoScrolledToTodayRef.current) return;
|
|
11210
12267
|
const container = scrollContainerRef.current;
|
|
11211
12268
|
if (!container || dateRange.length === 0) return;
|
|
11212
12269
|
const now = /* @__PURE__ */ new Date();
|
|
11213
12270
|
const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
|
|
11214
|
-
const
|
|
11215
|
-
if (
|
|
11216
|
-
const todayOffset =
|
|
12271
|
+
const todayIndex2 = dateRange.findIndex((day) => day.getTime() === today.getTime());
|
|
12272
|
+
if (todayIndex2 === -1) return;
|
|
12273
|
+
const todayOffset = todayIndex2 * dayWidth;
|
|
11217
12274
|
const containerWidth = container.clientWidth;
|
|
11218
12275
|
const scrollLeft = Math.round(todayOffset + dayWidth / 2 - containerWidth * 0.3);
|
|
11219
12276
|
container.scrollLeft = Math.max(0, scrollLeft);
|
|
11220
12277
|
hasAutoScrolledToTodayRef.current = true;
|
|
11221
12278
|
}, [dateRange, dayWidth, isTableMatrixMode]);
|
|
11222
|
-
(0,
|
|
12279
|
+
(0, import_react18.useEffect)(() => {
|
|
11223
12280
|
const container = scrollContainerRef.current;
|
|
11224
12281
|
if (!container) return;
|
|
11225
12282
|
let frameId = null;
|
|
@@ -11227,13 +12284,33 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11227
12284
|
frameId = null;
|
|
11228
12285
|
const nextHasRightShadow = container.scrollLeft > 0;
|
|
11229
12286
|
const nextViewportHeight = Math.max(0, container.clientHeight - timelineHeaderHeight);
|
|
12287
|
+
const nextViewportWidth = Math.max(0, container.clientWidth - (showTaskList ? taskListWidth : 0));
|
|
11230
12288
|
const nextScrollTop = container.scrollTop;
|
|
12289
|
+
const nextScrollLeft = container.scrollLeft;
|
|
12290
|
+
const nextChartScrollLeft = Math.max(0, nextScrollLeft);
|
|
11231
12291
|
setTaskListHasRightShadow(
|
|
11232
12292
|
(previous) => previous === nextHasRightShadow ? previous : nextHasRightShadow
|
|
11233
12293
|
);
|
|
11234
12294
|
setScrollViewport(
|
|
11235
12295
|
(previous) => previous.scrollTop === nextScrollTop && previous.viewportHeight === nextViewportHeight ? previous : { scrollTop: nextScrollTop, viewportHeight: nextViewportHeight }
|
|
11236
12296
|
);
|
|
12297
|
+
setPlanFactDateWindow((previous) => {
|
|
12298
|
+
if (!isPlanFactMode || dateRange.length === 0 || nextViewportWidth <= 0) {
|
|
12299
|
+
return previous === null ? previous : null;
|
|
12300
|
+
}
|
|
12301
|
+
const firstVisibleColumn = Math.max(0, Math.floor(nextChartScrollLeft / dayWidth));
|
|
12302
|
+
const visibleColumnCount = Math.max(1, Math.ceil(nextViewportWidth / dayWidth));
|
|
12303
|
+
const lastVisibleColumn = Math.min(dateRange.length - 1, firstVisibleColumn + visibleColumnCount - 1);
|
|
12304
|
+
const rangeStart = Math.max(
|
|
12305
|
+
0,
|
|
12306
|
+
Math.floor(Math.max(0, firstVisibleColumn - PLAN_FACT_COLUMN_OVERSCAN) / PLAN_FACT_COLUMN_WINDOW_STEP) * PLAN_FACT_COLUMN_WINDOW_STEP
|
|
12307
|
+
);
|
|
12308
|
+
const rangeEnd = Math.min(
|
|
12309
|
+
dateRange.length - 1,
|
|
12310
|
+
Math.ceil((lastVisibleColumn + PLAN_FACT_COLUMN_OVERSCAN + 1) / PLAN_FACT_COLUMN_WINDOW_STEP) * PLAN_FACT_COLUMN_WINDOW_STEP - 1
|
|
12311
|
+
);
|
|
12312
|
+
return previous?.start === rangeStart && previous.end === rangeEnd ? previous : { start: rangeStart, end: rangeEnd };
|
|
12313
|
+
});
|
|
11237
12314
|
};
|
|
11238
12315
|
const scheduleUpdate = () => {
|
|
11239
12316
|
if (frameId !== null) return;
|
|
@@ -11254,21 +12331,21 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11254
12331
|
container.removeEventListener("scroll", scheduleUpdate);
|
|
11255
12332
|
window.removeEventListener("resize", scheduleUpdate);
|
|
11256
12333
|
};
|
|
11257
|
-
}, [timelineHeaderHeight]);
|
|
11258
|
-
const scrollToToday = (0,
|
|
12334
|
+
}, [dateRange.length, dayWidth, isPlanFactMode, showTaskList, taskListWidth, timelineHeaderHeight]);
|
|
12335
|
+
const scrollToToday = (0, import_react18.useCallback)(() => {
|
|
11259
12336
|
if (isTableMatrixMode) return;
|
|
11260
12337
|
const container = scrollContainerRef.current;
|
|
11261
12338
|
if (!container || dateRange.length === 0) return;
|
|
11262
12339
|
const now = /* @__PURE__ */ new Date();
|
|
11263
12340
|
const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
|
|
11264
|
-
const
|
|
11265
|
-
if (
|
|
11266
|
-
const todayOffset =
|
|
12341
|
+
const todayIndex2 = dateRange.findIndex((day) => day.getTime() === today.getTime());
|
|
12342
|
+
if (todayIndex2 === -1) return;
|
|
12343
|
+
const todayOffset = todayIndex2 * dayWidth;
|
|
11267
12344
|
const containerWidth = container.clientWidth;
|
|
11268
12345
|
const scrollLeft = Math.round(todayOffset + dayWidth / 2 - containerWidth * 0.3);
|
|
11269
12346
|
container.scrollTo({ left: Math.max(0, scrollLeft), behavior: "smooth" });
|
|
11270
12347
|
}, [dateRange, dayWidth, isTableMatrixMode]);
|
|
11271
|
-
const scrollToTask = (0,
|
|
12348
|
+
const scrollToTask = (0, import_react18.useCallback)((taskId) => {
|
|
11272
12349
|
if (isTableMatrixMode) {
|
|
11273
12350
|
const container2 = scrollContainerRef.current;
|
|
11274
12351
|
if (!container2) return;
|
|
@@ -11295,7 +12372,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11295
12372
|
const scrollLeft = Math.round(taskOffset - dayWidth * 2);
|
|
11296
12373
|
container.scrollTo({ left: Math.max(0, scrollLeft), behavior: "smooth" });
|
|
11297
12374
|
}, [dateRange, dayWidth, effectiveRowHeight, isTableMatrixMode, tasks, visibleTasks]);
|
|
11298
|
-
const scrollToRow = (0,
|
|
12375
|
+
const scrollToRow = (0, import_react18.useCallback)((taskId, options = {}) => {
|
|
11299
12376
|
const container = scrollContainerRef.current;
|
|
11300
12377
|
if (!container) return;
|
|
11301
12378
|
const task = tasks.find((t) => t.id === taskId);
|
|
@@ -11324,21 +12401,21 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11324
12401
|
}
|
|
11325
12402
|
container.scrollTo({ top: scrollTop, behavior });
|
|
11326
12403
|
}, [effectiveRowHeight, tasks, visibleTasks]);
|
|
11327
|
-
const [dragGuideLines, setDragGuideLines] = (0,
|
|
11328
|
-
const [draggedTaskOverride, setDraggedTaskOverride] = (0,
|
|
11329
|
-
const [previewTasksById, setPreviewTasksById] = (0,
|
|
11330
|
-
(0,
|
|
12404
|
+
const [dragGuideLines, setDragGuideLines] = (0, import_react18.useState)(null);
|
|
12405
|
+
const [draggedTaskOverride, setDraggedTaskOverride] = (0, import_react18.useState)(null);
|
|
12406
|
+
const [previewTasksById, setPreviewTasksById] = (0, import_react18.useState)(/* @__PURE__ */ new Map());
|
|
12407
|
+
(0, import_react18.useEffect)(() => {
|
|
11331
12408
|
const result = validateDependencies(tasks);
|
|
11332
12409
|
setValidationResult(result);
|
|
11333
12410
|
onValidateDependencies?.(result);
|
|
11334
12411
|
}, [tasks, onValidateDependencies]);
|
|
11335
|
-
(0,
|
|
12412
|
+
(0, import_react18.useEffect)(() => () => {
|
|
11336
12413
|
if (clearSelectedTaskTimeoutRef.current !== null) {
|
|
11337
12414
|
window.clearTimeout(clearSelectedTaskTimeoutRef.current);
|
|
11338
12415
|
}
|
|
11339
12416
|
previewPositionStore.clear();
|
|
11340
12417
|
}, [previewPositionStore]);
|
|
11341
|
-
const handleTaskChange = (0,
|
|
12418
|
+
const handleTaskChange = (0, import_react18.useCallback)((updatedTasks) => {
|
|
11342
12419
|
const updatedTask = updatedTasks[0];
|
|
11343
12420
|
if (!updatedTask) return;
|
|
11344
12421
|
const originalTask = tasks.find((t) => t.id === updatedTask.id);
|
|
@@ -11384,7 +12461,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11384
12461
|
const cascadedTasks = disableConstraints ? [updatedTask] : universalCascade(updatedTask, newStart, newEnd, sourceTasks, businessDays, isCustomWeekend);
|
|
11385
12462
|
onTasksChange?.(cascadedTasks);
|
|
11386
12463
|
}, [tasks, onTasksChange, disableConstraints, editingTaskId, businessDays, isCustomWeekend]);
|
|
11387
|
-
const handleDelete = (0,
|
|
12464
|
+
const handleDelete = (0, import_react18.useCallback)((taskId) => {
|
|
11388
12465
|
const toDelete = /* @__PURE__ */ new Set([taskId]);
|
|
11389
12466
|
function collectDescendants(parentId) {
|
|
11390
12467
|
const children = getChildren(parentId, tasks);
|
|
@@ -11409,10 +12486,10 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11409
12486
|
}
|
|
11410
12487
|
toDelete.forEach((id) => onDelete?.(id));
|
|
11411
12488
|
}, [tasks, onTasksChange, onDelete]);
|
|
11412
|
-
const handleInsertAfter = (0,
|
|
12489
|
+
const handleInsertAfter = (0, import_react18.useCallback)((taskId, newTask) => {
|
|
11413
12490
|
onInsertAfter?.(taskId, newTask);
|
|
11414
12491
|
}, [onInsertAfter]);
|
|
11415
|
-
const handleReorder = (0,
|
|
12492
|
+
const handleReorder = (0, import_react18.useCallback)((reorderedTasks, movedTaskId, inferredParentId) => {
|
|
11416
12493
|
let updated = reorderedTasks;
|
|
11417
12494
|
if (movedTaskId) {
|
|
11418
12495
|
updated = updated.map((t) => {
|
|
@@ -11429,7 +12506,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11429
12506
|
}
|
|
11430
12507
|
onTasksChange?.(normalized);
|
|
11431
12508
|
}, [onTasksChange, onReorder]);
|
|
11432
|
-
const dependencyOverrides = (0,
|
|
12509
|
+
const dependencyOverrides = (0, import_react18.useMemo)(() => {
|
|
11433
12510
|
const map = new Map(cascadeOverrides);
|
|
11434
12511
|
if (draggedTaskOverride) {
|
|
11435
12512
|
map.set(draggedTaskOverride.taskId, {
|
|
@@ -11439,7 +12516,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11439
12516
|
}
|
|
11440
12517
|
return map;
|
|
11441
12518
|
}, [cascadeOverrides, draggedTaskOverride]);
|
|
11442
|
-
const handleCascadeProgress = (0,
|
|
12519
|
+
const handleCascadeProgress = (0, import_react18.useCallback)((overrides, previewTasks = []) => {
|
|
11443
12520
|
previewPositionStore.setPositions(overrides);
|
|
11444
12521
|
const renderedTaskIds = renderedTaskIdsRef.current;
|
|
11445
12522
|
const renderedOverrides = /* @__PURE__ */ new Map();
|
|
@@ -11454,26 +12531,26 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11454
12531
|
return arePreviewTaskMapsEqual(current, next) ? current : next;
|
|
11455
12532
|
});
|
|
11456
12533
|
}, [previewPositionStore]);
|
|
11457
|
-
const previewNormalizedTasks = (0,
|
|
12534
|
+
const previewNormalizedTasks = (0, import_react18.useMemo)(() => {
|
|
11458
12535
|
if (previewTasksById.size === 0) return normalizedTasks;
|
|
11459
12536
|
return normalizedTasks.map((task) => previewTasksById.get(task.id) ?? task);
|
|
11460
12537
|
}, [normalizedTasks, previewTasksById]);
|
|
11461
|
-
const previewVisibleTasks = (0,
|
|
12538
|
+
const previewVisibleTasks = (0, import_react18.useMemo)(() => {
|
|
11462
12539
|
if (previewTasksById.size === 0) return visibleTasks;
|
|
11463
12540
|
return visibleTasks.map((task) => previewTasksById.get(task.id) ?? task);
|
|
11464
12541
|
}, [visibleTasks, previewTasksById]);
|
|
11465
|
-
const visibleTaskIndexMap = (0,
|
|
12542
|
+
const visibleTaskIndexMap = (0, import_react18.useMemo)(
|
|
11466
12543
|
() => new Map(visibleTasks.map((task, index) => [task.id, index])),
|
|
11467
12544
|
[visibleTasks]
|
|
11468
12545
|
);
|
|
11469
|
-
const forcedRenderedTaskIds = (0,
|
|
12546
|
+
const forcedRenderedTaskIds = (0, import_react18.useMemo)(() => {
|
|
11470
12547
|
const ids = /* @__PURE__ */ new Set();
|
|
11471
12548
|
if (draggedTaskOverride) {
|
|
11472
12549
|
ids.add(draggedTaskOverride.taskId);
|
|
11473
12550
|
}
|
|
11474
12551
|
return ids;
|
|
11475
12552
|
}, [draggedTaskOverride]);
|
|
11476
|
-
const visibleTaskWindowIndices = (0,
|
|
12553
|
+
const visibleTaskWindowIndices = (0, import_react18.useMemo)(() => {
|
|
11477
12554
|
const totalTasks = visibleTasks.length;
|
|
11478
12555
|
if (totalTasks === 0) {
|
|
11479
12556
|
return [];
|
|
@@ -11499,35 +12576,44 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11499
12576
|
}
|
|
11500
12577
|
return Array.from(indices).sort((left, right) => left - right);
|
|
11501
12578
|
}, [effectiveRowHeight, forcedRenderedTaskIds, scrollViewport, visibleTaskIndexMap, visibleTasks.length]);
|
|
11502
|
-
const
|
|
12579
|
+
const visiblePlanFactDateIndices = (0, import_react18.useMemo)(() => {
|
|
12580
|
+
if (!isPlanFactMode || dateRange.length === 0 || !planFactDateWindow) {
|
|
12581
|
+
return void 0;
|
|
12582
|
+
}
|
|
12583
|
+
return Array.from(
|
|
12584
|
+
{ length: planFactDateWindow.end - planFactDateWindow.start + 1 },
|
|
12585
|
+
(_, index) => planFactDateWindow.start + index
|
|
12586
|
+
);
|
|
12587
|
+
}, [dateRange.length, isPlanFactMode, planFactDateWindow]);
|
|
12588
|
+
const renderedChartTasks = (0, import_react18.useMemo)(
|
|
11503
12589
|
() => visibleTaskWindowIndices.map((index) => {
|
|
11504
12590
|
const task = previewVisibleTasks[index];
|
|
11505
12591
|
return task ? { index, task } : null;
|
|
11506
12592
|
}).filter((entry) => entry !== null),
|
|
11507
12593
|
[previewVisibleTasks, visibleTaskWindowIndices]
|
|
11508
12594
|
);
|
|
11509
|
-
const renderedDependencyTasks = (0,
|
|
12595
|
+
const renderedDependencyTasks = (0, import_react18.useMemo)(
|
|
11510
12596
|
() => renderedChartTasks.map(({ task }) => task),
|
|
11511
12597
|
[renderedChartTasks]
|
|
11512
12598
|
);
|
|
11513
|
-
renderedTaskIdsRef.current = (0,
|
|
12599
|
+
renderedTaskIdsRef.current = (0, import_react18.useMemo)(
|
|
11514
12600
|
() => new Set(renderedChartTasks.map(({ task }) => task.id)),
|
|
11515
12601
|
[renderedChartTasks]
|
|
11516
12602
|
);
|
|
11517
|
-
const handleCascade = (0,
|
|
12603
|
+
const handleCascade = (0, import_react18.useCallback)((cascadedTasks) => {
|
|
11518
12604
|
onTasksChange?.(cascadedTasks);
|
|
11519
12605
|
}, [tasks, onTasksChange]);
|
|
11520
|
-
const handleTaskSelect = (0,
|
|
12606
|
+
const handleTaskSelect = (0, import_react18.useCallback)((taskId) => {
|
|
11521
12607
|
setSelectedTaskId(taskId);
|
|
11522
12608
|
}, []);
|
|
11523
|
-
const hoveredRowElementsRef = (0,
|
|
11524
|
-
const clearHoveredRows = (0,
|
|
12609
|
+
const hoveredRowElementsRef = (0, import_react18.useRef)([]);
|
|
12610
|
+
const clearHoveredRows = (0, import_react18.useCallback)(() => {
|
|
11525
12611
|
for (const element of hoveredRowElementsRef.current) {
|
|
11526
|
-
element.classList.remove("gantt-tl-row-hovered", "gantt-tr-row-hovered", "gantt-mx-row-hovered");
|
|
12612
|
+
element.classList.remove("gantt-tl-row-hovered", "gantt-tr-row-hovered", "gantt-mx-row-hovered", "gantt-pf-row-hovered");
|
|
11527
12613
|
}
|
|
11528
12614
|
hoveredRowElementsRef.current = [];
|
|
11529
12615
|
}, []);
|
|
11530
|
-
const applyHoveredRows = (0,
|
|
12616
|
+
const applyHoveredRows = (0, import_react18.useCallback)((taskId) => {
|
|
11531
12617
|
const root = scrollContentRef.current;
|
|
11532
12618
|
if (!root) return;
|
|
11533
12619
|
clearHoveredRows();
|
|
@@ -11544,10 +12630,13 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11544
12630
|
if (element.classList.contains("gantt-mx-row")) {
|
|
11545
12631
|
element.classList.add("gantt-mx-row-hovered");
|
|
11546
12632
|
}
|
|
12633
|
+
if (element.classList.contains("gantt-pf-row")) {
|
|
12634
|
+
element.classList.add("gantt-pf-row-hovered");
|
|
12635
|
+
}
|
|
11547
12636
|
}
|
|
11548
12637
|
hoveredRowElementsRef.current = nextHoveredRows;
|
|
11549
12638
|
}, [clearHoveredRows]);
|
|
11550
|
-
const handleSharedRowHover = (0,
|
|
12639
|
+
const handleSharedRowHover = (0, import_react18.useCallback)((event) => {
|
|
11551
12640
|
const target = event.target;
|
|
11552
12641
|
const row = target.closest("[data-gantt-task-row-id]");
|
|
11553
12642
|
const taskId = row?.dataset.ganttTaskRowId;
|
|
@@ -11557,7 +12646,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11557
12646
|
}
|
|
11558
12647
|
applyHoveredRows(taskId);
|
|
11559
12648
|
}, [applyHoveredRows]);
|
|
11560
|
-
const handleToggleCollapse = externalOnToggleCollapse ?? (0,
|
|
12649
|
+
const handleToggleCollapse = externalOnToggleCollapse ?? (0, import_react18.useCallback)((parentId) => {
|
|
11561
12650
|
setInternalCollapsedParentIds((prev) => {
|
|
11562
12651
|
const next = new Set(prev);
|
|
11563
12652
|
if (next.has(parentId)) {
|
|
@@ -11568,20 +12657,20 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11568
12657
|
return next;
|
|
11569
12658
|
});
|
|
11570
12659
|
}, []);
|
|
11571
|
-
const allParentIds = (0,
|
|
12660
|
+
const allParentIds = (0, import_react18.useMemo)(() => {
|
|
11572
12661
|
return new Set(
|
|
11573
12662
|
normalizedTasks.filter((t) => isTaskParent(t.id, normalizedTasks)).map((t) => t.id)
|
|
11574
12663
|
);
|
|
11575
12664
|
}, [normalizedTasks]);
|
|
11576
|
-
const handleCollapseAll = (0,
|
|
12665
|
+
const handleCollapseAll = (0, import_react18.useCallback)(() => {
|
|
11577
12666
|
if (externalCollapsedParentIds) return;
|
|
11578
12667
|
setInternalCollapsedParentIds(allParentIds);
|
|
11579
12668
|
}, [allParentIds, externalCollapsedParentIds]);
|
|
11580
|
-
const handleExpandAll = (0,
|
|
12669
|
+
const handleExpandAll = (0, import_react18.useCallback)(() => {
|
|
11581
12670
|
if (externalCollapsedParentIds) return;
|
|
11582
12671
|
setInternalCollapsedParentIds(/* @__PURE__ */ new Set());
|
|
11583
12672
|
}, [externalCollapsedParentIds]);
|
|
11584
|
-
const exportToPdf = (0,
|
|
12673
|
+
const exportToPdf = (0, import_react18.useCallback)(async (options) => {
|
|
11585
12674
|
const sourceContainer = containerRef.current;
|
|
11586
12675
|
const sourceContent = scrollContentRef.current;
|
|
11587
12676
|
if (!sourceContainer || !sourceContent || typeof window === "undefined" || typeof document === "undefined") {
|
|
@@ -11617,7 +12706,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11617
12706
|
orientation: options?.orientation
|
|
11618
12707
|
});
|
|
11619
12708
|
}, [showTaskList, showChart]);
|
|
11620
|
-
(0,
|
|
12709
|
+
(0, import_react18.useImperativeHandle)(
|
|
11621
12710
|
ref,
|
|
11622
12711
|
() => ({
|
|
11623
12712
|
scrollToToday,
|
|
@@ -11640,7 +12729,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11640
12729
|
}
|
|
11641
12730
|
return depth;
|
|
11642
12731
|
}
|
|
11643
|
-
const handlePromoteTask = (0,
|
|
12732
|
+
const handlePromoteTask = (0, import_react18.useCallback)((taskId) => {
|
|
11644
12733
|
if (onPromoteTask) {
|
|
11645
12734
|
onPromoteTask(taskId);
|
|
11646
12735
|
return;
|
|
@@ -11672,7 +12761,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11672
12761
|
]);
|
|
11673
12762
|
onTasksChange?.(reorderedTasks);
|
|
11674
12763
|
}, [tasks, onTasksChange, onPromoteTask]);
|
|
11675
|
-
const handleDemoteTask = (0,
|
|
12764
|
+
const handleDemoteTask = (0, import_react18.useCallback)((taskId, newParentId) => {
|
|
11676
12765
|
if (onDemoteTask) {
|
|
11677
12766
|
onDemoteTask(taskId, newParentId);
|
|
11678
12767
|
return;
|
|
@@ -11713,7 +12802,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11713
12802
|
};
|
|
11714
12803
|
onTasksChange?.([updatedDemotedTask]);
|
|
11715
12804
|
}, [tasks, onTasksChange, onDemoteTask]);
|
|
11716
|
-
const handleUngroupTask = (0,
|
|
12805
|
+
const handleUngroupTask = (0, import_react18.useCallback)((taskId) => {
|
|
11717
12806
|
if (onUngroupTask) {
|
|
11718
12807
|
onUngroupTask(taskId);
|
|
11719
12808
|
return;
|
|
@@ -11738,8 +12827,8 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11738
12827
|
onTasksChange?.(changedTasks);
|
|
11739
12828
|
}
|
|
11740
12829
|
}, [tasks, onTasksChange, onUngroupTask]);
|
|
11741
|
-
const panStateRef = (0,
|
|
11742
|
-
const handlePanStart = (0,
|
|
12830
|
+
const panStateRef = (0, import_react18.useRef)(null);
|
|
12831
|
+
const handlePanStart = (0, import_react18.useCallback)((e) => {
|
|
11743
12832
|
if (e.button !== 0) return;
|
|
11744
12833
|
const target = e.target;
|
|
11745
12834
|
if (target.closest("[data-taskbar]")) return;
|
|
@@ -11752,7 +12841,10 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11752
12841
|
startX: e.clientX,
|
|
11753
12842
|
startY: e.clientY,
|
|
11754
12843
|
scrollX: container.scrollLeft,
|
|
11755
|
-
scrollY: container.scrollTop
|
|
12844
|
+
scrollY: container.scrollTop,
|
|
12845
|
+
currentX: e.clientX,
|
|
12846
|
+
currentY: e.clientY,
|
|
12847
|
+
frameId: null
|
|
11756
12848
|
};
|
|
11757
12849
|
if (document.activeElement instanceof HTMLElement) {
|
|
11758
12850
|
document.activeElement.blur();
|
|
@@ -11760,17 +12852,38 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11760
12852
|
container.style.cursor = "grabbing";
|
|
11761
12853
|
e.preventDefault();
|
|
11762
12854
|
}, []);
|
|
11763
|
-
(0,
|
|
11764
|
-
const
|
|
12855
|
+
(0, import_react18.useEffect)(() => {
|
|
12856
|
+
const flushPanMove = () => {
|
|
11765
12857
|
const pan = panStateRef.current;
|
|
11766
12858
|
if (!pan?.active) return;
|
|
12859
|
+
pan.frameId = null;
|
|
11767
12860
|
const container = scrollContainerRef.current;
|
|
11768
12861
|
if (!container) return;
|
|
11769
|
-
|
|
11770
|
-
|
|
12862
|
+
const maxScrollLeft = Math.max(0, container.scrollWidth - container.clientWidth);
|
|
12863
|
+
const maxScrollTop = Math.max(0, container.scrollHeight - container.clientHeight);
|
|
12864
|
+
const nextScrollLeft = clampScrollValue(pan.scrollX - (pan.currentX - pan.startX), maxScrollLeft);
|
|
12865
|
+
const nextScrollTop = clampScrollValue(pan.scrollY - (pan.currentY - pan.startY), maxScrollTop);
|
|
12866
|
+
if (Math.abs(container.scrollLeft - nextScrollLeft) > 0.5) {
|
|
12867
|
+
container.scrollLeft = nextScrollLeft;
|
|
12868
|
+
}
|
|
12869
|
+
if (Math.abs(container.scrollTop - nextScrollTop) > 0.5) {
|
|
12870
|
+
container.scrollTop = nextScrollTop;
|
|
12871
|
+
}
|
|
12872
|
+
};
|
|
12873
|
+
const handlePanMove = (e) => {
|
|
12874
|
+
const pan = panStateRef.current;
|
|
12875
|
+
if (!pan?.active) return;
|
|
12876
|
+
pan.currentX = e.clientX;
|
|
12877
|
+
pan.currentY = e.clientY;
|
|
12878
|
+
if (pan.frameId !== null) return;
|
|
12879
|
+
pan.frameId = window.requestAnimationFrame(flushPanMove);
|
|
11771
12880
|
};
|
|
11772
12881
|
const handlePanEnd = () => {
|
|
11773
|
-
|
|
12882
|
+
const pan = panStateRef.current;
|
|
12883
|
+
if (!pan?.active) return;
|
|
12884
|
+
if (pan.frameId !== null) {
|
|
12885
|
+
window.cancelAnimationFrame(pan.frameId);
|
|
12886
|
+
}
|
|
11774
12887
|
panStateRef.current = null;
|
|
11775
12888
|
const container = scrollContainerRef.current;
|
|
11776
12889
|
if (container) container.style.cursor = "";
|
|
@@ -11782,19 +12895,19 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11782
12895
|
window.removeEventListener("mouseup", handlePanEnd);
|
|
11783
12896
|
};
|
|
11784
12897
|
}, []);
|
|
11785
|
-
return /* @__PURE__ */ (0,
|
|
12898
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
11786
12899
|
"div",
|
|
11787
12900
|
{
|
|
11788
12901
|
ref: containerRef,
|
|
11789
|
-
className: isTableMatrixMode ? "gantt-container gantt-container-tableMatrix" : "gantt-container",
|
|
11790
|
-
children: /* @__PURE__ */ (0,
|
|
12902
|
+
className: isTableMatrixMode ? "gantt-container gantt-container-tableMatrix" : isPlanFactMode ? "gantt-container gantt-container-planFact" : "gantt-container",
|
|
12903
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
11791
12904
|
"div",
|
|
11792
12905
|
{
|
|
11793
12906
|
ref: scrollContainerRef,
|
|
11794
12907
|
className: "gantt-scrollContainer",
|
|
11795
12908
|
style: { height: containerHeight ?? "auto", cursor: "grab" },
|
|
11796
12909
|
onMouseDown: handlePanStart,
|
|
11797
|
-
children: /* @__PURE__ */ (0,
|
|
12910
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
11798
12911
|
"div",
|
|
11799
12912
|
{
|
|
11800
12913
|
ref: scrollContentRef,
|
|
@@ -11802,7 +12915,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11802
12915
|
onMouseOver: handleSharedRowHover,
|
|
11803
12916
|
onMouseLeave: clearHoveredRows,
|
|
11804
12917
|
children: [
|
|
11805
|
-
/* @__PURE__ */ (0,
|
|
12918
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
11806
12919
|
TaskList,
|
|
11807
12920
|
{
|
|
11808
12921
|
tasks: normalizedTasks,
|
|
@@ -11855,17 +12968,17 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11855
12968
|
visibleRowIndices: visibleTaskWindowIndices
|
|
11856
12969
|
}
|
|
11857
12970
|
),
|
|
11858
|
-
/* @__PURE__ */ (0,
|
|
12971
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
11859
12972
|
"div",
|
|
11860
12973
|
{
|
|
11861
|
-
className: isTableMatrixMode || showChart ? "gantt-chartSurface" : "gantt-chartSurface gantt-chart-hidden",
|
|
12974
|
+
className: isTableMatrixMode || isPlanFactMode || showChart ? "gantt-chartSurface" : "gantt-chartSurface gantt-chart-hidden",
|
|
11862
12975
|
style: {
|
|
11863
|
-
minWidth: isTableMatrixMode ? matrixWidth !== void 0 ? `${matrixWidth}px` : void 0 : `${gridWidth}px`,
|
|
11864
|
-
width: isTableMatrixMode ? matrixWidth !== void 0 ? `${matrixWidth}px` : "max-content" : void 0,
|
|
11865
|
-
flex: isTableMatrixMode ? "0 0 auto" : 1,
|
|
11866
|
-
display: isTableMatrixMode || showChart ? void 0 : "none"
|
|
12976
|
+
minWidth: isTableMatrixMode ? matrixWidth !== void 0 ? `${matrixWidth}px` : void 0 : isPlanFactMode ? `${gridWidth}px` : `${gridWidth}px`,
|
|
12977
|
+
width: isTableMatrixMode ? matrixWidth !== void 0 ? `${matrixWidth}px` : "max-content" : isPlanFactMode ? `${gridWidth}px` : void 0,
|
|
12978
|
+
flex: isTableMatrixMode || isPlanFactMode ? "0 0 auto" : 1,
|
|
12979
|
+
display: isTableMatrixMode || isPlanFactMode || showChart ? void 0 : "none"
|
|
11867
12980
|
},
|
|
11868
|
-
children: isTableMatrixMode ? /* @__PURE__ */ (0,
|
|
12981
|
+
children: isTableMatrixMode ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
11869
12982
|
TableMatrix,
|
|
11870
12983
|
{
|
|
11871
12984
|
tasks: visibleTasks,
|
|
@@ -11882,14 +12995,34 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11882
12995
|
highlightedTaskIds: taskListHighlightedTaskIds,
|
|
11883
12996
|
filterMode
|
|
11884
12997
|
}
|
|
11885
|
-
) : /* @__PURE__ */ (0,
|
|
11886
|
-
|
|
12998
|
+
) : isPlanFactMode ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
12999
|
+
PlanFactMatrix,
|
|
13000
|
+
{
|
|
13001
|
+
tasks: visibleTasks,
|
|
13002
|
+
allTasks: normalizedTasks,
|
|
13003
|
+
dateRange,
|
|
13004
|
+
dayWidth,
|
|
13005
|
+
rowHeight: effectiveRowHeight,
|
|
13006
|
+
headerHeight: timelineHeaderHeight,
|
|
13007
|
+
bodyMinHeight: tableBodyMinHeight,
|
|
13008
|
+
selectedTaskId,
|
|
13009
|
+
onTaskSelect: handleTaskSelect,
|
|
13010
|
+
onTasksChange: handleTaskChange,
|
|
13011
|
+
onCellCommit: onPlanFactCellCommit,
|
|
13012
|
+
highlightedTaskIds: taskListHighlightedTaskIds,
|
|
13013
|
+
filterMode,
|
|
13014
|
+
visibleRowIndices: visibleTaskWindowIndices,
|
|
13015
|
+
visibleDateIndices: visiblePlanFactDateIndices,
|
|
13016
|
+
todayDateIndex: todayInRange ? todayIndex : void 0
|
|
13017
|
+
}
|
|
13018
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
|
|
13019
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
11887
13020
|
"div",
|
|
11888
13021
|
{
|
|
11889
13022
|
className: "gantt-stickyHeader",
|
|
11890
13023
|
style: { width: `${gridWidth}px`, height: `${timelineHeaderHeight}px` },
|
|
11891
13024
|
children: [
|
|
11892
|
-
/* @__PURE__ */ (0,
|
|
13025
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
11893
13026
|
TimeScaleHeader_default,
|
|
11894
13027
|
{
|
|
11895
13028
|
days: dateRange,
|
|
@@ -11902,7 +13035,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11902
13035
|
onTimelineHoverEnd: () => setActiveTimelineTooltip(null)
|
|
11903
13036
|
}
|
|
11904
13037
|
),
|
|
11905
|
-
activeTimelineTooltip && /* @__PURE__ */ (0,
|
|
13038
|
+
activeTimelineTooltip && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "gantt-timelineTooltipLayer", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
11906
13039
|
"div",
|
|
11907
13040
|
{
|
|
11908
13041
|
className: "gantt-timelineTooltip",
|
|
@@ -11916,7 +13049,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11916
13049
|
]
|
|
11917
13050
|
}
|
|
11918
13051
|
),
|
|
11919
|
-
/* @__PURE__ */ (0,
|
|
13052
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
11920
13053
|
"div",
|
|
11921
13054
|
{
|
|
11922
13055
|
className: "gantt-taskArea",
|
|
@@ -11926,7 +13059,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11926
13059
|
height: `${totalGridHeight}px`
|
|
11927
13060
|
},
|
|
11928
13061
|
children: [
|
|
11929
|
-
/* @__PURE__ */ (0,
|
|
13062
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
11930
13063
|
GridBackground_default,
|
|
11931
13064
|
{
|
|
11932
13065
|
dateRange,
|
|
@@ -11936,7 +13069,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11936
13069
|
isCustomWeekend
|
|
11937
13070
|
}
|
|
11938
13071
|
),
|
|
11939
|
-
todayInRange && /* @__PURE__ */ (0,
|
|
13072
|
+
todayInRange && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
11940
13073
|
TodayIndicator_default,
|
|
11941
13074
|
{
|
|
11942
13075
|
monthStart,
|
|
@@ -11945,7 +13078,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11945
13078
|
onHoverEnd: () => setActiveTimelineTooltip(null)
|
|
11946
13079
|
}
|
|
11947
13080
|
),
|
|
11948
|
-
visibleTimelineMarkers.length > 0 && /* @__PURE__ */ (0,
|
|
13081
|
+
visibleTimelineMarkers.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
11949
13082
|
TimelineMarkers_default,
|
|
11950
13083
|
{
|
|
11951
13084
|
rangeStart: monthStart,
|
|
@@ -11956,7 +13089,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11956
13089
|
onHoverEnd: () => setActiveTimelineTooltip(null)
|
|
11957
13090
|
}
|
|
11958
13091
|
),
|
|
11959
|
-
/* @__PURE__ */ (0,
|
|
13092
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
11960
13093
|
DependencyLines_default,
|
|
11961
13094
|
{
|
|
11962
13095
|
tasks: renderedDependencyTasks,
|
|
@@ -11974,7 +13107,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11974
13107
|
weekendPredicate: isCustomWeekend
|
|
11975
13108
|
}
|
|
11976
13109
|
),
|
|
11977
|
-
dragGuideLines && /* @__PURE__ */ (0,
|
|
13110
|
+
dragGuideLines && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
11978
13111
|
DragGuideLines_default,
|
|
11979
13112
|
{
|
|
11980
13113
|
isDragging: dragGuideLines.isDragging,
|
|
@@ -11984,7 +13117,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11984
13117
|
totalHeight: totalGridHeight
|
|
11985
13118
|
}
|
|
11986
13119
|
),
|
|
11987
|
-
renderedChartTasks.map(({ task, index }) => /* @__PURE__ */ (0,
|
|
13120
|
+
renderedChartTasks.map(({ task, index }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
11988
13121
|
"div",
|
|
11989
13122
|
{
|
|
11990
13123
|
style: {
|
|
@@ -11994,7 +13127,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11994
13127
|
right: 0,
|
|
11995
13128
|
height: `${effectiveRowHeight}px`
|
|
11996
13129
|
},
|
|
11997
|
-
children: /* @__PURE__ */ (0,
|
|
13130
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
11998
13131
|
TaskRow_default,
|
|
11999
13132
|
{
|
|
12000
13133
|
task,
|
|
@@ -12045,14 +13178,14 @@ function TaskGanttChartInner(props, ref) {
|
|
|
12045
13178
|
}
|
|
12046
13179
|
);
|
|
12047
13180
|
}
|
|
12048
|
-
var TaskGanttChart = (0,
|
|
12049
|
-
var GanttChart = (0,
|
|
13181
|
+
var TaskGanttChart = (0, import_react18.forwardRef)(TaskGanttChartInner);
|
|
13182
|
+
var GanttChart = (0, import_react18.forwardRef)(GanttChartInner);
|
|
12050
13183
|
GanttChart.displayName = "GanttChart";
|
|
12051
13184
|
|
|
12052
13185
|
// src/components/ui/Button.tsx
|
|
12053
|
-
var
|
|
12054
|
-
var
|
|
12055
|
-
var Button =
|
|
13186
|
+
var import_react19 = __toESM(require("react"));
|
|
13187
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
13188
|
+
var Button = import_react19.default.forwardRef(
|
|
12056
13189
|
({ className, variant = "default", size = "default", children, ...props }, ref) => {
|
|
12057
13190
|
const classes = [
|
|
12058
13191
|
"gantt-btn",
|
|
@@ -12060,7 +13193,7 @@ var Button = import_react18.default.forwardRef(
|
|
|
12060
13193
|
size !== "default" ? `gantt-btn-${size}` : "",
|
|
12061
13194
|
className || ""
|
|
12062
13195
|
].filter(Boolean).join(" ");
|
|
12063
|
-
return /* @__PURE__ */ (0,
|
|
13196
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { ref, className: classes, ...props, children });
|
|
12064
13197
|
}
|
|
12065
13198
|
);
|
|
12066
13199
|
Button.displayName = "Button";
|
|
@@ -12108,6 +13241,7 @@ var nameContains = (substring, caseSensitive = false) => (task) => {
|
|
|
12108
13241
|
GanttChart,
|
|
12109
13242
|
GridBackground,
|
|
12110
13243
|
Input,
|
|
13244
|
+
PlanFactMatrix,
|
|
12111
13245
|
Popover,
|
|
12112
13246
|
PopoverContent,
|
|
12113
13247
|
PopoverTrigger,
|