gantt-lib 0.112.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/index.css.map +1 -1
- package/dist/index.d.mts +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +629 -337
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +629 -337
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +71 -14
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -557,10 +557,10 @@ function buildTaskRangeFromStart(startDate, duration, businessDays = false, week
|
|
|
557
557
|
end: parseDateOnly(addBusinessDays(normalizedStart, duration, weekendPredicate))
|
|
558
558
|
};
|
|
559
559
|
}
|
|
560
|
-
const
|
|
560
|
+
const DAY_MS6 = 24 * 60 * 60 * 1e3;
|
|
561
561
|
return {
|
|
562
562
|
start: normalizedStart,
|
|
563
|
-
end: new Date(normalizedStart.getTime() + (Math.max(1, duration) - 1) *
|
|
563
|
+
end: new Date(normalizedStart.getTime() + (Math.max(1, duration) - 1) * DAY_MS6)
|
|
564
564
|
};
|
|
565
565
|
}
|
|
566
566
|
function buildTaskRangeFromEnd(endDate, duration, businessDays = false, weekendPredicate, snapDirection = -1) {
|
|
@@ -571,9 +571,9 @@ function buildTaskRangeFromEnd(endDate, duration, businessDays = false, weekendP
|
|
|
571
571
|
end: normalizedEnd
|
|
572
572
|
};
|
|
573
573
|
}
|
|
574
|
-
const
|
|
574
|
+
const DAY_MS6 = 24 * 60 * 60 * 1e3;
|
|
575
575
|
return {
|
|
576
|
-
start: new Date(normalizedEnd.getTime() - (Math.max(1, duration) - 1) *
|
|
576
|
+
start: new Date(normalizedEnd.getTime() - (Math.max(1, duration) - 1) * DAY_MS6),
|
|
577
577
|
end: normalizedEnd
|
|
578
578
|
};
|
|
579
579
|
}
|
|
@@ -988,13 +988,13 @@ function computeParentProgress(parentId, tasks) {
|
|
|
988
988
|
if (children.length === 0) {
|
|
989
989
|
return 0;
|
|
990
990
|
}
|
|
991
|
-
const
|
|
991
|
+
const DAY_MS6 = 24 * 60 * 60 * 1e3;
|
|
992
992
|
let totalWeight = 0;
|
|
993
993
|
let weightedSum = 0;
|
|
994
994
|
for (const child of children) {
|
|
995
995
|
const start = new Date(child.startDate).getTime();
|
|
996
996
|
const end = new Date(child.endDate).getTime();
|
|
997
|
-
const duration = (end - start +
|
|
997
|
+
const duration = (end - start + DAY_MS6) / DAY_MS6;
|
|
998
998
|
const progress = child.progress ?? 0;
|
|
999
999
|
totalWeight += duration;
|
|
1000
1000
|
weightedSum += duration * progress;
|
|
@@ -10448,8 +10448,9 @@ function TableMatrix({
|
|
|
10448
10448
|
}
|
|
10449
10449
|
|
|
10450
10450
|
// src/components/PlanFactMatrix/PlanFactMatrix.tsx
|
|
10451
|
-
import { useCallback as useCallback9, useEffect as useEffect9, useMemo as useMemo12, useRef as useRef10, useState as useState10 } from "react";
|
|
10451
|
+
import React15, { useCallback as useCallback9, useEffect as useEffect9, useMemo as useMemo12, useRef as useRef10, useState as useState10 } from "react";
|
|
10452
10452
|
import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
10453
|
+
var DAY_MS5 = 24 * 60 * 60 * 1e3;
|
|
10453
10454
|
function joinClasses2(...values) {
|
|
10454
10455
|
return values.filter(Boolean).join(" ");
|
|
10455
10456
|
}
|
|
@@ -10472,13 +10473,25 @@ function parseNumberInput(value) {
|
|
|
10472
10473
|
}
|
|
10473
10474
|
return parsed;
|
|
10474
10475
|
}
|
|
10475
|
-
function
|
|
10476
|
+
function getDateOnlyMs(date) {
|
|
10477
|
+
return Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate());
|
|
10478
|
+
}
|
|
10479
|
+
function getPlannedIndexRange(task, rangeStartMs, rangeLength) {
|
|
10480
|
+
if (rangeLength <= 0) return null;
|
|
10476
10481
|
const start = parseUTCDate(task.startDate);
|
|
10477
10482
|
const end = parseUTCDate(task.endDate);
|
|
10478
|
-
const
|
|
10479
|
-
const
|
|
10480
|
-
const
|
|
10481
|
-
|
|
10483
|
+
const startIndex = Math.ceil((getDateOnlyMs(start) - rangeStartMs) / DAY_MS5);
|
|
10484
|
+
const endIndex = Math.floor((getDateOnlyMs(end) - rangeStartMs) / DAY_MS5);
|
|
10485
|
+
const clampedStartIndex = Math.max(0, startIndex);
|
|
10486
|
+
const clampedEndIndex = Math.min(rangeLength - 1, endIndex);
|
|
10487
|
+
if (clampedStartIndex > clampedEndIndex) return null;
|
|
10488
|
+
return {
|
|
10489
|
+
startIndex: clampedStartIndex,
|
|
10490
|
+
endIndex: clampedEndIndex
|
|
10491
|
+
};
|
|
10492
|
+
}
|
|
10493
|
+
function isDateIndexWithinPlannedRange(dateIndex, range) {
|
|
10494
|
+
return !!range && range.startIndex <= dateIndex && dateIndex <= range.endIndex;
|
|
10482
10495
|
}
|
|
10483
10496
|
function formatValue(value) {
|
|
10484
10497
|
if (value === void 0) return "";
|
|
@@ -10577,6 +10590,261 @@ function PlanFactCellEditor({
|
|
|
10577
10590
|
}
|
|
10578
10591
|
);
|
|
10579
10592
|
}
|
|
10593
|
+
function getCellSignatureForTask(cell, taskId) {
|
|
10594
|
+
return cell?.taskId === taskId ? `${cell.dateIndex}:${cell.kind}` : "";
|
|
10595
|
+
}
|
|
10596
|
+
function getEditingCellSignatureForTask(cell, taskId) {
|
|
10597
|
+
return cell?.taskId === taskId ? `${cell.dateIndex}:${cell.kind}:${cell.startValue ?? ""}` : "";
|
|
10598
|
+
}
|
|
10599
|
+
function getRangeAnchorSignatureForTask(range, taskId) {
|
|
10600
|
+
return range?.anchor.taskId === taskId ? `${range.anchor.dateIndex}:${range.anchor.kind}` : "";
|
|
10601
|
+
}
|
|
10602
|
+
function doesRangeTouchRow(bounds, rowIndex) {
|
|
10603
|
+
if (!bounds) return false;
|
|
10604
|
+
const firstSubrowIndex = rowIndex * 2;
|
|
10605
|
+
const lastSubrowIndex = firstSubrowIndex + 1;
|
|
10606
|
+
return bounds.fromSubrowIndex <= lastSubrowIndex && bounds.toSubrowIndex >= firstSubrowIndex;
|
|
10607
|
+
}
|
|
10608
|
+
function areRangeBoundsEqual(left, right) {
|
|
10609
|
+
if (left === right) return true;
|
|
10610
|
+
if (!left || !right) return false;
|
|
10611
|
+
return left.fromDateIndex === right.fromDateIndex && left.toDateIndex === right.toDateIndex && left.fromSubrowIndex === right.fromSubrowIndex && left.toSubrowIndex === right.toSubrowIndex;
|
|
10612
|
+
}
|
|
10613
|
+
function PlanFactRowInner({
|
|
10614
|
+
task,
|
|
10615
|
+
rowIndex,
|
|
10616
|
+
dateRange,
|
|
10617
|
+
dateKeys,
|
|
10618
|
+
renderedDateIndices,
|
|
10619
|
+
rowHeight,
|
|
10620
|
+
subrowHeight,
|
|
10621
|
+
dayWidth,
|
|
10622
|
+
plannedRange,
|
|
10623
|
+
todayDateIndex,
|
|
10624
|
+
isParent,
|
|
10625
|
+
isHighlighted,
|
|
10626
|
+
selectedTaskId,
|
|
10627
|
+
activeCell,
|
|
10628
|
+
editingCell,
|
|
10629
|
+
selectedRange,
|
|
10630
|
+
renderedRangeBounds,
|
|
10631
|
+
didDragSelectRef,
|
|
10632
|
+
isSelectingRef,
|
|
10633
|
+
isFillDraggingRef,
|
|
10634
|
+
onTaskSelect,
|
|
10635
|
+
selectSingleCell,
|
|
10636
|
+
queueHoverCellUpdate,
|
|
10637
|
+
setActiveCell,
|
|
10638
|
+
setEditingCell,
|
|
10639
|
+
setFillRange,
|
|
10640
|
+
clearSelectedCells,
|
|
10641
|
+
commitCell,
|
|
10642
|
+
commitSelectedCells,
|
|
10643
|
+
moveActiveCell,
|
|
10644
|
+
extendSelectedRange,
|
|
10645
|
+
focusCell,
|
|
10646
|
+
showOverflowTooltip,
|
|
10647
|
+
hideOverflowTooltip
|
|
10648
|
+
}) {
|
|
10649
|
+
return /* @__PURE__ */ jsx18(
|
|
10650
|
+
"div",
|
|
10651
|
+
{
|
|
10652
|
+
"data-gantt-task-row-id": task.id,
|
|
10653
|
+
className: joinClasses2(
|
|
10654
|
+
"gantt-pf-row",
|
|
10655
|
+
isParent && "gantt-pf-row-parent",
|
|
10656
|
+
selectedTaskId === task.id && "gantt-pf-row-selected",
|
|
10657
|
+
isHighlighted && "gantt-pf-row-highlighted"
|
|
10658
|
+
),
|
|
10659
|
+
style: {
|
|
10660
|
+
top: `${rowIndex * rowHeight}px`,
|
|
10661
|
+
height: `${rowHeight}px`,
|
|
10662
|
+
gridTemplateColumns: `repeat(${dateRange.length}, ${dayWidth}px)`,
|
|
10663
|
+
["--gantt-pf-today-left"]: todayDateIndex !== void 0 && todayDateIndex >= 0 ? `${todayDateIndex * dayWidth}px` : void 0
|
|
10664
|
+
},
|
|
10665
|
+
onClick: () => onTaskSelect?.(task.id),
|
|
10666
|
+
children: renderedDateIndices.map((dateIndex) => {
|
|
10667
|
+
const dateKey = dateKeys[dateIndex];
|
|
10668
|
+
if (dateKey === void 0) return null;
|
|
10669
|
+
const planned = isDateIndexWithinPlannedRange(dateIndex, plannedRange);
|
|
10670
|
+
return ["plan", "fact"].map((kind) => {
|
|
10671
|
+
const subrowIndex = getSubrowIndex(rowIndex, kind);
|
|
10672
|
+
const isInRenderedRange = !!renderedRangeBounds && dateIndex >= renderedRangeBounds.fromDateIndex && dateIndex <= renderedRangeBounds.toDateIndex && subrowIndex >= renderedRangeBounds.fromSubrowIndex && subrowIndex <= renderedRangeBounds.toSubrowIndex;
|
|
10673
|
+
const planValue = task.planByDate?.[dateKey];
|
|
10674
|
+
const factValue = task.factByDate?.[dateKey];
|
|
10675
|
+
const value = kind === "plan" ? planValue : factValue;
|
|
10676
|
+
const factStatus = factValue === void 0 || planValue === void 0 ? null : factValue >= planValue ? "success" : "warning";
|
|
10677
|
+
const isActive = activeCell?.taskId === task.id && activeCell.dateIndex === dateIndex && activeCell.kind === kind;
|
|
10678
|
+
const isEditing = editingCell?.taskId === task.id && editingCell.dateIndex === dateIndex && editingCell.kind === kind;
|
|
10679
|
+
const currentCell = { taskId: task.id, dateIndex, kind };
|
|
10680
|
+
const isSelected = !isParent && isInRenderedRange;
|
|
10681
|
+
const showFillHandle = !isParent && !isEditing && isInRenderedRange && renderedRangeBounds !== null && dateIndex === renderedRangeBounds.toDateIndex && subrowIndex === renderedRangeBounds.toSubrowIndex;
|
|
10682
|
+
const isRangeAnchor = !showFillHandle && !isParent && selectedRange?.anchor.taskId === task.id && selectedRange.anchor.dateIndex === dateIndex && selectedRange.anchor.kind === kind;
|
|
10683
|
+
return /* @__PURE__ */ jsxs14(
|
|
10684
|
+
"div",
|
|
10685
|
+
{
|
|
10686
|
+
"data-plan-fact-task-id": task.id,
|
|
10687
|
+
"data-plan-fact-date-index": dateIndex,
|
|
10688
|
+
"data-plan-fact-kind": kind,
|
|
10689
|
+
className: joinClasses2(
|
|
10690
|
+
"gantt-pf-cell",
|
|
10691
|
+
`gantt-pf-cell-${kind}`,
|
|
10692
|
+
planned && kind === "plan" && "gantt-pf-cell-planned",
|
|
10693
|
+
value !== void 0 && "gantt-pf-cell-hasValue",
|
|
10694
|
+
kind === "fact" && factStatus === "success" && "gantt-pf-cell-factSuccess",
|
|
10695
|
+
kind === "fact" && factStatus === "warning" && "gantt-pf-cell-factWarning",
|
|
10696
|
+
isSelected && "gantt-pf-cell-selected",
|
|
10697
|
+
isInRenderedRange && renderedRangeBounds !== null && dateIndex === renderedRangeBounds.fromDateIndex && "gantt-pf-cell-rangeLeft",
|
|
10698
|
+
isInRenderedRange && renderedRangeBounds !== null && dateIndex === renderedRangeBounds.toDateIndex && "gantt-pf-cell-rangeRight",
|
|
10699
|
+
isInRenderedRange && renderedRangeBounds !== null && subrowIndex === renderedRangeBounds.fromSubrowIndex && "gantt-pf-cell-rangeTop",
|
|
10700
|
+
isInRenderedRange && renderedRangeBounds !== null && subrowIndex === renderedRangeBounds.toSubrowIndex && "gantt-pf-cell-rangeBottom",
|
|
10701
|
+
isRangeAnchor && "gantt-pf-cell-rangeAnchor",
|
|
10702
|
+
isActive && "gantt-pf-cell-active",
|
|
10703
|
+
isEditing && "gantt-pf-cell-editing",
|
|
10704
|
+
isParent && "gantt-pf-cell-readonly"
|
|
10705
|
+
),
|
|
10706
|
+
style: {
|
|
10707
|
+
gridColumn: dateIndex + 1,
|
|
10708
|
+
gridRow: kind === "plan" ? 1 : 2,
|
|
10709
|
+
height: `${subrowHeight}px`
|
|
10710
|
+
},
|
|
10711
|
+
tabIndex: isParent ? -1 : 0,
|
|
10712
|
+
onMouseDown: (event) => {
|
|
10713
|
+
if (isParent) return;
|
|
10714
|
+
event.preventDefault();
|
|
10715
|
+
event.stopPropagation();
|
|
10716
|
+
didDragSelectRef.current = false;
|
|
10717
|
+
isSelectingRef.current = true;
|
|
10718
|
+
selectSingleCell(currentCell);
|
|
10719
|
+
onTaskSelect?.(task.id);
|
|
10720
|
+
event.currentTarget.focus();
|
|
10721
|
+
},
|
|
10722
|
+
onMouseEnter: () => {
|
|
10723
|
+
if (isParent) return;
|
|
10724
|
+
if (!isFillDraggingRef.current && !isSelectingRef.current) return;
|
|
10725
|
+
queueHoverCellUpdate(currentCell);
|
|
10726
|
+
},
|
|
10727
|
+
onFocus: () => {
|
|
10728
|
+
if (isParent) return;
|
|
10729
|
+
setActiveCell({ taskId: task.id, dateIndex, kind });
|
|
10730
|
+
},
|
|
10731
|
+
onClick: (event) => {
|
|
10732
|
+
event.stopPropagation();
|
|
10733
|
+
if (didDragSelectRef.current) {
|
|
10734
|
+
didDragSelectRef.current = false;
|
|
10735
|
+
return;
|
|
10736
|
+
}
|
|
10737
|
+
onTaskSelect?.(task.id);
|
|
10738
|
+
if (isParent) return;
|
|
10739
|
+
selectSingleCell(currentCell);
|
|
10740
|
+
event.currentTarget.focus();
|
|
10741
|
+
},
|
|
10742
|
+
onDoubleClick: (event) => {
|
|
10743
|
+
event.stopPropagation();
|
|
10744
|
+
if (isParent) return;
|
|
10745
|
+
setEditingCell({ taskId: task.id, dateIndex, kind });
|
|
10746
|
+
},
|
|
10747
|
+
onKeyDown: (event) => {
|
|
10748
|
+
if (isParent || isEditing) return;
|
|
10749
|
+
if (event.key === "ArrowLeft" || event.key === "ArrowRight" || event.key === "ArrowUp" || event.key === "ArrowDown") {
|
|
10750
|
+
event.preventDefault();
|
|
10751
|
+
event.stopPropagation();
|
|
10752
|
+
const direction = event.key.replace("Arrow", "").toLowerCase();
|
|
10753
|
+
if (event.shiftKey) {
|
|
10754
|
+
extendSelectedRange(selectedRange?.focus ?? currentCell, direction);
|
|
10755
|
+
} else {
|
|
10756
|
+
moveActiveCell(currentCell, direction);
|
|
10757
|
+
}
|
|
10758
|
+
return;
|
|
10759
|
+
}
|
|
10760
|
+
if (event.key === "Enter" || event.key === "F2") {
|
|
10761
|
+
event.preventDefault();
|
|
10762
|
+
event.stopPropagation();
|
|
10763
|
+
setEditingCell(selectedRange?.anchor ?? currentCell);
|
|
10764
|
+
return;
|
|
10765
|
+
}
|
|
10766
|
+
if (event.key === "Backspace" || event.key === "Delete") {
|
|
10767
|
+
event.preventDefault();
|
|
10768
|
+
event.stopPropagation();
|
|
10769
|
+
clearSelectedCells();
|
|
10770
|
+
return;
|
|
10771
|
+
}
|
|
10772
|
+
if (event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {
|
|
10773
|
+
event.preventDefault();
|
|
10774
|
+
event.stopPropagation();
|
|
10775
|
+
setEditingCell({ ...currentCell, startValue: event.key });
|
|
10776
|
+
}
|
|
10777
|
+
},
|
|
10778
|
+
children: [
|
|
10779
|
+
isEditing ? /* @__PURE__ */ jsx18(
|
|
10780
|
+
PlanFactCellEditor,
|
|
10781
|
+
{
|
|
10782
|
+
value,
|
|
10783
|
+
startValue: editingCell.startValue,
|
|
10784
|
+
onCommit: (nextValue) => {
|
|
10785
|
+
commitCell(task, dateIndex, kind, nextValue);
|
|
10786
|
+
setEditingCell(null);
|
|
10787
|
+
const nextActiveCell = { taskId: task.id, dateIndex, kind };
|
|
10788
|
+
selectSingleCell(nextActiveCell);
|
|
10789
|
+
focusCell(nextActiveCell);
|
|
10790
|
+
},
|
|
10791
|
+
onCommitRange: (nextValue) => {
|
|
10792
|
+
commitSelectedCells(nextValue);
|
|
10793
|
+
setEditingCell(null);
|
|
10794
|
+
const nextActiveCell = { taskId: task.id, dateIndex, kind };
|
|
10795
|
+
selectSingleCell(nextActiveCell);
|
|
10796
|
+
focusCell(nextActiveCell);
|
|
10797
|
+
},
|
|
10798
|
+
onCancel: () => {
|
|
10799
|
+
setEditingCell(null);
|
|
10800
|
+
const nextActiveCell = { taskId: task.id, dateIndex, kind };
|
|
10801
|
+
selectSingleCell(nextActiveCell);
|
|
10802
|
+
focusCell(nextActiveCell);
|
|
10803
|
+
}
|
|
10804
|
+
}
|
|
10805
|
+
) : /* @__PURE__ */ jsx18(
|
|
10806
|
+
"span",
|
|
10807
|
+
{
|
|
10808
|
+
className: "gantt-pf-cellValue",
|
|
10809
|
+
onMouseEnter: (event) => {
|
|
10810
|
+
if (isParent || value === void 0) return;
|
|
10811
|
+
const compactValue = formatValue(value);
|
|
10812
|
+
const fullValue = formatTooltipValue(value);
|
|
10813
|
+
showOverflowTooltip(event.currentTarget, fullValue, compactValue !== fullValue);
|
|
10814
|
+
},
|
|
10815
|
+
onMouseLeave: hideOverflowTooltip,
|
|
10816
|
+
children: isParent ? "" : formatValue(value)
|
|
10817
|
+
}
|
|
10818
|
+
),
|
|
10819
|
+
showFillHandle && /* @__PURE__ */ jsx18(
|
|
10820
|
+
"span",
|
|
10821
|
+
{
|
|
10822
|
+
className: "gantt-pf-fillHandle",
|
|
10823
|
+
"aria-hidden": "true",
|
|
10824
|
+
onMouseDown: (event) => {
|
|
10825
|
+
event.preventDefault();
|
|
10826
|
+
event.stopPropagation();
|
|
10827
|
+
isSelectingRef.current = false;
|
|
10828
|
+
isFillDraggingRef.current = true;
|
|
10829
|
+
setFillRange(selectedRange);
|
|
10830
|
+
}
|
|
10831
|
+
}
|
|
10832
|
+
)
|
|
10833
|
+
]
|
|
10834
|
+
},
|
|
10835
|
+
`${task.id}:${dateKey}:${kind}`
|
|
10836
|
+
);
|
|
10837
|
+
});
|
|
10838
|
+
})
|
|
10839
|
+
}
|
|
10840
|
+
);
|
|
10841
|
+
}
|
|
10842
|
+
function arePlanFactRowsEqual(previous, next) {
|
|
10843
|
+
const previousRangeTouchesRow = doesRangeTouchRow(previous.renderedRangeBounds, previous.rowIndex);
|
|
10844
|
+
const nextRangeTouchesRow = doesRangeTouchRow(next.renderedRangeBounds, next.rowIndex);
|
|
10845
|
+
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));
|
|
10846
|
+
}
|
|
10847
|
+
var PlanFactRow = React15.memo(PlanFactRowInner, arePlanFactRowsEqual);
|
|
10580
10848
|
function PlanFactMatrix({
|
|
10581
10849
|
tasks,
|
|
10582
10850
|
allTasks = tasks,
|
|
@@ -10590,7 +10858,10 @@ function PlanFactMatrix({
|
|
|
10590
10858
|
onTasksChange,
|
|
10591
10859
|
onCellCommit,
|
|
10592
10860
|
highlightedTaskIds,
|
|
10593
|
-
filterMode = "highlight"
|
|
10861
|
+
filterMode = "highlight",
|
|
10862
|
+
visibleRowIndices,
|
|
10863
|
+
visibleDateIndices,
|
|
10864
|
+
todayDateIndex
|
|
10594
10865
|
}) {
|
|
10595
10866
|
const [activeCell, setActiveCell] = useState10(null);
|
|
10596
10867
|
const [editingCell, setEditingCell] = useState10(null);
|
|
@@ -10600,10 +10871,20 @@ function PlanFactMatrix({
|
|
|
10600
10871
|
const isSelectingRef = useRef10(false);
|
|
10601
10872
|
const isFillDraggingRef = useRef10(false);
|
|
10602
10873
|
const didDragSelectRef = useRef10(false);
|
|
10874
|
+
const pendingHoverCellRef = useRef10(null);
|
|
10875
|
+
const hoverFrameRef = useRef10(null);
|
|
10603
10876
|
const rootRef = useRef10(null);
|
|
10604
10877
|
const bodyRef = useRef10(null);
|
|
10605
10878
|
const totalWidth = dateRange.length * dayWidth;
|
|
10606
10879
|
const subrowHeight = rowHeight / 2;
|
|
10880
|
+
const renderedRowIndices = useMemo12(
|
|
10881
|
+
() => visibleRowIndices ?? tasks.map((_, index) => index),
|
|
10882
|
+
[tasks, visibleRowIndices]
|
|
10883
|
+
);
|
|
10884
|
+
const renderedDateIndices = useMemo12(
|
|
10885
|
+
() => visibleDateIndices ?? dateRange.map((_, index) => index),
|
|
10886
|
+
[dateRange, visibleDateIndices]
|
|
10887
|
+
);
|
|
10607
10888
|
const parentTaskIds = useMemo12(() => {
|
|
10608
10889
|
const ids = /* @__PURE__ */ new Set();
|
|
10609
10890
|
for (const task of allTasks) {
|
|
@@ -10612,11 +10893,32 @@ function PlanFactMatrix({
|
|
|
10612
10893
|
return ids;
|
|
10613
10894
|
}, [allTasks]);
|
|
10614
10895
|
const dateKeys = useMemo12(() => dateRange.map(formatDateKey), [dateRange]);
|
|
10896
|
+
const dateRangeStartMs = dateRange[0] ? getDateOnlyMs(dateRange[0]) : 0;
|
|
10615
10897
|
const taskIndexById = useMemo12(() => {
|
|
10616
10898
|
const indexById = /* @__PURE__ */ new Map();
|
|
10617
10899
|
tasks.forEach((task, index) => indexById.set(task.id, index));
|
|
10618
10900
|
return indexById;
|
|
10619
10901
|
}, [tasks]);
|
|
10902
|
+
const taskById = useMemo12(
|
|
10903
|
+
() => new Map(tasks.map((task) => [task.id, task])),
|
|
10904
|
+
[tasks]
|
|
10905
|
+
);
|
|
10906
|
+
const monthSeparatorIndices = useMemo12(() => {
|
|
10907
|
+
const indices = [];
|
|
10908
|
+
for (let index = 1; index < dateRange.length; index += 1) {
|
|
10909
|
+
if (dateRange[index].getUTCDate() === 1) {
|
|
10910
|
+
indices.push(index);
|
|
10911
|
+
}
|
|
10912
|
+
}
|
|
10913
|
+
return indices;
|
|
10914
|
+
}, [dateRange]);
|
|
10915
|
+
const plannedRangeByTaskId = useMemo12(() => {
|
|
10916
|
+
const rangeByTaskId = /* @__PURE__ */ new Map();
|
|
10917
|
+
for (const task of tasks) {
|
|
10918
|
+
rangeByTaskId.set(task.id, getPlannedIndexRange(task, dateRangeStartMs, dateRange.length));
|
|
10919
|
+
}
|
|
10920
|
+
return rangeByTaskId;
|
|
10921
|
+
}, [dateRange.length, dateRangeStartMs, tasks]);
|
|
10620
10922
|
const focusCell = useCallback9((cell) => {
|
|
10621
10923
|
window.requestAnimationFrame(() => {
|
|
10622
10924
|
const selector = [
|
|
@@ -10628,6 +10930,11 @@ function PlanFactMatrix({
|
|
|
10628
10930
|
});
|
|
10629
10931
|
}, []);
|
|
10630
10932
|
const clearSelection = useCallback9(() => {
|
|
10933
|
+
if (hoverFrameRef.current !== null) {
|
|
10934
|
+
window.cancelAnimationFrame(hoverFrameRef.current);
|
|
10935
|
+
hoverFrameRef.current = null;
|
|
10936
|
+
}
|
|
10937
|
+
pendingHoverCellRef.current = null;
|
|
10631
10938
|
isSelectingRef.current = false;
|
|
10632
10939
|
isFillDraggingRef.current = false;
|
|
10633
10940
|
didDragSelectRef.current = false;
|
|
@@ -10640,6 +10947,29 @@ function PlanFactMatrix({
|
|
|
10640
10947
|
const hideOverflowTooltip = useCallback9(() => {
|
|
10641
10948
|
setOverflowTooltip(null);
|
|
10642
10949
|
}, []);
|
|
10950
|
+
const flushPendingHoverCell = useCallback9(() => {
|
|
10951
|
+
hoverFrameRef.current = null;
|
|
10952
|
+
const currentCell = pendingHoverCellRef.current;
|
|
10953
|
+
if (!currentCell) return;
|
|
10954
|
+
if (isFillDraggingRef.current && selectedRange) {
|
|
10955
|
+
setFillRange({ anchor: selectedRange.anchor, focus: currentCell });
|
|
10956
|
+
setActiveCell(currentCell);
|
|
10957
|
+
onTaskSelect?.(currentCell.taskId);
|
|
10958
|
+
return;
|
|
10959
|
+
}
|
|
10960
|
+
if (!isSelectingRef.current) return;
|
|
10961
|
+
didDragSelectRef.current = true;
|
|
10962
|
+
setSelectedRange((currentRange) => ({
|
|
10963
|
+
anchor: currentRange?.anchor ?? currentCell,
|
|
10964
|
+
focus: currentCell
|
|
10965
|
+
}));
|
|
10966
|
+
onTaskSelect?.(currentCell.taskId);
|
|
10967
|
+
}, [onTaskSelect, selectedRange]);
|
|
10968
|
+
const queueHoverCellUpdate = useCallback9((cell) => {
|
|
10969
|
+
pendingHoverCellRef.current = cell;
|
|
10970
|
+
if (hoverFrameRef.current !== null) return;
|
|
10971
|
+
hoverFrameRef.current = window.requestAnimationFrame(flushPendingHoverCell);
|
|
10972
|
+
}, [flushPendingHoverCell]);
|
|
10643
10973
|
const showOverflowTooltip = useCallback9((target, label, force = false) => {
|
|
10644
10974
|
if (!rootRef.current || !label) return;
|
|
10645
10975
|
if (!force && target.scrollWidth <= target.clientWidth) {
|
|
@@ -10678,6 +11008,11 @@ function PlanFactMatrix({
|
|
|
10678
11008
|
)
|
|
10679
11009
|
};
|
|
10680
11010
|
}, [taskIndexById]);
|
|
11011
|
+
const renderedRange = fillRange ?? selectedRange;
|
|
11012
|
+
const renderedRangeBounds = useMemo12(
|
|
11013
|
+
() => renderedRange ? getRangeBounds(renderedRange) : null,
|
|
11014
|
+
[getRangeBounds, renderedRange]
|
|
11015
|
+
);
|
|
10681
11016
|
const getCellFromPosition = useCallback9((subrowIndex, dateIndex) => {
|
|
10682
11017
|
const task = tasks[Math.floor(subrowIndex / 2)];
|
|
10683
11018
|
if (!task) return null;
|
|
@@ -10697,33 +11032,6 @@ function PlanFactMatrix({
|
|
|
10697
11032
|
const cellSubrowIndex = getSubrowIndex(cellTaskIndex, cell.kind);
|
|
10698
11033
|
return cell.dateIndex >= bounds.fromDateIndex && cell.dateIndex <= bounds.toDateIndex && cellSubrowIndex >= bounds.fromSubrowIndex && cellSubrowIndex <= bounds.toSubrowIndex;
|
|
10699
11034
|
}, [getRangeBounds, taskIndexById]);
|
|
10700
|
-
const isCellInSelectedRange = useCallback9((cell) => {
|
|
10701
|
-
if (!selectedRange) return false;
|
|
10702
|
-
return isCellInRange(cell, fillRange ?? selectedRange);
|
|
10703
|
-
}, [fillRange, isCellInRange, selectedRange]);
|
|
10704
|
-
const getSelectedRangeEdgeClasses = useCallback9((cell) => {
|
|
10705
|
-
if (!selectedRange) return [];
|
|
10706
|
-
const range = fillRange ?? selectedRange;
|
|
10707
|
-
const bounds = getRangeBounds(range);
|
|
10708
|
-
const taskIndex = taskIndexById.get(cell.taskId);
|
|
10709
|
-
if (!bounds || taskIndex === void 0 || !isCellInRange(cell, range)) return [];
|
|
10710
|
-
const subrowIndex = getSubrowIndex(taskIndex, cell.kind);
|
|
10711
|
-
return [
|
|
10712
|
-
cell.dateIndex === bounds.fromDateIndex && "gantt-pf-cell-rangeLeft",
|
|
10713
|
-
cell.dateIndex === bounds.toDateIndex && "gantt-pf-cell-rangeRight",
|
|
10714
|
-
subrowIndex === bounds.fromSubrowIndex && "gantt-pf-cell-rangeTop",
|
|
10715
|
-
subrowIndex === bounds.toSubrowIndex && "gantt-pf-cell-rangeBottom"
|
|
10716
|
-
];
|
|
10717
|
-
}, [fillRange, getRangeBounds, isCellInRange, selectedRange, taskIndexById]);
|
|
10718
|
-
const isFillHandleCell = useCallback9((cell) => {
|
|
10719
|
-
if (!selectedRange) return false;
|
|
10720
|
-
const range = fillRange ?? selectedRange;
|
|
10721
|
-
const bounds = getRangeBounds(range);
|
|
10722
|
-
const taskIndex = taskIndexById.get(cell.taskId);
|
|
10723
|
-
if (!bounds || taskIndex === void 0 || !isCellInRange(cell, range)) return false;
|
|
10724
|
-
const subrowIndex = getSubrowIndex(taskIndex, cell.kind);
|
|
10725
|
-
return cell.dateIndex === bounds.toDateIndex && subrowIndex === bounds.toSubrowIndex;
|
|
10726
|
-
}, [fillRange, getRangeBounds, isCellInRange, selectedRange, taskIndexById]);
|
|
10727
11035
|
const commitCell = useCallback9((task, dateIndex, kind, value) => {
|
|
10728
11036
|
const dateKey = dateKeys[dateIndex];
|
|
10729
11037
|
const source = kind === "plan" ? task.planByDate : task.factByDate;
|
|
@@ -10746,40 +11054,45 @@ function PlanFactMatrix({
|
|
|
10746
11054
|
value
|
|
10747
11055
|
});
|
|
10748
11056
|
}, [dateKeys, dateRange, onCellCommit, onTasksChange]);
|
|
10749
|
-
const
|
|
10750
|
-
if (!selectedRange) {
|
|
10751
|
-
if (!activeCell) return;
|
|
10752
|
-
const task = tasks.find((candidate) => candidate.id === activeCell.taskId);
|
|
10753
|
-
if (!task || parentTaskIds.has(task.id)) return;
|
|
10754
|
-
commitCell(task, activeCell.dateIndex, activeCell.kind, void 0);
|
|
10755
|
-
return;
|
|
10756
|
-
}
|
|
11057
|
+
const commitRangeCells = useCallback9((bounds, value, mode) => {
|
|
10757
11058
|
const changedTasksById = /* @__PURE__ */ new Map();
|
|
10758
|
-
for (
|
|
10759
|
-
|
|
10760
|
-
|
|
10761
|
-
|
|
11059
|
+
for (let subrowIndex = bounds.fromSubrowIndex; subrowIndex <= bounds.toSubrowIndex; subrowIndex += 1) {
|
|
11060
|
+
const task = tasks[Math.floor(subrowIndex / 2)];
|
|
11061
|
+
if (!task || parentTaskIds.has(task.id)) continue;
|
|
11062
|
+
const kind = subrowIndex % 2 === 0 ? "plan" : "fact";
|
|
11063
|
+
const currentChangedTask = changedTasksById.get(task.id) ?? task;
|
|
11064
|
+
let nextPlanByDate = currentChangedTask.planByDate;
|
|
11065
|
+
let nextFactByDate = currentChangedTask.factByDate;
|
|
10762
11066
|
let didChange = false;
|
|
10763
|
-
for (let dateIndex =
|
|
11067
|
+
for (let dateIndex = bounds.fromDateIndex; dateIndex <= bounds.toDateIndex; dateIndex += 1) {
|
|
10764
11068
|
const dateKey = dateKeys[dateIndex];
|
|
10765
|
-
|
|
10766
|
-
|
|
11069
|
+
if (dateKey === void 0) continue;
|
|
11070
|
+
const currentValues = kind === "plan" ? nextPlanByDate : nextFactByDate;
|
|
11071
|
+
const currentValue = currentValues?.[dateKey];
|
|
11072
|
+
const nextValue = mode === "clear" ? void 0 : value;
|
|
11073
|
+
if (currentValue === nextValue) continue;
|
|
11074
|
+
if (kind === "plan") {
|
|
10767
11075
|
nextPlanByDate = { ...nextPlanByDate ?? {} };
|
|
10768
|
-
|
|
10769
|
-
|
|
10770
|
-
|
|
10771
|
-
|
|
10772
|
-
|
|
11076
|
+
if (nextValue === void 0) {
|
|
11077
|
+
delete nextPlanByDate[dateKey];
|
|
11078
|
+
} else {
|
|
11079
|
+
nextPlanByDate[dateKey] = nextValue;
|
|
11080
|
+
}
|
|
11081
|
+
} else {
|
|
10773
11082
|
nextFactByDate = { ...nextFactByDate ?? {} };
|
|
10774
|
-
|
|
10775
|
-
|
|
11083
|
+
if (nextValue === void 0) {
|
|
11084
|
+
delete nextFactByDate[dateKey];
|
|
11085
|
+
} else {
|
|
11086
|
+
nextFactByDate[dateKey] = nextValue;
|
|
11087
|
+
}
|
|
10776
11088
|
}
|
|
11089
|
+
didChange = true;
|
|
10777
11090
|
}
|
|
10778
11091
|
if (didChange) {
|
|
10779
11092
|
changedTasksById.set(task.id, {
|
|
10780
|
-
...
|
|
10781
|
-
...nextPlanByDate !==
|
|
10782
|
-
...nextFactByDate !==
|
|
11093
|
+
...currentChangedTask,
|
|
11094
|
+
...nextPlanByDate !== currentChangedTask.planByDate ? { planByDate: nextPlanByDate ?? {} } : {},
|
|
11095
|
+
...nextFactByDate !== currentChangedTask.factByDate ? { factByDate: nextFactByDate ?? {} } : {}
|
|
10783
11096
|
});
|
|
10784
11097
|
}
|
|
10785
11098
|
}
|
|
@@ -10787,67 +11100,46 @@ function PlanFactMatrix({
|
|
|
10787
11100
|
if (changedTasks.length > 0) {
|
|
10788
11101
|
onTasksChange?.(changedTasks);
|
|
10789
11102
|
}
|
|
10790
|
-
}, [
|
|
11103
|
+
}, [dateKeys, onTasksChange, parentTaskIds, tasks]);
|
|
11104
|
+
const clearSelectedCells = useCallback9(() => {
|
|
11105
|
+
const activeRange = fillRange ?? selectedRange;
|
|
11106
|
+
if (!activeRange) {
|
|
11107
|
+
if (!activeCell) return;
|
|
11108
|
+
const task = taskById.get(activeCell.taskId);
|
|
11109
|
+
if (!task || parentTaskIds.has(task.id)) return;
|
|
11110
|
+
commitCell(task, activeCell.dateIndex, activeCell.kind, void 0);
|
|
11111
|
+
return;
|
|
11112
|
+
}
|
|
11113
|
+
const bounds = getRangeBounds(activeRange);
|
|
11114
|
+
if (bounds) {
|
|
11115
|
+
commitRangeCells(bounds, void 0, "clear");
|
|
11116
|
+
}
|
|
11117
|
+
}, [activeCell, commitCell, commitRangeCells, fillRange, getRangeBounds, parentTaskIds, selectedRange, taskById]);
|
|
10791
11118
|
const commitSelectedCells = useCallback9((value) => {
|
|
10792
|
-
|
|
11119
|
+
const activeRange = fillRange ?? selectedRange;
|
|
11120
|
+
if (!activeRange) {
|
|
10793
11121
|
if (!activeCell) return;
|
|
10794
|
-
const task =
|
|
11122
|
+
const task = taskById.get(activeCell.taskId);
|
|
10795
11123
|
if (!task || parentTaskIds.has(task.id)) return;
|
|
10796
11124
|
commitCell(task, activeCell.dateIndex, activeCell.kind, value);
|
|
10797
11125
|
return;
|
|
10798
11126
|
}
|
|
10799
|
-
const
|
|
10800
|
-
|
|
10801
|
-
|
|
10802
|
-
let nextPlanByDate = task.planByDate;
|
|
10803
|
-
let nextFactByDate = task.factByDate;
|
|
10804
|
-
let didChange = false;
|
|
10805
|
-
for (let dateIndex = 0; dateIndex < dateKeys.length; dateIndex += 1) {
|
|
10806
|
-
const dateKey = dateKeys[dateIndex];
|
|
10807
|
-
const planCell = { taskId: task.id, dateIndex, kind: "plan" };
|
|
10808
|
-
if (isCellInSelectedRange(planCell) && nextPlanByDate?.[dateKey] !== value) {
|
|
10809
|
-
nextPlanByDate = { ...nextPlanByDate ?? {} };
|
|
10810
|
-
if (value === void 0) {
|
|
10811
|
-
delete nextPlanByDate[dateKey];
|
|
10812
|
-
} else {
|
|
10813
|
-
nextPlanByDate[dateKey] = value;
|
|
10814
|
-
}
|
|
10815
|
-
didChange = true;
|
|
10816
|
-
}
|
|
10817
|
-
const factCell = { taskId: task.id, dateIndex, kind: "fact" };
|
|
10818
|
-
if (isCellInSelectedRange(factCell) && nextFactByDate?.[dateKey] !== value) {
|
|
10819
|
-
nextFactByDate = { ...nextFactByDate ?? {} };
|
|
10820
|
-
if (value === void 0) {
|
|
10821
|
-
delete nextFactByDate[dateKey];
|
|
10822
|
-
} else {
|
|
10823
|
-
nextFactByDate[dateKey] = value;
|
|
10824
|
-
}
|
|
10825
|
-
didChange = true;
|
|
10826
|
-
}
|
|
10827
|
-
}
|
|
10828
|
-
if (didChange) {
|
|
10829
|
-
changedTasksById.set(task.id, {
|
|
10830
|
-
...task,
|
|
10831
|
-
...nextPlanByDate !== task.planByDate ? { planByDate: nextPlanByDate ?? {} } : {},
|
|
10832
|
-
...nextFactByDate !== task.factByDate ? { factByDate: nextFactByDate ?? {} } : {}
|
|
10833
|
-
});
|
|
10834
|
-
}
|
|
10835
|
-
}
|
|
10836
|
-
const changedTasks = Array.from(changedTasksById.values());
|
|
10837
|
-
if (changedTasks.length > 0) {
|
|
10838
|
-
onTasksChange?.(changedTasks);
|
|
11127
|
+
const bounds = getRangeBounds(activeRange);
|
|
11128
|
+
if (bounds) {
|
|
11129
|
+
commitRangeCells(bounds, value, "set");
|
|
10839
11130
|
}
|
|
10840
|
-
}, [activeCell, commitCell,
|
|
11131
|
+
}, [activeCell, commitCell, commitRangeCells, fillRange, getRangeBounds, parentTaskIds, selectedRange, taskById]);
|
|
10841
11132
|
const getCellValue = useCallback9((cell) => {
|
|
10842
|
-
const task =
|
|
11133
|
+
const task = taskById.get(cell.taskId);
|
|
10843
11134
|
if (!task) return void 0;
|
|
10844
11135
|
const dateKey = dateKeys[cell.dateIndex];
|
|
10845
11136
|
return cell.kind === "plan" ? task.planByDate?.[dateKey] : task.factByDate?.[dateKey];
|
|
10846
|
-
}, [dateKeys,
|
|
10847
|
-
const applyFillRange = useCallback9(() => {
|
|
10848
|
-
|
|
11137
|
+
}, [dateKeys, taskById]);
|
|
11138
|
+
const applyFillRange = useCallback9((nextFillRange) => {
|
|
11139
|
+
const targetRange = nextFillRange ?? fillRange;
|
|
11140
|
+
if (!selectedRange || !targetRange) return;
|
|
10849
11141
|
const sourceBounds = getRangeBounds(selectedRange);
|
|
10850
|
-
const targetBounds = getRangeBounds(
|
|
11142
|
+
const targetBounds = getRangeBounds(targetRange);
|
|
10851
11143
|
if (!sourceBounds || !targetBounds) return;
|
|
10852
11144
|
const sourceDateSpan = sourceBounds.toDateIndex - sourceBounds.fromDateIndex + 1;
|
|
10853
11145
|
const sourceSubrowSpan = sourceBounds.toSubrowIndex - sourceBounds.fromSubrowIndex + 1;
|
|
@@ -10855,7 +11147,7 @@ function PlanFactMatrix({
|
|
|
10855
11147
|
for (let subrowIndex = targetBounds.fromSubrowIndex; subrowIndex <= targetBounds.toSubrowIndex; subrowIndex += 1) {
|
|
10856
11148
|
const targetCellForRow = getCellFromPosition(subrowIndex, targetBounds.fromDateIndex);
|
|
10857
11149
|
if (!targetCellForRow || parentTaskIds.has(targetCellForRow.taskId)) continue;
|
|
10858
|
-
const originalTask =
|
|
11150
|
+
const originalTask = taskById.get(targetCellForRow.taskId);
|
|
10859
11151
|
if (!originalTask) continue;
|
|
10860
11152
|
let changedTask = changedTasksById.get(originalTask.id) ?? originalTask;
|
|
10861
11153
|
let nextPlanByDate = changedTask.planByDate;
|
|
@@ -10901,8 +11193,8 @@ function PlanFactMatrix({
|
|
|
10901
11193
|
if (changedTasks.length > 0) {
|
|
10902
11194
|
onTasksChange?.(changedTasks);
|
|
10903
11195
|
}
|
|
10904
|
-
setSelectedRange(
|
|
10905
|
-
setActiveCell(
|
|
11196
|
+
setSelectedRange(targetRange);
|
|
11197
|
+
setActiveCell(targetRange.anchor);
|
|
10906
11198
|
setFillRange(null);
|
|
10907
11199
|
}, [
|
|
10908
11200
|
dateKeys,
|
|
@@ -10914,7 +11206,7 @@ function PlanFactMatrix({
|
|
|
10914
11206
|
onTasksChange,
|
|
10915
11207
|
parentTaskIds,
|
|
10916
11208
|
selectedRange,
|
|
10917
|
-
|
|
11209
|
+
taskById
|
|
10918
11210
|
]);
|
|
10919
11211
|
const moveActiveCell = useCallback9((cell, direction) => {
|
|
10920
11212
|
const taskIndex = tasks.findIndex((task) => task.id === cell.taskId);
|
|
@@ -10986,9 +11278,19 @@ function PlanFactMatrix({
|
|
|
10986
11278
|
}, [dateRange.length, focusCell, onTaskSelect, parentTaskIds, selectedRange, tasks]);
|
|
10987
11279
|
useEffect9(() => {
|
|
10988
11280
|
const endSelection = () => {
|
|
11281
|
+
let pendingFillRange = null;
|
|
11282
|
+
if (hoverFrameRef.current !== null) {
|
|
11283
|
+
window.cancelAnimationFrame(hoverFrameRef.current);
|
|
11284
|
+
hoverFrameRef.current = null;
|
|
11285
|
+
const pendingCell = pendingHoverCellRef.current;
|
|
11286
|
+
if (pendingCell && isFillDraggingRef.current && selectedRange) {
|
|
11287
|
+
pendingFillRange = { anchor: selectedRange.anchor, focus: pendingCell };
|
|
11288
|
+
}
|
|
11289
|
+
flushPendingHoverCell();
|
|
11290
|
+
}
|
|
10989
11291
|
if (isFillDraggingRef.current) {
|
|
10990
11292
|
isFillDraggingRef.current = false;
|
|
10991
|
-
applyFillRange();
|
|
11293
|
+
applyFillRange(pendingFillRange);
|
|
10992
11294
|
}
|
|
10993
11295
|
isSelectingRef.current = false;
|
|
10994
11296
|
};
|
|
@@ -10996,7 +11298,12 @@ function PlanFactMatrix({
|
|
|
10996
11298
|
return () => {
|
|
10997
11299
|
window.removeEventListener("mouseup", endSelection);
|
|
10998
11300
|
};
|
|
10999
|
-
}, [applyFillRange]);
|
|
11301
|
+
}, [applyFillRange, flushPendingHoverCell]);
|
|
11302
|
+
useEffect9(() => () => {
|
|
11303
|
+
if (hoverFrameRef.current !== null) {
|
|
11304
|
+
window.cancelAnimationFrame(hoverFrameRef.current);
|
|
11305
|
+
}
|
|
11306
|
+
}, []);
|
|
11000
11307
|
useEffect9(() => {
|
|
11001
11308
|
const handleKeyDown = (event) => {
|
|
11002
11309
|
if (event.key !== "Escape") return;
|
|
@@ -11026,15 +11333,39 @@ function PlanFactMatrix({
|
|
|
11026
11333
|
["--gantt-pf-day-width"]: `${dayWidth}px`
|
|
11027
11334
|
},
|
|
11028
11335
|
children: [
|
|
11029
|
-
/* @__PURE__ */
|
|
11030
|
-
|
|
11336
|
+
/* @__PURE__ */ jsxs14("div", { className: "gantt-pf-header", style: { width: `${totalWidth}px`, height: `${headerHeight}px` }, children: [
|
|
11337
|
+
/* @__PURE__ */ jsx18(
|
|
11338
|
+
TimeScaleHeader_default,
|
|
11339
|
+
{
|
|
11340
|
+
days: dateRange,
|
|
11341
|
+
dayWidth,
|
|
11342
|
+
headerHeight: headerHeight - 1,
|
|
11343
|
+
viewMode: "day"
|
|
11344
|
+
}
|
|
11345
|
+
),
|
|
11346
|
+
todayDateIndex !== void 0 && todayDateIndex >= 0 && /* @__PURE__ */ jsx18(
|
|
11347
|
+
"span",
|
|
11348
|
+
{
|
|
11349
|
+
className: "gantt-pf-headerTodayLine",
|
|
11350
|
+
"aria-hidden": "true",
|
|
11351
|
+
style: {
|
|
11352
|
+
left: `${todayDateIndex * dayWidth}px`,
|
|
11353
|
+
top: `${Math.max(0, headerHeight / 2)}px`
|
|
11354
|
+
}
|
|
11355
|
+
}
|
|
11356
|
+
)
|
|
11357
|
+
] }),
|
|
11358
|
+
/* @__PURE__ */ jsx18("div", { className: "gantt-pf-monthSeparatorLayer", "aria-hidden": "true", children: monthSeparatorIndices.map((dateIndex) => /* @__PURE__ */ jsx18(
|
|
11359
|
+
"span",
|
|
11031
11360
|
{
|
|
11032
|
-
|
|
11033
|
-
|
|
11034
|
-
|
|
11035
|
-
|
|
11036
|
-
|
|
11037
|
-
|
|
11361
|
+
className: "gantt-pf-monthSeparator",
|
|
11362
|
+
style: {
|
|
11363
|
+
left: `${Math.round(dateIndex * dayWidth)}px`,
|
|
11364
|
+
top: `${Math.max(0, headerHeight / 2)}px`
|
|
11365
|
+
}
|
|
11366
|
+
},
|
|
11367
|
+
`month-separator-${dateIndex}`
|
|
11368
|
+
)) }),
|
|
11038
11369
|
/* @__PURE__ */ jsx18(
|
|
11039
11370
|
"div",
|
|
11040
11371
|
{
|
|
@@ -11045,202 +11376,48 @@ function PlanFactMatrix({
|
|
|
11045
11376
|
minHeight: bodyMinHeight,
|
|
11046
11377
|
width: `${totalWidth}px`
|
|
11047
11378
|
},
|
|
11048
|
-
children:
|
|
11379
|
+
children: renderedRowIndices.map((rowIndex) => {
|
|
11380
|
+
const task = tasks[rowIndex];
|
|
11381
|
+
if (!task) return null;
|
|
11049
11382
|
const isParent = parentTaskIds.has(task.id);
|
|
11050
11383
|
const isHighlighted = filterMode === "highlight" && !!highlightedTaskIds?.has(task.id);
|
|
11051
11384
|
return /* @__PURE__ */ jsx18(
|
|
11052
|
-
|
|
11385
|
+
PlanFactRow,
|
|
11053
11386
|
{
|
|
11054
|
-
|
|
11055
|
-
|
|
11056
|
-
|
|
11057
|
-
|
|
11058
|
-
|
|
11059
|
-
|
|
11060
|
-
|
|
11061
|
-
|
|
11062
|
-
|
|
11063
|
-
|
|
11064
|
-
|
|
11065
|
-
|
|
11066
|
-
|
|
11067
|
-
|
|
11068
|
-
|
|
11069
|
-
|
|
11070
|
-
|
|
11071
|
-
|
|
11072
|
-
|
|
11073
|
-
|
|
11074
|
-
|
|
11075
|
-
|
|
11076
|
-
|
|
11077
|
-
|
|
11078
|
-
|
|
11079
|
-
|
|
11080
|
-
|
|
11081
|
-
|
|
11082
|
-
|
|
11083
|
-
|
|
11084
|
-
|
|
11085
|
-
|
|
11086
|
-
|
|
11087
|
-
|
|
11088
|
-
"gantt-pf-cell",
|
|
11089
|
-
`gantt-pf-cell-${kind}`,
|
|
11090
|
-
planned && kind === "plan" && !isParent && "gantt-pf-cell-planned",
|
|
11091
|
-
value !== void 0 && "gantt-pf-cell-hasValue",
|
|
11092
|
-
kind === "fact" && factStatus === "success" && "gantt-pf-cell-factSuccess",
|
|
11093
|
-
kind === "fact" && factStatus === "warning" && "gantt-pf-cell-factWarning",
|
|
11094
|
-
isSelected && "gantt-pf-cell-selected",
|
|
11095
|
-
...getSelectedRangeEdgeClasses(currentCell),
|
|
11096
|
-
isRangeAnchor && "gantt-pf-cell-rangeAnchor",
|
|
11097
|
-
isActive && "gantt-pf-cell-active",
|
|
11098
|
-
isEditing && "gantt-pf-cell-editing",
|
|
11099
|
-
isParent && "gantt-pf-cell-readonly"
|
|
11100
|
-
),
|
|
11101
|
-
style: {
|
|
11102
|
-
gridColumn: dateIndex + 1,
|
|
11103
|
-
gridRow: kind === "plan" ? 1 : 2,
|
|
11104
|
-
height: `${subrowHeight}px`
|
|
11105
|
-
},
|
|
11106
|
-
tabIndex: isParent ? -1 : 0,
|
|
11107
|
-
onMouseDown: (event) => {
|
|
11108
|
-
if (isParent) return;
|
|
11109
|
-
event.preventDefault();
|
|
11110
|
-
event.stopPropagation();
|
|
11111
|
-
didDragSelectRef.current = false;
|
|
11112
|
-
isSelectingRef.current = true;
|
|
11113
|
-
selectSingleCell(currentCell);
|
|
11114
|
-
onTaskSelect?.(task.id);
|
|
11115
|
-
event.currentTarget.focus();
|
|
11116
|
-
},
|
|
11117
|
-
onMouseEnter: () => {
|
|
11118
|
-
if (!isParent && isFillDraggingRef.current && selectedRange) {
|
|
11119
|
-
setFillRange({ anchor: selectedRange.anchor, focus: currentCell });
|
|
11120
|
-
setActiveCell(currentCell);
|
|
11121
|
-
onTaskSelect?.(task.id);
|
|
11122
|
-
return;
|
|
11123
|
-
}
|
|
11124
|
-
if (isParent || !isSelectingRef.current) return;
|
|
11125
|
-
didDragSelectRef.current = true;
|
|
11126
|
-
setSelectedRange((currentRange) => ({
|
|
11127
|
-
anchor: currentRange?.anchor ?? currentCell,
|
|
11128
|
-
focus: currentCell
|
|
11129
|
-
}));
|
|
11130
|
-
onTaskSelect?.(task.id);
|
|
11131
|
-
},
|
|
11132
|
-
onFocus: () => {
|
|
11133
|
-
if (isParent) return;
|
|
11134
|
-
setActiveCell({ taskId: task.id, dateIndex, kind });
|
|
11135
|
-
},
|
|
11136
|
-
onClick: (event) => {
|
|
11137
|
-
event.stopPropagation();
|
|
11138
|
-
if (didDragSelectRef.current) {
|
|
11139
|
-
didDragSelectRef.current = false;
|
|
11140
|
-
return;
|
|
11141
|
-
}
|
|
11142
|
-
onTaskSelect?.(task.id);
|
|
11143
|
-
if (isParent) return;
|
|
11144
|
-
selectSingleCell(currentCell);
|
|
11145
|
-
event.currentTarget.focus();
|
|
11146
|
-
},
|
|
11147
|
-
onDoubleClick: (event) => {
|
|
11148
|
-
event.stopPropagation();
|
|
11149
|
-
if (isParent) return;
|
|
11150
|
-
setEditingCell({ taskId: task.id, dateIndex, kind });
|
|
11151
|
-
},
|
|
11152
|
-
onKeyDown: (event) => {
|
|
11153
|
-
if (isParent || isEditing) return;
|
|
11154
|
-
if (event.key === "ArrowLeft" || event.key === "ArrowRight" || event.key === "ArrowUp" || event.key === "ArrowDown") {
|
|
11155
|
-
event.preventDefault();
|
|
11156
|
-
event.stopPropagation();
|
|
11157
|
-
const direction = event.key.replace("Arrow", "").toLowerCase();
|
|
11158
|
-
if (event.shiftKey) {
|
|
11159
|
-
extendSelectedRange(selectedRange?.focus ?? currentCell, direction);
|
|
11160
|
-
} else {
|
|
11161
|
-
moveActiveCell(currentCell, direction);
|
|
11162
|
-
}
|
|
11163
|
-
return;
|
|
11164
|
-
}
|
|
11165
|
-
if (event.key === "Enter" || event.key === "F2") {
|
|
11166
|
-
event.preventDefault();
|
|
11167
|
-
event.stopPropagation();
|
|
11168
|
-
setEditingCell(selectedRange?.anchor ?? currentCell);
|
|
11169
|
-
return;
|
|
11170
|
-
}
|
|
11171
|
-
if (event.key === "Backspace" || event.key === "Delete") {
|
|
11172
|
-
event.preventDefault();
|
|
11173
|
-
event.stopPropagation();
|
|
11174
|
-
clearSelectedCells();
|
|
11175
|
-
return;
|
|
11176
|
-
}
|
|
11177
|
-
if (event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {
|
|
11178
|
-
event.preventDefault();
|
|
11179
|
-
event.stopPropagation();
|
|
11180
|
-
setEditingCell({ ...currentCell, startValue: event.key });
|
|
11181
|
-
}
|
|
11182
|
-
},
|
|
11183
|
-
children: [
|
|
11184
|
-
isEditing ? /* @__PURE__ */ jsx18(
|
|
11185
|
-
PlanFactCellEditor,
|
|
11186
|
-
{
|
|
11187
|
-
value,
|
|
11188
|
-
startValue: editingCell.startValue,
|
|
11189
|
-
onCommit: (nextValue) => {
|
|
11190
|
-
commitCell(task, dateIndex, kind, nextValue);
|
|
11191
|
-
setEditingCell(null);
|
|
11192
|
-
const nextActiveCell = { taskId: task.id, dateIndex, kind };
|
|
11193
|
-
selectSingleCell(nextActiveCell);
|
|
11194
|
-
focusCell(nextActiveCell);
|
|
11195
|
-
},
|
|
11196
|
-
onCommitRange: (nextValue) => {
|
|
11197
|
-
commitSelectedCells(nextValue);
|
|
11198
|
-
setEditingCell(null);
|
|
11199
|
-
const nextActiveCell = { taskId: task.id, dateIndex, kind };
|
|
11200
|
-
setActiveCell(nextActiveCell);
|
|
11201
|
-
focusCell(nextActiveCell);
|
|
11202
|
-
},
|
|
11203
|
-
onCancel: () => {
|
|
11204
|
-
setEditingCell(null);
|
|
11205
|
-
const nextActiveCell = { taskId: task.id, dateIndex, kind };
|
|
11206
|
-
setActiveCell(nextActiveCell);
|
|
11207
|
-
focusCell(nextActiveCell);
|
|
11208
|
-
}
|
|
11209
|
-
}
|
|
11210
|
-
) : /* @__PURE__ */ jsx18(
|
|
11211
|
-
"span",
|
|
11212
|
-
{
|
|
11213
|
-
className: "gantt-pf-cellValue",
|
|
11214
|
-
onMouseEnter: (event) => {
|
|
11215
|
-
if (isParent || value === void 0) return;
|
|
11216
|
-
const compactValue = formatValue(value);
|
|
11217
|
-
const fullValue = formatTooltipValue(value);
|
|
11218
|
-
showOverflowTooltip(event.currentTarget, fullValue, compactValue !== fullValue);
|
|
11219
|
-
},
|
|
11220
|
-
onMouseLeave: hideOverflowTooltip,
|
|
11221
|
-
children: isParent ? "" : formatValue(value)
|
|
11222
|
-
}
|
|
11223
|
-
),
|
|
11224
|
-
showFillHandle && /* @__PURE__ */ jsx18(
|
|
11225
|
-
"span",
|
|
11226
|
-
{
|
|
11227
|
-
className: "gantt-pf-fillHandle",
|
|
11228
|
-
"aria-hidden": "true",
|
|
11229
|
-
onMouseDown: (event) => {
|
|
11230
|
-
event.preventDefault();
|
|
11231
|
-
event.stopPropagation();
|
|
11232
|
-
isSelectingRef.current = false;
|
|
11233
|
-
isFillDraggingRef.current = true;
|
|
11234
|
-
setFillRange(selectedRange);
|
|
11235
|
-
}
|
|
11236
|
-
}
|
|
11237
|
-
)
|
|
11238
|
-
]
|
|
11239
|
-
},
|
|
11240
|
-
`${task.id}:${dateKey}:${kind}`
|
|
11241
|
-
);
|
|
11242
|
-
});
|
|
11243
|
-
})
|
|
11387
|
+
task,
|
|
11388
|
+
rowIndex,
|
|
11389
|
+
dateRange,
|
|
11390
|
+
dateKeys,
|
|
11391
|
+
renderedDateIndices,
|
|
11392
|
+
rowHeight,
|
|
11393
|
+
subrowHeight,
|
|
11394
|
+
dayWidth,
|
|
11395
|
+
plannedRange: plannedRangeByTaskId.get(task.id) ?? null,
|
|
11396
|
+
todayDateIndex,
|
|
11397
|
+
isParent,
|
|
11398
|
+
isHighlighted,
|
|
11399
|
+
selectedTaskId,
|
|
11400
|
+
activeCell,
|
|
11401
|
+
editingCell,
|
|
11402
|
+
selectedRange,
|
|
11403
|
+
renderedRangeBounds,
|
|
11404
|
+
didDragSelectRef,
|
|
11405
|
+
isSelectingRef,
|
|
11406
|
+
isFillDraggingRef,
|
|
11407
|
+
onTaskSelect,
|
|
11408
|
+
selectSingleCell,
|
|
11409
|
+
queueHoverCellUpdate,
|
|
11410
|
+
setActiveCell,
|
|
11411
|
+
setEditingCell,
|
|
11412
|
+
setFillRange,
|
|
11413
|
+
clearSelectedCells,
|
|
11414
|
+
commitCell,
|
|
11415
|
+
commitSelectedCells,
|
|
11416
|
+
moveActiveCell,
|
|
11417
|
+
extendSelectedRange,
|
|
11418
|
+
focusCell,
|
|
11419
|
+
showOverflowTooltip,
|
|
11420
|
+
hideOverflowTooltip
|
|
11244
11421
|
},
|
|
11245
11422
|
task.id
|
|
11246
11423
|
);
|
|
@@ -11676,6 +11853,57 @@ function createTaskPreviewPositionStore() {
|
|
|
11676
11853
|
import { Fragment as Fragment4, jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
11677
11854
|
var SCROLL_TO_ROW_CONTEXT_ROWS = 2;
|
|
11678
11855
|
var TASK_ROW_OVERSCAN = 8;
|
|
11856
|
+
var PLAN_FACT_COLUMN_OVERSCAN = 24;
|
|
11857
|
+
var PLAN_FACT_COLUMN_WINDOW_STEP = 14;
|
|
11858
|
+
function getFullMonthDays(tasks) {
|
|
11859
|
+
if (!tasks || tasks.length === 0) {
|
|
11860
|
+
return getMultiMonthDays(tasks);
|
|
11861
|
+
}
|
|
11862
|
+
let minDate = null;
|
|
11863
|
+
let maxDate = null;
|
|
11864
|
+
for (const task of tasks) {
|
|
11865
|
+
const start = parseUTCDate(task.startDate);
|
|
11866
|
+
const end = parseUTCDate(task.endDate);
|
|
11867
|
+
if (!minDate || start.getTime() < minDate.getTime()) {
|
|
11868
|
+
minDate = start;
|
|
11869
|
+
}
|
|
11870
|
+
if (!maxDate || end.getTime() > maxDate.getTime()) {
|
|
11871
|
+
maxDate = end;
|
|
11872
|
+
}
|
|
11873
|
+
}
|
|
11874
|
+
if (!minDate || !maxDate) {
|
|
11875
|
+
return getMultiMonthDays(tasks);
|
|
11876
|
+
}
|
|
11877
|
+
const startOfMonth2 = new Date(Date.UTC(minDate.getUTCFullYear(), minDate.getUTCMonth(), 1));
|
|
11878
|
+
const endOfMonth = new Date(Date.UTC(maxDate.getUTCFullYear(), maxDate.getUTCMonth() + 1, 0));
|
|
11879
|
+
const days = [];
|
|
11880
|
+
const current = new Date(startOfMonth2);
|
|
11881
|
+
while (current.getTime() <= endOfMonth.getTime()) {
|
|
11882
|
+
days.push(new Date(Date.UTC(
|
|
11883
|
+
current.getUTCFullYear(),
|
|
11884
|
+
current.getUTCMonth(),
|
|
11885
|
+
current.getUTCDate()
|
|
11886
|
+
)));
|
|
11887
|
+
current.setUTCDate(current.getUTCDate() + 1);
|
|
11888
|
+
}
|
|
11889
|
+
return days;
|
|
11890
|
+
}
|
|
11891
|
+
function getPlanFactRangeTasks(tasks) {
|
|
11892
|
+
const rangeTasks = [];
|
|
11893
|
+
for (const task of tasks) {
|
|
11894
|
+
rangeTasks.push({ startDate: task.startDate, endDate: task.endDate });
|
|
11895
|
+
for (const dateKey of Object.keys(task.planByDate ?? {})) {
|
|
11896
|
+
rangeTasks.push({ startDate: dateKey, endDate: dateKey });
|
|
11897
|
+
}
|
|
11898
|
+
for (const dateKey of Object.keys(task.factByDate ?? {})) {
|
|
11899
|
+
rangeTasks.push({ startDate: dateKey, endDate: dateKey });
|
|
11900
|
+
}
|
|
11901
|
+
}
|
|
11902
|
+
return rangeTasks;
|
|
11903
|
+
}
|
|
11904
|
+
function clampScrollValue(value, max) {
|
|
11905
|
+
return Math.min(max, Math.max(0, value));
|
|
11906
|
+
}
|
|
11679
11907
|
function arePositionMapsEqual(left, right) {
|
|
11680
11908
|
if (left.size !== right.size) return false;
|
|
11681
11909
|
for (const [taskId, leftPosition] of left) {
|
|
@@ -11798,6 +12026,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11798
12026
|
const [taskListHasRightShadow, setTaskListHasRightShadow] = useState11(false);
|
|
11799
12027
|
const [internalTaskDateChangeMode, setInternalTaskDateChangeMode] = useState11("preserve-duration");
|
|
11800
12028
|
const [scrollViewport, setScrollViewport] = useState11({ scrollTop: 0, viewportHeight: 0 });
|
|
12029
|
+
const [planFactDateWindow, setPlanFactDateWindow] = useState11(null);
|
|
11801
12030
|
const [selectedChip, setSelectedChip] = useState11(null);
|
|
11802
12031
|
const [activeTimelineTooltip, setActiveTimelineTooltip] = useState11(null);
|
|
11803
12032
|
const [internalCollapsedParentIds, setInternalCollapsedParentIds] = useState11(/* @__PURE__ */ new Set());
|
|
@@ -11816,6 +12045,9 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11816
12045
|
[customDays, isWeekend3]
|
|
11817
12046
|
);
|
|
11818
12047
|
const dateRangeTasks = useMemo13(() => {
|
|
12048
|
+
if (isPlanFactMode) {
|
|
12049
|
+
return getPlanFactRangeTasks(normalizedTasks);
|
|
12050
|
+
}
|
|
11819
12051
|
if (!showBaseline) {
|
|
11820
12052
|
return normalizedTasks;
|
|
11821
12053
|
}
|
|
@@ -11824,8 +12056,11 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11824
12056
|
startDate: task.baselineStartDate && parseUTCDate(task.baselineStartDate).getTime() < parseUTCDate(task.startDate).getTime() ? task.baselineStartDate : task.startDate,
|
|
11825
12057
|
endDate: task.baselineEndDate && parseUTCDate(task.baselineEndDate).getTime() > parseUTCDate(task.endDate).getTime() ? task.baselineEndDate : task.endDate
|
|
11826
12058
|
}));
|
|
11827
|
-
}, [normalizedTasks, showBaseline]);
|
|
11828
|
-
const dateRange = useMemo13(
|
|
12059
|
+
}, [isPlanFactMode, normalizedTasks, showBaseline]);
|
|
12060
|
+
const dateRange = useMemo13(
|
|
12061
|
+
() => isPlanFactMode ? getFullMonthDays(dateRangeTasks) : getMultiMonthDays(dateRangeTasks),
|
|
12062
|
+
[dateRangeTasks, isPlanFactMode]
|
|
12063
|
+
);
|
|
11829
12064
|
const [validationResult, setValidationResult] = useState11(null);
|
|
11830
12065
|
const [cascadeOverrides, setCascadeOverrides] = useState11(/* @__PURE__ */ new Map());
|
|
11831
12066
|
const gridWidth = useMemo13(
|
|
@@ -11891,11 +12126,12 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11891
12126
|
const firstDay = dateRange[0];
|
|
11892
12127
|
return new Date(Date.UTC(firstDay.getUTCFullYear(), firstDay.getUTCMonth(), 1));
|
|
11893
12128
|
}, [dateRange]);
|
|
11894
|
-
const
|
|
12129
|
+
const todayIndex = useMemo13(() => {
|
|
11895
12130
|
const now = /* @__PURE__ */ new Date();
|
|
11896
12131
|
const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
|
|
11897
|
-
return dateRange.
|
|
12132
|
+
return dateRange.findIndex((day) => day.getTime() === today.getTime());
|
|
11898
12133
|
}, [dateRange]);
|
|
12134
|
+
const todayInRange = todayIndex !== -1;
|
|
11899
12135
|
const visibleTimelineMarkers = useMemo13(() => {
|
|
11900
12136
|
if (isTableMatrixMode || !timelineMarkers || timelineMarkers.length === 0 || dateRange.length === 0) {
|
|
11901
12137
|
return [];
|
|
@@ -11914,9 +12150,9 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11914
12150
|
if (!container || dateRange.length === 0) return;
|
|
11915
12151
|
const now = /* @__PURE__ */ new Date();
|
|
11916
12152
|
const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
|
|
11917
|
-
const
|
|
11918
|
-
if (
|
|
11919
|
-
const todayOffset =
|
|
12153
|
+
const todayIndex2 = dateRange.findIndex((day) => day.getTime() === today.getTime());
|
|
12154
|
+
if (todayIndex2 === -1) return;
|
|
12155
|
+
const todayOffset = todayIndex2 * dayWidth;
|
|
11920
12156
|
const containerWidth = container.clientWidth;
|
|
11921
12157
|
const scrollLeft = Math.round(todayOffset + dayWidth / 2 - containerWidth * 0.3);
|
|
11922
12158
|
container.scrollLeft = Math.max(0, scrollLeft);
|
|
@@ -11930,13 +12166,33 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11930
12166
|
frameId = null;
|
|
11931
12167
|
const nextHasRightShadow = container.scrollLeft > 0;
|
|
11932
12168
|
const nextViewportHeight = Math.max(0, container.clientHeight - timelineHeaderHeight);
|
|
12169
|
+
const nextViewportWidth = Math.max(0, container.clientWidth - (showTaskList ? taskListWidth : 0));
|
|
11933
12170
|
const nextScrollTop = container.scrollTop;
|
|
12171
|
+
const nextScrollLeft = container.scrollLeft;
|
|
12172
|
+
const nextChartScrollLeft = Math.max(0, nextScrollLeft);
|
|
11934
12173
|
setTaskListHasRightShadow(
|
|
11935
12174
|
(previous) => previous === nextHasRightShadow ? previous : nextHasRightShadow
|
|
11936
12175
|
);
|
|
11937
12176
|
setScrollViewport(
|
|
11938
12177
|
(previous) => previous.scrollTop === nextScrollTop && previous.viewportHeight === nextViewportHeight ? previous : { scrollTop: nextScrollTop, viewportHeight: nextViewportHeight }
|
|
11939
12178
|
);
|
|
12179
|
+
setPlanFactDateWindow((previous) => {
|
|
12180
|
+
if (!isPlanFactMode || dateRange.length === 0 || nextViewportWidth <= 0) {
|
|
12181
|
+
return previous === null ? previous : null;
|
|
12182
|
+
}
|
|
12183
|
+
const firstVisibleColumn = Math.max(0, Math.floor(nextChartScrollLeft / dayWidth));
|
|
12184
|
+
const visibleColumnCount = Math.max(1, Math.ceil(nextViewportWidth / dayWidth));
|
|
12185
|
+
const lastVisibleColumn = Math.min(dateRange.length - 1, firstVisibleColumn + visibleColumnCount - 1);
|
|
12186
|
+
const rangeStart = Math.max(
|
|
12187
|
+
0,
|
|
12188
|
+
Math.floor(Math.max(0, firstVisibleColumn - PLAN_FACT_COLUMN_OVERSCAN) / PLAN_FACT_COLUMN_WINDOW_STEP) * PLAN_FACT_COLUMN_WINDOW_STEP
|
|
12189
|
+
);
|
|
12190
|
+
const rangeEnd = Math.min(
|
|
12191
|
+
dateRange.length - 1,
|
|
12192
|
+
Math.ceil((lastVisibleColumn + PLAN_FACT_COLUMN_OVERSCAN + 1) / PLAN_FACT_COLUMN_WINDOW_STEP) * PLAN_FACT_COLUMN_WINDOW_STEP - 1
|
|
12193
|
+
);
|
|
12194
|
+
return previous?.start === rangeStart && previous.end === rangeEnd ? previous : { start: rangeStart, end: rangeEnd };
|
|
12195
|
+
});
|
|
11940
12196
|
};
|
|
11941
12197
|
const scheduleUpdate = () => {
|
|
11942
12198
|
if (frameId !== null) return;
|
|
@@ -11957,16 +12213,16 @@ function TaskGanttChartInner(props, ref) {
|
|
|
11957
12213
|
container.removeEventListener("scroll", scheduleUpdate);
|
|
11958
12214
|
window.removeEventListener("resize", scheduleUpdate);
|
|
11959
12215
|
};
|
|
11960
|
-
}, [timelineHeaderHeight]);
|
|
12216
|
+
}, [dateRange.length, dayWidth, isPlanFactMode, showTaskList, taskListWidth, timelineHeaderHeight]);
|
|
11961
12217
|
const scrollToToday = useCallback10(() => {
|
|
11962
12218
|
if (isTableMatrixMode) return;
|
|
11963
12219
|
const container = scrollContainerRef.current;
|
|
11964
12220
|
if (!container || dateRange.length === 0) return;
|
|
11965
12221
|
const now = /* @__PURE__ */ new Date();
|
|
11966
12222
|
const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
|
|
11967
|
-
const
|
|
11968
|
-
if (
|
|
11969
|
-
const todayOffset =
|
|
12223
|
+
const todayIndex2 = dateRange.findIndex((day) => day.getTime() === today.getTime());
|
|
12224
|
+
if (todayIndex2 === -1) return;
|
|
12225
|
+
const todayOffset = todayIndex2 * dayWidth;
|
|
11970
12226
|
const containerWidth = container.clientWidth;
|
|
11971
12227
|
const scrollLeft = Math.round(todayOffset + dayWidth / 2 - containerWidth * 0.3);
|
|
11972
12228
|
container.scrollTo({ left: Math.max(0, scrollLeft), behavior: "smooth" });
|
|
@@ -12202,6 +12458,15 @@ function TaskGanttChartInner(props, ref) {
|
|
|
12202
12458
|
}
|
|
12203
12459
|
return Array.from(indices).sort((left, right) => left - right);
|
|
12204
12460
|
}, [effectiveRowHeight, forcedRenderedTaskIds, scrollViewport, visibleTaskIndexMap, visibleTasks.length]);
|
|
12461
|
+
const visiblePlanFactDateIndices = useMemo13(() => {
|
|
12462
|
+
if (!isPlanFactMode || dateRange.length === 0 || !planFactDateWindow) {
|
|
12463
|
+
return void 0;
|
|
12464
|
+
}
|
|
12465
|
+
return Array.from(
|
|
12466
|
+
{ length: planFactDateWindow.end - planFactDateWindow.start + 1 },
|
|
12467
|
+
(_, index) => planFactDateWindow.start + index
|
|
12468
|
+
);
|
|
12469
|
+
}, [dateRange.length, isPlanFactMode, planFactDateWindow]);
|
|
12205
12470
|
const renderedChartTasks = useMemo13(
|
|
12206
12471
|
() => visibleTaskWindowIndices.map((index) => {
|
|
12207
12472
|
const task = previewVisibleTasks[index];
|
|
@@ -12458,7 +12723,10 @@ function TaskGanttChartInner(props, ref) {
|
|
|
12458
12723
|
startX: e.clientX,
|
|
12459
12724
|
startY: e.clientY,
|
|
12460
12725
|
scrollX: container.scrollLeft,
|
|
12461
|
-
scrollY: container.scrollTop
|
|
12726
|
+
scrollY: container.scrollTop,
|
|
12727
|
+
currentX: e.clientX,
|
|
12728
|
+
currentY: e.clientY,
|
|
12729
|
+
frameId: null
|
|
12462
12730
|
};
|
|
12463
12731
|
if (document.activeElement instanceof HTMLElement) {
|
|
12464
12732
|
document.activeElement.blur();
|
|
@@ -12467,16 +12735,37 @@ function TaskGanttChartInner(props, ref) {
|
|
|
12467
12735
|
e.preventDefault();
|
|
12468
12736
|
}, []);
|
|
12469
12737
|
useEffect10(() => {
|
|
12470
|
-
const
|
|
12738
|
+
const flushPanMove = () => {
|
|
12471
12739
|
const pan = panStateRef.current;
|
|
12472
12740
|
if (!pan?.active) return;
|
|
12741
|
+
pan.frameId = null;
|
|
12473
12742
|
const container = scrollContainerRef.current;
|
|
12474
12743
|
if (!container) return;
|
|
12475
|
-
|
|
12476
|
-
|
|
12744
|
+
const maxScrollLeft = Math.max(0, container.scrollWidth - container.clientWidth);
|
|
12745
|
+
const maxScrollTop = Math.max(0, container.scrollHeight - container.clientHeight);
|
|
12746
|
+
const nextScrollLeft = clampScrollValue(pan.scrollX - (pan.currentX - pan.startX), maxScrollLeft);
|
|
12747
|
+
const nextScrollTop = clampScrollValue(pan.scrollY - (pan.currentY - pan.startY), maxScrollTop);
|
|
12748
|
+
if (Math.abs(container.scrollLeft - nextScrollLeft) > 0.5) {
|
|
12749
|
+
container.scrollLeft = nextScrollLeft;
|
|
12750
|
+
}
|
|
12751
|
+
if (Math.abs(container.scrollTop - nextScrollTop) > 0.5) {
|
|
12752
|
+
container.scrollTop = nextScrollTop;
|
|
12753
|
+
}
|
|
12754
|
+
};
|
|
12755
|
+
const handlePanMove = (e) => {
|
|
12756
|
+
const pan = panStateRef.current;
|
|
12757
|
+
if (!pan?.active) return;
|
|
12758
|
+
pan.currentX = e.clientX;
|
|
12759
|
+
pan.currentY = e.clientY;
|
|
12760
|
+
if (pan.frameId !== null) return;
|
|
12761
|
+
pan.frameId = window.requestAnimationFrame(flushPanMove);
|
|
12477
12762
|
};
|
|
12478
12763
|
const handlePanEnd = () => {
|
|
12479
|
-
|
|
12764
|
+
const pan = panStateRef.current;
|
|
12765
|
+
if (!pan?.active) return;
|
|
12766
|
+
if (pan.frameId !== null) {
|
|
12767
|
+
window.cancelAnimationFrame(pan.frameId);
|
|
12768
|
+
}
|
|
12480
12769
|
panStateRef.current = null;
|
|
12481
12770
|
const container = scrollContainerRef.current;
|
|
12482
12771
|
if (container) container.style.cursor = "";
|
|
@@ -12603,7 +12892,10 @@ function TaskGanttChartInner(props, ref) {
|
|
|
12603
12892
|
onTasksChange: handleTaskChange,
|
|
12604
12893
|
onCellCommit: onPlanFactCellCommit,
|
|
12605
12894
|
highlightedTaskIds: taskListHighlightedTaskIds,
|
|
12606
|
-
filterMode
|
|
12895
|
+
filterMode,
|
|
12896
|
+
visibleRowIndices: visibleTaskWindowIndices,
|
|
12897
|
+
visibleDateIndices: visiblePlanFactDateIndices,
|
|
12898
|
+
todayDateIndex: todayInRange ? todayIndex : void 0
|
|
12607
12899
|
}
|
|
12608
12900
|
) : /* @__PURE__ */ jsxs15(Fragment4, { children: [
|
|
12609
12901
|
/* @__PURE__ */ jsxs15(
|