gantt-task-react-v 1.3.0 → 1.3.2
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/gantt-task-react.es.js +326 -1
- package/dist/gantt-task-react.umd.js +326 -1
- package/dist/helpers/use-incremental-coordinates.d.ts +17 -0
- package/dist/helpers/use-memory-management.d.ts +122 -0
- package/dist/helpers/use-optimized-data-structures.d.ts +24 -0
- package/dist/helpers/use-optimized-svg-rendering.d.ts +117 -0
- package/dist/helpers/use-performance-monitor.d.ts +106 -0
- package/dist/helpers/use-progressive-loading.d.ts +63 -0
- package/dist/helpers/use-spatial-dependency-map.d.ts +49 -0
- package/dist/helpers/use-web-worker.d.ts +50 -0
- package/package.json +7 -5
|
@@ -17486,6 +17486,308 @@ const useHorizontalScrollbars = () => {
|
|
|
17486
17486
|
scrollToRightStep
|
|
17487
17487
|
];
|
|
17488
17488
|
};
|
|
17489
|
+
const usePerformanceMonitor = (enabled = true) => {
|
|
17490
|
+
const metricsRef = useRef([]);
|
|
17491
|
+
const benchmarksRef = useRef(/* @__PURE__ */ new Map());
|
|
17492
|
+
const frameTimesRef = useRef([]);
|
|
17493
|
+
const lastFrameTimeRef = useRef(performance.now());
|
|
17494
|
+
const updateFPS = useCallback(() => {
|
|
17495
|
+
if (!enabled)
|
|
17496
|
+
return;
|
|
17497
|
+
const now = performance.now();
|
|
17498
|
+
const deltaTime = now - lastFrameTimeRef.current;
|
|
17499
|
+
lastFrameTimeRef.current = now;
|
|
17500
|
+
frameTimesRef.current.push(deltaTime);
|
|
17501
|
+
if (frameTimesRef.current.length > 60) {
|
|
17502
|
+
frameTimesRef.current.shift();
|
|
17503
|
+
}
|
|
17504
|
+
}, [enabled]);
|
|
17505
|
+
const getFPS = useCallback(() => {
|
|
17506
|
+
if (frameTimesRef.current.length === 0)
|
|
17507
|
+
return 0;
|
|
17508
|
+
const avgFrameTime = frameTimesRef.current.reduce((sum, time) => sum + time, 0) / frameTimesRef.current.length;
|
|
17509
|
+
return Math.round(1e3 / avgFrameTime);
|
|
17510
|
+
}, []);
|
|
17511
|
+
const startMeasurement = useCallback(
|
|
17512
|
+
(name, metadata) => {
|
|
17513
|
+
if (!enabled)
|
|
17514
|
+
return;
|
|
17515
|
+
performance.mark(`${name}-start`);
|
|
17516
|
+
benchmarksRef.current.set(name, {
|
|
17517
|
+
name,
|
|
17518
|
+
startTime: performance.now(),
|
|
17519
|
+
metadata
|
|
17520
|
+
});
|
|
17521
|
+
},
|
|
17522
|
+
[enabled]
|
|
17523
|
+
);
|
|
17524
|
+
const endMeasurement = useCallback(
|
|
17525
|
+
(name) => {
|
|
17526
|
+
if (!enabled)
|
|
17527
|
+
return 0;
|
|
17528
|
+
const benchmark = benchmarksRef.current.get(name);
|
|
17529
|
+
if (!benchmark) {
|
|
17530
|
+
console.warn(`No benchmark found for ${name}`);
|
|
17531
|
+
return 0;
|
|
17532
|
+
}
|
|
17533
|
+
const endTime = performance.now();
|
|
17534
|
+
const duration = endTime - benchmark.startTime;
|
|
17535
|
+
performance.mark(`${name}-end`);
|
|
17536
|
+
performance.measure(name, `${name}-start`, `${name}-end`);
|
|
17537
|
+
benchmark.endTime = endTime;
|
|
17538
|
+
benchmark.duration = duration;
|
|
17539
|
+
return duration;
|
|
17540
|
+
},
|
|
17541
|
+
[enabled]
|
|
17542
|
+
);
|
|
17543
|
+
const measureFunction = useCallback(
|
|
17544
|
+
(name, fn, metadata) => {
|
|
17545
|
+
return (...args) => {
|
|
17546
|
+
if (!enabled)
|
|
17547
|
+
return fn(...args);
|
|
17548
|
+
startMeasurement(name, metadata);
|
|
17549
|
+
try {
|
|
17550
|
+
const result = fn(...args);
|
|
17551
|
+
return result;
|
|
17552
|
+
} finally {
|
|
17553
|
+
endMeasurement(name);
|
|
17554
|
+
}
|
|
17555
|
+
};
|
|
17556
|
+
},
|
|
17557
|
+
[enabled, startMeasurement, endMeasurement]
|
|
17558
|
+
);
|
|
17559
|
+
const measureAsyncFunction = useCallback(
|
|
17560
|
+
(name, fn, metadata) => {
|
|
17561
|
+
return async (...args) => {
|
|
17562
|
+
if (!enabled)
|
|
17563
|
+
return fn(...args);
|
|
17564
|
+
startMeasurement(name, metadata);
|
|
17565
|
+
try {
|
|
17566
|
+
const result = await fn(...args);
|
|
17567
|
+
return result;
|
|
17568
|
+
} finally {
|
|
17569
|
+
endMeasurement(name);
|
|
17570
|
+
}
|
|
17571
|
+
};
|
|
17572
|
+
},
|
|
17573
|
+
[enabled, startMeasurement, endMeasurement]
|
|
17574
|
+
);
|
|
17575
|
+
const getPerformanceReport = useCallback(() => {
|
|
17576
|
+
const entries = performance.getEntriesByType(
|
|
17577
|
+
"measure"
|
|
17578
|
+
);
|
|
17579
|
+
const report = {};
|
|
17580
|
+
entries.forEach((entry) => {
|
|
17581
|
+
if (!report[entry.name]) {
|
|
17582
|
+
report[entry.name] = {
|
|
17583
|
+
count: 0,
|
|
17584
|
+
totalTime: 0,
|
|
17585
|
+
avgTime: 0,
|
|
17586
|
+
maxTime: 0,
|
|
17587
|
+
minTime: Infinity
|
|
17588
|
+
};
|
|
17589
|
+
}
|
|
17590
|
+
const stat = report[entry.name];
|
|
17591
|
+
stat.count++;
|
|
17592
|
+
stat.totalTime += entry.duration;
|
|
17593
|
+
stat.maxTime = Math.max(stat.maxTime, entry.duration);
|
|
17594
|
+
stat.minTime = Math.min(stat.minTime, entry.duration);
|
|
17595
|
+
stat.avgTime = stat.totalTime / stat.count;
|
|
17596
|
+
});
|
|
17597
|
+
return {
|
|
17598
|
+
measurements: report,
|
|
17599
|
+
fps: getFPS(),
|
|
17600
|
+
currentMetrics: metricsRef.current[metricsRef.current.length - 1],
|
|
17601
|
+
allMetrics: [...metricsRef.current]
|
|
17602
|
+
};
|
|
17603
|
+
}, [getFPS]);
|
|
17604
|
+
const addMetrics = useCallback(
|
|
17605
|
+
(metrics) => {
|
|
17606
|
+
if (!enabled)
|
|
17607
|
+
return;
|
|
17608
|
+
const fullMetrics = {
|
|
17609
|
+
...metrics,
|
|
17610
|
+
timestamp: Date.now()
|
|
17611
|
+
};
|
|
17612
|
+
metricsRef.current.push(fullMetrics);
|
|
17613
|
+
if (metricsRef.current.length > 100) {
|
|
17614
|
+
metricsRef.current.shift();
|
|
17615
|
+
}
|
|
17616
|
+
},
|
|
17617
|
+
[enabled]
|
|
17618
|
+
);
|
|
17619
|
+
const clearMeasurements = useCallback(() => {
|
|
17620
|
+
performance.clearMarks();
|
|
17621
|
+
performance.clearMeasures();
|
|
17622
|
+
benchmarksRef.current.clear();
|
|
17623
|
+
metricsRef.current.length = 0;
|
|
17624
|
+
frameTimesRef.current.length = 0;
|
|
17625
|
+
}, []);
|
|
17626
|
+
const getMemoryUsage = useCallback(() => {
|
|
17627
|
+
if ("memory" in performance) {
|
|
17628
|
+
const memory = performance.memory;
|
|
17629
|
+
return memory ? memory.usedJSHeapSize : 0;
|
|
17630
|
+
}
|
|
17631
|
+
return 0;
|
|
17632
|
+
}, []);
|
|
17633
|
+
return {
|
|
17634
|
+
startMeasurement,
|
|
17635
|
+
endMeasurement,
|
|
17636
|
+
measureFunction,
|
|
17637
|
+
measureAsyncFunction,
|
|
17638
|
+
getPerformanceReport,
|
|
17639
|
+
addMetrics,
|
|
17640
|
+
clearMeasurements,
|
|
17641
|
+
updateFPS,
|
|
17642
|
+
getFPS,
|
|
17643
|
+
getMemoryUsage,
|
|
17644
|
+
enabled
|
|
17645
|
+
};
|
|
17646
|
+
};
|
|
17647
|
+
const useAdaptivePerformance = (thresholds) => {
|
|
17648
|
+
const { getFPS, getPerformanceReport } = usePerformanceMonitor();
|
|
17649
|
+
const performanceLevelRef = useRef("high");
|
|
17650
|
+
const updatePerformanceLevel = useCallback(() => {
|
|
17651
|
+
var _a;
|
|
17652
|
+
const fps = getFPS();
|
|
17653
|
+
const report = getPerformanceReport();
|
|
17654
|
+
const renderTime = ((_a = report.measurements["render"]) == null ? void 0 : _a.avgTime) || 0;
|
|
17655
|
+
if (fps < thresholds.fpsThreshold * 0.5 || renderTime > thresholds.renderTimeThreshold * 2) {
|
|
17656
|
+
performanceLevelRef.current = "low";
|
|
17657
|
+
} else if (fps < thresholds.fpsThreshold || renderTime > thresholds.renderTimeThreshold) {
|
|
17658
|
+
performanceLevelRef.current = "medium";
|
|
17659
|
+
} else {
|
|
17660
|
+
performanceLevelRef.current = "high";
|
|
17661
|
+
}
|
|
17662
|
+
return performanceLevelRef.current;
|
|
17663
|
+
}, [getFPS, getPerformanceReport, thresholds]);
|
|
17664
|
+
const getQualitySettings = useCallback(() => {
|
|
17665
|
+
const level = performanceLevelRef.current;
|
|
17666
|
+
switch (level) {
|
|
17667
|
+
case "low":
|
|
17668
|
+
return {
|
|
17669
|
+
enableAnimations: false,
|
|
17670
|
+
renderQuality: "low",
|
|
17671
|
+
maxVisibleTasks: 100,
|
|
17672
|
+
updateFrequency: 500
|
|
17673
|
+
// ms
|
|
17674
|
+
};
|
|
17675
|
+
case "medium":
|
|
17676
|
+
return {
|
|
17677
|
+
enableAnimations: true,
|
|
17678
|
+
renderQuality: "medium",
|
|
17679
|
+
maxVisibleTasks: 500,
|
|
17680
|
+
updateFrequency: 100
|
|
17681
|
+
};
|
|
17682
|
+
case "high":
|
|
17683
|
+
default:
|
|
17684
|
+
return {
|
|
17685
|
+
enableAnimations: true,
|
|
17686
|
+
renderQuality: "high",
|
|
17687
|
+
maxVisibleTasks: 1e3,
|
|
17688
|
+
updateFrequency: 16
|
|
17689
|
+
// 60fps
|
|
17690
|
+
};
|
|
17691
|
+
}
|
|
17692
|
+
}, []);
|
|
17693
|
+
return {
|
|
17694
|
+
performanceLevel: performanceLevelRef.current,
|
|
17695
|
+
updatePerformanceLevel,
|
|
17696
|
+
getQualitySettings
|
|
17697
|
+
};
|
|
17698
|
+
};
|
|
17699
|
+
const useIncrementalCoordinates = (visibleTasks, visibleTasksMirror, taskToRowIndexMap, startDate, viewMode, rtl, fullRowHeight, taskHeight, taskYOffset, distances, svgWidth, renderedRowIndexes, renderedColumnIndexes) => {
|
|
17700
|
+
const cacheRef = useRef({
|
|
17701
|
+
coordinates: /* @__PURE__ */ new Map(),
|
|
17702
|
+
lastUpdateParams: null
|
|
17703
|
+
});
|
|
17704
|
+
return useMemo(() => {
|
|
17705
|
+
const cache = cacheRef.current;
|
|
17706
|
+
const currentParams = {
|
|
17707
|
+
startDate,
|
|
17708
|
+
viewMode,
|
|
17709
|
+
rtl,
|
|
17710
|
+
fullRowHeight,
|
|
17711
|
+
taskHeight,
|
|
17712
|
+
taskYOffset,
|
|
17713
|
+
svgWidth,
|
|
17714
|
+
distances
|
|
17715
|
+
};
|
|
17716
|
+
const needsFullRecalc = !cache.lastUpdateParams || cache.lastUpdateParams.startDate.getTime() !== startDate.getTime() || cache.lastUpdateParams.viewMode !== viewMode || cache.lastUpdateParams.rtl !== rtl || cache.lastUpdateParams.fullRowHeight !== fullRowHeight || cache.lastUpdateParams.taskHeight !== taskHeight || cache.lastUpdateParams.taskYOffset !== taskYOffset || cache.lastUpdateParams.svgWidth !== svgWidth || JSON.stringify(cache.lastUpdateParams.distances) !== JSON.stringify(distances);
|
|
17717
|
+
if (needsFullRecalc) {
|
|
17718
|
+
cache.coordinates.clear();
|
|
17719
|
+
}
|
|
17720
|
+
const tasksToCalculate = /* @__PURE__ */ new Set();
|
|
17721
|
+
if (renderedRowIndexes && renderedColumnIndexes) {
|
|
17722
|
+
const [startRow, endRow] = renderedRowIndexes;
|
|
17723
|
+
const rowBuffer = Math.max(5, Math.ceil((endRow - startRow) * 0.5));
|
|
17724
|
+
const bufferedStartRow = Math.max(0, startRow - rowBuffer);
|
|
17725
|
+
const bufferedEndRow = endRow + rowBuffer;
|
|
17726
|
+
visibleTasks.forEach((task, index2) => {
|
|
17727
|
+
if (task.type === "empty" || !visibleTasksMirror[task.id])
|
|
17728
|
+
return;
|
|
17729
|
+
if (index2 >= bufferedStartRow && index2 <= bufferedEndRow) {
|
|
17730
|
+
tasksToCalculate.add(task.id);
|
|
17731
|
+
}
|
|
17732
|
+
});
|
|
17733
|
+
} else {
|
|
17734
|
+
visibleTasks.forEach((task) => {
|
|
17735
|
+
if (task.type !== "empty" && visibleTasksMirror[task.id]) {
|
|
17736
|
+
tasksToCalculate.add(task.id);
|
|
17737
|
+
}
|
|
17738
|
+
});
|
|
17739
|
+
}
|
|
17740
|
+
if (!needsFullRecalc) {
|
|
17741
|
+
for (const [taskId] of cache.coordinates) {
|
|
17742
|
+
if (!tasksToCalculate.has(taskId)) {
|
|
17743
|
+
cache.coordinates.delete(taskId);
|
|
17744
|
+
}
|
|
17745
|
+
}
|
|
17746
|
+
}
|
|
17747
|
+
const res = /* @__PURE__ */ new Map();
|
|
17748
|
+
visibleTasks.forEach((task) => {
|
|
17749
|
+
if (task.type === "empty" || !tasksToCalculate.has(task.id))
|
|
17750
|
+
return;
|
|
17751
|
+
const { id, comparisonLevel = 1 } = task;
|
|
17752
|
+
const cacheKey = `${id}_${comparisonLevel}`;
|
|
17753
|
+
let taskCoordinates = cache.coordinates.get(cacheKey);
|
|
17754
|
+
if (!taskCoordinates || needsFullRecalc) {
|
|
17755
|
+
taskCoordinates = countTaskCoordinates(
|
|
17756
|
+
task,
|
|
17757
|
+
taskToRowIndexMap,
|
|
17758
|
+
startDate,
|
|
17759
|
+
viewMode,
|
|
17760
|
+
rtl,
|
|
17761
|
+
fullRowHeight,
|
|
17762
|
+
taskHeight,
|
|
17763
|
+
taskYOffset,
|
|
17764
|
+
distances,
|
|
17765
|
+
svgWidth
|
|
17766
|
+
);
|
|
17767
|
+
cache.coordinates.set(cacheKey, taskCoordinates);
|
|
17768
|
+
}
|
|
17769
|
+
const resByLevel = res.get(comparisonLevel) || /* @__PURE__ */ new Map();
|
|
17770
|
+
resByLevel.set(id, taskCoordinates);
|
|
17771
|
+
res.set(comparisonLevel, resByLevel);
|
|
17772
|
+
});
|
|
17773
|
+
cache.lastUpdateParams = currentParams;
|
|
17774
|
+
return res;
|
|
17775
|
+
}, [
|
|
17776
|
+
visibleTasks,
|
|
17777
|
+
visibleTasksMirror,
|
|
17778
|
+
taskToRowIndexMap,
|
|
17779
|
+
startDate,
|
|
17780
|
+
viewMode,
|
|
17781
|
+
rtl,
|
|
17782
|
+
fullRowHeight,
|
|
17783
|
+
taskHeight,
|
|
17784
|
+
taskYOffset,
|
|
17785
|
+
distances,
|
|
17786
|
+
svgWidth,
|
|
17787
|
+
renderedRowIndexes,
|
|
17788
|
+
renderedColumnIndexes
|
|
17789
|
+
]);
|
|
17790
|
+
};
|
|
17489
17791
|
const fillMinAndMaxChildsMap = (resOnLevel, task, childTasksOnLevel) => {
|
|
17490
17792
|
const childs = childTasksOnLevel.get(task.id);
|
|
17491
17793
|
if (!childs || childs.length === 0) {
|
|
@@ -19105,6 +19407,11 @@ const Gantt = (props) => {
|
|
|
19105
19407
|
() => getChildsAndRoots(sortedTasks, null),
|
|
19106
19408
|
[sortedTasks]
|
|
19107
19409
|
);
|
|
19410
|
+
const adaptiveSettings = useAdaptivePerformance({
|
|
19411
|
+
fpsThreshold: 30,
|
|
19412
|
+
renderTimeThreshold: 16
|
|
19413
|
+
// 60fps = 16ms per frame
|
|
19414
|
+
});
|
|
19108
19415
|
const minAndMaxChildsMap = useMemo(
|
|
19109
19416
|
() => getMinAndMaxChildsMap(rootTasksMap, childTasksMap),
|
|
19110
19417
|
[rootTasksMap, childTasksMap]
|
|
@@ -19278,7 +19585,7 @@ const Gantt = (props) => {
|
|
|
19278
19585
|
svgWidth
|
|
19279
19586
|
]
|
|
19280
19587
|
);
|
|
19281
|
-
const
|
|
19588
|
+
const originalMapTaskToCoordinates = useMemo(
|
|
19282
19589
|
() => getMapTaskToCoordinates(
|
|
19283
19590
|
sortedTasks,
|
|
19284
19591
|
visibleTasksMirror,
|
|
@@ -19306,6 +19613,24 @@ const Gantt = (props) => {
|
|
|
19306
19613
|
visibleTasksMirror
|
|
19307
19614
|
]
|
|
19308
19615
|
);
|
|
19616
|
+
const optimizedMapTaskToCoordinates = useIncrementalCoordinates(
|
|
19617
|
+
visibleTasks,
|
|
19618
|
+
visibleTasksMirror,
|
|
19619
|
+
taskToRowIndexMap,
|
|
19620
|
+
startDate,
|
|
19621
|
+
viewMode,
|
|
19622
|
+
rtl,
|
|
19623
|
+
fullRowHeight,
|
|
19624
|
+
taskHeight,
|
|
19625
|
+
taskYOffset,
|
|
19626
|
+
distances,
|
|
19627
|
+
svgWidth,
|
|
19628
|
+
null,
|
|
19629
|
+
// renderedRowIndexes - can be integrated later with virtualization
|
|
19630
|
+
null
|
|
19631
|
+
// renderedColumnIndexes - can be integrated later with virtualization
|
|
19632
|
+
);
|
|
19633
|
+
const mapTaskToCoordinates = adaptiveSettings.performanceLevel === "high" ? optimizedMapTaskToCoordinates : originalMapTaskToCoordinates;
|
|
19309
19634
|
const scrollToTask = useCallback(
|
|
19310
19635
|
(task) => {
|
|
19311
19636
|
const { x1 } = getTaskCoordinates(task, mapTaskToCoordinates);
|
|
@@ -17503,6 +17503,308 @@
|
|
|
17503
17503
|
scrollToRightStep
|
|
17504
17504
|
];
|
|
17505
17505
|
};
|
|
17506
|
+
const usePerformanceMonitor = (enabled = true) => {
|
|
17507
|
+
const metricsRef = React.useRef([]);
|
|
17508
|
+
const benchmarksRef = React.useRef(/* @__PURE__ */ new Map());
|
|
17509
|
+
const frameTimesRef = React.useRef([]);
|
|
17510
|
+
const lastFrameTimeRef = React.useRef(performance.now());
|
|
17511
|
+
const updateFPS = React.useCallback(() => {
|
|
17512
|
+
if (!enabled)
|
|
17513
|
+
return;
|
|
17514
|
+
const now = performance.now();
|
|
17515
|
+
const deltaTime = now - lastFrameTimeRef.current;
|
|
17516
|
+
lastFrameTimeRef.current = now;
|
|
17517
|
+
frameTimesRef.current.push(deltaTime);
|
|
17518
|
+
if (frameTimesRef.current.length > 60) {
|
|
17519
|
+
frameTimesRef.current.shift();
|
|
17520
|
+
}
|
|
17521
|
+
}, [enabled]);
|
|
17522
|
+
const getFPS = React.useCallback(() => {
|
|
17523
|
+
if (frameTimesRef.current.length === 0)
|
|
17524
|
+
return 0;
|
|
17525
|
+
const avgFrameTime = frameTimesRef.current.reduce((sum, time) => sum + time, 0) / frameTimesRef.current.length;
|
|
17526
|
+
return Math.round(1e3 / avgFrameTime);
|
|
17527
|
+
}, []);
|
|
17528
|
+
const startMeasurement = React.useCallback(
|
|
17529
|
+
(name, metadata) => {
|
|
17530
|
+
if (!enabled)
|
|
17531
|
+
return;
|
|
17532
|
+
performance.mark(`${name}-start`);
|
|
17533
|
+
benchmarksRef.current.set(name, {
|
|
17534
|
+
name,
|
|
17535
|
+
startTime: performance.now(),
|
|
17536
|
+
metadata
|
|
17537
|
+
});
|
|
17538
|
+
},
|
|
17539
|
+
[enabled]
|
|
17540
|
+
);
|
|
17541
|
+
const endMeasurement = React.useCallback(
|
|
17542
|
+
(name) => {
|
|
17543
|
+
if (!enabled)
|
|
17544
|
+
return 0;
|
|
17545
|
+
const benchmark = benchmarksRef.current.get(name);
|
|
17546
|
+
if (!benchmark) {
|
|
17547
|
+
console.warn(`No benchmark found for ${name}`);
|
|
17548
|
+
return 0;
|
|
17549
|
+
}
|
|
17550
|
+
const endTime = performance.now();
|
|
17551
|
+
const duration = endTime - benchmark.startTime;
|
|
17552
|
+
performance.mark(`${name}-end`);
|
|
17553
|
+
performance.measure(name, `${name}-start`, `${name}-end`);
|
|
17554
|
+
benchmark.endTime = endTime;
|
|
17555
|
+
benchmark.duration = duration;
|
|
17556
|
+
return duration;
|
|
17557
|
+
},
|
|
17558
|
+
[enabled]
|
|
17559
|
+
);
|
|
17560
|
+
const measureFunction = React.useCallback(
|
|
17561
|
+
(name, fn, metadata) => {
|
|
17562
|
+
return (...args) => {
|
|
17563
|
+
if (!enabled)
|
|
17564
|
+
return fn(...args);
|
|
17565
|
+
startMeasurement(name, metadata);
|
|
17566
|
+
try {
|
|
17567
|
+
const result = fn(...args);
|
|
17568
|
+
return result;
|
|
17569
|
+
} finally {
|
|
17570
|
+
endMeasurement(name);
|
|
17571
|
+
}
|
|
17572
|
+
};
|
|
17573
|
+
},
|
|
17574
|
+
[enabled, startMeasurement, endMeasurement]
|
|
17575
|
+
);
|
|
17576
|
+
const measureAsyncFunction = React.useCallback(
|
|
17577
|
+
(name, fn, metadata) => {
|
|
17578
|
+
return async (...args) => {
|
|
17579
|
+
if (!enabled)
|
|
17580
|
+
return fn(...args);
|
|
17581
|
+
startMeasurement(name, metadata);
|
|
17582
|
+
try {
|
|
17583
|
+
const result = await fn(...args);
|
|
17584
|
+
return result;
|
|
17585
|
+
} finally {
|
|
17586
|
+
endMeasurement(name);
|
|
17587
|
+
}
|
|
17588
|
+
};
|
|
17589
|
+
},
|
|
17590
|
+
[enabled, startMeasurement, endMeasurement]
|
|
17591
|
+
);
|
|
17592
|
+
const getPerformanceReport = React.useCallback(() => {
|
|
17593
|
+
const entries = performance.getEntriesByType(
|
|
17594
|
+
"measure"
|
|
17595
|
+
);
|
|
17596
|
+
const report = {};
|
|
17597
|
+
entries.forEach((entry) => {
|
|
17598
|
+
if (!report[entry.name]) {
|
|
17599
|
+
report[entry.name] = {
|
|
17600
|
+
count: 0,
|
|
17601
|
+
totalTime: 0,
|
|
17602
|
+
avgTime: 0,
|
|
17603
|
+
maxTime: 0,
|
|
17604
|
+
minTime: Infinity
|
|
17605
|
+
};
|
|
17606
|
+
}
|
|
17607
|
+
const stat = report[entry.name];
|
|
17608
|
+
stat.count++;
|
|
17609
|
+
stat.totalTime += entry.duration;
|
|
17610
|
+
stat.maxTime = Math.max(stat.maxTime, entry.duration);
|
|
17611
|
+
stat.minTime = Math.min(stat.minTime, entry.duration);
|
|
17612
|
+
stat.avgTime = stat.totalTime / stat.count;
|
|
17613
|
+
});
|
|
17614
|
+
return {
|
|
17615
|
+
measurements: report,
|
|
17616
|
+
fps: getFPS(),
|
|
17617
|
+
currentMetrics: metricsRef.current[metricsRef.current.length - 1],
|
|
17618
|
+
allMetrics: [...metricsRef.current]
|
|
17619
|
+
};
|
|
17620
|
+
}, [getFPS]);
|
|
17621
|
+
const addMetrics = React.useCallback(
|
|
17622
|
+
(metrics) => {
|
|
17623
|
+
if (!enabled)
|
|
17624
|
+
return;
|
|
17625
|
+
const fullMetrics = {
|
|
17626
|
+
...metrics,
|
|
17627
|
+
timestamp: Date.now()
|
|
17628
|
+
};
|
|
17629
|
+
metricsRef.current.push(fullMetrics);
|
|
17630
|
+
if (metricsRef.current.length > 100) {
|
|
17631
|
+
metricsRef.current.shift();
|
|
17632
|
+
}
|
|
17633
|
+
},
|
|
17634
|
+
[enabled]
|
|
17635
|
+
);
|
|
17636
|
+
const clearMeasurements = React.useCallback(() => {
|
|
17637
|
+
performance.clearMarks();
|
|
17638
|
+
performance.clearMeasures();
|
|
17639
|
+
benchmarksRef.current.clear();
|
|
17640
|
+
metricsRef.current.length = 0;
|
|
17641
|
+
frameTimesRef.current.length = 0;
|
|
17642
|
+
}, []);
|
|
17643
|
+
const getMemoryUsage = React.useCallback(() => {
|
|
17644
|
+
if ("memory" in performance) {
|
|
17645
|
+
const memory = performance.memory;
|
|
17646
|
+
return memory ? memory.usedJSHeapSize : 0;
|
|
17647
|
+
}
|
|
17648
|
+
return 0;
|
|
17649
|
+
}, []);
|
|
17650
|
+
return {
|
|
17651
|
+
startMeasurement,
|
|
17652
|
+
endMeasurement,
|
|
17653
|
+
measureFunction,
|
|
17654
|
+
measureAsyncFunction,
|
|
17655
|
+
getPerformanceReport,
|
|
17656
|
+
addMetrics,
|
|
17657
|
+
clearMeasurements,
|
|
17658
|
+
updateFPS,
|
|
17659
|
+
getFPS,
|
|
17660
|
+
getMemoryUsage,
|
|
17661
|
+
enabled
|
|
17662
|
+
};
|
|
17663
|
+
};
|
|
17664
|
+
const useAdaptivePerformance = (thresholds) => {
|
|
17665
|
+
const { getFPS, getPerformanceReport } = usePerformanceMonitor();
|
|
17666
|
+
const performanceLevelRef = React.useRef("high");
|
|
17667
|
+
const updatePerformanceLevel = React.useCallback(() => {
|
|
17668
|
+
var _a;
|
|
17669
|
+
const fps = getFPS();
|
|
17670
|
+
const report = getPerformanceReport();
|
|
17671
|
+
const renderTime = ((_a = report.measurements["render"]) == null ? void 0 : _a.avgTime) || 0;
|
|
17672
|
+
if (fps < thresholds.fpsThreshold * 0.5 || renderTime > thresholds.renderTimeThreshold * 2) {
|
|
17673
|
+
performanceLevelRef.current = "low";
|
|
17674
|
+
} else if (fps < thresholds.fpsThreshold || renderTime > thresholds.renderTimeThreshold) {
|
|
17675
|
+
performanceLevelRef.current = "medium";
|
|
17676
|
+
} else {
|
|
17677
|
+
performanceLevelRef.current = "high";
|
|
17678
|
+
}
|
|
17679
|
+
return performanceLevelRef.current;
|
|
17680
|
+
}, [getFPS, getPerformanceReport, thresholds]);
|
|
17681
|
+
const getQualitySettings = React.useCallback(() => {
|
|
17682
|
+
const level = performanceLevelRef.current;
|
|
17683
|
+
switch (level) {
|
|
17684
|
+
case "low":
|
|
17685
|
+
return {
|
|
17686
|
+
enableAnimations: false,
|
|
17687
|
+
renderQuality: "low",
|
|
17688
|
+
maxVisibleTasks: 100,
|
|
17689
|
+
updateFrequency: 500
|
|
17690
|
+
// ms
|
|
17691
|
+
};
|
|
17692
|
+
case "medium":
|
|
17693
|
+
return {
|
|
17694
|
+
enableAnimations: true,
|
|
17695
|
+
renderQuality: "medium",
|
|
17696
|
+
maxVisibleTasks: 500,
|
|
17697
|
+
updateFrequency: 100
|
|
17698
|
+
};
|
|
17699
|
+
case "high":
|
|
17700
|
+
default:
|
|
17701
|
+
return {
|
|
17702
|
+
enableAnimations: true,
|
|
17703
|
+
renderQuality: "high",
|
|
17704
|
+
maxVisibleTasks: 1e3,
|
|
17705
|
+
updateFrequency: 16
|
|
17706
|
+
// 60fps
|
|
17707
|
+
};
|
|
17708
|
+
}
|
|
17709
|
+
}, []);
|
|
17710
|
+
return {
|
|
17711
|
+
performanceLevel: performanceLevelRef.current,
|
|
17712
|
+
updatePerformanceLevel,
|
|
17713
|
+
getQualitySettings
|
|
17714
|
+
};
|
|
17715
|
+
};
|
|
17716
|
+
const useIncrementalCoordinates = (visibleTasks, visibleTasksMirror, taskToRowIndexMap, startDate, viewMode, rtl, fullRowHeight, taskHeight, taskYOffset, distances, svgWidth, renderedRowIndexes, renderedColumnIndexes) => {
|
|
17717
|
+
const cacheRef = React.useRef({
|
|
17718
|
+
coordinates: /* @__PURE__ */ new Map(),
|
|
17719
|
+
lastUpdateParams: null
|
|
17720
|
+
});
|
|
17721
|
+
return React.useMemo(() => {
|
|
17722
|
+
const cache = cacheRef.current;
|
|
17723
|
+
const currentParams = {
|
|
17724
|
+
startDate,
|
|
17725
|
+
viewMode,
|
|
17726
|
+
rtl,
|
|
17727
|
+
fullRowHeight,
|
|
17728
|
+
taskHeight,
|
|
17729
|
+
taskYOffset,
|
|
17730
|
+
svgWidth,
|
|
17731
|
+
distances
|
|
17732
|
+
};
|
|
17733
|
+
const needsFullRecalc = !cache.lastUpdateParams || cache.lastUpdateParams.startDate.getTime() !== startDate.getTime() || cache.lastUpdateParams.viewMode !== viewMode || cache.lastUpdateParams.rtl !== rtl || cache.lastUpdateParams.fullRowHeight !== fullRowHeight || cache.lastUpdateParams.taskHeight !== taskHeight || cache.lastUpdateParams.taskYOffset !== taskYOffset || cache.lastUpdateParams.svgWidth !== svgWidth || JSON.stringify(cache.lastUpdateParams.distances) !== JSON.stringify(distances);
|
|
17734
|
+
if (needsFullRecalc) {
|
|
17735
|
+
cache.coordinates.clear();
|
|
17736
|
+
}
|
|
17737
|
+
const tasksToCalculate = /* @__PURE__ */ new Set();
|
|
17738
|
+
if (renderedRowIndexes && renderedColumnIndexes) {
|
|
17739
|
+
const [startRow, endRow] = renderedRowIndexes;
|
|
17740
|
+
const rowBuffer = Math.max(5, Math.ceil((endRow - startRow) * 0.5));
|
|
17741
|
+
const bufferedStartRow = Math.max(0, startRow - rowBuffer);
|
|
17742
|
+
const bufferedEndRow = endRow + rowBuffer;
|
|
17743
|
+
visibleTasks.forEach((task, index2) => {
|
|
17744
|
+
if (task.type === "empty" || !visibleTasksMirror[task.id])
|
|
17745
|
+
return;
|
|
17746
|
+
if (index2 >= bufferedStartRow && index2 <= bufferedEndRow) {
|
|
17747
|
+
tasksToCalculate.add(task.id);
|
|
17748
|
+
}
|
|
17749
|
+
});
|
|
17750
|
+
} else {
|
|
17751
|
+
visibleTasks.forEach((task) => {
|
|
17752
|
+
if (task.type !== "empty" && visibleTasksMirror[task.id]) {
|
|
17753
|
+
tasksToCalculate.add(task.id);
|
|
17754
|
+
}
|
|
17755
|
+
});
|
|
17756
|
+
}
|
|
17757
|
+
if (!needsFullRecalc) {
|
|
17758
|
+
for (const [taskId] of cache.coordinates) {
|
|
17759
|
+
if (!tasksToCalculate.has(taskId)) {
|
|
17760
|
+
cache.coordinates.delete(taskId);
|
|
17761
|
+
}
|
|
17762
|
+
}
|
|
17763
|
+
}
|
|
17764
|
+
const res = /* @__PURE__ */ new Map();
|
|
17765
|
+
visibleTasks.forEach((task) => {
|
|
17766
|
+
if (task.type === "empty" || !tasksToCalculate.has(task.id))
|
|
17767
|
+
return;
|
|
17768
|
+
const { id, comparisonLevel = 1 } = task;
|
|
17769
|
+
const cacheKey = `${id}_${comparisonLevel}`;
|
|
17770
|
+
let taskCoordinates = cache.coordinates.get(cacheKey);
|
|
17771
|
+
if (!taskCoordinates || needsFullRecalc) {
|
|
17772
|
+
taskCoordinates = countTaskCoordinates(
|
|
17773
|
+
task,
|
|
17774
|
+
taskToRowIndexMap,
|
|
17775
|
+
startDate,
|
|
17776
|
+
viewMode,
|
|
17777
|
+
rtl,
|
|
17778
|
+
fullRowHeight,
|
|
17779
|
+
taskHeight,
|
|
17780
|
+
taskYOffset,
|
|
17781
|
+
distances,
|
|
17782
|
+
svgWidth
|
|
17783
|
+
);
|
|
17784
|
+
cache.coordinates.set(cacheKey, taskCoordinates);
|
|
17785
|
+
}
|
|
17786
|
+
const resByLevel = res.get(comparisonLevel) || /* @__PURE__ */ new Map();
|
|
17787
|
+
resByLevel.set(id, taskCoordinates);
|
|
17788
|
+
res.set(comparisonLevel, resByLevel);
|
|
17789
|
+
});
|
|
17790
|
+
cache.lastUpdateParams = currentParams;
|
|
17791
|
+
return res;
|
|
17792
|
+
}, [
|
|
17793
|
+
visibleTasks,
|
|
17794
|
+
visibleTasksMirror,
|
|
17795
|
+
taskToRowIndexMap,
|
|
17796
|
+
startDate,
|
|
17797
|
+
viewMode,
|
|
17798
|
+
rtl,
|
|
17799
|
+
fullRowHeight,
|
|
17800
|
+
taskHeight,
|
|
17801
|
+
taskYOffset,
|
|
17802
|
+
distances,
|
|
17803
|
+
svgWidth,
|
|
17804
|
+
renderedRowIndexes,
|
|
17805
|
+
renderedColumnIndexes
|
|
17806
|
+
]);
|
|
17807
|
+
};
|
|
17506
17808
|
const fillMinAndMaxChildsMap = (resOnLevel, task, childTasksOnLevel) => {
|
|
17507
17809
|
const childs = childTasksOnLevel.get(task.id);
|
|
17508
17810
|
if (!childs || childs.length === 0) {
|
|
@@ -19122,6 +19424,11 @@
|
|
|
19122
19424
|
() => getChildsAndRoots(sortedTasks, null),
|
|
19123
19425
|
[sortedTasks]
|
|
19124
19426
|
);
|
|
19427
|
+
const adaptiveSettings = useAdaptivePerformance({
|
|
19428
|
+
fpsThreshold: 30,
|
|
19429
|
+
renderTimeThreshold: 16
|
|
19430
|
+
// 60fps = 16ms per frame
|
|
19431
|
+
});
|
|
19125
19432
|
const minAndMaxChildsMap = React.useMemo(
|
|
19126
19433
|
() => getMinAndMaxChildsMap(rootTasksMap, childTasksMap),
|
|
19127
19434
|
[rootTasksMap, childTasksMap]
|
|
@@ -19295,7 +19602,7 @@
|
|
|
19295
19602
|
svgWidth
|
|
19296
19603
|
]
|
|
19297
19604
|
);
|
|
19298
|
-
const
|
|
19605
|
+
const originalMapTaskToCoordinates = React.useMemo(
|
|
19299
19606
|
() => getMapTaskToCoordinates(
|
|
19300
19607
|
sortedTasks,
|
|
19301
19608
|
visibleTasksMirror,
|
|
@@ -19323,6 +19630,24 @@
|
|
|
19323
19630
|
visibleTasksMirror
|
|
19324
19631
|
]
|
|
19325
19632
|
);
|
|
19633
|
+
const optimizedMapTaskToCoordinates = useIncrementalCoordinates(
|
|
19634
|
+
visibleTasks,
|
|
19635
|
+
visibleTasksMirror,
|
|
19636
|
+
taskToRowIndexMap,
|
|
19637
|
+
startDate,
|
|
19638
|
+
viewMode,
|
|
19639
|
+
rtl,
|
|
19640
|
+
fullRowHeight,
|
|
19641
|
+
taskHeight,
|
|
19642
|
+
taskYOffset,
|
|
19643
|
+
distances,
|
|
19644
|
+
svgWidth,
|
|
19645
|
+
null,
|
|
19646
|
+
// renderedRowIndexes - can be integrated later with virtualization
|
|
19647
|
+
null
|
|
19648
|
+
// renderedColumnIndexes - can be integrated later with virtualization
|
|
19649
|
+
);
|
|
19650
|
+
const mapTaskToCoordinates = adaptiveSettings.performanceLevel === "high" ? optimizedMapTaskToCoordinates : originalMapTaskToCoordinates;
|
|
19326
19651
|
const scrollToTask = React.useCallback(
|
|
19327
19652
|
(task) => {
|
|
19328
19653
|
const { x1 } = getTaskCoordinates(task, mapTaskToCoordinates);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Distances, MapTaskToCoordinates, TaskCoordinates, RenderTask, TaskToRowIndexMap, ViewMode } from "../types";
|
|
2
|
+
import type { OptimizedListParams } from "./use-optimized-list";
|
|
3
|
+
/**
|
|
4
|
+
* Optimized hook for calculating task coordinates incrementally
|
|
5
|
+
* Only recalculates coordinates for visible tasks and caches results
|
|
6
|
+
*/
|
|
7
|
+
export declare const useIncrementalCoordinates: (visibleTasks: readonly RenderTask[], visibleTasksMirror: Readonly<Record<string, true>>, taskToRowIndexMap: TaskToRowIndexMap, startDate: Date, viewMode: ViewMode, rtl: boolean, fullRowHeight: number, taskHeight: number, taskYOffset: number, distances: Distances, svgWidth: number, renderedRowIndexes: OptimizedListParams | null, renderedColumnIndexes: OptimizedListParams | null) => MapTaskToCoordinates;
|
|
8
|
+
/**
|
|
9
|
+
* Hook for getting coordinates of tasks in a specific range only
|
|
10
|
+
* Useful for virtual scrolling scenarios
|
|
11
|
+
*/
|
|
12
|
+
export declare const useRangedCoordinates: (tasks: readonly RenderTask[], taskToRowIndexMap: TaskToRowIndexMap, startDate: Date, viewMode: ViewMode, rtl: boolean, fullRowHeight: number, taskHeight: number, taskYOffset: number, distances: Distances, svgWidth: number, startIndex: number, endIndex: number, comparisonLevel?: number) => Map<string, TaskCoordinates>;
|
|
13
|
+
/**
|
|
14
|
+
* Hook for smart coordinate invalidation
|
|
15
|
+
* Tracks which tasks need coordinate recalculation based on their dependencies
|
|
16
|
+
*/
|
|
17
|
+
export declare const useCoordinateInvalidation: (tasks: readonly RenderTask[], changedTaskIds: Set<string>) => Set<string>;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { TaskCoordinates } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* Generic object pool for reusing objects to reduce garbage collection
|
|
4
|
+
*/
|
|
5
|
+
declare class ObjectPool<T> {
|
|
6
|
+
private pool;
|
|
7
|
+
private createFn;
|
|
8
|
+
private resetFn?;
|
|
9
|
+
private maxSize;
|
|
10
|
+
constructor(createFn: () => T, resetFn?: (obj: T) => void, maxSize?: number);
|
|
11
|
+
acquire(): T;
|
|
12
|
+
release(obj: T): void;
|
|
13
|
+
clear(): void;
|
|
14
|
+
get size(): number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Task coordinates object pool for reducing memory allocations
|
|
18
|
+
*/
|
|
19
|
+
export declare const useTaskCoordinatesPool: (maxSize?: number) => {
|
|
20
|
+
acquire: () => TaskCoordinates;
|
|
21
|
+
release: (coords: TaskCoordinates) => void;
|
|
22
|
+
clear: () => void;
|
|
23
|
+
pool: ObjectPool<TaskCoordinates>;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Array pool for reusing arrays to reduce allocations
|
|
27
|
+
*/
|
|
28
|
+
export declare const useArrayPool: <T>(maxSize?: number) => {
|
|
29
|
+
acquire: () => T[];
|
|
30
|
+
release: (arr: T[]) => void;
|
|
31
|
+
clear: () => void;
|
|
32
|
+
pool: ObjectPool<T[]>;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Map pool for reusing Map objects
|
|
36
|
+
*/
|
|
37
|
+
export declare const useMapPool: <K, V>(maxSize?: number) => {
|
|
38
|
+
acquire: () => Map<K, V>;
|
|
39
|
+
release: (map: Map<K, V>) => void;
|
|
40
|
+
clear: () => void;
|
|
41
|
+
pool: ObjectPool<Map<K, V>>;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Set pool for reusing Set objects
|
|
45
|
+
*/
|
|
46
|
+
export declare const useSetPool: <T>(maxSize?: number) => {
|
|
47
|
+
acquire: () => Set<T>;
|
|
48
|
+
release: (set: Set<T>) => void;
|
|
49
|
+
clear: () => void;
|
|
50
|
+
pool: ObjectPool<Set<T>>;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Memory manager that coordinates multiple object pools
|
|
54
|
+
*/
|
|
55
|
+
export declare const useMemoryManager: () => {
|
|
56
|
+
coordinatesPool: {
|
|
57
|
+
acquire: () => TaskCoordinates;
|
|
58
|
+
release: (coords: TaskCoordinates) => void;
|
|
59
|
+
clear: () => void;
|
|
60
|
+
pool: ObjectPool<TaskCoordinates>;
|
|
61
|
+
};
|
|
62
|
+
arrayPool: {
|
|
63
|
+
acquire: () => unknown[];
|
|
64
|
+
release: (arr: unknown[]) => void;
|
|
65
|
+
clear: () => void;
|
|
66
|
+
pool: ObjectPool<unknown[]>;
|
|
67
|
+
};
|
|
68
|
+
mapPool: {
|
|
69
|
+
acquire: () => Map<unknown, unknown>;
|
|
70
|
+
release: (map: Map<unknown, unknown>) => void;
|
|
71
|
+
clear: () => void;
|
|
72
|
+
pool: ObjectPool<Map<unknown, unknown>>;
|
|
73
|
+
};
|
|
74
|
+
setPool: {
|
|
75
|
+
acquire: () => Set<unknown>;
|
|
76
|
+
release: (set: Set<unknown>) => void;
|
|
77
|
+
clear: () => void;
|
|
78
|
+
pool: ObjectPool<Set<unknown>>;
|
|
79
|
+
};
|
|
80
|
+
memoryStats: {
|
|
81
|
+
coordinatesPoolSize: number;
|
|
82
|
+
arrayPoolSize: number;
|
|
83
|
+
mapPoolSize: number;
|
|
84
|
+
setPoolSize: number;
|
|
85
|
+
};
|
|
86
|
+
clearAllPools: () => void;
|
|
87
|
+
forceGarbageCollection: () => void;
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Memory-efficient batch processor that reuses objects
|
|
91
|
+
*/
|
|
92
|
+
export declare const useBatchProcessor: <T, R>(batchSize?: number) => {
|
|
93
|
+
processBatch: (items: T[], processor: (batch: T[]) => Promise<R[]> | R[], onProgress?: (processed: number, total: number) => void) => Promise<R[]>;
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Weak reference manager for preventing memory leaks
|
|
97
|
+
*/
|
|
98
|
+
export declare const useWeakReferenceManager: () => {
|
|
99
|
+
addWeakRef: (obj: object) => WeakRef<object>;
|
|
100
|
+
cleanupDeadRefs: () => number;
|
|
101
|
+
getAliveRefCount: () => number;
|
|
102
|
+
totalRefs: number;
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* Memory monitoring hook for tracking memory usage
|
|
106
|
+
*/
|
|
107
|
+
export declare const useMemoryMonitor: (intervalMs?: number) => {
|
|
108
|
+
memoryInfo: {
|
|
109
|
+
usedJSHeapSize: number;
|
|
110
|
+
totalJSHeapSize: number;
|
|
111
|
+
jsHeapSizeLimit: number;
|
|
112
|
+
};
|
|
113
|
+
updateMemoryInfo: () => void;
|
|
114
|
+
startMonitoring: () => () => void;
|
|
115
|
+
getMemoryPressure: () => number;
|
|
116
|
+
};
|
|
117
|
+
declare global {
|
|
118
|
+
interface Window {
|
|
119
|
+
gc?: () => void;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { RenderTask, TaskMapByLevel, ChildByLevelMap, RootMapByLevel } from "../types";
|
|
2
|
+
export interface OptimizedDataStructures {
|
|
3
|
+
tasksByLevel: Map<number, RenderTask[]>;
|
|
4
|
+
tasksMap: TaskMapByLevel;
|
|
5
|
+
childTasksMap: ChildByLevelMap;
|
|
6
|
+
rootTasksMap: RootMapByLevel;
|
|
7
|
+
taskIndicesByLevel: Map<number, Map<string, number>>;
|
|
8
|
+
visibleTasksAtLevel: Map<number, RenderTask[]>;
|
|
9
|
+
taskParentMap: Map<string, string | null>;
|
|
10
|
+
taskDepthMap: Map<string, number>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Pre-computes optimized data structures for faster lookups
|
|
14
|
+
* Reduces O(n) operations to O(1) for common queries
|
|
15
|
+
*/
|
|
16
|
+
export declare const useOptimizedDataStructures: (tasks: readonly RenderTask[]) => OptimizedDataStructures;
|
|
17
|
+
/**
|
|
18
|
+
* Hook for getting tasks at specific level with O(1) access
|
|
19
|
+
*/
|
|
20
|
+
export declare const useTasksAtLevel: (optimizedData: OptimizedDataStructures, level: number) => RenderTask[];
|
|
21
|
+
/**
|
|
22
|
+
* Hook for getting visible tasks in a specific range for virtualization
|
|
23
|
+
*/
|
|
24
|
+
export declare const useVisibleTasksInRange: (optimizedData: OptimizedDataStructures, level: number, startIndex: number, endIndex: number) => RenderTask[];
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { RenderTask, TaskCoordinates } from "../types";
|
|
3
|
+
export interface SVGBatch {
|
|
4
|
+
tasks: RenderTask[];
|
|
5
|
+
dependencies: string[];
|
|
6
|
+
selectedTasks: string[];
|
|
7
|
+
holidays: string[];
|
|
8
|
+
}
|
|
9
|
+
export interface SVGRenderContext {
|
|
10
|
+
additionalLeftSpace: number;
|
|
11
|
+
fullRowHeight: number;
|
|
12
|
+
taskHeight: number;
|
|
13
|
+
svgWidth: number;
|
|
14
|
+
svgHeight: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Hook for batched SVG rendering to reduce DOM operations
|
|
18
|
+
*/
|
|
19
|
+
export declare const useBatchedSVGRenderer: () => {
|
|
20
|
+
clearBatch: () => void;
|
|
21
|
+
addTaskToBatch: (task: RenderTask) => void;
|
|
22
|
+
addDependencyToBatch: (dependency: string) => void;
|
|
23
|
+
addSelectedTaskToBatch: (selectedTask: string) => void;
|
|
24
|
+
addHolidayToBatch: (holiday: string) => void;
|
|
25
|
+
getBatchData: () => {
|
|
26
|
+
tasks: RenderTask[];
|
|
27
|
+
dependencies: string[];
|
|
28
|
+
selectedTasks: string[];
|
|
29
|
+
holidays: string[];
|
|
30
|
+
};
|
|
31
|
+
currentBatch: SVGBatch;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Hook for SVG element pooling to reuse DOM elements
|
|
35
|
+
*/
|
|
36
|
+
export declare const useSVGElementPool: () => {
|
|
37
|
+
acquireRect: () => SVGRectElement;
|
|
38
|
+
releaseRect: (rect: SVGRectElement) => void;
|
|
39
|
+
acquirePath: () => SVGPathElement;
|
|
40
|
+
releasePath: (path: SVGPathElement) => void;
|
|
41
|
+
acquireText: () => SVGTextElement;
|
|
42
|
+
releaseText: (text: SVGTextElement) => void;
|
|
43
|
+
acquireGroup: () => SVGGElement;
|
|
44
|
+
releaseGroup: (group: SVGGElement) => void;
|
|
45
|
+
clearPools: () => void;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Hook for virtual SVG rendering - only renders visible elements
|
|
49
|
+
*/
|
|
50
|
+
export declare const useVirtualSVGRenderer: (allTasks: RenderTask[], getTaskCoordinates: (task: RenderTask) => TaskCoordinates, viewportBounds: {
|
|
51
|
+
minX: number;
|
|
52
|
+
maxX: number;
|
|
53
|
+
minY: number;
|
|
54
|
+
maxY: number;
|
|
55
|
+
}) => {
|
|
56
|
+
visibleTasks: RenderTask[];
|
|
57
|
+
getVisibleTasksInRange: (startIndex: number, endIndex: number) => RenderTask[];
|
|
58
|
+
totalVisibleCount: number;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Hook for optimized SVG coordinate transformations
|
|
62
|
+
*/
|
|
63
|
+
export declare const useSVGCoordinateTransforms: () => {
|
|
64
|
+
getTransform: (x: number, y: number) => string;
|
|
65
|
+
getScaleTransform: (scaleX: number, scaleY: number) => string;
|
|
66
|
+
clearTransformCache: () => void;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Hook for Level-of-Detail (LOD) rendering
|
|
70
|
+
* Reduces rendering complexity based on zoom level
|
|
71
|
+
*/
|
|
72
|
+
export declare const useLODRenderer: (zoomLevel: number, taskCount: number) => {
|
|
73
|
+
showLabels: boolean;
|
|
74
|
+
showProgress: boolean;
|
|
75
|
+
showDependencies: boolean;
|
|
76
|
+
taskDetail: "minimal";
|
|
77
|
+
maxVisibleTasks: number;
|
|
78
|
+
} | {
|
|
79
|
+
showLabels: boolean;
|
|
80
|
+
showProgress: boolean;
|
|
81
|
+
showDependencies: boolean;
|
|
82
|
+
taskDetail: "reduced";
|
|
83
|
+
maxVisibleTasks: number;
|
|
84
|
+
} | {
|
|
85
|
+
showLabels: boolean;
|
|
86
|
+
showProgress: boolean;
|
|
87
|
+
showDependencies: boolean;
|
|
88
|
+
taskDetail: "full";
|
|
89
|
+
maxVisibleTasks: number;
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Hook for efficient SVG path generation
|
|
93
|
+
*/
|
|
94
|
+
export declare const useSVGPathGenerator: () => {
|
|
95
|
+
generateTaskPath: (x: number, y: number, width: number, height: number, cornerRadius?: number) => string;
|
|
96
|
+
generateProgressPath: (x: number, y: number, width: number, height: number, progressPercent: number) => string;
|
|
97
|
+
generateArrowPath: (fromX: number, fromY: number, toX: number, toY: number, arrowSize?: number) => string;
|
|
98
|
+
clearPathCache: () => void;
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Hook for SVG performance optimization
|
|
102
|
+
*/
|
|
103
|
+
export declare const useSVGPerformanceOptimizer: () => {
|
|
104
|
+
optimizeRenderList: (elements: React.ReactElement[]) => React.ReactElement<any, string | React.JSXElementConstructor<any>>[];
|
|
105
|
+
batchSVGUpdates: (updates: Array<() => void>) => void;
|
|
106
|
+
shouldSkipRender: (bounds: {
|
|
107
|
+
x: number;
|
|
108
|
+
y: number;
|
|
109
|
+
width?: number;
|
|
110
|
+
height?: number;
|
|
111
|
+
}, viewportBounds: {
|
|
112
|
+
minX: number;
|
|
113
|
+
maxX: number;
|
|
114
|
+
minY: number;
|
|
115
|
+
maxY: number;
|
|
116
|
+
}) => boolean;
|
|
117
|
+
};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
export interface PerformanceMetrics {
|
|
2
|
+
renderTime: number;
|
|
3
|
+
coordinateCalculationTime: number;
|
|
4
|
+
dependencyCalculationTime: number;
|
|
5
|
+
sortingTime: number;
|
|
6
|
+
totalTasks: number;
|
|
7
|
+
visibleTasks: number;
|
|
8
|
+
fps: number;
|
|
9
|
+
memoryUsage: number;
|
|
10
|
+
timestamp: number;
|
|
11
|
+
}
|
|
12
|
+
export interface PerformanceBenchmark {
|
|
13
|
+
name: string;
|
|
14
|
+
startTime: number;
|
|
15
|
+
endTime?: number;
|
|
16
|
+
duration?: number;
|
|
17
|
+
metadata?: Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Performance monitor for tracking Gantt chart performance metrics
|
|
21
|
+
*/
|
|
22
|
+
export declare const usePerformanceMonitor: (enabled?: boolean) => {
|
|
23
|
+
startMeasurement: (name: string, metadata?: Record<string, unknown>) => void;
|
|
24
|
+
endMeasurement: (name: string) => number;
|
|
25
|
+
measureFunction: <T extends unknown[], R>(name: string, fn: (...args: T) => R, metadata?: Record<string, unknown>) => (...args: T) => R;
|
|
26
|
+
measureAsyncFunction: <T_1 extends unknown[], R_1>(name: string, fn: (...args: T_1) => Promise<R_1>, metadata?: Record<string, unknown>) => (...args: T_1) => Promise<R_1>;
|
|
27
|
+
getPerformanceReport: () => {
|
|
28
|
+
measurements: Record<string, {
|
|
29
|
+
count: number;
|
|
30
|
+
totalTime: number;
|
|
31
|
+
avgTime: number;
|
|
32
|
+
maxTime: number;
|
|
33
|
+
minTime: number;
|
|
34
|
+
}>;
|
|
35
|
+
fps: number;
|
|
36
|
+
currentMetrics: PerformanceMetrics;
|
|
37
|
+
allMetrics: PerformanceMetrics[];
|
|
38
|
+
};
|
|
39
|
+
addMetrics: (metrics: Omit<PerformanceMetrics, "timestamp">) => void;
|
|
40
|
+
clearMeasurements: () => void;
|
|
41
|
+
updateFPS: () => void;
|
|
42
|
+
getFPS: () => number;
|
|
43
|
+
getMemoryUsage: () => number;
|
|
44
|
+
enabled: boolean;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Hook for measuring render performance
|
|
48
|
+
*/
|
|
49
|
+
export declare const useRenderPerformance: (componentName: string) => {
|
|
50
|
+
measureRender: (fn: () => void) => () => void;
|
|
51
|
+
renderCount: number;
|
|
52
|
+
lastRenderTime: number;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Hook for performance budgeting
|
|
56
|
+
*/
|
|
57
|
+
export declare const usePerformanceBudget: (budgets: Record<string, number>) => {
|
|
58
|
+
checkBudgets: () => {
|
|
59
|
+
operation: string;
|
|
60
|
+
actual: number;
|
|
61
|
+
budget: number;
|
|
62
|
+
timestamp: number;
|
|
63
|
+
}[];
|
|
64
|
+
getBudgetStatus: () => Record<string, {
|
|
65
|
+
budget: number;
|
|
66
|
+
actual: number;
|
|
67
|
+
status: "ok" | "warning" | "violation";
|
|
68
|
+
}>;
|
|
69
|
+
violations: {
|
|
70
|
+
operation: string;
|
|
71
|
+
actual: number;
|
|
72
|
+
budget: number;
|
|
73
|
+
timestamp: number;
|
|
74
|
+
}[];
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Hook for performance-aware rendering
|
|
78
|
+
* Automatically reduces quality when performance is poor
|
|
79
|
+
*/
|
|
80
|
+
export declare const useAdaptivePerformance: (thresholds: {
|
|
81
|
+
fpsThreshold: number;
|
|
82
|
+
renderTimeThreshold: number;
|
|
83
|
+
}) => {
|
|
84
|
+
performanceLevel: "medium" | "high" | "low";
|
|
85
|
+
updatePerformanceLevel: () => "medium" | "high" | "low";
|
|
86
|
+
getQualitySettings: () => {
|
|
87
|
+
enableAnimations: boolean;
|
|
88
|
+
renderQuality: string;
|
|
89
|
+
maxVisibleTasks: number;
|
|
90
|
+
updateFrequency: number;
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Hook for throttling expensive operations based on performance
|
|
95
|
+
*/
|
|
96
|
+
export declare const usePerformanceThrottling: () => {
|
|
97
|
+
throttle: <T extends unknown[], R>(key: string, fn: (...args: T) => R, baseDelay?: number) => (...args: T) => R | undefined;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Development-only performance debugging utilities
|
|
101
|
+
*/
|
|
102
|
+
export declare const usePerformanceDebugger: () => {
|
|
103
|
+
logPerformanceReport: () => void;
|
|
104
|
+
exportPerformanceData: () => void;
|
|
105
|
+
clearMeasurements: () => void;
|
|
106
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { RenderTask } from "../types";
|
|
2
|
+
import type { OptimizedListParams } from "./use-optimized-list";
|
|
3
|
+
export interface ProgressiveLoadingConfig {
|
|
4
|
+
/** Number of tasks to load per chunk */
|
|
5
|
+
chunkSize: number;
|
|
6
|
+
/** Buffer size for preloading (in chunks) */
|
|
7
|
+
preloadBuffer: number;
|
|
8
|
+
/** Function to load a chunk of tasks */
|
|
9
|
+
loadTaskChunk: (startIndex: number, endIndex: number) => Promise<RenderTask[]>;
|
|
10
|
+
/** Total number of tasks available */
|
|
11
|
+
totalTaskCount: number;
|
|
12
|
+
/** Enable progressive loading */
|
|
13
|
+
enabled: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface ProgressiveLoadingState {
|
|
16
|
+
/** Currently loaded tasks */
|
|
17
|
+
loadedTasks: readonly RenderTask[];
|
|
18
|
+
/** Loading state */
|
|
19
|
+
isLoading: boolean;
|
|
20
|
+
/** Error state */
|
|
21
|
+
error: Error | null;
|
|
22
|
+
/** Loaded chunk ranges */
|
|
23
|
+
loadedRanges: Set<string>;
|
|
24
|
+
/** Currently loading chunks */
|
|
25
|
+
loadingChunks: Set<string>;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Hook for progressive loading of large task datasets
|
|
29
|
+
* Loads tasks in chunks based on viewport visibility
|
|
30
|
+
*/
|
|
31
|
+
export declare const useProgressiveLoading: (initialTasks: readonly RenderTask[], config: Partial<ProgressiveLoadingConfig>, renderedIndexes: OptimizedListParams | null) => ProgressiveLoadingState & {
|
|
32
|
+
/** Force load a specific range */
|
|
33
|
+
loadRange: (startIndex: number, endIndex: number) => Promise<void>;
|
|
34
|
+
/** Preload next chunks based on scroll direction */
|
|
35
|
+
preloadNext: (direction: "up" | "down") => Promise<void>;
|
|
36
|
+
/** Clear loaded data and reset */
|
|
37
|
+
reset: () => void;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Hook for chunked task processing
|
|
41
|
+
* Processes large task arrays in smaller chunks to avoid blocking the main thread
|
|
42
|
+
*/
|
|
43
|
+
export declare const useChunkedProcessing: <T, R>(data: T[], processor: (chunk: T[]) => R[], chunkSize?: number) => {
|
|
44
|
+
processedData: R[];
|
|
45
|
+
isProcessing: boolean;
|
|
46
|
+
progress: number;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Enhanced progressive loading with smart caching
|
|
50
|
+
*/
|
|
51
|
+
export declare const useSmartProgressiveLoading: (config: Partial<ProgressiveLoadingConfig> & {
|
|
52
|
+
/** Cache expiry time in milliseconds */
|
|
53
|
+
cacheExpiry?: number;
|
|
54
|
+
/** Maximum cache size (number of chunks) */
|
|
55
|
+
maxCacheSize?: number;
|
|
56
|
+
}, renderedIndexes: OptimizedListParams | null) => ProgressiveLoadingState & {
|
|
57
|
+
/** Force load a specific range */
|
|
58
|
+
loadRange: (startIndex: number, endIndex: number) => Promise<void>;
|
|
59
|
+
/** Preload next chunks based on scroll direction */
|
|
60
|
+
preloadNext: (direction: "up" | "down") => Promise<void>;
|
|
61
|
+
/** Clear loaded data and reset */
|
|
62
|
+
reset: () => void;
|
|
63
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { DependencyMap, DependentMap, DependencyMargins, ExpandedDependency, ExpandedDependent, MapTaskToCoordinates, TaskMapByLevel, RenderTask, TaskCoordinates } from "../types";
|
|
2
|
+
import type { OptimizedListParams } from "./use-optimized-list";
|
|
3
|
+
interface SpatialBounds {
|
|
4
|
+
minX: number;
|
|
5
|
+
maxX: number;
|
|
6
|
+
minY: number;
|
|
7
|
+
maxY: number;
|
|
8
|
+
}
|
|
9
|
+
interface SpatialNode {
|
|
10
|
+
taskId: string;
|
|
11
|
+
bounds: SpatialBounds;
|
|
12
|
+
dependencies: ExpandedDependency[];
|
|
13
|
+
dependents: ExpandedDependent[];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Spatial hash map for efficient spatial queries
|
|
17
|
+
* Divides space into grid cells for O(1) spatial lookups
|
|
18
|
+
*/
|
|
19
|
+
declare class SpatialHashMap {
|
|
20
|
+
private cellSize;
|
|
21
|
+
private grid;
|
|
22
|
+
private taskNodes;
|
|
23
|
+
constructor(cellSize?: number);
|
|
24
|
+
private getBoundsFromCoordinates;
|
|
25
|
+
insert(taskId: string, coordinates: TaskCoordinates, dependencies?: ExpandedDependency[], dependents?: ExpandedDependent[]): void;
|
|
26
|
+
query(bounds: SpatialBounds): SpatialNode[];
|
|
27
|
+
private boundsIntersect;
|
|
28
|
+
getNode(taskId: string): SpatialNode | undefined;
|
|
29
|
+
clear(): void;
|
|
30
|
+
remove(taskId: string): void;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Hook for optimized dependency calculations using spatial indexing
|
|
34
|
+
*/
|
|
35
|
+
export declare const useSpatialDependencyMap: (tasks: readonly RenderTask[], visibleTasksMirror: Readonly<Record<string, true>>, tasksMap: TaskMapByLevel, mapTaskToCoordinates: MapTaskToCoordinates, fullRowHeight: number, isShowCriticalPath: boolean, renderedRowIndexes: OptimizedListParams | null, renderedColumnIndexes: OptimizedListParams | null) => [DependencyMap, DependentMap, DependencyMargins, SpatialHashMap];
|
|
36
|
+
/**
|
|
37
|
+
* Hook for querying dependencies in a specific spatial region
|
|
38
|
+
*/
|
|
39
|
+
export declare const useSpatialDependencyQuery: (spatialMap: SpatialHashMap, queryBounds: SpatialBounds) => SpatialNode[];
|
|
40
|
+
/**
|
|
41
|
+
* Hook for optimized dependency updates
|
|
42
|
+
* Only recalculates dependencies for tasks that actually changed
|
|
43
|
+
*/
|
|
44
|
+
export declare const useIncrementalDependencyUpdate: (spatialMap: SpatialHashMap, changedTaskIds: Set<string>, allTasks: readonly RenderTask[]) => (newTaskCoordinates: Map<string, TaskCoordinates>) => void;
|
|
45
|
+
/**
|
|
46
|
+
* Utility function to create viewport bounds from rendered indexes
|
|
47
|
+
*/
|
|
48
|
+
export declare const createViewportBounds: (renderedRowIndexes: OptimizedListParams | null, renderedColumnIndexes: OptimizedListParams | null, fullRowHeight: number, columnWidth: number) => SpatialBounds | null;
|
|
49
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { RenderTask, ViewMode, Distances, TaskCoordinates } from "../types";
|
|
2
|
+
export interface WorkerMessage {
|
|
3
|
+
id: string;
|
|
4
|
+
type: "calculate-coordinates" | "process-dependencies" | "sort-tasks" | "filter-tasks";
|
|
5
|
+
data: unknown;
|
|
6
|
+
}
|
|
7
|
+
export interface WorkerResponse {
|
|
8
|
+
id: string;
|
|
9
|
+
type: string;
|
|
10
|
+
result?: unknown;
|
|
11
|
+
error?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface CoordinateCalculationData {
|
|
14
|
+
tasks: RenderTask[];
|
|
15
|
+
startDate: number;
|
|
16
|
+
viewMode: ViewMode;
|
|
17
|
+
rtl: boolean;
|
|
18
|
+
fullRowHeight: number;
|
|
19
|
+
taskHeight: number;
|
|
20
|
+
taskYOffset: number;
|
|
21
|
+
distances: Distances;
|
|
22
|
+
svgWidth: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Hook for managing Web Worker communications for heavy calculations
|
|
26
|
+
*/
|
|
27
|
+
export declare const useGanttWebWorker: () => {
|
|
28
|
+
isWorkerAvailable: boolean;
|
|
29
|
+
sendMessage: (message: Omit<WorkerMessage, "id">, timeoutMs?: number) => Promise<unknown>;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Hook for calculating task coordinates using Web Worker
|
|
33
|
+
*/
|
|
34
|
+
export declare const useWorkerCoordinateCalculation: (tasks: readonly RenderTask[], startDate: Date, viewMode: ViewMode, rtl: boolean, fullRowHeight: number, taskHeight: number, taskYOffset: number, distances: Distances, svgWidth: number) => {
|
|
35
|
+
coordinates: Map<string, TaskCoordinates>;
|
|
36
|
+
isCalculating: boolean;
|
|
37
|
+
recalculate: () => Promise<Map<string, TaskCoordinates>>;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Hook for sorting tasks using Web Worker
|
|
41
|
+
*/
|
|
42
|
+
export declare const useWorkerTaskSorting: () => {
|
|
43
|
+
sortTasks: (tasks: RenderTask[]) => Promise<RenderTask[]>;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Hook for filtering tasks using Web Worker
|
|
47
|
+
*/
|
|
48
|
+
export declare const useWorkerTaskFiltering: () => {
|
|
49
|
+
filterTasks: (tasks: RenderTask[], filterFn: string) => Promise<RenderTask[]>;
|
|
50
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gantt-task-react-v",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.2",
|
|
4
4
|
"description": "Interactive Gantt Chart for React with TypeScript.",
|
|
5
5
|
"author": "aguilanbon",
|
|
6
6
|
"homepage": "https://github.com/aguilanbon/gantt-task-react-v",
|
|
@@ -43,8 +43,9 @@
|
|
|
43
43
|
"@floating-ui/dom": "1.6.3",
|
|
44
44
|
"@floating-ui/react": "0.26.11",
|
|
45
45
|
"date-fns": "3.6.0",
|
|
46
|
-
"i18next": "^
|
|
47
|
-
"react-i18next": "^15.
|
|
46
|
+
"i18next": "^25.5.2",
|
|
47
|
+
"react-i18next": "^15.7.3",
|
|
48
|
+
"react-window": "^2.1.1"
|
|
48
49
|
},
|
|
49
50
|
"peerDependencies": {
|
|
50
51
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc",
|
|
@@ -61,11 +62,11 @@
|
|
|
61
62
|
"@storybook/addon-onboarding": "8.2.10",
|
|
62
63
|
"@storybook/blocks": "8.2.10",
|
|
63
64
|
"@storybook/cli": "8.2.10",
|
|
65
|
+
"@storybook/core-server": "8.2.10",
|
|
66
|
+
"@storybook/jest": "0.2.3",
|
|
64
67
|
"@storybook/react": "8.2.10",
|
|
65
68
|
"@storybook/react-vite": "8.2.10",
|
|
66
69
|
"@storybook/test": "8.2.10",
|
|
67
|
-
"@storybook/core-server": "8.2.10",
|
|
68
|
-
"@storybook/jest": "0.2.3",
|
|
69
70
|
"@storybook/test-runner": "0.23.0",
|
|
70
71
|
"@storybook/testing-library": "^0.2.2",
|
|
71
72
|
"@testing-library/jest-dom": "^6.4.2",
|
|
@@ -75,6 +76,7 @@
|
|
|
75
76
|
"@types/node": "^20.12.4",
|
|
76
77
|
"@types/react": "^18.2.74",
|
|
77
78
|
"@types/react-dom": "^18.2.24",
|
|
79
|
+
"@types/react-window": "^1.8.8",
|
|
78
80
|
"@typescript-eslint/eslint-plugin": "^7.5.0",
|
|
79
81
|
"@typescript-eslint/parser": "^7.5.0",
|
|
80
82
|
"@vitejs/plugin-react": "4.2.1",
|