gantt-lib 0.6.2 → 0.7.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 +17 -2
- package/dist/index.d.ts +17 -2
- package/dist/index.js +281 -67
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +280 -67
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +112 -32
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -196,33 +196,33 @@ function detectCycles(tasks) {
|
|
|
196
196
|
return { hasCycle: false };
|
|
197
197
|
}
|
|
198
198
|
function computeLagFromDates(linkType, predStart, predEnd, succStart, succEnd) {
|
|
199
|
-
const
|
|
199
|
+
const DAY_MS2 = 24 * 60 * 60 * 1e3;
|
|
200
200
|
const pS = Date.UTC(predStart.getUTCFullYear(), predStart.getUTCMonth(), predStart.getUTCDate());
|
|
201
201
|
const pE = Date.UTC(predEnd.getUTCFullYear(), predEnd.getUTCMonth(), predEnd.getUTCDate());
|
|
202
202
|
const sS = Date.UTC(succStart.getUTCFullYear(), succStart.getUTCMonth(), succStart.getUTCDate());
|
|
203
203
|
const sE = Date.UTC(succEnd.getUTCFullYear(), succEnd.getUTCMonth(), succEnd.getUTCDate());
|
|
204
204
|
switch (linkType) {
|
|
205
205
|
case "FS":
|
|
206
|
-
return Math.round((sS - pE) /
|
|
206
|
+
return Math.round((sS - pE) / DAY_MS2) - 1;
|
|
207
207
|
case "SS":
|
|
208
|
-
return Math.round((sS - pS) /
|
|
208
|
+
return Math.round((sS - pS) / DAY_MS2);
|
|
209
209
|
case "FF":
|
|
210
|
-
return Math.round((sE - pE) /
|
|
210
|
+
return Math.round((sE - pE) / DAY_MS2);
|
|
211
211
|
case "SF":
|
|
212
|
-
return Math.round((sE - pS) /
|
|
212
|
+
return Math.round((sE - pS) / DAY_MS2) + 1;
|
|
213
213
|
}
|
|
214
214
|
}
|
|
215
215
|
function calculateSuccessorDate(predecessorStart, predecessorEnd, linkType, lag = 0) {
|
|
216
|
-
const
|
|
216
|
+
const DAY_MS2 = 24 * 60 * 60 * 1e3;
|
|
217
217
|
switch (linkType) {
|
|
218
218
|
case "FS":
|
|
219
|
-
return new Date(predecessorEnd.getTime() + (lag + 1) *
|
|
219
|
+
return new Date(predecessorEnd.getTime() + (lag + 1) * DAY_MS2);
|
|
220
220
|
case "SS":
|
|
221
|
-
return new Date(predecessorStart.getTime() + lag *
|
|
221
|
+
return new Date(predecessorStart.getTime() + lag * DAY_MS2);
|
|
222
222
|
case "FF":
|
|
223
|
-
return new Date(predecessorEnd.getTime() + lag *
|
|
223
|
+
return new Date(predecessorEnd.getTime() + lag * DAY_MS2);
|
|
224
224
|
case "SF":
|
|
225
|
-
return new Date(predecessorStart.getTime() + (lag - 1) *
|
|
225
|
+
return new Date(predecessorStart.getTime() + (lag - 1) * DAY_MS2);
|
|
226
226
|
}
|
|
227
227
|
}
|
|
228
228
|
function validateDependencies(tasks) {
|
|
@@ -454,13 +454,13 @@ function computeParentProgress(parentId, tasks) {
|
|
|
454
454
|
if (children.length === 0) {
|
|
455
455
|
return 0;
|
|
456
456
|
}
|
|
457
|
-
const
|
|
457
|
+
const DAY_MS2 = 24 * 60 * 60 * 1e3;
|
|
458
458
|
let totalWeight = 0;
|
|
459
459
|
let weightedSum = 0;
|
|
460
460
|
for (const child of children) {
|
|
461
461
|
const start = new Date(child.startDate).getTime();
|
|
462
462
|
const end = new Date(child.endDate).getTime();
|
|
463
|
-
const duration = (end - start +
|
|
463
|
+
const duration = (end - start + DAY_MS2) / DAY_MS2;
|
|
464
464
|
const progress = child.progress ?? 0;
|
|
465
465
|
totalWeight += duration;
|
|
466
466
|
weightedSum += duration * progress;
|
|
@@ -1997,6 +1997,36 @@ var DependencyLines_default = DependencyLines;
|
|
|
1997
1997
|
// src/components/TaskList/TaskList.tsx
|
|
1998
1998
|
import React11, { useMemo as useMemo8, useCallback as useCallback5, useState as useState6, useEffect as useEffect5, useRef as useRef5 } from "react";
|
|
1999
1999
|
|
|
2000
|
+
// src/utils/taskListReorder.ts
|
|
2001
|
+
function getVisibleReorderPosition(orderedTasks, visibleTasks, movedTaskId, originVisibleIndex, dropVisibleIndex) {
|
|
2002
|
+
const originOrderedIndex = orderedTasks.findIndex((task) => task.id === movedTaskId);
|
|
2003
|
+
if (originOrderedIndex === -1) {
|
|
2004
|
+
return null;
|
|
2005
|
+
}
|
|
2006
|
+
const reorderedWithoutMoved = orderedTasks.filter((task) => task.id !== movedTaskId);
|
|
2007
|
+
const visibleWithoutMoved = visibleTasks.filter((task) => task.id !== movedTaskId);
|
|
2008
|
+
const visibleInsertIndex = originVisibleIndex < dropVisibleIndex ? dropVisibleIndex - 1 : dropVisibleIndex;
|
|
2009
|
+
if (visibleWithoutMoved.length === 0) {
|
|
2010
|
+
return { originOrderedIndex, insertIndex: 0 };
|
|
2011
|
+
}
|
|
2012
|
+
if (visibleInsertIndex <= 0) {
|
|
2013
|
+
return {
|
|
2014
|
+
originOrderedIndex,
|
|
2015
|
+
insertIndex: reorderedWithoutMoved.findIndex((task) => task.id === visibleWithoutMoved[0].id)
|
|
2016
|
+
};
|
|
2017
|
+
}
|
|
2018
|
+
if (visibleInsertIndex >= visibleWithoutMoved.length) {
|
|
2019
|
+
return {
|
|
2020
|
+
originOrderedIndex,
|
|
2021
|
+
insertIndex: reorderedWithoutMoved.length
|
|
2022
|
+
};
|
|
2023
|
+
}
|
|
2024
|
+
return {
|
|
2025
|
+
originOrderedIndex,
|
|
2026
|
+
insertIndex: reorderedWithoutMoved.findIndex((task) => task.id === visibleWithoutMoved[visibleInsertIndex].id)
|
|
2027
|
+
};
|
|
2028
|
+
}
|
|
2029
|
+
|
|
2000
2030
|
// src/components/ui/Popover.tsx
|
|
2001
2031
|
import * as RadixPopover from "@radix-ui/react-popover";
|
|
2002
2032
|
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
@@ -2352,6 +2382,16 @@ var LINK_TYPE_LABELS = {
|
|
|
2352
2382
|
|
|
2353
2383
|
// src/components/TaskList/TaskListRow.tsx
|
|
2354
2384
|
import { Fragment as Fragment2, jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2385
|
+
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
2386
|
+
var getInclusiveDurationDays = (startDate, endDate) => {
|
|
2387
|
+
const start = parseUTCDate(startDate);
|
|
2388
|
+
const end = parseUTCDate(endDate);
|
|
2389
|
+
return Math.max(1, Math.round((end.getTime() - start.getTime()) / DAY_MS) + 1);
|
|
2390
|
+
};
|
|
2391
|
+
var getEndDateFromDuration = (startDate, durationDays) => {
|
|
2392
|
+
const start = parseUTCDate(startDate);
|
|
2393
|
+
return new Date(start.getTime() + (durationDays - 1) * DAY_MS).toISOString().split("T")[0];
|
|
2394
|
+
};
|
|
2355
2395
|
var TrashIcon = () => /* @__PURE__ */ jsxs9("svg", { xmlns: "http://www.w3.org/2000/svg", width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
2356
2396
|
/* @__PURE__ */ jsx12("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6" }),
|
|
2357
2397
|
/* @__PURE__ */ jsx12("path", { d: "M3 6h18" }),
|
|
@@ -2366,6 +2406,7 @@ var DragHandleIcon = () => /* @__PURE__ */ jsxs9("svg", { width: "10", height: "
|
|
|
2366
2406
|
/* @__PURE__ */ jsx12("circle", { cx: "2", cy: "12", r: "1.5" }),
|
|
2367
2407
|
/* @__PURE__ */ jsx12("circle", { cx: "8", cy: "12", r: "1.5" })
|
|
2368
2408
|
] });
|
|
2409
|
+
var ChevronRightIcon = () => /* @__PURE__ */ jsx12("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx12("path", { d: "m9 18 6-6-6-6" }) });
|
|
2369
2410
|
var HierarchyButton = ({
|
|
2370
2411
|
isChild,
|
|
2371
2412
|
isParent,
|
|
@@ -2534,11 +2575,16 @@ var TaskListRow = React9.memo(
|
|
|
2534
2575
|
const [editingName, setEditingName] = useState4(false);
|
|
2535
2576
|
const [nameValue, setNameValue] = useState4("");
|
|
2536
2577
|
const nameInputRef = useRef3(null);
|
|
2578
|
+
const [editingDuration, setEditingDuration] = useState4(false);
|
|
2579
|
+
const [durationValue, setDurationValue] = useState4(getInclusiveDurationDays(task.startDate, task.endDate));
|
|
2580
|
+
const durationInputRef = useRef3(null);
|
|
2537
2581
|
const [editingProgress, setEditingProgress] = useState4(false);
|
|
2538
2582
|
const [progressValue, setProgressValue] = useState4(0);
|
|
2539
2583
|
const progressInputRef = useRef3(null);
|
|
2540
2584
|
const [overflowOpen, setOverflowOpen] = useState4(false);
|
|
2541
|
-
const
|
|
2585
|
+
const nameConfirmedRef = useRef3(false);
|
|
2586
|
+
const durationConfirmedRef = useRef3(false);
|
|
2587
|
+
const progressConfirmedRef = useRef3(false);
|
|
2542
2588
|
const autoEditedForRef = useRef3(null);
|
|
2543
2589
|
const editTriggerRef = useRef3("doubleclick");
|
|
2544
2590
|
const [deletePending, setDeletePending] = useState4(false);
|
|
@@ -2593,7 +2639,7 @@ var TaskListRow = React9.memo(
|
|
|
2593
2639
|
useEffect3(() => {
|
|
2594
2640
|
if (editingTaskId === task.id && !disableTaskNameEditing && autoEditedForRef.current !== editingTaskId) {
|
|
2595
2641
|
autoEditedForRef.current = editingTaskId;
|
|
2596
|
-
|
|
2642
|
+
nameConfirmedRef.current = false;
|
|
2597
2643
|
editTriggerRef.current = "autoedit";
|
|
2598
2644
|
setNameValue(task.name);
|
|
2599
2645
|
setEditingName(true);
|
|
@@ -2608,7 +2654,7 @@ var TaskListRow = React9.memo(
|
|
|
2608
2654
|
const handleNameDoubleClick = useCallback4((e) => {
|
|
2609
2655
|
if (disableTaskNameEditing) return;
|
|
2610
2656
|
e.stopPropagation();
|
|
2611
|
-
|
|
2657
|
+
nameConfirmedRef.current = false;
|
|
2612
2658
|
editTriggerRef.current = "doubleclick";
|
|
2613
2659
|
setNameValue(task.name);
|
|
2614
2660
|
setEditingName(true);
|
|
@@ -2617,7 +2663,7 @@ var TaskListRow = React9.memo(
|
|
|
2617
2663
|
if (editingProgress) return;
|
|
2618
2664
|
if (!editingName && !disableTaskNameEditing && e.key === "F2") {
|
|
2619
2665
|
e.preventDefault();
|
|
2620
|
-
|
|
2666
|
+
nameConfirmedRef.current = false;
|
|
2621
2667
|
editTriggerRef.current = "keypress";
|
|
2622
2668
|
setNameValue(task.name);
|
|
2623
2669
|
setEditingName(true);
|
|
@@ -2625,15 +2671,15 @@ var TaskListRow = React9.memo(
|
|
|
2625
2671
|
}
|
|
2626
2672
|
if (!editingName && !disableTaskNameEditing && e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
|
|
2627
2673
|
e.preventDefault();
|
|
2628
|
-
|
|
2674
|
+
nameConfirmedRef.current = false;
|
|
2629
2675
|
editTriggerRef.current = "keypress";
|
|
2630
2676
|
setNameValue(e.key);
|
|
2631
2677
|
setEditingName(true);
|
|
2632
2678
|
}
|
|
2633
2679
|
}, [editingName, disableTaskNameEditing, task.name]);
|
|
2634
2680
|
const handleNameSave = useCallback4(() => {
|
|
2635
|
-
if (
|
|
2636
|
-
|
|
2681
|
+
if (nameConfirmedRef.current) {
|
|
2682
|
+
nameConfirmedRef.current = false;
|
|
2637
2683
|
return;
|
|
2638
2684
|
}
|
|
2639
2685
|
if (nameValue.trim()) {
|
|
@@ -2646,7 +2692,7 @@ var TaskListRow = React9.memo(
|
|
|
2646
2692
|
}, []);
|
|
2647
2693
|
const handleNameKeyDown = useCallback4((e) => {
|
|
2648
2694
|
if (e.key === "Enter") {
|
|
2649
|
-
|
|
2695
|
+
nameConfirmedRef.current = true;
|
|
2650
2696
|
if (nameValue.trim()) {
|
|
2651
2697
|
onTaskChange?.({ ...task, name: nameValue.trim() });
|
|
2652
2698
|
}
|
|
@@ -2655,15 +2701,54 @@ var TaskListRow = React9.memo(
|
|
|
2655
2701
|
handleNameCancel();
|
|
2656
2702
|
}
|
|
2657
2703
|
}, [nameValue, task, onTaskChange, handleNameCancel]);
|
|
2704
|
+
const handleDurationClick = useCallback4((e) => {
|
|
2705
|
+
if (task.locked) return;
|
|
2706
|
+
e.stopPropagation();
|
|
2707
|
+
durationConfirmedRef.current = false;
|
|
2708
|
+
setDurationValue(getInclusiveDurationDays(task.startDate, task.endDate));
|
|
2709
|
+
setEditingDuration(true);
|
|
2710
|
+
}, [task.locked, task.startDate, task.endDate]);
|
|
2711
|
+
const applyDurationChange = useCallback4((nextDuration) => {
|
|
2712
|
+
const normalizedDuration = Math.max(1, Math.round(nextDuration) || 1);
|
|
2713
|
+
setDurationValue(normalizedDuration);
|
|
2714
|
+
}, []);
|
|
2715
|
+
const handleDurationSave = useCallback4(() => {
|
|
2716
|
+
if (durationConfirmedRef.current) {
|
|
2717
|
+
durationConfirmedRef.current = false;
|
|
2718
|
+
return;
|
|
2719
|
+
}
|
|
2720
|
+
const normalizedDuration = Math.max(1, Math.round(durationValue) || 1);
|
|
2721
|
+
onTaskChange?.({ ...task, endDate: getEndDateFromDuration(task.startDate, normalizedDuration) });
|
|
2722
|
+
setEditingDuration(false);
|
|
2723
|
+
}, [durationValue, task, onTaskChange]);
|
|
2724
|
+
const handleDurationCancel = useCallback4(() => {
|
|
2725
|
+
setDurationValue(getInclusiveDurationDays(task.startDate, task.endDate));
|
|
2726
|
+
setEditingDuration(false);
|
|
2727
|
+
}, [task.startDate, task.endDate]);
|
|
2728
|
+
const handleDurationAdjust = useCallback4((delta) => {
|
|
2729
|
+
applyDurationChange(durationValue + delta);
|
|
2730
|
+
}, [applyDurationChange, durationValue]);
|
|
2731
|
+
const handleDurationKeyDown = useCallback4((e) => {
|
|
2732
|
+
e.stopPropagation();
|
|
2733
|
+
if (e.key === "Enter") {
|
|
2734
|
+
durationConfirmedRef.current = true;
|
|
2735
|
+
const normalizedDuration = Math.max(1, Math.round(durationValue) || 1);
|
|
2736
|
+
onTaskChange?.({ ...task, endDate: getEndDateFromDuration(task.startDate, normalizedDuration) });
|
|
2737
|
+
setEditingDuration(false);
|
|
2738
|
+
} else if (e.key === "Escape") {
|
|
2739
|
+
handleDurationCancel();
|
|
2740
|
+
}
|
|
2741
|
+
}, [durationValue, task, onTaskChange, handleDurationCancel]);
|
|
2658
2742
|
const handleProgressClick = useCallback4((e) => {
|
|
2743
|
+
if (task.locked) return;
|
|
2659
2744
|
e.stopPropagation();
|
|
2660
|
-
|
|
2745
|
+
progressConfirmedRef.current = false;
|
|
2661
2746
|
setProgressValue(task.progress ?? 0);
|
|
2662
2747
|
setEditingProgress(true);
|
|
2663
|
-
}, [task.progress]);
|
|
2748
|
+
}, [task.progress, task.locked]);
|
|
2664
2749
|
const handleProgressSave = useCallback4(() => {
|
|
2665
|
-
if (
|
|
2666
|
-
|
|
2750
|
+
if (progressConfirmedRef.current) {
|
|
2751
|
+
progressConfirmedRef.current = false;
|
|
2667
2752
|
return;
|
|
2668
2753
|
}
|
|
2669
2754
|
const clampedValue = Math.max(0, Math.min(100, progressValue));
|
|
@@ -2673,10 +2758,13 @@ var TaskListRow = React9.memo(
|
|
|
2673
2758
|
const handleProgressCancel = useCallback4(() => {
|
|
2674
2759
|
setEditingProgress(false);
|
|
2675
2760
|
}, []);
|
|
2761
|
+
const handleProgressAdjust = useCallback4((delta) => {
|
|
2762
|
+
setProgressValue((current) => Math.max(0, Math.min(100, current + delta)));
|
|
2763
|
+
}, []);
|
|
2676
2764
|
const handleProgressKeyDown = useCallback4((e) => {
|
|
2677
2765
|
e.stopPropagation();
|
|
2678
2766
|
if (e.key === "Enter") {
|
|
2679
|
-
|
|
2767
|
+
progressConfirmedRef.current = true;
|
|
2680
2768
|
const clampedValue = Math.max(0, Math.min(100, progressValue));
|
|
2681
2769
|
onTaskChange?.({ ...task, progress: clampedValue });
|
|
2682
2770
|
setEditingProgress(false);
|
|
@@ -2690,6 +2778,15 @@ var TaskListRow = React9.memo(
|
|
|
2690
2778
|
progressInputRef.current.select();
|
|
2691
2779
|
}
|
|
2692
2780
|
}, [editingProgress]);
|
|
2781
|
+
useEffect3(() => {
|
|
2782
|
+
setDurationValue(getInclusiveDurationDays(task.startDate, task.endDate));
|
|
2783
|
+
}, [task.startDate, task.endDate]);
|
|
2784
|
+
useEffect3(() => {
|
|
2785
|
+
if (editingDuration && durationInputRef.current) {
|
|
2786
|
+
durationInputRef.current.focus();
|
|
2787
|
+
durationInputRef.current.select();
|
|
2788
|
+
}
|
|
2789
|
+
}, [editingDuration]);
|
|
2693
2790
|
const handleStartDateChange = useCallback4((newDateISO) => {
|
|
2694
2791
|
if (!newDateISO) return;
|
|
2695
2792
|
const origStart = parseUTCDate(task.startDate);
|
|
@@ -2754,7 +2851,7 @@ var TaskListRow = React9.memo(
|
|
|
2754
2851
|
onChipSelect?.(null);
|
|
2755
2852
|
}, [selectedChip, onRemoveDependency, onChipSelect]);
|
|
2756
2853
|
const startDateISO = toISODate(task.startDate);
|
|
2757
|
-
const endDateISO = toISODate(task.endDate);
|
|
2854
|
+
const endDateISO = editingDuration ? getEndDateFromDuration(task.startDate, durationValue) : toISODate(task.endDate);
|
|
2758
2855
|
return /* @__PURE__ */ jsxs9(
|
|
2759
2856
|
"div",
|
|
2760
2857
|
{
|
|
@@ -2780,21 +2877,12 @@ var TaskListRow = React9.memo(
|
|
|
2780
2877
|
},
|
|
2781
2878
|
tabIndex: isSelected ? 0 : -1,
|
|
2782
2879
|
children: [
|
|
2783
|
-
/* @__PURE__ */
|
|
2880
|
+
/* @__PURE__ */ jsxs9(
|
|
2784
2881
|
"div",
|
|
2785
2882
|
{
|
|
2786
2883
|
className: "gantt-tl-cell gantt-tl-cell-number",
|
|
2787
2884
|
onClick: handleNumberClick,
|
|
2788
|
-
children:
|
|
2789
|
-
"button",
|
|
2790
|
-
{
|
|
2791
|
-
type: "button",
|
|
2792
|
-
className: "gantt-tl-collapse-btn",
|
|
2793
|
-
onClick: handleToggleCollapse,
|
|
2794
|
-
"aria-label": isCollapsed ? "\u0420\u0430\u0437\u0432\u0435\u0440\u043D\u0443\u0442\u044C" : "\u0421\u0432\u0435\u0440\u043D\u0443\u0442\u044C",
|
|
2795
|
-
children: isCollapsed ? "+" : "-"
|
|
2796
|
-
}
|
|
2797
|
-
) : /* @__PURE__ */ jsxs9(Fragment2, { children: [
|
|
2885
|
+
children: [
|
|
2798
2886
|
/* @__PURE__ */ jsx12(
|
|
2799
2887
|
"span",
|
|
2800
2888
|
{
|
|
@@ -2810,10 +2898,20 @@ var TaskListRow = React9.memo(
|
|
|
2810
2898
|
}
|
|
2811
2899
|
),
|
|
2812
2900
|
/* @__PURE__ */ jsx12("span", { className: "gantt-tl-num-label", children: rowIndex + 1 })
|
|
2813
|
-
]
|
|
2901
|
+
]
|
|
2814
2902
|
}
|
|
2815
2903
|
),
|
|
2816
2904
|
/* @__PURE__ */ jsxs9("div", { className: "gantt-tl-cell gantt-tl-cell-name", children: [
|
|
2905
|
+
isParent && !editingName && /* @__PURE__ */ jsx12(
|
|
2906
|
+
"button",
|
|
2907
|
+
{
|
|
2908
|
+
type: "button",
|
|
2909
|
+
className: `gantt-tl-collapse-btn ${isCollapsed ? "gantt-tl-collapse-btn-collapsed" : ""}`,
|
|
2910
|
+
onClick: handleToggleCollapse,
|
|
2911
|
+
"aria-label": isCollapsed ? "Expand children" : "Collapse children",
|
|
2912
|
+
children: /* @__PURE__ */ jsx12(ChevronRightIcon, {})
|
|
2913
|
+
}
|
|
2914
|
+
),
|
|
2817
2915
|
editingName && /* @__PURE__ */ jsx12(
|
|
2818
2916
|
Input,
|
|
2819
2917
|
{
|
|
@@ -2823,7 +2921,7 @@ var TaskListRow = React9.memo(
|
|
|
2823
2921
|
onChange: (e) => setNameValue(e.target.value),
|
|
2824
2922
|
onBlur: handleNameSave,
|
|
2825
2923
|
onKeyDown: handleNameKeyDown,
|
|
2826
|
-
className: "gantt-tl-name-input",
|
|
2924
|
+
className: ["gantt-tl-name-input", isChild ? "gantt-tl-name-input-child" : ""].filter(Boolean).join(" "),
|
|
2827
2925
|
onClick: (e) => e.stopPropagation()
|
|
2828
2926
|
}
|
|
2829
2927
|
),
|
|
@@ -2831,7 +2929,13 @@ var TaskListRow = React9.memo(
|
|
|
2831
2929
|
"button",
|
|
2832
2930
|
{
|
|
2833
2931
|
type: "button",
|
|
2834
|
-
className:
|
|
2932
|
+
className: [
|
|
2933
|
+
"gantt-tl-name-trigger",
|
|
2934
|
+
disableTaskNameEditing ? "gantt-tl-name-locked" : "",
|
|
2935
|
+
isParent ? "gantt-tl-name-trigger-parent" : "",
|
|
2936
|
+
isChild ? "gantt-tl-name-trigger-child" : ""
|
|
2937
|
+
].filter(Boolean).join(" "),
|
|
2938
|
+
title: task.name,
|
|
2835
2939
|
onClick: handleNameClick,
|
|
2836
2940
|
onDoubleClick: handleNameDoubleClick,
|
|
2837
2941
|
style: editingName ? { visibility: "hidden", pointerEvents: "none" } : void 0,
|
|
@@ -2920,22 +3024,91 @@ var TaskListRow = React9.memo(
|
|
|
2920
3024
|
disabled: task.locked
|
|
2921
3025
|
}
|
|
2922
3026
|
) }),
|
|
3027
|
+
/* @__PURE__ */ jsxs9("div", { className: "gantt-tl-cell gantt-tl-cell-duration", onClick: handleDurationClick, children: [
|
|
3028
|
+
editingDuration && /* @__PURE__ */ jsxs9("div", { className: "gantt-tl-number-editor", onClick: (e) => e.stopPropagation(), children: [
|
|
3029
|
+
/* @__PURE__ */ jsx12(
|
|
3030
|
+
Input,
|
|
3031
|
+
{
|
|
3032
|
+
ref: durationInputRef,
|
|
3033
|
+
type: "number",
|
|
3034
|
+
min: 1,
|
|
3035
|
+
step: 1,
|
|
3036
|
+
value: durationValue,
|
|
3037
|
+
onChange: (e) => applyDurationChange(parseInt(e.target.value, 10) || 1),
|
|
3038
|
+
onBlur: handleDurationSave,
|
|
3039
|
+
onKeyDown: handleDurationKeyDown,
|
|
3040
|
+
className: "gantt-tl-number-input"
|
|
3041
|
+
}
|
|
3042
|
+
),
|
|
3043
|
+
/* @__PURE__ */ jsxs9("div", { className: "gantt-tl-number-steppers", "aria-hidden": "true", children: [
|
|
3044
|
+
/* @__PURE__ */ jsx12(
|
|
3045
|
+
"button",
|
|
3046
|
+
{
|
|
3047
|
+
type: "button",
|
|
3048
|
+
className: "gantt-tl-number-stepper",
|
|
3049
|
+
tabIndex: -1,
|
|
3050
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
3051
|
+
onClick: () => handleDurationAdjust(1),
|
|
3052
|
+
children: /* @__PURE__ */ jsx12("svg", { xmlns: "http://www.w3.org/2000/svg", width: "10", height: "10", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx12("path", { d: "m18 15-6-6-6 6" }) })
|
|
3053
|
+
}
|
|
3054
|
+
),
|
|
3055
|
+
/* @__PURE__ */ jsx12(
|
|
3056
|
+
"button",
|
|
3057
|
+
{
|
|
3058
|
+
type: "button",
|
|
3059
|
+
className: "gantt-tl-number-stepper",
|
|
3060
|
+
tabIndex: -1,
|
|
3061
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
3062
|
+
onClick: () => handleDurationAdjust(-1),
|
|
3063
|
+
children: /* @__PURE__ */ jsx12("svg", { xmlns: "http://www.w3.org/2000/svg", width: "10", height: "10", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx12("path", { d: "m6 9 6 6 6-6" }) })
|
|
3064
|
+
}
|
|
3065
|
+
)
|
|
3066
|
+
] })
|
|
3067
|
+
] }),
|
|
3068
|
+
/* @__PURE__ */ jsx12("span", { style: editingDuration ? { visibility: "hidden", pointerEvents: "none" } : void 0, children: getInclusiveDurationDays(task.startDate, task.endDate) })
|
|
3069
|
+
] }),
|
|
2923
3070
|
/* @__PURE__ */ jsxs9("div", { className: "gantt-tl-cell gantt-tl-cell-progress", onClick: handleProgressClick, children: [
|
|
2924
|
-
editingProgress && /* @__PURE__ */
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
3071
|
+
editingProgress && /* @__PURE__ */ jsxs9("div", { className: "gantt-tl-number-editor", onClick: (e) => e.stopPropagation(), children: [
|
|
3072
|
+
/* @__PURE__ */ jsx12(
|
|
3073
|
+
Input,
|
|
3074
|
+
{
|
|
3075
|
+
ref: progressInputRef,
|
|
3076
|
+
type: "number",
|
|
3077
|
+
min: 0,
|
|
3078
|
+
max: 100,
|
|
3079
|
+
step: 1,
|
|
3080
|
+
value: progressValue,
|
|
3081
|
+
onChange: (e) => setProgressValue(parseInt(e.target.value, 10) || 0),
|
|
3082
|
+
onBlur: handleProgressSave,
|
|
3083
|
+
onKeyDown: handleProgressKeyDown,
|
|
3084
|
+
className: "gantt-tl-number-input"
|
|
3085
|
+
}
|
|
3086
|
+
),
|
|
3087
|
+
/* @__PURE__ */ jsxs9("div", { className: "gantt-tl-number-steppers", "aria-hidden": "true", children: [
|
|
3088
|
+
/* @__PURE__ */ jsx12(
|
|
3089
|
+
"button",
|
|
3090
|
+
{
|
|
3091
|
+
type: "button",
|
|
3092
|
+
className: "gantt-tl-number-stepper",
|
|
3093
|
+
tabIndex: -1,
|
|
3094
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
3095
|
+
onClick: () => handleProgressAdjust(1),
|
|
3096
|
+
children: /* @__PURE__ */ jsx12("svg", { xmlns: "http://www.w3.org/2000/svg", width: "10", height: "10", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx12("path", { d: "m18 15-6-6-6 6" }) })
|
|
3097
|
+
}
|
|
3098
|
+
),
|
|
3099
|
+
/* @__PURE__ */ jsx12(
|
|
3100
|
+
"button",
|
|
3101
|
+
{
|
|
3102
|
+
type: "button",
|
|
3103
|
+
className: "gantt-tl-number-stepper",
|
|
3104
|
+
tabIndex: -1,
|
|
3105
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
3106
|
+
onClick: () => handleProgressAdjust(-1),
|
|
3107
|
+
children: /* @__PURE__ */ jsx12("svg", { xmlns: "http://www.w3.org/2000/svg", width: "10", height: "10", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx12("path", { d: "m6 9 6 6 6-6" }) })
|
|
3108
|
+
}
|
|
3109
|
+
)
|
|
3110
|
+
] })
|
|
3111
|
+
] }),
|
|
2939
3112
|
/* @__PURE__ */ jsx12("span", { style: editingProgress ? { visibility: "hidden", pointerEvents: "none" } : void 0, children: task.progress ? `${Math.round(task.progress)}%` : "0%" })
|
|
2940
3113
|
] }),
|
|
2941
3114
|
/* @__PURE__ */ jsx12(
|
|
@@ -3092,15 +3265,17 @@ var NewTaskRow = ({ rowHeight, onConfirm, onCancel }) => {
|
|
|
3092
3265
|
// src/components/TaskList/TaskList.tsx
|
|
3093
3266
|
import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
3094
3267
|
var LINK_TYPE_ORDER = ["FS", "SS", "FF", "SF"];
|
|
3268
|
+
var MIN_TASK_LIST_WIDTH = 640;
|
|
3095
3269
|
var TaskList = ({
|
|
3096
3270
|
tasks,
|
|
3097
3271
|
rowHeight,
|
|
3098
3272
|
headerHeight,
|
|
3099
|
-
taskListWidth =
|
|
3273
|
+
taskListWidth = 640,
|
|
3100
3274
|
onTaskChange,
|
|
3101
3275
|
selectedTaskId,
|
|
3102
3276
|
onTaskSelect,
|
|
3103
3277
|
show = true,
|
|
3278
|
+
hasRightShadow = false,
|
|
3104
3279
|
disableTaskNameEditing = false,
|
|
3105
3280
|
disableDependencyEditing = false,
|
|
3106
3281
|
onScrollToTask,
|
|
@@ -3239,11 +3414,13 @@ var TaskList = ({
|
|
|
3239
3414
|
const [draggingIndex, setDraggingIndex] = useState6(null);
|
|
3240
3415
|
const [dragOverIndex, setDragOverIndex] = useState6(null);
|
|
3241
3416
|
const dragOriginIndexRef = useRef5(null);
|
|
3417
|
+
const dragTaskIdRef = useRef5(null);
|
|
3242
3418
|
const handleDragStart = useCallback5((index, e) => {
|
|
3243
3419
|
e.dataTransfer.effectAllowed = "move";
|
|
3244
3420
|
setDraggingIndex(index);
|
|
3245
3421
|
dragOriginIndexRef.current = index;
|
|
3246
|
-
|
|
3422
|
+
dragTaskIdRef.current = visibleTasks[index]?.id ?? null;
|
|
3423
|
+
}, [visibleTasks]);
|
|
3247
3424
|
const handleDragOver = useCallback5((index, e) => {
|
|
3248
3425
|
e.preventDefault();
|
|
3249
3426
|
e.dataTransfer.dropEffect = "move";
|
|
@@ -3251,16 +3428,32 @@ var TaskList = ({
|
|
|
3251
3428
|
}, []);
|
|
3252
3429
|
const handleDrop = useCallback5((dropIndex, e) => {
|
|
3253
3430
|
e.preventDefault();
|
|
3254
|
-
const
|
|
3255
|
-
|
|
3431
|
+
const originVisibleIndex = dragOriginIndexRef.current;
|
|
3432
|
+
const movedTaskId = dragTaskIdRef.current;
|
|
3433
|
+
if (originVisibleIndex === null || movedTaskId === null || originVisibleIndex === dropIndex) {
|
|
3434
|
+
setDraggingIndex(null);
|
|
3435
|
+
setDragOverIndex(null);
|
|
3436
|
+
dragOriginIndexRef.current = null;
|
|
3437
|
+
dragTaskIdRef.current = null;
|
|
3438
|
+
return;
|
|
3439
|
+
}
|
|
3440
|
+
const reorderPosition = getVisibleReorderPosition(
|
|
3441
|
+
orderedTasks,
|
|
3442
|
+
visibleTasks,
|
|
3443
|
+
movedTaskId,
|
|
3444
|
+
originVisibleIndex,
|
|
3445
|
+
dropIndex
|
|
3446
|
+
);
|
|
3447
|
+
if (!reorderPosition) {
|
|
3256
3448
|
setDraggingIndex(null);
|
|
3257
3449
|
setDragOverIndex(null);
|
|
3258
3450
|
dragOriginIndexRef.current = null;
|
|
3451
|
+
dragTaskIdRef.current = null;
|
|
3259
3452
|
return;
|
|
3260
3453
|
}
|
|
3454
|
+
const { originOrderedIndex, insertIndex } = reorderPosition;
|
|
3261
3455
|
const reordered = [...orderedTasks];
|
|
3262
|
-
const [moved] = reordered.splice(
|
|
3263
|
-
const insertIndex = dropIndex === visibleTasks.length ? visibleTasks.length - 1 : originIndex < dropIndex ? dropIndex - 1 : dropIndex;
|
|
3456
|
+
const [moved] = reordered.splice(originOrderedIndex, 1);
|
|
3264
3457
|
const isChild = !!moved.parentId;
|
|
3265
3458
|
const isParent = tasks.some((t) => t.parentId === moved.id);
|
|
3266
3459
|
const taskType = isParent ? "PARENT" : isChild ? "CHILD" : "ROOT";
|
|
@@ -3270,10 +3463,11 @@ var TaskList = ({
|
|
|
3270
3463
|
name: moved.name,
|
|
3271
3464
|
type: taskType,
|
|
3272
3465
|
parentId: moved.parentId,
|
|
3273
|
-
originIndex,
|
|
3466
|
+
originIndex: originOrderedIndex,
|
|
3467
|
+
originVisibleIndex,
|
|
3274
3468
|
dropIndex,
|
|
3275
3469
|
insertIndex,
|
|
3276
|
-
direction:
|
|
3470
|
+
direction: originVisibleIndex < dropIndex ? "DOWN" : "UP"
|
|
3277
3471
|
});
|
|
3278
3472
|
console.log("[TASKS ARRAY LENGTH]", orderedTasks.length);
|
|
3279
3473
|
let inferredParentId;
|
|
@@ -3360,11 +3554,13 @@ var TaskList = ({
|
|
|
3360
3554
|
setDraggingIndex(null);
|
|
3361
3555
|
setDragOverIndex(null);
|
|
3362
3556
|
dragOriginIndexRef.current = null;
|
|
3363
|
-
|
|
3557
|
+
dragTaskIdRef.current = null;
|
|
3558
|
+
}, [orderedTasks, visibleTasks, onReorder, onTaskSelect]);
|
|
3364
3559
|
const handleDragEnd = useCallback5(() => {
|
|
3365
3560
|
setDraggingIndex(null);
|
|
3366
3561
|
setDragOverIndex(null);
|
|
3367
3562
|
dragOriginIndexRef.current = null;
|
|
3563
|
+
dragTaskIdRef.current = null;
|
|
3368
3564
|
}, []);
|
|
3369
3565
|
const handleConfirmNewTask = useCallback5((name) => {
|
|
3370
3566
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -3388,18 +3584,20 @@ var TaskList = ({
|
|
|
3388
3584
|
setIsCreating(false);
|
|
3389
3585
|
}, [onAdd]);
|
|
3390
3586
|
const handleCancelNewTask = useCallback5(() => setIsCreating(false), []);
|
|
3587
|
+
const effectiveTaskListWidth = Math.max(taskListWidth, MIN_TASK_LIST_WIDTH);
|
|
3391
3588
|
return /* @__PURE__ */ jsx14(
|
|
3392
3589
|
"div",
|
|
3393
3590
|
{
|
|
3394
3591
|
ref: overlayRef,
|
|
3395
|
-
className: `gantt-tl-overlay${show ? "" : " gantt-tl-hidden"}`,
|
|
3396
|
-
style: { width: `${
|
|
3592
|
+
className: `gantt-tl-overlay${show ? "" : " gantt-tl-hidden"}${hasRightShadow ? " gantt-tl-overlay-shadowed" : ""}`,
|
|
3593
|
+
style: { width: `${effectiveTaskListWidth}px`, minWidth: `${MIN_TASK_LIST_WIDTH}px` },
|
|
3397
3594
|
children: /* @__PURE__ */ jsxs11("div", { className: "gantt-tl-table", children: [
|
|
3398
3595
|
/* @__PURE__ */ jsxs11("div", { className: "gantt-tl-header", style: { height: `${headerHeight + 0.5}px` }, children: [
|
|
3399
3596
|
/* @__PURE__ */ jsx14("div", { className: "gantt-tl-headerCell gantt-tl-cell-number", children: "\u2116" }),
|
|
3400
3597
|
/* @__PURE__ */ jsx14("div", { className: "gantt-tl-headerCell gantt-tl-cell-name", children: "\u0418\u043C\u044F" }),
|
|
3401
3598
|
/* @__PURE__ */ jsx14("div", { className: "gantt-tl-headerCell gantt-tl-cell-date", children: "\u041D\u0430\u0447\u0430\u043B\u043E" }),
|
|
3402
3599
|
/* @__PURE__ */ jsx14("div", { className: "gantt-tl-headerCell gantt-tl-cell-date", children: "\u041E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u0435" }),
|
|
3600
|
+
/* @__PURE__ */ jsx14("div", { className: "gantt-tl-headerCell gantt-tl-cell-duration", children: "\u0414\u043D." }),
|
|
3403
3601
|
/* @__PURE__ */ jsx14("div", { className: "gantt-tl-headerCell gantt-tl-cell-progress", children: "%" }),
|
|
3404
3602
|
/* @__PURE__ */ jsxs11("div", { className: "gantt-tl-headerCell gantt-tl-cell-deps", style: { position: "relative" }, children: [
|
|
3405
3603
|
/* @__PURE__ */ jsxs11(Popover, { open: typeMenuOpen, onOpenChange: setTypeMenuOpen, children: [
|
|
@@ -3525,7 +3723,7 @@ var GanttChart = forwardRef(({
|
|
|
3525
3723
|
disableConstraints,
|
|
3526
3724
|
onCascade,
|
|
3527
3725
|
showTaskList = false,
|
|
3528
|
-
taskListWidth =
|
|
3726
|
+
taskListWidth = 660,
|
|
3529
3727
|
disableTaskNameEditing = false,
|
|
3530
3728
|
disableDependencyEditing = false,
|
|
3531
3729
|
highlightExpiredTasks = false,
|
|
@@ -3537,6 +3735,7 @@ var GanttChart = forwardRef(({
|
|
|
3537
3735
|
}, ref) => {
|
|
3538
3736
|
const scrollContainerRef = useRef6(null);
|
|
3539
3737
|
const [selectedTaskId, setSelectedTaskId] = useState7(null);
|
|
3738
|
+
const [taskListHasRightShadow, setTaskListHasRightShadow] = useState7(false);
|
|
3540
3739
|
const [selectedChip, setSelectedChip] = useState7(null);
|
|
3541
3740
|
const [collapsedParentIds, setCollapsedParentIds] = useState7(/* @__PURE__ */ new Set());
|
|
3542
3741
|
const [editingTaskId, setEditingTaskId] = useState7(null);
|
|
@@ -3583,6 +3782,18 @@ var GanttChart = forwardRef(({
|
|
|
3583
3782
|
const scrollLeft = Math.round(todayOffset - containerWidth / 2 + dayWidth / 2);
|
|
3584
3783
|
container.scrollLeft = Math.max(0, scrollLeft);
|
|
3585
3784
|
}, []);
|
|
3785
|
+
useEffect6(() => {
|
|
3786
|
+
const container = scrollContainerRef.current;
|
|
3787
|
+
if (!container) return;
|
|
3788
|
+
const updateShadow = () => {
|
|
3789
|
+
setTaskListHasRightShadow(container.scrollLeft > 0);
|
|
3790
|
+
};
|
|
3791
|
+
updateShadow();
|
|
3792
|
+
container.addEventListener("scroll", updateShadow, { passive: true });
|
|
3793
|
+
return () => {
|
|
3794
|
+
container.removeEventListener("scroll", updateShadow);
|
|
3795
|
+
};
|
|
3796
|
+
}, []);
|
|
3586
3797
|
const scrollToToday = useCallback6(() => {
|
|
3587
3798
|
const container = scrollContainerRef.current;
|
|
3588
3799
|
if (!container || dateRange.length === 0) return;
|
|
@@ -3986,6 +4197,7 @@ var GanttChart = forwardRef(({
|
|
|
3986
4197
|
selectedTaskId: selectedTaskId ?? void 0,
|
|
3987
4198
|
onTaskSelect: handleTaskSelect,
|
|
3988
4199
|
show: showTaskList,
|
|
4200
|
+
hasRightShadow: taskListHasRightShadow,
|
|
3989
4201
|
disableTaskNameEditing,
|
|
3990
4202
|
disableDependencyEditing,
|
|
3991
4203
|
onScrollToTask: scrollToTask,
|
|
@@ -4148,6 +4360,7 @@ export {
|
|
|
4148
4360
|
getMultiMonthDays,
|
|
4149
4361
|
getSuccessorChain,
|
|
4150
4362
|
getTransitiveCascadeChain,
|
|
4363
|
+
getVisibleReorderPosition,
|
|
4151
4364
|
isTaskParent,
|
|
4152
4365
|
isToday,
|
|
4153
4366
|
isWeekend,
|