gantt-lib 0.3.3 → 0.4.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 +19 -1
- package/dist/index.d.ts +19 -1
- package/dist/index.js +427 -182
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +408 -162
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +129 -286
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
// src/components/GanttChart/GanttChart.tsx
|
|
4
|
-
import { useMemo as useMemo9, useCallback as useCallback6, useRef as
|
|
4
|
+
import { useMemo as useMemo9, useCallback as useCallback6, useRef as useRef6, useState as useState7, useEffect as useEffect6, useImperativeHandle, forwardRef } from "react";
|
|
5
5
|
|
|
6
6
|
// src/utils/dateUtils.ts
|
|
7
7
|
var parseUTCDate = (date) => {
|
|
@@ -42,9 +42,9 @@ var getDayOffset = (date, monthStart) => {
|
|
|
42
42
|
var isToday = (date) => {
|
|
43
43
|
const now = /* @__PURE__ */ new Date();
|
|
44
44
|
const today = new Date(Date.UTC(
|
|
45
|
-
now.
|
|
46
|
-
now.
|
|
47
|
-
now.
|
|
45
|
+
now.getFullYear(),
|
|
46
|
+
now.getMonth(),
|
|
47
|
+
now.getDate()
|
|
48
48
|
));
|
|
49
49
|
const compareDate = new Date(Date.UTC(
|
|
50
50
|
date.getUTCFullYear(),
|
|
@@ -523,7 +523,7 @@ var calculateGridLines = (dateRange, dayWidth) => {
|
|
|
523
523
|
for (let i = 0; i < dateRange.length; i++) {
|
|
524
524
|
const date = dateRange[i];
|
|
525
525
|
const x = Math.round(i * dayWidth);
|
|
526
|
-
const isMonthStart = date.getUTCDate() === 1;
|
|
526
|
+
const isMonthStart = i === 0 ? false : date.getUTCDate() === 1;
|
|
527
527
|
const isWeekStart = date.getUTCDay() === 1;
|
|
528
528
|
lines.push({ x, isMonthStart, isWeekStart });
|
|
529
529
|
}
|
|
@@ -1102,7 +1102,7 @@ var TaskRow = React2.memo(
|
|
|
1102
1102
|
const isExpired = useMemo2(() => {
|
|
1103
1103
|
if (!highlightExpiredTasks) return false;
|
|
1104
1104
|
const now = /* @__PURE__ */ new Date();
|
|
1105
|
-
const today = new Date(Date.UTC(now.
|
|
1105
|
+
const today = new Date(Date.UTC(now.getFullYear(), now.getMonth(), now.getDate()));
|
|
1106
1106
|
const taskStart = parseUTCDate(task.startDate);
|
|
1107
1107
|
const taskEnd = parseUTCDate(task.endDate);
|
|
1108
1108
|
const actualProgress = task.progress ?? 0;
|
|
@@ -1322,7 +1322,7 @@ var TodayIndicator_default = TodayIndicator;
|
|
|
1322
1322
|
import React4, { useMemo as useMemo4 } from "react";
|
|
1323
1323
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1324
1324
|
var arePropsEqual2 = (prevProps, nextProps) => {
|
|
1325
|
-
return prevProps.dayWidth === nextProps.dayWidth && prevProps.dateRange.length === nextProps.dateRange.length && prevProps.totalHeight
|
|
1325
|
+
return prevProps.dayWidth === nextProps.dayWidth && prevProps.dateRange.length === nextProps.dateRange.length && prevProps.totalHeight === nextProps.totalHeight;
|
|
1326
1326
|
};
|
|
1327
1327
|
var GridBackground = React4.memo(
|
|
1328
1328
|
({ dateRange, dayWidth, totalHeight }) => {
|
|
@@ -1609,7 +1609,7 @@ DependencyLines.displayName = "DependencyLines";
|
|
|
1609
1609
|
var DependencyLines_default = DependencyLines;
|
|
1610
1610
|
|
|
1611
1611
|
// src/components/TaskList/TaskList.tsx
|
|
1612
|
-
import
|
|
1612
|
+
import React11, { useMemo as useMemo8, useCallback as useCallback5, useState as useState6, useEffect as useEffect5, useRef as useRef5 } from "react";
|
|
1613
1613
|
|
|
1614
1614
|
// src/components/ui/Popover.tsx
|
|
1615
1615
|
import * as RadixPopover from "@radix-ui/react-popover";
|
|
@@ -1683,6 +1683,7 @@ import {
|
|
|
1683
1683
|
format as format2,
|
|
1684
1684
|
addMonths,
|
|
1685
1685
|
subMonths,
|
|
1686
|
+
addDays,
|
|
1686
1687
|
isSameDay,
|
|
1687
1688
|
getDay,
|
|
1688
1689
|
isToday as isToday2,
|
|
@@ -1796,7 +1797,73 @@ var Calendar = ({
|
|
|
1796
1797
|
() => months.map(renderMonth),
|
|
1797
1798
|
[months, renderMonth]
|
|
1798
1799
|
);
|
|
1799
|
-
|
|
1800
|
+
const handleDayShift = useCallback2(
|
|
1801
|
+
(deltaDays) => {
|
|
1802
|
+
if (!onSelect || disabled) return;
|
|
1803
|
+
const baseDate = selected ?? /* @__PURE__ */ new Date();
|
|
1804
|
+
onSelect(addDays(baseDate, deltaDays));
|
|
1805
|
+
},
|
|
1806
|
+
[onSelect, selected, disabled]
|
|
1807
|
+
);
|
|
1808
|
+
const handleToday = useCallback2(() => {
|
|
1809
|
+
if (!onSelect || disabled) return;
|
|
1810
|
+
onSelect(/* @__PURE__ */ new Date());
|
|
1811
|
+
}, [onSelect, disabled]);
|
|
1812
|
+
return /* @__PURE__ */ jsxs6("div", { ref: scrollRef, className: "gantt-cal-container", children: [
|
|
1813
|
+
renderedMonths,
|
|
1814
|
+
/* @__PURE__ */ jsxs6("div", { className: "gantt-cal-nav", children: [
|
|
1815
|
+
/* @__PURE__ */ jsx9(
|
|
1816
|
+
"button",
|
|
1817
|
+
{
|
|
1818
|
+
type: "button",
|
|
1819
|
+
className: "gantt-btn gantt-btn-sm",
|
|
1820
|
+
onClick: () => handleDayShift(-7),
|
|
1821
|
+
disabled,
|
|
1822
|
+
children: "-7"
|
|
1823
|
+
}
|
|
1824
|
+
),
|
|
1825
|
+
/* @__PURE__ */ jsx9(
|
|
1826
|
+
"button",
|
|
1827
|
+
{
|
|
1828
|
+
type: "button",
|
|
1829
|
+
className: "gantt-btn gantt-btn-sm",
|
|
1830
|
+
onClick: () => handleDayShift(-1),
|
|
1831
|
+
disabled,
|
|
1832
|
+
children: "-1"
|
|
1833
|
+
}
|
|
1834
|
+
),
|
|
1835
|
+
/* @__PURE__ */ jsx9(
|
|
1836
|
+
"button",
|
|
1837
|
+
{
|
|
1838
|
+
type: "button",
|
|
1839
|
+
className: "gantt-btn gantt-btn-sm",
|
|
1840
|
+
onClick: handleToday,
|
|
1841
|
+
disabled,
|
|
1842
|
+
children: "\u0421\u0435\u0433\u043E\u0434\u043D\u044F"
|
|
1843
|
+
}
|
|
1844
|
+
),
|
|
1845
|
+
/* @__PURE__ */ jsx9(
|
|
1846
|
+
"button",
|
|
1847
|
+
{
|
|
1848
|
+
type: "button",
|
|
1849
|
+
className: "gantt-btn gantt-btn-sm",
|
|
1850
|
+
onClick: () => handleDayShift(1),
|
|
1851
|
+
disabled,
|
|
1852
|
+
children: "+1"
|
|
1853
|
+
}
|
|
1854
|
+
),
|
|
1855
|
+
/* @__PURE__ */ jsx9(
|
|
1856
|
+
"button",
|
|
1857
|
+
{
|
|
1858
|
+
type: "button",
|
|
1859
|
+
className: "gantt-btn gantt-btn-sm",
|
|
1860
|
+
onClick: () => handleDayShift(7),
|
|
1861
|
+
disabled,
|
|
1862
|
+
children: "+7"
|
|
1863
|
+
}
|
|
1864
|
+
)
|
|
1865
|
+
] })
|
|
1866
|
+
] });
|
|
1800
1867
|
};
|
|
1801
1868
|
Calendar.displayName = "Calendar";
|
|
1802
1869
|
|
|
@@ -1904,6 +1971,7 @@ var TrashIcon = () => /* @__PURE__ */ jsxs9("svg", { xmlns: "http://www.w3.org/2
|
|
|
1904
1971
|
/* @__PURE__ */ jsx12("path", { d: "M3 6h18" }),
|
|
1905
1972
|
/* @__PURE__ */ jsx12("path", { d: "M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })
|
|
1906
1973
|
] });
|
|
1974
|
+
var PlusIcon = () => /* @__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: "M12 5v14M5 12h14" }) });
|
|
1907
1975
|
function formatDepDescription(type, lag) {
|
|
1908
1976
|
const effectiveLag = lag ?? 0;
|
|
1909
1977
|
if (type === "FS") {
|
|
@@ -1945,12 +2013,19 @@ var DepChip = ({
|
|
|
1945
2013
|
const handleClick = (e) => {
|
|
1946
2014
|
e.stopPropagation();
|
|
1947
2015
|
if (disableDependencyEditing) return;
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
2016
|
+
if (isSelected) {
|
|
2017
|
+
e.preventDefault();
|
|
2018
|
+
onChipSelect?.(null);
|
|
2019
|
+
return;
|
|
1952
2020
|
}
|
|
2021
|
+
onChipSelect?.({ successorId: taskId, predecessorId: dep.taskId, linkType: dep.type });
|
|
2022
|
+
onScrollToTask?.(dep.taskId);
|
|
1953
2023
|
};
|
|
2024
|
+
const handleOpenChange = useCallback4((open) => {
|
|
2025
|
+
if (!open) {
|
|
2026
|
+
onChipSelect?.(null);
|
|
2027
|
+
}
|
|
2028
|
+
}, [onChipSelect]);
|
|
1954
2029
|
const handleTrashClick = (e) => {
|
|
1955
2030
|
e.stopPropagation();
|
|
1956
2031
|
onRemoveDependency?.(taskId, dep.taskId, dep.type);
|
|
@@ -1959,50 +2034,26 @@ var DepChip = ({
|
|
|
1959
2034
|
const Icon = LINK_TYPE_ICONS[dep.type];
|
|
1960
2035
|
const depPrefix = formatDepDescription(dep.type, lag);
|
|
1961
2036
|
const depName = predecessorName ?? dep.taskId;
|
|
1962
|
-
return /* @__PURE__ */ jsxs9(
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
/* @__PURE__ */ jsx12(
|
|
1966
|
-
"span",
|
|
1967
|
-
{
|
|
1968
|
-
className: `gantt-tl-dep-chip${isSelected ? " gantt-tl-dep-chip-selected" : ""}`,
|
|
1969
|
-
onClick: handleClick,
|
|
1970
|
-
children: /* @__PURE__ */ jsxs9(Fragment2, { children: [
|
|
1971
|
-
/* @__PURE__ */ jsx12(Icon, {}),
|
|
1972
|
-
lag != null && lag !== 0 ? lag > 0 ? `+${lag}` : `${lag}` : ""
|
|
1973
|
-
] })
|
|
1974
|
-
}
|
|
1975
|
-
),
|
|
1976
|
-
!disableDependencyEditing && /* @__PURE__ */ jsx12(
|
|
1977
|
-
"button",
|
|
1978
|
-
{
|
|
1979
|
-
type: "button",
|
|
1980
|
-
className: "gantt-tl-dep-chip-trash",
|
|
1981
|
-
"aria-label": "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u0432\u044F\u0437\u044C",
|
|
1982
|
-
onClick: handleTrashClick,
|
|
1983
|
-
children: /* @__PURE__ */ jsx12(TrashIcon, {})
|
|
1984
|
-
}
|
|
1985
|
-
)
|
|
1986
|
-
] }) }),
|
|
1987
|
-
/* @__PURE__ */ jsxs9(
|
|
1988
|
-
PopoverContent,
|
|
2037
|
+
return /* @__PURE__ */ jsxs9("span", { className: "gantt-tl-dep-chip-wrapper", children: [
|
|
2038
|
+
/* @__PURE__ */ jsx12(
|
|
2039
|
+
"span",
|
|
1989
2040
|
{
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2041
|
+
className: `gantt-tl-dep-chip${isSelected ? " gantt-tl-dep-chip-selected" : ""}`,
|
|
2042
|
+
onClick: handleClick,
|
|
2043
|
+
children: /* @__PURE__ */ jsxs9(Fragment2, { children: [
|
|
2044
|
+
/* @__PURE__ */ jsx12(Icon, {}),
|
|
2045
|
+
lag != null && lag !== 0 ? lag > 0 ? `+${lag}` : `${lag}` : ""
|
|
2046
|
+
] })
|
|
2047
|
+
}
|
|
2048
|
+
),
|
|
2049
|
+
!disableDependencyEditing && /* @__PURE__ */ jsx12(
|
|
2050
|
+
"button",
|
|
2051
|
+
{
|
|
2052
|
+
type: "button",
|
|
2053
|
+
className: "gantt-tl-dep-chip-trash",
|
|
2054
|
+
"aria-label": "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u0432\u044F\u0437\u044C",
|
|
2055
|
+
onClick: handleTrashClick,
|
|
2056
|
+
children: /* @__PURE__ */ jsx12(TrashIcon, {})
|
|
2006
2057
|
}
|
|
2007
2058
|
)
|
|
2008
2059
|
] });
|
|
@@ -2030,12 +2081,19 @@ var TaskListRow = React9.memo(
|
|
|
2030
2081
|
onRemoveDependency,
|
|
2031
2082
|
selectedChip,
|
|
2032
2083
|
onChipSelect,
|
|
2033
|
-
onScrollToTask
|
|
2084
|
+
onScrollToTask,
|
|
2085
|
+
onDelete,
|
|
2086
|
+
onAdd,
|
|
2087
|
+
onInsertAfter,
|
|
2088
|
+
editingTaskId
|
|
2034
2089
|
}) => {
|
|
2035
2090
|
const [editingName, setEditingName] = useState4(false);
|
|
2036
2091
|
const [nameValue, setNameValue] = useState4("");
|
|
2037
2092
|
const nameInputRef = useRef3(null);
|
|
2038
2093
|
const [overflowOpen, setOverflowOpen] = useState4(false);
|
|
2094
|
+
const confirmedRef = useRef3(false);
|
|
2095
|
+
const autoEditedForRef = useRef3(null);
|
|
2096
|
+
const editTriggerRef = useRef3("doubleclick");
|
|
2039
2097
|
const isSelected = selectedTaskId === task.id;
|
|
2040
2098
|
const isPicking = selectingPredecessorFor != null;
|
|
2041
2099
|
const isSourceRow = isPicking && selectingPredecessorFor === task.id;
|
|
@@ -2059,15 +2117,59 @@ var TaskListRow = React9.memo(
|
|
|
2059
2117
|
useEffect3(() => {
|
|
2060
2118
|
if (editingName && nameInputRef.current) {
|
|
2061
2119
|
nameInputRef.current.focus();
|
|
2120
|
+
if (editTriggerRef.current === "keypress") {
|
|
2121
|
+
const len = nameInputRef.current.value.length;
|
|
2122
|
+
nameInputRef.current.setSelectionRange(len, len);
|
|
2123
|
+
} else {
|
|
2124
|
+
nameInputRef.current.select();
|
|
2125
|
+
}
|
|
2062
2126
|
}
|
|
2063
2127
|
}, [editingName]);
|
|
2128
|
+
useEffect3(() => {
|
|
2129
|
+
if (editingTaskId === task.id && !disableTaskNameEditing && autoEditedForRef.current !== editingTaskId) {
|
|
2130
|
+
autoEditedForRef.current = editingTaskId;
|
|
2131
|
+
confirmedRef.current = false;
|
|
2132
|
+
editTriggerRef.current = "autoedit";
|
|
2133
|
+
setNameValue(task.name);
|
|
2134
|
+
setEditingName(true);
|
|
2135
|
+
}
|
|
2136
|
+
}, [editingTaskId, task.id, disableTaskNameEditing]);
|
|
2064
2137
|
const handleNameClick = useCallback4((e) => {
|
|
2065
2138
|
if (disableTaskNameEditing) return;
|
|
2066
2139
|
e.stopPropagation();
|
|
2140
|
+
onRowClick?.(task.id);
|
|
2141
|
+
onScrollToTask?.(task.id);
|
|
2142
|
+
}, [task.id, disableTaskNameEditing, onRowClick, onScrollToTask]);
|
|
2143
|
+
const handleNameDoubleClick = useCallback4((e) => {
|
|
2144
|
+
if (disableTaskNameEditing) return;
|
|
2145
|
+
e.stopPropagation();
|
|
2146
|
+
confirmedRef.current = false;
|
|
2147
|
+
editTriggerRef.current = "doubleclick";
|
|
2067
2148
|
setNameValue(task.name);
|
|
2068
2149
|
setEditingName(true);
|
|
2069
2150
|
}, [task.name, disableTaskNameEditing]);
|
|
2151
|
+
const handleRowKeyDown = useCallback4((e) => {
|
|
2152
|
+
if (!editingName && !disableTaskNameEditing && e.key === "F2") {
|
|
2153
|
+
e.preventDefault();
|
|
2154
|
+
confirmedRef.current = false;
|
|
2155
|
+
editTriggerRef.current = "keypress";
|
|
2156
|
+
setNameValue(task.name);
|
|
2157
|
+
setEditingName(true);
|
|
2158
|
+
return;
|
|
2159
|
+
}
|
|
2160
|
+
if (!editingName && !disableTaskNameEditing && e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
|
|
2161
|
+
e.preventDefault();
|
|
2162
|
+
confirmedRef.current = false;
|
|
2163
|
+
editTriggerRef.current = "keypress";
|
|
2164
|
+
setNameValue(e.key);
|
|
2165
|
+
setEditingName(true);
|
|
2166
|
+
}
|
|
2167
|
+
}, [editingName, disableTaskNameEditing, task.name]);
|
|
2070
2168
|
const handleNameSave = useCallback4(() => {
|
|
2169
|
+
if (confirmedRef.current) {
|
|
2170
|
+
confirmedRef.current = false;
|
|
2171
|
+
return;
|
|
2172
|
+
}
|
|
2071
2173
|
if (nameValue.trim()) {
|
|
2072
2174
|
onTaskChange?.({ ...task, name: nameValue.trim() });
|
|
2073
2175
|
}
|
|
@@ -2077,9 +2179,16 @@ var TaskListRow = React9.memo(
|
|
|
2077
2179
|
setEditingName(false);
|
|
2078
2180
|
}, []);
|
|
2079
2181
|
const handleNameKeyDown = useCallback4((e) => {
|
|
2080
|
-
if (e.key === "Enter")
|
|
2081
|
-
|
|
2082
|
-
|
|
2182
|
+
if (e.key === "Enter") {
|
|
2183
|
+
confirmedRef.current = true;
|
|
2184
|
+
if (nameValue.trim()) {
|
|
2185
|
+
onTaskChange?.({ ...task, name: nameValue.trim() });
|
|
2186
|
+
}
|
|
2187
|
+
setEditingName(false);
|
|
2188
|
+
} else if (e.key === "Escape") {
|
|
2189
|
+
handleNameCancel();
|
|
2190
|
+
}
|
|
2191
|
+
}, [nameValue, task, onTaskChange, handleNameCancel]);
|
|
2083
2192
|
const handleStartDateChange = useCallback4((newDateISO) => {
|
|
2084
2193
|
if (!newDateISO) return;
|
|
2085
2194
|
const origStart = parseUTCDate(task.startDate);
|
|
@@ -2104,8 +2213,7 @@ var TaskListRow = React9.memo(
|
|
|
2104
2213
|
const handleNumberClick = useCallback4((e) => {
|
|
2105
2214
|
e.stopPropagation();
|
|
2106
2215
|
onRowClick?.(task.id);
|
|
2107
|
-
|
|
2108
|
-
}, [task.id, onRowClick, onScrollToTask]);
|
|
2216
|
+
}, [task.id, onRowClick]);
|
|
2109
2217
|
const handleAddClick = useCallback4((e) => {
|
|
2110
2218
|
e.stopPropagation();
|
|
2111
2219
|
onSetSelectingPredecessorFor?.(task.id);
|
|
@@ -2116,6 +2224,10 @@ var TaskListRow = React9.memo(
|
|
|
2116
2224
|
if (!selectingPredecessorFor || !activeLinkType) return;
|
|
2117
2225
|
onAddDependency?.(task.id, selectingPredecessorFor, activeLinkType);
|
|
2118
2226
|
}, [isPicking, isSourceRow, selectingPredecessorFor, task.id, activeLinkType, onAddDependency]);
|
|
2227
|
+
const handleCancelPicking = useCallback4((e) => {
|
|
2228
|
+
e.stopPropagation();
|
|
2229
|
+
onSetSelectingPredecessorFor?.(null);
|
|
2230
|
+
}, [onSetSelectingPredecessorFor]);
|
|
2119
2231
|
const isSelectedPredecessor = selectedChip != null && selectedChip.predecessorId === task.id;
|
|
2120
2232
|
const handleDeleteSelected = useCallback4((e) => {
|
|
2121
2233
|
e.stopPropagation();
|
|
@@ -2134,23 +2246,17 @@ var TaskListRow = React9.memo(
|
|
|
2134
2246
|
isPicking && !isSourceRow ? "gantt-tl-row-picking" : "",
|
|
2135
2247
|
isSourceRow ? "gantt-tl-row-picking-self" : ""
|
|
2136
2248
|
].filter(Boolean).join(" "),
|
|
2137
|
-
style: { minHeight: `${rowHeight}px
|
|
2249
|
+
style: { minHeight: `${rowHeight}px`, position: "relative" },
|
|
2138
2250
|
onClick: handleRowClickInternal,
|
|
2251
|
+
onKeyDown: handleRowKeyDown,
|
|
2252
|
+
tabIndex: isSelected ? 0 : -1,
|
|
2139
2253
|
children: [
|
|
2140
|
-
/* @__PURE__ */
|
|
2254
|
+
/* @__PURE__ */ jsx12(
|
|
2141
2255
|
"div",
|
|
2142
2256
|
{
|
|
2143
2257
|
className: "gantt-tl-cell gantt-tl-cell-number",
|
|
2144
2258
|
onClick: handleNumberClick,
|
|
2145
|
-
|
|
2146
|
-
children: [
|
|
2147
|
-
/* @__PURE__ */ jsx12("span", { className: "gantt-tl-num-label", children: rowIndex + 1 }),
|
|
2148
|
-
/* @__PURE__ */ jsxs9("svg", { className: "gantt-tl-num-icon", 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: [
|
|
2149
|
-
/* @__PURE__ */ jsx12("path", { d: "M17 12H3" }),
|
|
2150
|
-
/* @__PURE__ */ jsx12("path", { d: "m11 18 6-6-6-6" }),
|
|
2151
|
-
/* @__PURE__ */ jsx12("path", { d: "M21 5v14" })
|
|
2152
|
-
] })
|
|
2153
|
-
]
|
|
2259
|
+
children: /* @__PURE__ */ jsx12("span", { className: "gantt-tl-num-label", children: rowIndex + 1 })
|
|
2154
2260
|
}
|
|
2155
2261
|
),
|
|
2156
2262
|
/* @__PURE__ */ jsxs9("div", { className: "gantt-tl-cell gantt-tl-cell-name", children: [
|
|
@@ -2173,10 +2279,56 @@ var TaskListRow = React9.memo(
|
|
|
2173
2279
|
type: "button",
|
|
2174
2280
|
className: `gantt-tl-name-trigger ${disableTaskNameEditing ? "gantt-tl-name-locked" : ""}`,
|
|
2175
2281
|
onClick: handleNameClick,
|
|
2282
|
+
onDoubleClick: handleNameDoubleClick,
|
|
2176
2283
|
style: editingName ? { visibility: "hidden", pointerEvents: "none" } : void 0,
|
|
2177
2284
|
children: task.name
|
|
2178
2285
|
}
|
|
2179
|
-
)
|
|
2286
|
+
),
|
|
2287
|
+
!editingName && /* @__PURE__ */ jsxs9("div", { className: "gantt-tl-name-actions", children: [
|
|
2288
|
+
onInsertAfter && /* @__PURE__ */ jsx12(
|
|
2289
|
+
"button",
|
|
2290
|
+
{
|
|
2291
|
+
type: "button",
|
|
2292
|
+
className: "gantt-tl-name-action-btn gantt-tl-action-insert",
|
|
2293
|
+
onClick: (e) => {
|
|
2294
|
+
e.stopPropagation();
|
|
2295
|
+
const now = /* @__PURE__ */ new Date();
|
|
2296
|
+
const todayISO = new Date(Date.UTC(
|
|
2297
|
+
now.getUTCFullYear(),
|
|
2298
|
+
now.getUTCMonth(),
|
|
2299
|
+
now.getUTCDate()
|
|
2300
|
+
)).toISOString().split("T")[0];
|
|
2301
|
+
const endISO = new Date(Date.UTC(
|
|
2302
|
+
now.getUTCFullYear(),
|
|
2303
|
+
now.getUTCMonth(),
|
|
2304
|
+
now.getUTCDate() + 7
|
|
2305
|
+
)).toISOString().split("T")[0];
|
|
2306
|
+
const newTask = {
|
|
2307
|
+
id: crypto.randomUUID(),
|
|
2308
|
+
name: "\u041D\u043E\u0432\u0430\u044F \u0437\u0430\u0434\u0430\u0447\u0430",
|
|
2309
|
+
startDate: todayISO,
|
|
2310
|
+
endDate: endISO
|
|
2311
|
+
};
|
|
2312
|
+
onInsertAfter(task.id, newTask);
|
|
2313
|
+
},
|
|
2314
|
+
"aria-label": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0437\u0430\u0434\u0430\u0447\u0443 \u043F\u043E\u0441\u043B\u0435 \u044D\u0442\u043E\u0439",
|
|
2315
|
+
children: /* @__PURE__ */ jsx12(PlusIcon, {})
|
|
2316
|
+
}
|
|
2317
|
+
),
|
|
2318
|
+
onDelete && /* @__PURE__ */ jsx12(
|
|
2319
|
+
"button",
|
|
2320
|
+
{
|
|
2321
|
+
type: "button",
|
|
2322
|
+
className: "gantt-tl-name-action-btn gantt-tl-action-delete",
|
|
2323
|
+
onClick: (e) => {
|
|
2324
|
+
e.stopPropagation();
|
|
2325
|
+
onDelete(task.id);
|
|
2326
|
+
},
|
|
2327
|
+
"aria-label": "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0437\u0430\u0434\u0430\u0447\u0443",
|
|
2328
|
+
children: /* @__PURE__ */ jsx12(TrashIcon, {})
|
|
2329
|
+
}
|
|
2330
|
+
)
|
|
2331
|
+
] })
|
|
2180
2332
|
] }),
|
|
2181
2333
|
/* @__PURE__ */ jsx12("div", { className: "gantt-tl-cell gantt-tl-cell-date", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx12(
|
|
2182
2334
|
DatePicker,
|
|
@@ -2202,7 +2354,7 @@ var TaskListRow = React9.memo(
|
|
|
2202
2354
|
"div",
|
|
2203
2355
|
{
|
|
2204
2356
|
className: "gantt-tl-cell gantt-tl-cell-deps",
|
|
2205
|
-
onClick:
|
|
2357
|
+
onClick: isSourceRow ? handleCancelPicking : isPicking ? handlePredecessorPick : void 0,
|
|
2206
2358
|
children: isSourceRow ? /* @__PURE__ */ jsx12("span", { className: "gantt-tl-dep-source-hint", children: "\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0437\u0430\u0434\u0430\u0447\u0443" }) : isSelectedPredecessor && !disableDependencyEditing ? (
|
|
2207
2359
|
/* Full-replacement: "Зависит от [name]" → hover → "Удалить" */
|
|
2208
2360
|
/* @__PURE__ */ jsxs9(
|
|
@@ -2279,7 +2431,7 @@ var TaskListRow = React9.memo(
|
|
|
2279
2431
|
"button",
|
|
2280
2432
|
{
|
|
2281
2433
|
type: "button",
|
|
2282
|
-
className: "gantt-tl-dep-add"
|
|
2434
|
+
className: `gantt-tl-dep-add gantt-tl-dep-add-hover${selectedChip ? " gantt-tl-dep-add-hidden" : ""}`,
|
|
2283
2435
|
onClick: handleAddClick,
|
|
2284
2436
|
"aria-label": "\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0441\u0432\u044F\u0437\u044C",
|
|
2285
2437
|
children: "+"
|
|
@@ -2295,14 +2447,68 @@ var TaskListRow = React9.memo(
|
|
|
2295
2447
|
);
|
|
2296
2448
|
TaskListRow.displayName = "TaskListRow";
|
|
2297
2449
|
|
|
2298
|
-
// src/components/TaskList/
|
|
2450
|
+
// src/components/TaskList/NewTaskRow.tsx
|
|
2451
|
+
import { useState as useState5, useRef as useRef4, useEffect as useEffect4 } from "react";
|
|
2299
2452
|
import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2453
|
+
var NewTaskRow = ({ rowHeight, onConfirm, onCancel }) => {
|
|
2454
|
+
const [nameValue, setNameValue] = useState5("");
|
|
2455
|
+
const inputRef = useRef4(null);
|
|
2456
|
+
const confirmedRef = useRef4(false);
|
|
2457
|
+
useEffect4(() => {
|
|
2458
|
+
if (inputRef.current) {
|
|
2459
|
+
inputRef.current.focus();
|
|
2460
|
+
inputRef.current.select();
|
|
2461
|
+
}
|
|
2462
|
+
}, []);
|
|
2463
|
+
const handleKeyDown = (e) => {
|
|
2464
|
+
if (e.key === "Enter") {
|
|
2465
|
+
if (nameValue.trim()) {
|
|
2466
|
+
confirmedRef.current = true;
|
|
2467
|
+
onConfirm(nameValue.trim());
|
|
2468
|
+
} else {
|
|
2469
|
+
onCancel();
|
|
2470
|
+
}
|
|
2471
|
+
} else if (e.key === "Escape") {
|
|
2472
|
+
onCancel();
|
|
2473
|
+
}
|
|
2474
|
+
};
|
|
2475
|
+
const handleBlur = () => {
|
|
2476
|
+
if (confirmedRef.current) return;
|
|
2477
|
+
if (nameValue.trim()) {
|
|
2478
|
+
confirmedRef.current = true;
|
|
2479
|
+
onConfirm(nameValue.trim());
|
|
2480
|
+
} else {
|
|
2481
|
+
onCancel();
|
|
2482
|
+
}
|
|
2483
|
+
};
|
|
2484
|
+
return /* @__PURE__ */ jsxs10("div", { className: "gantt-tl-row gantt-tl-row-new", style: { minHeight: `${rowHeight}px` }, children: [
|
|
2485
|
+
/* @__PURE__ */ jsx13("div", { className: "gantt-tl-cell gantt-tl-cell-number" }),
|
|
2486
|
+
/* @__PURE__ */ jsx13("div", { className: "gantt-tl-cell gantt-tl-cell-name gantt-tl-cell-new-name", children: /* @__PURE__ */ jsx13(
|
|
2487
|
+
Input,
|
|
2488
|
+
{
|
|
2489
|
+
ref: inputRef,
|
|
2490
|
+
value: nameValue,
|
|
2491
|
+
onChange: (e) => setNameValue(e.target.value),
|
|
2492
|
+
onKeyDown: handleKeyDown,
|
|
2493
|
+
onBlur: handleBlur,
|
|
2494
|
+
placeholder: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435",
|
|
2495
|
+
className: "gantt-tl-name-input"
|
|
2496
|
+
}
|
|
2497
|
+
) }),
|
|
2498
|
+
/* @__PURE__ */ jsx13("div", { className: "gantt-tl-cell" }),
|
|
2499
|
+
/* @__PURE__ */ jsx13("div", { className: "gantt-tl-cell" }),
|
|
2500
|
+
/* @__PURE__ */ jsx13("div", { className: "gantt-tl-cell" })
|
|
2501
|
+
] });
|
|
2502
|
+
};
|
|
2503
|
+
|
|
2504
|
+
// src/components/TaskList/TaskList.tsx
|
|
2505
|
+
import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2300
2506
|
var LINK_TYPE_ORDER = ["FS", "SS", "FF", "SF"];
|
|
2301
2507
|
var TaskList = ({
|
|
2302
2508
|
tasks,
|
|
2303
2509
|
rowHeight,
|
|
2304
2510
|
headerHeight,
|
|
2305
|
-
taskListWidth =
|
|
2511
|
+
taskListWidth = 472,
|
|
2306
2512
|
onTaskChange,
|
|
2307
2513
|
selectedTaskId,
|
|
2308
2514
|
onTaskSelect,
|
|
@@ -2310,7 +2516,11 @@ var TaskList = ({
|
|
|
2310
2516
|
disableTaskNameEditing = false,
|
|
2311
2517
|
disableDependencyEditing = false,
|
|
2312
2518
|
onScrollToTask,
|
|
2313
|
-
onSelectedChipChange
|
|
2519
|
+
onSelectedChipChange,
|
|
2520
|
+
onAdd,
|
|
2521
|
+
onDelete,
|
|
2522
|
+
onInsertAfter,
|
|
2523
|
+
editingTaskId: propEditingTaskId
|
|
2314
2524
|
}) => {
|
|
2315
2525
|
const totalHeight = useMemo8(
|
|
2316
2526
|
() => tasks.length * rowHeight,
|
|
@@ -2319,17 +2529,17 @@ var TaskList = ({
|
|
|
2319
2529
|
const handleRowClick = useCallback5((taskId) => {
|
|
2320
2530
|
onTaskSelect?.(taskId);
|
|
2321
2531
|
}, [onTaskSelect]);
|
|
2322
|
-
const [activeLinkType, setActiveLinkType] =
|
|
2323
|
-
const [selectingPredecessorFor, setSelectingPredecessorFor] =
|
|
2324
|
-
const [typeMenuOpen, setTypeMenuOpen] =
|
|
2325
|
-
const [cycleError, setCycleError] =
|
|
2326
|
-
const overlayRef =
|
|
2327
|
-
const [selectedChip, setSelectedChip] =
|
|
2532
|
+
const [activeLinkType, setActiveLinkType] = useState6("FS");
|
|
2533
|
+
const [selectingPredecessorFor, setSelectingPredecessorFor] = useState6(null);
|
|
2534
|
+
const [typeMenuOpen, setTypeMenuOpen] = useState6(false);
|
|
2535
|
+
const [cycleError, setCycleError] = useState6(false);
|
|
2536
|
+
const overlayRef = useRef5(null);
|
|
2537
|
+
const [selectedChip, setSelectedChip] = useState6(null);
|
|
2328
2538
|
const handleChipSelect = useCallback5((chip) => {
|
|
2329
2539
|
setSelectedChip(chip);
|
|
2330
2540
|
onSelectedChipChange?.(chip);
|
|
2331
2541
|
}, [onSelectedChipChange]);
|
|
2332
|
-
|
|
2542
|
+
useEffect5(() => {
|
|
2333
2543
|
if (!selectingPredecessorFor && !selectedChip) return;
|
|
2334
2544
|
const handleKeyDown = (e) => {
|
|
2335
2545
|
if (e.key === "Escape") {
|
|
@@ -2410,21 +2620,44 @@ var TaskList = ({
|
|
|
2410
2620
|
);
|
|
2411
2621
|
onTaskChange?.({ ...task, dependencies: updatedDeps });
|
|
2412
2622
|
}, [tasks, onTaskChange]);
|
|
2413
|
-
|
|
2623
|
+
const [isCreating, setIsCreating] = useState6(false);
|
|
2624
|
+
const handleConfirmNewTask = useCallback5((name) => {
|
|
2625
|
+
const now = /* @__PURE__ */ new Date();
|
|
2626
|
+
const todayISO = new Date(Date.UTC(
|
|
2627
|
+
now.getUTCFullYear(),
|
|
2628
|
+
now.getUTCMonth(),
|
|
2629
|
+
now.getUTCDate()
|
|
2630
|
+
)).toISOString().split("T")[0];
|
|
2631
|
+
const endISO = new Date(Date.UTC(
|
|
2632
|
+
now.getUTCFullYear(),
|
|
2633
|
+
now.getUTCMonth(),
|
|
2634
|
+
now.getUTCDate() + 7
|
|
2635
|
+
)).toISOString().split("T")[0];
|
|
2636
|
+
const newTask = {
|
|
2637
|
+
id: crypto.randomUUID(),
|
|
2638
|
+
name,
|
|
2639
|
+
startDate: todayISO,
|
|
2640
|
+
endDate: endISO
|
|
2641
|
+
};
|
|
2642
|
+
onAdd?.(newTask);
|
|
2643
|
+
setIsCreating(false);
|
|
2644
|
+
}, [onAdd]);
|
|
2645
|
+
const handleCancelNewTask = useCallback5(() => setIsCreating(false), []);
|
|
2646
|
+
return /* @__PURE__ */ jsx14(
|
|
2414
2647
|
"div",
|
|
2415
2648
|
{
|
|
2416
2649
|
ref: overlayRef,
|
|
2417
2650
|
className: `gantt-tl-overlay${show ? "" : " gantt-tl-hidden"}`,
|
|
2418
2651
|
style: { width: `${taskListWidth}px` },
|
|
2419
|
-
children: /* @__PURE__ */
|
|
2420
|
-
/* @__PURE__ */
|
|
2421
|
-
/* @__PURE__ */
|
|
2422
|
-
/* @__PURE__ */
|
|
2423
|
-
/* @__PURE__ */
|
|
2424
|
-
/* @__PURE__ */
|
|
2425
|
-
/* @__PURE__ */
|
|
2426
|
-
/* @__PURE__ */
|
|
2427
|
-
/* @__PURE__ */
|
|
2652
|
+
children: /* @__PURE__ */ jsxs11("div", { className: "gantt-tl-table", children: [
|
|
2653
|
+
/* @__PURE__ */ jsxs11("div", { className: "gantt-tl-header", style: { height: `${headerHeight + 0.5}px` }, children: [
|
|
2654
|
+
/* @__PURE__ */ jsx14("div", { className: "gantt-tl-headerCell gantt-tl-cell-number", children: "\u2116" }),
|
|
2655
|
+
/* @__PURE__ */ jsx14("div", { className: "gantt-tl-headerCell gantt-tl-cell-name", children: "\u0418\u043C\u044F" }),
|
|
2656
|
+
/* @__PURE__ */ jsx14("div", { className: "gantt-tl-headerCell gantt-tl-cell-date", children: "\u041D\u0430\u0447\u0430\u043B\u043E" }),
|
|
2657
|
+
/* @__PURE__ */ jsx14("div", { className: "gantt-tl-headerCell gantt-tl-cell-date", children: "\u041E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u0435" }),
|
|
2658
|
+
/* @__PURE__ */ jsxs11("div", { className: "gantt-tl-headerCell gantt-tl-cell-deps", style: { position: "relative" }, children: [
|
|
2659
|
+
/* @__PURE__ */ jsxs11(Popover, { open: typeMenuOpen, onOpenChange: setTypeMenuOpen, children: [
|
|
2660
|
+
/* @__PURE__ */ jsx14(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs11(
|
|
2428
2661
|
"button",
|
|
2429
2662
|
{
|
|
2430
2663
|
className: "gantt-tl-dep-type-trigger",
|
|
@@ -2432,12 +2665,12 @@ var TaskList = ({
|
|
|
2432
2665
|
onClick: (e) => e.stopPropagation(),
|
|
2433
2666
|
children: [
|
|
2434
2667
|
"\u0421\u0432\u044F\u0437\u0438 ",
|
|
2435
|
-
|
|
2668
|
+
React11.createElement(LINK_TYPE_ICONS[activeLinkType]),
|
|
2436
2669
|
" \u25BE"
|
|
2437
2670
|
]
|
|
2438
2671
|
}
|
|
2439
2672
|
) }),
|
|
2440
|
-
/* @__PURE__ */
|
|
2673
|
+
/* @__PURE__ */ jsx14(PopoverContent, { portal: true, align: "start", children: /* @__PURE__ */ jsx14("div", { className: "gantt-tl-dep-type-menu", children: LINK_TYPE_ORDER.map((lt) => /* @__PURE__ */ jsxs11(
|
|
2441
2674
|
"button",
|
|
2442
2675
|
{
|
|
2443
2676
|
className: `gantt-tl-dep-type-option${activeLinkType === lt ? " active" : ""}`,
|
|
@@ -2446,17 +2679,17 @@ var TaskList = ({
|
|
|
2446
2679
|
setTypeMenuOpen(false);
|
|
2447
2680
|
},
|
|
2448
2681
|
children: [
|
|
2449
|
-
|
|
2450
|
-
/* @__PURE__ */
|
|
2682
|
+
React11.createElement(LINK_TYPE_ICONS[lt]),
|
|
2683
|
+
/* @__PURE__ */ jsx14("span", { children: LINK_TYPE_LABELS[lt] })
|
|
2451
2684
|
]
|
|
2452
2685
|
},
|
|
2453
2686
|
lt
|
|
2454
2687
|
)) }) })
|
|
2455
2688
|
] }),
|
|
2456
|
-
cycleError && /* @__PURE__ */
|
|
2689
|
+
cycleError && /* @__PURE__ */ jsx14("div", { className: "gantt-tl-dep-error", children: "\u0426\u0438\u043A\u043B \u0437\u0430\u0432\u0438\u0441\u0438\u043C\u043E\u0441\u0442\u0435\u0439!" })
|
|
2457
2690
|
] })
|
|
2458
2691
|
] }),
|
|
2459
|
-
/* @__PURE__ */
|
|
2692
|
+
/* @__PURE__ */ jsx14("div", { className: "gantt-tl-body", style: { height: `${totalHeight}px` }, children: tasks.map((task, index) => /* @__PURE__ */ jsx14(
|
|
2460
2693
|
TaskListRow,
|
|
2461
2694
|
{
|
|
2462
2695
|
task,
|
|
@@ -2475,17 +2708,38 @@ var TaskList = ({
|
|
|
2475
2708
|
onRemoveDependency: handleRemoveDependency,
|
|
2476
2709
|
selectedChip,
|
|
2477
2710
|
onChipSelect: handleChipSelect,
|
|
2478
|
-
onScrollToTask
|
|
2711
|
+
onScrollToTask,
|
|
2712
|
+
onDelete,
|
|
2713
|
+
onAdd,
|
|
2714
|
+
onInsertAfter,
|
|
2715
|
+
editingTaskId: propEditingTaskId
|
|
2479
2716
|
},
|
|
2480
2717
|
task.id
|
|
2481
|
-
)) })
|
|
2718
|
+
)) }),
|
|
2719
|
+
isCreating && /* @__PURE__ */ jsx14(
|
|
2720
|
+
NewTaskRow,
|
|
2721
|
+
{
|
|
2722
|
+
rowHeight,
|
|
2723
|
+
onConfirm: handleConfirmNewTask,
|
|
2724
|
+
onCancel: handleCancelNewTask
|
|
2725
|
+
}
|
|
2726
|
+
),
|
|
2727
|
+
onAdd && !isCreating && /* @__PURE__ */ jsx14(
|
|
2728
|
+
"button",
|
|
2729
|
+
{
|
|
2730
|
+
className: "gantt-tl-add-btn",
|
|
2731
|
+
onClick: () => setIsCreating(true),
|
|
2732
|
+
type: "button",
|
|
2733
|
+
children: "+ \u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0437\u0430\u0434\u0430\u0447\u0443"
|
|
2734
|
+
}
|
|
2735
|
+
)
|
|
2482
2736
|
] })
|
|
2483
2737
|
}
|
|
2484
2738
|
);
|
|
2485
2739
|
};
|
|
2486
2740
|
|
|
2487
2741
|
// src/components/GanttChart/GanttChart.tsx
|
|
2488
|
-
import { jsx as
|
|
2742
|
+
import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
2489
2743
|
var GanttChart = forwardRef(({
|
|
2490
2744
|
tasks,
|
|
2491
2745
|
dayWidth = 40,
|
|
@@ -2501,14 +2755,18 @@ var GanttChart = forwardRef(({
|
|
|
2501
2755
|
taskListWidth = 520,
|
|
2502
2756
|
disableTaskNameEditing = false,
|
|
2503
2757
|
disableDependencyEditing = false,
|
|
2504
|
-
highlightExpiredTasks = false
|
|
2758
|
+
highlightExpiredTasks = false,
|
|
2759
|
+
onAdd,
|
|
2760
|
+
onDelete,
|
|
2761
|
+
onInsertAfter,
|
|
2762
|
+
editingTaskId
|
|
2505
2763
|
}, ref) => {
|
|
2506
|
-
const scrollContainerRef =
|
|
2507
|
-
const [selectedTaskId, setSelectedTaskId] =
|
|
2508
|
-
const [selectedChip, setSelectedChip] =
|
|
2764
|
+
const scrollContainerRef = useRef6(null);
|
|
2765
|
+
const [selectedTaskId, setSelectedTaskId] = useState7(null);
|
|
2766
|
+
const [selectedChip, setSelectedChip] = useState7(null);
|
|
2509
2767
|
const dateRange = useMemo9(() => getMultiMonthDays(tasks), [tasks]);
|
|
2510
|
-
const [validationResult, setValidationResult] =
|
|
2511
|
-
const [cascadeOverrides, setCascadeOverrides] =
|
|
2768
|
+
const [validationResult, setValidationResult] = useState7(null);
|
|
2769
|
+
const [cascadeOverrides, setCascadeOverrides] = useState7(/* @__PURE__ */ new Map());
|
|
2512
2770
|
const gridWidth = useMemo9(
|
|
2513
2771
|
() => Math.round(dateRange.length * dayWidth),
|
|
2514
2772
|
[dateRange.length, dayWidth]
|
|
@@ -2529,7 +2787,7 @@ var GanttChart = forwardRef(({
|
|
|
2529
2787
|
const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
|
|
2530
2788
|
return dateRange.some((day) => day.getTime() === today.getTime());
|
|
2531
2789
|
}, [dateRange]);
|
|
2532
|
-
|
|
2790
|
+
useEffect6(() => {
|
|
2533
2791
|
const container = scrollContainerRef.current;
|
|
2534
2792
|
if (!container || dateRange.length === 0) return;
|
|
2535
2793
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -2551,7 +2809,7 @@ var GanttChart = forwardRef(({
|
|
|
2551
2809
|
const todayOffset = todayIndex * dayWidth;
|
|
2552
2810
|
const containerWidth = container.clientWidth;
|
|
2553
2811
|
const scrollLeft = Math.round(todayOffset - containerWidth / 2 + dayWidth / 2);
|
|
2554
|
-
container.
|
|
2812
|
+
container.scrollTo({ left: Math.max(0, scrollLeft), behavior: "smooth" });
|
|
2555
2813
|
}, [dateRange, dayWidth]);
|
|
2556
2814
|
const scrollToTask = useCallback6((taskId) => {
|
|
2557
2815
|
const container = scrollContainerRef.current;
|
|
@@ -2568,7 +2826,7 @@ var GanttChart = forwardRef(({
|
|
|
2568
2826
|
if (taskIndex === -1) return;
|
|
2569
2827
|
const taskOffset = taskIndex * dayWidth;
|
|
2570
2828
|
const scrollLeft = Math.round(taskOffset - dayWidth * 2);
|
|
2571
|
-
container.
|
|
2829
|
+
container.scrollTo({ left: Math.max(0, scrollLeft), behavior: "smooth" });
|
|
2572
2830
|
}, [tasks, dateRange, dayWidth]);
|
|
2573
2831
|
useImperativeHandle(
|
|
2574
2832
|
ref,
|
|
@@ -2578,9 +2836,9 @@ var GanttChart = forwardRef(({
|
|
|
2578
2836
|
}),
|
|
2579
2837
|
[scrollToToday, scrollToTask]
|
|
2580
2838
|
);
|
|
2581
|
-
const [dragGuideLines, setDragGuideLines] =
|
|
2582
|
-
const [draggedTaskOverride, setDraggedTaskOverride] =
|
|
2583
|
-
|
|
2839
|
+
const [dragGuideLines, setDragGuideLines] = useState7(null);
|
|
2840
|
+
const [draggedTaskOverride, setDraggedTaskOverride] = useState7(null);
|
|
2841
|
+
useEffect6(() => {
|
|
2584
2842
|
const result = validateDependencies(tasks);
|
|
2585
2843
|
setValidationResult(result);
|
|
2586
2844
|
onValidateDependencies?.(result);
|
|
@@ -2596,41 +2854,16 @@ var GanttChart = forwardRef(({
|
|
|
2596
2854
|
const newStart = new Date(updatedTask.startDate);
|
|
2597
2855
|
const newEnd = new Date(updatedTask.endDate);
|
|
2598
2856
|
const datesChanged = origStart.getTime() !== newStart.getTime() || origEnd.getTime() !== newEnd.getTime();
|
|
2599
|
-
const now = /* @__PURE__ */ new Date();
|
|
2600
|
-
const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
|
|
2601
|
-
const msPerDay = 1e3 * 60 * 60 * 24;
|
|
2602
|
-
let tasksToProcess;
|
|
2603
|
-
let cascadedTasksForCallback = [];
|
|
2604
2857
|
if (!datesChanged) {
|
|
2605
2858
|
onChange?.((currentTasks) => currentTasks.map((t) => t.id === updatedTask.id ? updatedTask : t));
|
|
2606
2859
|
return;
|
|
2607
2860
|
}
|
|
2861
|
+
let cascadedTasksForCallback;
|
|
2608
2862
|
if (disableConstraints) {
|
|
2609
|
-
tasksToProcess = [updatedTask];
|
|
2610
2863
|
cascadedTasksForCallback = [updatedTask];
|
|
2611
2864
|
} else {
|
|
2612
|
-
const cascadedTask = updatedTask;
|
|
2613
2865
|
const cascadedChain = cascadeByLinks(updatedTask.id, newStart, newEnd, tasks);
|
|
2614
|
-
|
|
2615
|
-
cascadedTasksForCallback = tasksToProcess;
|
|
2616
|
-
}
|
|
2617
|
-
console.log("[GanttChart handleTaskChange] IsExpired calculation:");
|
|
2618
|
-
for (const t of tasksToProcess) {
|
|
2619
|
-
const taskStart = new Date(t.startDate);
|
|
2620
|
-
const taskEnd = new Date(t.endDate);
|
|
2621
|
-
const actualProgress = t.progress ?? 0;
|
|
2622
|
-
if (actualProgress >= 100) {
|
|
2623
|
-
console.log(` [${t.id}] START=${t.startDate} END=${t.endDate} TODAY=${today.toISOString().split("T")[0]} PROGRESS=${actualProgress}% EXPECTED=N/A (completed) EXPIRED=NO`);
|
|
2624
|
-
continue;
|
|
2625
|
-
}
|
|
2626
|
-
const duration = taskEnd.getTime() - taskStart.getTime() + msPerDay;
|
|
2627
|
-
const elapsedFromToday = today.getTime() - taskStart.getTime();
|
|
2628
|
-
const elapsed = Math.min(Math.max(0, elapsedFromToday), duration);
|
|
2629
|
-
const expectedProgress = Math.min(100, Math.max(0, elapsed / duration * 100));
|
|
2630
|
-
const isExpired = actualProgress < expectedProgress;
|
|
2631
|
-
const durationDays = Math.round(duration / msPerDay);
|
|
2632
|
-
const elapsedDays = Math.round(elapsed / msPerDay);
|
|
2633
|
-
console.log(` [${t.id}] START=${t.startDate} END=${t.endDate} TODAY=${today.toISOString().split("T")[0]} PROGRESS=${actualProgress}% DURATION=${durationDays}d ELAPSED=${elapsedDays}d EXPECTED=${expectedProgress.toFixed(1)}% EXPIRED=${isExpired ? "YES" : "NO"}`);
|
|
2866
|
+
cascadedTasksForCallback = [updatedTask, ...cascadedChain];
|
|
2634
2867
|
}
|
|
2635
2868
|
if (disableConstraints) {
|
|
2636
2869
|
onChange?.((currentTasks) => currentTasks.map((t) => t.id === updatedTask.id ? updatedTask : t));
|
|
@@ -2642,6 +2875,15 @@ var GanttChart = forwardRef(({
|
|
|
2642
2875
|
onCascade?.(cascadedTasksForCallback);
|
|
2643
2876
|
}
|
|
2644
2877
|
}, [tasks, onChange, disableConstraints, onCascade]);
|
|
2878
|
+
const handleDelete = useCallback6((taskId) => {
|
|
2879
|
+
onChange?.(
|
|
2880
|
+
(currentTasks) => currentTasks.filter((t) => t.id !== taskId).map((t) => ({
|
|
2881
|
+
...t,
|
|
2882
|
+
dependencies: (t.dependencies ?? []).filter((d) => d.taskId !== taskId)
|
|
2883
|
+
}))
|
|
2884
|
+
);
|
|
2885
|
+
onDelete?.(taskId);
|
|
2886
|
+
}, [onChange, onDelete]);
|
|
2645
2887
|
const dependencyOverrides = useMemo9(() => {
|
|
2646
2888
|
const map = new Map(cascadeOverrides);
|
|
2647
2889
|
if (draggedTaskOverride) {
|
|
@@ -2665,7 +2907,7 @@ var GanttChart = forwardRef(({
|
|
|
2665
2907
|
const handleTaskSelect = useCallback6((taskId) => {
|
|
2666
2908
|
setSelectedTaskId(taskId);
|
|
2667
2909
|
}, []);
|
|
2668
|
-
const panStateRef =
|
|
2910
|
+
const panStateRef = useRef6(null);
|
|
2669
2911
|
const handlePanStart = useCallback6((e) => {
|
|
2670
2912
|
if (e.button !== 0) return;
|
|
2671
2913
|
const target = e.target;
|
|
@@ -2687,7 +2929,7 @@ var GanttChart = forwardRef(({
|
|
|
2687
2929
|
container.style.cursor = "grabbing";
|
|
2688
2930
|
e.preventDefault();
|
|
2689
2931
|
}, []);
|
|
2690
|
-
|
|
2932
|
+
useEffect6(() => {
|
|
2691
2933
|
const handlePanMove = (e) => {
|
|
2692
2934
|
const pan = panStateRef.current;
|
|
2693
2935
|
if (!pan?.active) return;
|
|
@@ -2709,15 +2951,15 @@ var GanttChart = forwardRef(({
|
|
|
2709
2951
|
window.removeEventListener("mouseup", handlePanEnd);
|
|
2710
2952
|
};
|
|
2711
2953
|
}, []);
|
|
2712
|
-
return /* @__PURE__ */
|
|
2954
|
+
return /* @__PURE__ */ jsx15("div", { className: "gantt-container", children: /* @__PURE__ */ jsx15(
|
|
2713
2955
|
"div",
|
|
2714
2956
|
{
|
|
2715
2957
|
ref: scrollContainerRef,
|
|
2716
2958
|
className: "gantt-scrollContainer",
|
|
2717
2959
|
style: { height: containerHeight ?? "auto", cursor: "grab" },
|
|
2718
2960
|
onMouseDown: handlePanStart,
|
|
2719
|
-
children: /* @__PURE__ */
|
|
2720
|
-
/* @__PURE__ */
|
|
2961
|
+
children: /* @__PURE__ */ jsxs12("div", { className: "gantt-scrollContent", children: [
|
|
2962
|
+
/* @__PURE__ */ jsx15(
|
|
2721
2963
|
TaskList,
|
|
2722
2964
|
{
|
|
2723
2965
|
tasks,
|
|
@@ -2731,11 +2973,15 @@ var GanttChart = forwardRef(({
|
|
|
2731
2973
|
disableTaskNameEditing,
|
|
2732
2974
|
disableDependencyEditing,
|
|
2733
2975
|
onScrollToTask: scrollToTask,
|
|
2734
|
-
onSelectedChipChange: setSelectedChip
|
|
2976
|
+
onSelectedChipChange: setSelectedChip,
|
|
2977
|
+
onAdd,
|
|
2978
|
+
onDelete: handleDelete,
|
|
2979
|
+
onInsertAfter,
|
|
2980
|
+
editingTaskId
|
|
2735
2981
|
}
|
|
2736
2982
|
),
|
|
2737
|
-
/* @__PURE__ */
|
|
2738
|
-
/* @__PURE__ */
|
|
2983
|
+
/* @__PURE__ */ jsxs12("div", { style: { minWidth: `${gridWidth}px`, flex: 1 }, children: [
|
|
2984
|
+
/* @__PURE__ */ jsx15("div", { className: "gantt-stickyHeader", style: { width: `${gridWidth}px` }, children: /* @__PURE__ */ jsx15(
|
|
2739
2985
|
TimeScaleHeader_default,
|
|
2740
2986
|
{
|
|
2741
2987
|
days: dateRange,
|
|
@@ -2743,7 +2989,7 @@ var GanttChart = forwardRef(({
|
|
|
2743
2989
|
headerHeight
|
|
2744
2990
|
}
|
|
2745
2991
|
) }),
|
|
2746
|
-
/* @__PURE__ */
|
|
2992
|
+
/* @__PURE__ */ jsxs12(
|
|
2747
2993
|
"div",
|
|
2748
2994
|
{
|
|
2749
2995
|
className: "gantt-taskArea",
|
|
@@ -2752,7 +2998,7 @@ var GanttChart = forwardRef(({
|
|
|
2752
2998
|
width: `${gridWidth}px`
|
|
2753
2999
|
},
|
|
2754
3000
|
children: [
|
|
2755
|
-
/* @__PURE__ */
|
|
3001
|
+
/* @__PURE__ */ jsx15(
|
|
2756
3002
|
GridBackground_default,
|
|
2757
3003
|
{
|
|
2758
3004
|
dateRange,
|
|
@@ -2760,8 +3006,8 @@ var GanttChart = forwardRef(({
|
|
|
2760
3006
|
totalHeight: totalGridHeight
|
|
2761
3007
|
}
|
|
2762
3008
|
),
|
|
2763
|
-
todayInRange && /* @__PURE__ */
|
|
2764
|
-
/* @__PURE__ */
|
|
3009
|
+
todayInRange && /* @__PURE__ */ jsx15(TodayIndicator_default, { monthStart, dayWidth }),
|
|
3010
|
+
/* @__PURE__ */ jsx15(
|
|
2765
3011
|
DependencyLines_default,
|
|
2766
3012
|
{
|
|
2767
3013
|
tasks,
|
|
@@ -2773,7 +3019,7 @@ var GanttChart = forwardRef(({
|
|
|
2773
3019
|
selectedDep: selectedChip
|
|
2774
3020
|
}
|
|
2775
3021
|
),
|
|
2776
|
-
dragGuideLines && /* @__PURE__ */
|
|
3022
|
+
dragGuideLines && /* @__PURE__ */ jsx15(
|
|
2777
3023
|
DragGuideLines_default,
|
|
2778
3024
|
{
|
|
2779
3025
|
isDragging: dragGuideLines.isDragging,
|
|
@@ -2783,7 +3029,7 @@ var GanttChart = forwardRef(({
|
|
|
2783
3029
|
totalHeight: totalGridHeight
|
|
2784
3030
|
}
|
|
2785
3031
|
),
|
|
2786
|
-
tasks.map((task, index) => /* @__PURE__ */
|
|
3032
|
+
tasks.map((task, index) => /* @__PURE__ */ jsx15(
|
|
2787
3033
|
TaskRow_default,
|
|
2788
3034
|
{
|
|
2789
3035
|
task,
|
|
@@ -2822,9 +3068,9 @@ var GanttChart = forwardRef(({
|
|
|
2822
3068
|
GanttChart.displayName = "GanttChart";
|
|
2823
3069
|
|
|
2824
3070
|
// src/components/ui/Button.tsx
|
|
2825
|
-
import
|
|
2826
|
-
import { jsx as
|
|
2827
|
-
var Button =
|
|
3071
|
+
import React13 from "react";
|
|
3072
|
+
import { jsx as jsx16 } from "react/jsx-runtime";
|
|
3073
|
+
var Button = React13.forwardRef(
|
|
2828
3074
|
({ className, variant = "default", size = "default", children, ...props }, ref) => {
|
|
2829
3075
|
const classes = [
|
|
2830
3076
|
"gantt-btn",
|
|
@@ -2832,7 +3078,7 @@ var Button = React12.forwardRef(
|
|
|
2832
3078
|
size !== "default" ? `gantt-btn-${size}` : "",
|
|
2833
3079
|
className || ""
|
|
2834
3080
|
].filter(Boolean).join(" ");
|
|
2835
|
-
return /* @__PURE__ */
|
|
3081
|
+
return /* @__PURE__ */ jsx16("button", { ref, className: classes, ...props, children });
|
|
2836
3082
|
}
|
|
2837
3083
|
);
|
|
2838
3084
|
Button.displayName = "Button";
|