gantt-lib 0.3.4 → 0.4.1
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 -1
- package/dist/index.d.ts +17 -1
- package/dist/index.js +433 -153
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +414 -133
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +106 -23
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -78,7 +78,7 @@ __export(index_exports, {
|
|
|
78
78
|
module.exports = __toCommonJS(index_exports);
|
|
79
79
|
|
|
80
80
|
// src/components/GanttChart/GanttChart.tsx
|
|
81
|
-
var
|
|
81
|
+
var import_react13 = require("react");
|
|
82
82
|
|
|
83
83
|
// src/utils/dateUtils.ts
|
|
84
84
|
var parseUTCDate = (date) => {
|
|
@@ -119,9 +119,9 @@ var getDayOffset = (date, monthStart) => {
|
|
|
119
119
|
var isToday = (date) => {
|
|
120
120
|
const now = /* @__PURE__ */ new Date();
|
|
121
121
|
const today = new Date(Date.UTC(
|
|
122
|
-
now.
|
|
123
|
-
now.
|
|
124
|
-
now.
|
|
122
|
+
now.getFullYear(),
|
|
123
|
+
now.getMonth(),
|
|
124
|
+
now.getDate()
|
|
125
125
|
));
|
|
126
126
|
const compareDate = new Date(Date.UTC(
|
|
127
127
|
date.getUTCFullYear(),
|
|
@@ -600,7 +600,7 @@ var calculateGridLines = (dateRange, dayWidth) => {
|
|
|
600
600
|
for (let i = 0; i < dateRange.length; i++) {
|
|
601
601
|
const date = dateRange[i];
|
|
602
602
|
const x = Math.round(i * dayWidth);
|
|
603
|
-
const isMonthStart = date.getUTCDate() === 1;
|
|
603
|
+
const isMonthStart = i === 0 ? false : date.getUTCDate() === 1;
|
|
604
604
|
const isWeekStart = date.getUTCDay() === 1;
|
|
605
605
|
lines.push({ x, isMonthStart, isWeekStart });
|
|
606
606
|
}
|
|
@@ -1179,7 +1179,7 @@ var TaskRow = import_react3.default.memo(
|
|
|
1179
1179
|
const isExpired = (0, import_react3.useMemo)(() => {
|
|
1180
1180
|
if (!highlightExpiredTasks) return false;
|
|
1181
1181
|
const now = /* @__PURE__ */ new Date();
|
|
1182
|
-
const today = new Date(Date.UTC(now.
|
|
1182
|
+
const today = new Date(Date.UTC(now.getFullYear(), now.getMonth(), now.getDate()));
|
|
1183
1183
|
const taskStart = parseUTCDate(task.startDate);
|
|
1184
1184
|
const taskEnd = parseUTCDate(task.endDate);
|
|
1185
1185
|
const actualProgress = task.progress ?? 0;
|
|
@@ -1686,7 +1686,7 @@ DependencyLines.displayName = "DependencyLines";
|
|
|
1686
1686
|
var DependencyLines_default = DependencyLines;
|
|
1687
1687
|
|
|
1688
1688
|
// src/components/TaskList/TaskList.tsx
|
|
1689
|
-
var
|
|
1689
|
+
var import_react12 = __toESM(require("react"));
|
|
1690
1690
|
|
|
1691
1691
|
// src/components/ui/Popover.tsx
|
|
1692
1692
|
var RadixPopover = __toESM(require("@radix-ui/react-popover"));
|
|
@@ -1855,7 +1855,73 @@ var Calendar = ({
|
|
|
1855
1855
|
() => months.map(renderMonth),
|
|
1856
1856
|
[months, renderMonth]
|
|
1857
1857
|
);
|
|
1858
|
-
|
|
1858
|
+
const handleDayShift = (0, import_react8.useCallback)(
|
|
1859
|
+
(deltaDays) => {
|
|
1860
|
+
if (!onSelect || disabled) return;
|
|
1861
|
+
const baseDate = selected ?? /* @__PURE__ */ new Date();
|
|
1862
|
+
onSelect((0, import_date_fns2.addDays)(baseDate, deltaDays));
|
|
1863
|
+
},
|
|
1864
|
+
[onSelect, selected, disabled]
|
|
1865
|
+
);
|
|
1866
|
+
const handleToday = (0, import_react8.useCallback)(() => {
|
|
1867
|
+
if (!onSelect || disabled) return;
|
|
1868
|
+
onSelect(/* @__PURE__ */ new Date());
|
|
1869
|
+
}, [onSelect, disabled]);
|
|
1870
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { ref: scrollRef, className: "gantt-cal-container", children: [
|
|
1871
|
+
renderedMonths,
|
|
1872
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "gantt-cal-nav", children: [
|
|
1873
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1874
|
+
"button",
|
|
1875
|
+
{
|
|
1876
|
+
type: "button",
|
|
1877
|
+
className: "gantt-btn gantt-btn-sm",
|
|
1878
|
+
onClick: () => handleDayShift(-7),
|
|
1879
|
+
disabled,
|
|
1880
|
+
children: "-7"
|
|
1881
|
+
}
|
|
1882
|
+
),
|
|
1883
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1884
|
+
"button",
|
|
1885
|
+
{
|
|
1886
|
+
type: "button",
|
|
1887
|
+
className: "gantt-btn gantt-btn-sm",
|
|
1888
|
+
onClick: () => handleDayShift(-1),
|
|
1889
|
+
disabled,
|
|
1890
|
+
children: "-1"
|
|
1891
|
+
}
|
|
1892
|
+
),
|
|
1893
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1894
|
+
"button",
|
|
1895
|
+
{
|
|
1896
|
+
type: "button",
|
|
1897
|
+
className: "gantt-btn gantt-btn-sm",
|
|
1898
|
+
onClick: handleToday,
|
|
1899
|
+
disabled,
|
|
1900
|
+
children: "\u0421\u0435\u0433\u043E\u0434\u043D\u044F"
|
|
1901
|
+
}
|
|
1902
|
+
),
|
|
1903
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1904
|
+
"button",
|
|
1905
|
+
{
|
|
1906
|
+
type: "button",
|
|
1907
|
+
className: "gantt-btn gantt-btn-sm",
|
|
1908
|
+
onClick: () => handleDayShift(1),
|
|
1909
|
+
disabled,
|
|
1910
|
+
children: "+1"
|
|
1911
|
+
}
|
|
1912
|
+
),
|
|
1913
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1914
|
+
"button",
|
|
1915
|
+
{
|
|
1916
|
+
type: "button",
|
|
1917
|
+
className: "gantt-btn gantt-btn-sm",
|
|
1918
|
+
onClick: () => handleDayShift(7),
|
|
1919
|
+
disabled,
|
|
1920
|
+
children: "+7"
|
|
1921
|
+
}
|
|
1922
|
+
)
|
|
1923
|
+
] })
|
|
1924
|
+
] });
|
|
1859
1925
|
};
|
|
1860
1926
|
Calendar.displayName = "Calendar";
|
|
1861
1927
|
|
|
@@ -1963,6 +2029,7 @@ var TrashIcon = () => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("svg", { xm
|
|
|
1963
2029
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M3 6h18" }),
|
|
1964
2030
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })
|
|
1965
2031
|
] });
|
|
2032
|
+
var PlusIcon = () => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("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__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M12 5v14M5 12h14" }) });
|
|
1966
2033
|
function formatDepDescription(type, lag) {
|
|
1967
2034
|
const effectiveLag = lag ?? 0;
|
|
1968
2035
|
if (type === "FS") {
|
|
@@ -2004,12 +2071,19 @@ var DepChip = ({
|
|
|
2004
2071
|
const handleClick = (e) => {
|
|
2005
2072
|
e.stopPropagation();
|
|
2006
2073
|
if (disableDependencyEditing) return;
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2074
|
+
if (isSelected) {
|
|
2075
|
+
e.preventDefault();
|
|
2076
|
+
onChipSelect?.(null);
|
|
2077
|
+
return;
|
|
2011
2078
|
}
|
|
2079
|
+
onChipSelect?.({ successorId: taskId, predecessorId: dep.taskId, linkType: dep.type });
|
|
2080
|
+
onScrollToTask?.(dep.taskId);
|
|
2012
2081
|
};
|
|
2082
|
+
const handleOpenChange = (0, import_react10.useCallback)((open) => {
|
|
2083
|
+
if (!open) {
|
|
2084
|
+
onChipSelect?.(null);
|
|
2085
|
+
}
|
|
2086
|
+
}, [onChipSelect]);
|
|
2013
2087
|
const handleTrashClick = (e) => {
|
|
2014
2088
|
e.stopPropagation();
|
|
2015
2089
|
onRemoveDependency?.(taskId, dep.taskId, dep.type);
|
|
@@ -2018,50 +2092,26 @@ var DepChip = ({
|
|
|
2018
2092
|
const Icon = LINK_TYPE_ICONS[dep.type];
|
|
2019
2093
|
const depPrefix = formatDepDescription(dep.type, lag);
|
|
2020
2094
|
const depName = predecessorName ?? dep.taskId;
|
|
2021
|
-
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2025
|
-
"span",
|
|
2026
|
-
{
|
|
2027
|
-
className: `gantt-tl-dep-chip${isSelected ? " gantt-tl-dep-chip-selected" : ""}`,
|
|
2028
|
-
onClick: handleClick,
|
|
2029
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
2030
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Icon, {}),
|
|
2031
|
-
lag != null && lag !== 0 ? lag > 0 ? `+${lag}` : `${lag}` : ""
|
|
2032
|
-
] })
|
|
2033
|
-
}
|
|
2034
|
-
),
|
|
2035
|
-
!disableDependencyEditing && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2036
|
-
"button",
|
|
2037
|
-
{
|
|
2038
|
-
type: "button",
|
|
2039
|
-
className: "gantt-tl-dep-chip-trash",
|
|
2040
|
-
"aria-label": "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u0432\u044F\u0437\u044C",
|
|
2041
|
-
onClick: handleTrashClick,
|
|
2042
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TrashIcon, {})
|
|
2043
|
-
}
|
|
2044
|
-
)
|
|
2045
|
-
] }) }),
|
|
2046
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
2047
|
-
PopoverContent,
|
|
2095
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "gantt-tl-dep-chip-wrapper", children: [
|
|
2096
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2097
|
+
"span",
|
|
2048
2098
|
{
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2099
|
+
className: `gantt-tl-dep-chip${isSelected ? " gantt-tl-dep-chip-selected" : ""}`,
|
|
2100
|
+
onClick: handleClick,
|
|
2101
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
2102
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Icon, {}),
|
|
2103
|
+
lag != null && lag !== 0 ? lag > 0 ? `+${lag}` : `${lag}` : ""
|
|
2104
|
+
] })
|
|
2105
|
+
}
|
|
2106
|
+
),
|
|
2107
|
+
!disableDependencyEditing && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2108
|
+
"button",
|
|
2109
|
+
{
|
|
2110
|
+
type: "button",
|
|
2111
|
+
className: "gantt-tl-dep-chip-trash",
|
|
2112
|
+
"aria-label": "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u0432\u044F\u0437\u044C",
|
|
2113
|
+
onClick: handleTrashClick,
|
|
2114
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TrashIcon, {})
|
|
2065
2115
|
}
|
|
2066
2116
|
)
|
|
2067
2117
|
] });
|
|
@@ -2089,12 +2139,19 @@ var TaskListRow = import_react10.default.memo(
|
|
|
2089
2139
|
onRemoveDependency,
|
|
2090
2140
|
selectedChip,
|
|
2091
2141
|
onChipSelect,
|
|
2092
|
-
onScrollToTask
|
|
2142
|
+
onScrollToTask,
|
|
2143
|
+
onDelete,
|
|
2144
|
+
onAdd,
|
|
2145
|
+
onInsertAfter,
|
|
2146
|
+
editingTaskId
|
|
2093
2147
|
}) => {
|
|
2094
2148
|
const [editingName, setEditingName] = (0, import_react10.useState)(false);
|
|
2095
2149
|
const [nameValue, setNameValue] = (0, import_react10.useState)("");
|
|
2096
2150
|
const nameInputRef = (0, import_react10.useRef)(null);
|
|
2097
2151
|
const [overflowOpen, setOverflowOpen] = (0, import_react10.useState)(false);
|
|
2152
|
+
const confirmedRef = (0, import_react10.useRef)(false);
|
|
2153
|
+
const autoEditedForRef = (0, import_react10.useRef)(null);
|
|
2154
|
+
const editTriggerRef = (0, import_react10.useRef)("doubleclick");
|
|
2098
2155
|
const isSelected = selectedTaskId === task.id;
|
|
2099
2156
|
const isPicking = selectingPredecessorFor != null;
|
|
2100
2157
|
const isSourceRow = isPicking && selectingPredecessorFor === task.id;
|
|
@@ -2118,15 +2175,59 @@ var TaskListRow = import_react10.default.memo(
|
|
|
2118
2175
|
(0, import_react10.useEffect)(() => {
|
|
2119
2176
|
if (editingName && nameInputRef.current) {
|
|
2120
2177
|
nameInputRef.current.focus();
|
|
2178
|
+
if (editTriggerRef.current === "keypress") {
|
|
2179
|
+
const len = nameInputRef.current.value.length;
|
|
2180
|
+
nameInputRef.current.setSelectionRange(len, len);
|
|
2181
|
+
} else {
|
|
2182
|
+
nameInputRef.current.select();
|
|
2183
|
+
}
|
|
2121
2184
|
}
|
|
2122
2185
|
}, [editingName]);
|
|
2186
|
+
(0, import_react10.useEffect)(() => {
|
|
2187
|
+
if (editingTaskId === task.id && !disableTaskNameEditing && autoEditedForRef.current !== editingTaskId) {
|
|
2188
|
+
autoEditedForRef.current = editingTaskId;
|
|
2189
|
+
confirmedRef.current = false;
|
|
2190
|
+
editTriggerRef.current = "autoedit";
|
|
2191
|
+
setNameValue(task.name);
|
|
2192
|
+
setEditingName(true);
|
|
2193
|
+
}
|
|
2194
|
+
}, [editingTaskId, task.id, disableTaskNameEditing]);
|
|
2123
2195
|
const handleNameClick = (0, import_react10.useCallback)((e) => {
|
|
2124
2196
|
if (disableTaskNameEditing) return;
|
|
2125
2197
|
e.stopPropagation();
|
|
2198
|
+
onRowClick?.(task.id);
|
|
2199
|
+
onScrollToTask?.(task.id);
|
|
2200
|
+
}, [task.id, disableTaskNameEditing, onRowClick, onScrollToTask]);
|
|
2201
|
+
const handleNameDoubleClick = (0, import_react10.useCallback)((e) => {
|
|
2202
|
+
if (disableTaskNameEditing) return;
|
|
2203
|
+
e.stopPropagation();
|
|
2204
|
+
confirmedRef.current = false;
|
|
2205
|
+
editTriggerRef.current = "doubleclick";
|
|
2126
2206
|
setNameValue(task.name);
|
|
2127
2207
|
setEditingName(true);
|
|
2128
2208
|
}, [task.name, disableTaskNameEditing]);
|
|
2209
|
+
const handleRowKeyDown = (0, import_react10.useCallback)((e) => {
|
|
2210
|
+
if (!editingName && !disableTaskNameEditing && e.key === "F2") {
|
|
2211
|
+
e.preventDefault();
|
|
2212
|
+
confirmedRef.current = false;
|
|
2213
|
+
editTriggerRef.current = "keypress";
|
|
2214
|
+
setNameValue(task.name);
|
|
2215
|
+
setEditingName(true);
|
|
2216
|
+
return;
|
|
2217
|
+
}
|
|
2218
|
+
if (!editingName && !disableTaskNameEditing && e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
|
|
2219
|
+
e.preventDefault();
|
|
2220
|
+
confirmedRef.current = false;
|
|
2221
|
+
editTriggerRef.current = "keypress";
|
|
2222
|
+
setNameValue(e.key);
|
|
2223
|
+
setEditingName(true);
|
|
2224
|
+
}
|
|
2225
|
+
}, [editingName, disableTaskNameEditing, task.name]);
|
|
2129
2226
|
const handleNameSave = (0, import_react10.useCallback)(() => {
|
|
2227
|
+
if (confirmedRef.current) {
|
|
2228
|
+
confirmedRef.current = false;
|
|
2229
|
+
return;
|
|
2230
|
+
}
|
|
2130
2231
|
if (nameValue.trim()) {
|
|
2131
2232
|
onTaskChange?.({ ...task, name: nameValue.trim() });
|
|
2132
2233
|
}
|
|
@@ -2136,9 +2237,16 @@ var TaskListRow = import_react10.default.memo(
|
|
|
2136
2237
|
setEditingName(false);
|
|
2137
2238
|
}, []);
|
|
2138
2239
|
const handleNameKeyDown = (0, import_react10.useCallback)((e) => {
|
|
2139
|
-
if (e.key === "Enter")
|
|
2140
|
-
|
|
2141
|
-
|
|
2240
|
+
if (e.key === "Enter") {
|
|
2241
|
+
confirmedRef.current = true;
|
|
2242
|
+
if (nameValue.trim()) {
|
|
2243
|
+
onTaskChange?.({ ...task, name: nameValue.trim() });
|
|
2244
|
+
}
|
|
2245
|
+
setEditingName(false);
|
|
2246
|
+
} else if (e.key === "Escape") {
|
|
2247
|
+
handleNameCancel();
|
|
2248
|
+
}
|
|
2249
|
+
}, [nameValue, task, onTaskChange, handleNameCancel]);
|
|
2142
2250
|
const handleStartDateChange = (0, import_react10.useCallback)((newDateISO) => {
|
|
2143
2251
|
if (!newDateISO) return;
|
|
2144
2252
|
const origStart = parseUTCDate(task.startDate);
|
|
@@ -2163,8 +2271,7 @@ var TaskListRow = import_react10.default.memo(
|
|
|
2163
2271
|
const handleNumberClick = (0, import_react10.useCallback)((e) => {
|
|
2164
2272
|
e.stopPropagation();
|
|
2165
2273
|
onRowClick?.(task.id);
|
|
2166
|
-
|
|
2167
|
-
}, [task.id, onRowClick, onScrollToTask]);
|
|
2274
|
+
}, [task.id, onRowClick]);
|
|
2168
2275
|
const handleAddClick = (0, import_react10.useCallback)((e) => {
|
|
2169
2276
|
e.stopPropagation();
|
|
2170
2277
|
onSetSelectingPredecessorFor?.(task.id);
|
|
@@ -2175,6 +2282,10 @@ var TaskListRow = import_react10.default.memo(
|
|
|
2175
2282
|
if (!selectingPredecessorFor || !activeLinkType) return;
|
|
2176
2283
|
onAddDependency?.(task.id, selectingPredecessorFor, activeLinkType);
|
|
2177
2284
|
}, [isPicking, isSourceRow, selectingPredecessorFor, task.id, activeLinkType, onAddDependency]);
|
|
2285
|
+
const handleCancelPicking = (0, import_react10.useCallback)((e) => {
|
|
2286
|
+
e.stopPropagation();
|
|
2287
|
+
onSetSelectingPredecessorFor?.(null);
|
|
2288
|
+
}, [onSetSelectingPredecessorFor]);
|
|
2178
2289
|
const isSelectedPredecessor = selectedChip != null && selectedChip.predecessorId === task.id;
|
|
2179
2290
|
const handleDeleteSelected = (0, import_react10.useCallback)((e) => {
|
|
2180
2291
|
e.stopPropagation();
|
|
@@ -2193,23 +2304,17 @@ var TaskListRow = import_react10.default.memo(
|
|
|
2193
2304
|
isPicking && !isSourceRow ? "gantt-tl-row-picking" : "",
|
|
2194
2305
|
isSourceRow ? "gantt-tl-row-picking-self" : ""
|
|
2195
2306
|
].filter(Boolean).join(" "),
|
|
2196
|
-
style: { minHeight: `${rowHeight}px
|
|
2307
|
+
style: { minHeight: `${rowHeight}px`, position: "relative" },
|
|
2197
2308
|
onClick: handleRowClickInternal,
|
|
2309
|
+
onKeyDown: handleRowKeyDown,
|
|
2310
|
+
tabIndex: isSelected ? 0 : -1,
|
|
2198
2311
|
children: [
|
|
2199
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.
|
|
2312
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2200
2313
|
"div",
|
|
2201
2314
|
{
|
|
2202
2315
|
className: "gantt-tl-cell gantt-tl-cell-number",
|
|
2203
2316
|
onClick: handleNumberClick,
|
|
2204
|
-
|
|
2205
|
-
children: [
|
|
2206
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "gantt-tl-num-label", children: rowIndex + 1 }),
|
|
2207
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("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: [
|
|
2208
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M17 12H3" }),
|
|
2209
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "m11 18 6-6-6-6" }),
|
|
2210
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M21 5v14" })
|
|
2211
|
-
] })
|
|
2212
|
-
]
|
|
2317
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "gantt-tl-num-label", children: rowIndex + 1 })
|
|
2213
2318
|
}
|
|
2214
2319
|
),
|
|
2215
2320
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-cell gantt-tl-cell-name", children: [
|
|
@@ -2232,10 +2337,56 @@ var TaskListRow = import_react10.default.memo(
|
|
|
2232
2337
|
type: "button",
|
|
2233
2338
|
className: `gantt-tl-name-trigger ${disableTaskNameEditing ? "gantt-tl-name-locked" : ""}`,
|
|
2234
2339
|
onClick: handleNameClick,
|
|
2340
|
+
onDoubleClick: handleNameDoubleClick,
|
|
2235
2341
|
style: editingName ? { visibility: "hidden", pointerEvents: "none" } : void 0,
|
|
2236
2342
|
children: task.name
|
|
2237
2343
|
}
|
|
2238
|
-
)
|
|
2344
|
+
),
|
|
2345
|
+
!editingName && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-name-actions", children: [
|
|
2346
|
+
onInsertAfter && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2347
|
+
"button",
|
|
2348
|
+
{
|
|
2349
|
+
type: "button",
|
|
2350
|
+
className: "gantt-tl-name-action-btn gantt-tl-action-insert",
|
|
2351
|
+
onClick: (e) => {
|
|
2352
|
+
e.stopPropagation();
|
|
2353
|
+
const now = /* @__PURE__ */ new Date();
|
|
2354
|
+
const todayISO = new Date(Date.UTC(
|
|
2355
|
+
now.getUTCFullYear(),
|
|
2356
|
+
now.getUTCMonth(),
|
|
2357
|
+
now.getUTCDate()
|
|
2358
|
+
)).toISOString().split("T")[0];
|
|
2359
|
+
const endISO = new Date(Date.UTC(
|
|
2360
|
+
now.getUTCFullYear(),
|
|
2361
|
+
now.getUTCMonth(),
|
|
2362
|
+
now.getUTCDate() + 7
|
|
2363
|
+
)).toISOString().split("T")[0];
|
|
2364
|
+
const newTask = {
|
|
2365
|
+
id: crypto.randomUUID(),
|
|
2366
|
+
name: "\u041D\u043E\u0432\u0430\u044F \u0437\u0430\u0434\u0430\u0447\u0430",
|
|
2367
|
+
startDate: todayISO,
|
|
2368
|
+
endDate: endISO
|
|
2369
|
+
};
|
|
2370
|
+
onInsertAfter(task.id, newTask);
|
|
2371
|
+
},
|
|
2372
|
+
"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",
|
|
2373
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PlusIcon, {})
|
|
2374
|
+
}
|
|
2375
|
+
),
|
|
2376
|
+
onDelete && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2377
|
+
"button",
|
|
2378
|
+
{
|
|
2379
|
+
type: "button",
|
|
2380
|
+
className: "gantt-tl-name-action-btn gantt-tl-action-delete",
|
|
2381
|
+
onClick: (e) => {
|
|
2382
|
+
e.stopPropagation();
|
|
2383
|
+
onDelete(task.id);
|
|
2384
|
+
},
|
|
2385
|
+
"aria-label": "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0437\u0430\u0434\u0430\u0447\u0443",
|
|
2386
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TrashIcon, {})
|
|
2387
|
+
}
|
|
2388
|
+
)
|
|
2389
|
+
] })
|
|
2239
2390
|
] }),
|
|
2240
2391
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "gantt-tl-cell gantt-tl-cell-date", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2241
2392
|
DatePicker,
|
|
@@ -2261,7 +2412,7 @@ var TaskListRow = import_react10.default.memo(
|
|
|
2261
2412
|
"div",
|
|
2262
2413
|
{
|
|
2263
2414
|
className: "gantt-tl-cell gantt-tl-cell-deps",
|
|
2264
|
-
onClick:
|
|
2415
|
+
onClick: isSourceRow ? handleCancelPicking : isPicking ? handlePredecessorPick : void 0,
|
|
2265
2416
|
children: isSourceRow ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "gantt-tl-dep-source-hint", children: "\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0437\u0430\u0434\u0430\u0447\u0443" }) : isSelectedPredecessor && !disableDependencyEditing ? (
|
|
2266
2417
|
/* Full-replacement: "Зависит от [name]" → hover → "Удалить" */
|
|
2267
2418
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
@@ -2338,7 +2489,7 @@ var TaskListRow = import_react10.default.memo(
|
|
|
2338
2489
|
"button",
|
|
2339
2490
|
{
|
|
2340
2491
|
type: "button",
|
|
2341
|
-
className: "gantt-tl-dep-add"
|
|
2492
|
+
className: `gantt-tl-dep-add gantt-tl-dep-add-hover${selectedChip ? " gantt-tl-dep-add-hidden" : ""}`,
|
|
2342
2493
|
onClick: handleAddClick,
|
|
2343
2494
|
"aria-label": "\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0441\u0432\u044F\u0437\u044C",
|
|
2344
2495
|
children: "+"
|
|
@@ -2354,14 +2505,68 @@ var TaskListRow = import_react10.default.memo(
|
|
|
2354
2505
|
);
|
|
2355
2506
|
TaskListRow.displayName = "TaskListRow";
|
|
2356
2507
|
|
|
2357
|
-
// src/components/TaskList/
|
|
2508
|
+
// src/components/TaskList/NewTaskRow.tsx
|
|
2509
|
+
var import_react11 = require("react");
|
|
2358
2510
|
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
2511
|
+
var NewTaskRow = ({ rowHeight, onConfirm, onCancel }) => {
|
|
2512
|
+
const [nameValue, setNameValue] = (0, import_react11.useState)("");
|
|
2513
|
+
const inputRef = (0, import_react11.useRef)(null);
|
|
2514
|
+
const confirmedRef = (0, import_react11.useRef)(false);
|
|
2515
|
+
(0, import_react11.useEffect)(() => {
|
|
2516
|
+
if (inputRef.current) {
|
|
2517
|
+
inputRef.current.focus();
|
|
2518
|
+
inputRef.current.select();
|
|
2519
|
+
}
|
|
2520
|
+
}, []);
|
|
2521
|
+
const handleKeyDown = (e) => {
|
|
2522
|
+
if (e.key === "Enter") {
|
|
2523
|
+
if (nameValue.trim()) {
|
|
2524
|
+
confirmedRef.current = true;
|
|
2525
|
+
onConfirm(nameValue.trim());
|
|
2526
|
+
} else {
|
|
2527
|
+
onCancel();
|
|
2528
|
+
}
|
|
2529
|
+
} else if (e.key === "Escape") {
|
|
2530
|
+
onCancel();
|
|
2531
|
+
}
|
|
2532
|
+
};
|
|
2533
|
+
const handleBlur = () => {
|
|
2534
|
+
if (confirmedRef.current) return;
|
|
2535
|
+
if (nameValue.trim()) {
|
|
2536
|
+
confirmedRef.current = true;
|
|
2537
|
+
onConfirm(nameValue.trim());
|
|
2538
|
+
} else {
|
|
2539
|
+
onCancel();
|
|
2540
|
+
}
|
|
2541
|
+
};
|
|
2542
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "gantt-tl-row gantt-tl-row-new", style: { minHeight: `${rowHeight}px` }, children: [
|
|
2543
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "gantt-tl-cell gantt-tl-cell-number" }),
|
|
2544
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "gantt-tl-cell gantt-tl-cell-name gantt-tl-cell-new-name", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2545
|
+
Input,
|
|
2546
|
+
{
|
|
2547
|
+
ref: inputRef,
|
|
2548
|
+
value: nameValue,
|
|
2549
|
+
onChange: (e) => setNameValue(e.target.value),
|
|
2550
|
+
onKeyDown: handleKeyDown,
|
|
2551
|
+
onBlur: handleBlur,
|
|
2552
|
+
placeholder: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435",
|
|
2553
|
+
className: "gantt-tl-name-input"
|
|
2554
|
+
}
|
|
2555
|
+
) }),
|
|
2556
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "gantt-tl-cell" }),
|
|
2557
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "gantt-tl-cell" }),
|
|
2558
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "gantt-tl-cell" })
|
|
2559
|
+
] });
|
|
2560
|
+
};
|
|
2561
|
+
|
|
2562
|
+
// src/components/TaskList/TaskList.tsx
|
|
2563
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
2359
2564
|
var LINK_TYPE_ORDER = ["FS", "SS", "FF", "SF"];
|
|
2360
2565
|
var TaskList = ({
|
|
2361
2566
|
tasks,
|
|
2362
2567
|
rowHeight,
|
|
2363
2568
|
headerHeight,
|
|
2364
|
-
taskListWidth =
|
|
2569
|
+
taskListWidth = 472,
|
|
2365
2570
|
onTaskChange,
|
|
2366
2571
|
selectedTaskId,
|
|
2367
2572
|
onTaskSelect,
|
|
@@ -2369,26 +2574,30 @@ var TaskList = ({
|
|
|
2369
2574
|
disableTaskNameEditing = false,
|
|
2370
2575
|
disableDependencyEditing = false,
|
|
2371
2576
|
onScrollToTask,
|
|
2372
|
-
onSelectedChipChange
|
|
2577
|
+
onSelectedChipChange,
|
|
2578
|
+
onAdd,
|
|
2579
|
+
onDelete,
|
|
2580
|
+
onInsertAfter,
|
|
2581
|
+
editingTaskId: propEditingTaskId
|
|
2373
2582
|
}) => {
|
|
2374
|
-
const totalHeight = (0,
|
|
2583
|
+
const totalHeight = (0, import_react12.useMemo)(
|
|
2375
2584
|
() => tasks.length * rowHeight,
|
|
2376
2585
|
[tasks.length, rowHeight]
|
|
2377
2586
|
);
|
|
2378
|
-
const handleRowClick = (0,
|
|
2587
|
+
const handleRowClick = (0, import_react12.useCallback)((taskId) => {
|
|
2379
2588
|
onTaskSelect?.(taskId);
|
|
2380
2589
|
}, [onTaskSelect]);
|
|
2381
|
-
const [activeLinkType, setActiveLinkType] = (0,
|
|
2382
|
-
const [selectingPredecessorFor, setSelectingPredecessorFor] = (0,
|
|
2383
|
-
const [typeMenuOpen, setTypeMenuOpen] = (0,
|
|
2384
|
-
const [cycleError, setCycleError] = (0,
|
|
2385
|
-
const overlayRef = (0,
|
|
2386
|
-
const [selectedChip, setSelectedChip] = (0,
|
|
2387
|
-
const handleChipSelect = (0,
|
|
2590
|
+
const [activeLinkType, setActiveLinkType] = (0, import_react12.useState)("FS");
|
|
2591
|
+
const [selectingPredecessorFor, setSelectingPredecessorFor] = (0, import_react12.useState)(null);
|
|
2592
|
+
const [typeMenuOpen, setTypeMenuOpen] = (0, import_react12.useState)(false);
|
|
2593
|
+
const [cycleError, setCycleError] = (0, import_react12.useState)(false);
|
|
2594
|
+
const overlayRef = (0, import_react12.useRef)(null);
|
|
2595
|
+
const [selectedChip, setSelectedChip] = (0, import_react12.useState)(null);
|
|
2596
|
+
const handleChipSelect = (0, import_react12.useCallback)((chip) => {
|
|
2388
2597
|
setSelectedChip(chip);
|
|
2389
2598
|
onSelectedChipChange?.(chip);
|
|
2390
2599
|
}, [onSelectedChipChange]);
|
|
2391
|
-
(0,
|
|
2600
|
+
(0, import_react12.useEffect)(() => {
|
|
2392
2601
|
if (!selectingPredecessorFor && !selectedChip) return;
|
|
2393
2602
|
const handleKeyDown = (e) => {
|
|
2394
2603
|
if (e.key === "Escape") {
|
|
@@ -2412,7 +2621,7 @@ var TaskList = ({
|
|
|
2412
2621
|
document.removeEventListener("mousedown", handleMouseDown, true);
|
|
2413
2622
|
};
|
|
2414
2623
|
}, [selectingPredecessorFor, selectedChip, onSelectedChipChange]);
|
|
2415
|
-
const handleAddDependency = (0,
|
|
2624
|
+
const handleAddDependency = (0, import_react12.useCallback)((successorTaskId, predecessorTaskId, linkType) => {
|
|
2416
2625
|
if (successorTaskId === predecessorTaskId) return;
|
|
2417
2626
|
const successor = tasks.find((t) => t.id === successorTaskId);
|
|
2418
2627
|
if (!successor) return;
|
|
@@ -2461,7 +2670,7 @@ var TaskList = ({
|
|
|
2461
2670
|
}
|
|
2462
2671
|
setSelectingPredecessorFor(null);
|
|
2463
2672
|
}, [tasks, onTaskChange]);
|
|
2464
|
-
const handleRemoveDependency = (0,
|
|
2673
|
+
const handleRemoveDependency = (0, import_react12.useCallback)((taskId, predecessorTaskId, linkType) => {
|
|
2465
2674
|
const task = tasks.find((t) => t.id === taskId);
|
|
2466
2675
|
if (!task) return;
|
|
2467
2676
|
const updatedDeps = (task.dependencies ?? []).filter(
|
|
@@ -2469,21 +2678,44 @@ var TaskList = ({
|
|
|
2469
2678
|
);
|
|
2470
2679
|
onTaskChange?.({ ...task, dependencies: updatedDeps });
|
|
2471
2680
|
}, [tasks, onTaskChange]);
|
|
2472
|
-
|
|
2681
|
+
const [isCreating, setIsCreating] = (0, import_react12.useState)(false);
|
|
2682
|
+
const handleConfirmNewTask = (0, import_react12.useCallback)((name) => {
|
|
2683
|
+
const now = /* @__PURE__ */ new Date();
|
|
2684
|
+
const todayISO = new Date(Date.UTC(
|
|
2685
|
+
now.getUTCFullYear(),
|
|
2686
|
+
now.getUTCMonth(),
|
|
2687
|
+
now.getUTCDate()
|
|
2688
|
+
)).toISOString().split("T")[0];
|
|
2689
|
+
const endISO = new Date(Date.UTC(
|
|
2690
|
+
now.getUTCFullYear(),
|
|
2691
|
+
now.getUTCMonth(),
|
|
2692
|
+
now.getUTCDate() + 7
|
|
2693
|
+
)).toISOString().split("T")[0];
|
|
2694
|
+
const newTask = {
|
|
2695
|
+
id: crypto.randomUUID(),
|
|
2696
|
+
name,
|
|
2697
|
+
startDate: todayISO,
|
|
2698
|
+
endDate: endISO
|
|
2699
|
+
};
|
|
2700
|
+
onAdd?.(newTask);
|
|
2701
|
+
setIsCreating(false);
|
|
2702
|
+
}, [onAdd]);
|
|
2703
|
+
const handleCancelNewTask = (0, import_react12.useCallback)(() => setIsCreating(false), []);
|
|
2704
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2473
2705
|
"div",
|
|
2474
2706
|
{
|
|
2475
2707
|
ref: overlayRef,
|
|
2476
2708
|
className: `gantt-tl-overlay${show ? "" : " gantt-tl-hidden"}`,
|
|
2477
2709
|
style: { width: `${taskListWidth}px` },
|
|
2478
|
-
children: /* @__PURE__ */ (0,
|
|
2479
|
-
/* @__PURE__ */ (0,
|
|
2480
|
-
/* @__PURE__ */ (0,
|
|
2481
|
-
/* @__PURE__ */ (0,
|
|
2482
|
-
/* @__PURE__ */ (0,
|
|
2483
|
-
/* @__PURE__ */ (0,
|
|
2484
|
-
/* @__PURE__ */ (0,
|
|
2485
|
-
/* @__PURE__ */ (0,
|
|
2486
|
-
/* @__PURE__ */ (0,
|
|
2710
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "gantt-tl-table", children: [
|
|
2711
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "gantt-tl-header", style: { height: `${headerHeight + 0.5}px` }, children: [
|
|
2712
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "gantt-tl-headerCell gantt-tl-cell-number", children: "\u2116" }),
|
|
2713
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "gantt-tl-headerCell gantt-tl-cell-name", children: "\u0418\u043C\u044F" }),
|
|
2714
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "gantt-tl-headerCell gantt-tl-cell-date", children: "\u041D\u0430\u0447\u0430\u043B\u043E" }),
|
|
2715
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "gantt-tl-headerCell gantt-tl-cell-date", children: "\u041E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u0435" }),
|
|
2716
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "gantt-tl-headerCell gantt-tl-cell-deps", style: { position: "relative" }, children: [
|
|
2717
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(Popover, { open: typeMenuOpen, onOpenChange: setTypeMenuOpen, children: [
|
|
2718
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
2487
2719
|
"button",
|
|
2488
2720
|
{
|
|
2489
2721
|
className: "gantt-tl-dep-type-trigger",
|
|
@@ -2491,12 +2723,12 @@ var TaskList = ({
|
|
|
2491
2723
|
onClick: (e) => e.stopPropagation(),
|
|
2492
2724
|
children: [
|
|
2493
2725
|
"\u0421\u0432\u044F\u0437\u0438 ",
|
|
2494
|
-
|
|
2726
|
+
import_react12.default.createElement(LINK_TYPE_ICONS[activeLinkType]),
|
|
2495
2727
|
" \u25BE"
|
|
2496
2728
|
]
|
|
2497
2729
|
}
|
|
2498
2730
|
) }),
|
|
2499
|
-
/* @__PURE__ */ (0,
|
|
2731
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(PopoverContent, { portal: true, align: "start", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "gantt-tl-dep-type-menu", children: LINK_TYPE_ORDER.map((lt) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
2500
2732
|
"button",
|
|
2501
2733
|
{
|
|
2502
2734
|
className: `gantt-tl-dep-type-option${activeLinkType === lt ? " active" : ""}`,
|
|
@@ -2505,17 +2737,17 @@ var TaskList = ({
|
|
|
2505
2737
|
setTypeMenuOpen(false);
|
|
2506
2738
|
},
|
|
2507
2739
|
children: [
|
|
2508
|
-
|
|
2509
|
-
/* @__PURE__ */ (0,
|
|
2740
|
+
import_react12.default.createElement(LINK_TYPE_ICONS[lt]),
|
|
2741
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: LINK_TYPE_LABELS[lt] })
|
|
2510
2742
|
]
|
|
2511
2743
|
},
|
|
2512
2744
|
lt
|
|
2513
2745
|
)) }) })
|
|
2514
2746
|
] }),
|
|
2515
|
-
cycleError && /* @__PURE__ */ (0,
|
|
2747
|
+
cycleError && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "gantt-tl-dep-error", children: "\u0426\u0438\u043A\u043B \u0437\u0430\u0432\u0438\u0441\u0438\u043C\u043E\u0441\u0442\u0435\u0439!" })
|
|
2516
2748
|
] })
|
|
2517
2749
|
] }),
|
|
2518
|
-
/* @__PURE__ */ (0,
|
|
2750
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "gantt-tl-body", style: { height: `${totalHeight}px` }, children: tasks.map((task, index) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2519
2751
|
TaskListRow,
|
|
2520
2752
|
{
|
|
2521
2753
|
task,
|
|
@@ -2534,18 +2766,39 @@ var TaskList = ({
|
|
|
2534
2766
|
onRemoveDependency: handleRemoveDependency,
|
|
2535
2767
|
selectedChip,
|
|
2536
2768
|
onChipSelect: handleChipSelect,
|
|
2537
|
-
onScrollToTask
|
|
2769
|
+
onScrollToTask,
|
|
2770
|
+
onDelete,
|
|
2771
|
+
onAdd,
|
|
2772
|
+
onInsertAfter,
|
|
2773
|
+
editingTaskId: propEditingTaskId
|
|
2538
2774
|
},
|
|
2539
2775
|
task.id
|
|
2540
|
-
)) })
|
|
2776
|
+
)) }),
|
|
2777
|
+
isCreating && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2778
|
+
NewTaskRow,
|
|
2779
|
+
{
|
|
2780
|
+
rowHeight,
|
|
2781
|
+
onConfirm: handleConfirmNewTask,
|
|
2782
|
+
onCancel: handleCancelNewTask
|
|
2783
|
+
}
|
|
2784
|
+
),
|
|
2785
|
+
onAdd && !isCreating && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2786
|
+
"button",
|
|
2787
|
+
{
|
|
2788
|
+
className: "gantt-tl-add-btn",
|
|
2789
|
+
onClick: () => setIsCreating(true),
|
|
2790
|
+
type: "button",
|
|
2791
|
+
children: "+ \u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0437\u0430\u0434\u0430\u0447\u0443"
|
|
2792
|
+
}
|
|
2793
|
+
)
|
|
2541
2794
|
] })
|
|
2542
2795
|
}
|
|
2543
2796
|
);
|
|
2544
2797
|
};
|
|
2545
2798
|
|
|
2546
2799
|
// src/components/GanttChart/GanttChart.tsx
|
|
2547
|
-
var
|
|
2548
|
-
var GanttChart = (0,
|
|
2800
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
2801
|
+
var GanttChart = (0, import_react13.forwardRef)(({
|
|
2549
2802
|
tasks,
|
|
2550
2803
|
dayWidth = 40,
|
|
2551
2804
|
rowHeight = 40,
|
|
@@ -2560,35 +2813,39 @@ var GanttChart = (0, import_react12.forwardRef)(({
|
|
|
2560
2813
|
taskListWidth = 520,
|
|
2561
2814
|
disableTaskNameEditing = false,
|
|
2562
2815
|
disableDependencyEditing = false,
|
|
2563
|
-
highlightExpiredTasks = false
|
|
2816
|
+
highlightExpiredTasks = false,
|
|
2817
|
+
onAdd,
|
|
2818
|
+
onDelete,
|
|
2819
|
+
onInsertAfter
|
|
2564
2820
|
}, ref) => {
|
|
2565
|
-
const scrollContainerRef = (0,
|
|
2566
|
-
const [selectedTaskId, setSelectedTaskId] = (0,
|
|
2567
|
-
const [selectedChip, setSelectedChip] = (0,
|
|
2568
|
-
const
|
|
2569
|
-
const
|
|
2570
|
-
const [
|
|
2571
|
-
const
|
|
2821
|
+
const scrollContainerRef = (0, import_react13.useRef)(null);
|
|
2822
|
+
const [selectedTaskId, setSelectedTaskId] = (0, import_react13.useState)(null);
|
|
2823
|
+
const [selectedChip, setSelectedChip] = (0, import_react13.useState)(null);
|
|
2824
|
+
const [editingTaskId, setEditingTaskId] = (0, import_react13.useState)(null);
|
|
2825
|
+
const dateRange = (0, import_react13.useMemo)(() => getMultiMonthDays(tasks), [tasks]);
|
|
2826
|
+
const [validationResult, setValidationResult] = (0, import_react13.useState)(null);
|
|
2827
|
+
const [cascadeOverrides, setCascadeOverrides] = (0, import_react13.useState)(/* @__PURE__ */ new Map());
|
|
2828
|
+
const gridWidth = (0, import_react13.useMemo)(
|
|
2572
2829
|
() => Math.round(dateRange.length * dayWidth),
|
|
2573
2830
|
[dateRange.length, dayWidth]
|
|
2574
2831
|
);
|
|
2575
|
-
const totalGridHeight = (0,
|
|
2832
|
+
const totalGridHeight = (0, import_react13.useMemo)(
|
|
2576
2833
|
() => tasks.length * rowHeight,
|
|
2577
2834
|
[tasks.length, rowHeight]
|
|
2578
2835
|
);
|
|
2579
|
-
const monthStart = (0,
|
|
2836
|
+
const monthStart = (0, import_react13.useMemo)(() => {
|
|
2580
2837
|
if (dateRange.length === 0) {
|
|
2581
2838
|
return new Date(Date.UTC((/* @__PURE__ */ new Date()).getUTCFullYear(), (/* @__PURE__ */ new Date()).getUTCMonth(), 1));
|
|
2582
2839
|
}
|
|
2583
2840
|
const firstDay = dateRange[0];
|
|
2584
2841
|
return new Date(Date.UTC(firstDay.getUTCFullYear(), firstDay.getUTCMonth(), 1));
|
|
2585
2842
|
}, [dateRange]);
|
|
2586
|
-
const todayInRange = (0,
|
|
2843
|
+
const todayInRange = (0, import_react13.useMemo)(() => {
|
|
2587
2844
|
const now = /* @__PURE__ */ new Date();
|
|
2588
2845
|
const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
|
|
2589
2846
|
return dateRange.some((day) => day.getTime() === today.getTime());
|
|
2590
2847
|
}, [dateRange]);
|
|
2591
|
-
(0,
|
|
2848
|
+
(0, import_react13.useEffect)(() => {
|
|
2592
2849
|
const container = scrollContainerRef.current;
|
|
2593
2850
|
if (!container || dateRange.length === 0) return;
|
|
2594
2851
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -2600,7 +2857,7 @@ var GanttChart = (0, import_react12.forwardRef)(({
|
|
|
2600
2857
|
const scrollLeft = Math.round(todayOffset - containerWidth / 2 + dayWidth / 2);
|
|
2601
2858
|
container.scrollLeft = Math.max(0, scrollLeft);
|
|
2602
2859
|
}, []);
|
|
2603
|
-
const scrollToToday = (0,
|
|
2860
|
+
const scrollToToday = (0, import_react13.useCallback)(() => {
|
|
2604
2861
|
const container = scrollContainerRef.current;
|
|
2605
2862
|
if (!container || dateRange.length === 0) return;
|
|
2606
2863
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -2612,7 +2869,7 @@ var GanttChart = (0, import_react12.forwardRef)(({
|
|
|
2612
2869
|
const scrollLeft = Math.round(todayOffset - containerWidth / 2 + dayWidth / 2);
|
|
2613
2870
|
container.scrollTo({ left: Math.max(0, scrollLeft), behavior: "smooth" });
|
|
2614
2871
|
}, [dateRange, dayWidth]);
|
|
2615
|
-
const scrollToTask = (0,
|
|
2872
|
+
const scrollToTask = (0, import_react13.useCallback)((taskId) => {
|
|
2616
2873
|
const container = scrollContainerRef.current;
|
|
2617
2874
|
if (!container || dateRange.length === 0) return;
|
|
2618
2875
|
const task = tasks.find((t) => t.id === taskId);
|
|
@@ -2629,7 +2886,7 @@ var GanttChart = (0, import_react12.forwardRef)(({
|
|
|
2629
2886
|
const scrollLeft = Math.round(taskOffset - dayWidth * 2);
|
|
2630
2887
|
container.scrollTo({ left: Math.max(0, scrollLeft), behavior: "smooth" });
|
|
2631
2888
|
}, [tasks, dateRange, dayWidth]);
|
|
2632
|
-
(0,
|
|
2889
|
+
(0, import_react13.useImperativeHandle)(
|
|
2633
2890
|
ref,
|
|
2634
2891
|
() => ({
|
|
2635
2892
|
scrollToToday,
|
|
@@ -2637,17 +2894,20 @@ var GanttChart = (0, import_react12.forwardRef)(({
|
|
|
2637
2894
|
}),
|
|
2638
2895
|
[scrollToToday, scrollToTask]
|
|
2639
2896
|
);
|
|
2640
|
-
const [dragGuideLines, setDragGuideLines] = (0,
|
|
2641
|
-
const [draggedTaskOverride, setDraggedTaskOverride] = (0,
|
|
2642
|
-
(0,
|
|
2897
|
+
const [dragGuideLines, setDragGuideLines] = (0, import_react13.useState)(null);
|
|
2898
|
+
const [draggedTaskOverride, setDraggedTaskOverride] = (0, import_react13.useState)(null);
|
|
2899
|
+
(0, import_react13.useEffect)(() => {
|
|
2643
2900
|
const result = validateDependencies(tasks);
|
|
2644
2901
|
setValidationResult(result);
|
|
2645
2902
|
onValidateDependencies?.(result);
|
|
2646
2903
|
}, [tasks, onValidateDependencies]);
|
|
2647
|
-
const handleTaskChange = (0,
|
|
2904
|
+
const handleTaskChange = (0, import_react13.useCallback)((updatedTask) => {
|
|
2648
2905
|
const originalTask = tasks.find((t) => t.id === updatedTask.id);
|
|
2649
2906
|
if (!originalTask) {
|
|
2650
2907
|
onChange?.((currentTasks) => currentTasks.map((t) => t.id === updatedTask.id ? updatedTask : t));
|
|
2908
|
+
if (editingTaskId === updatedTask.id) {
|
|
2909
|
+
setEditingTaskId(null);
|
|
2910
|
+
}
|
|
2651
2911
|
return;
|
|
2652
2912
|
}
|
|
2653
2913
|
const origStart = new Date(originalTask.startDate);
|
|
@@ -2657,6 +2917,9 @@ var GanttChart = (0, import_react12.forwardRef)(({
|
|
|
2657
2917
|
const datesChanged = origStart.getTime() !== newStart.getTime() || origEnd.getTime() !== newEnd.getTime();
|
|
2658
2918
|
if (!datesChanged) {
|
|
2659
2919
|
onChange?.((currentTasks) => currentTasks.map((t) => t.id === updatedTask.id ? updatedTask : t));
|
|
2920
|
+
if (editingTaskId === updatedTask.id) {
|
|
2921
|
+
setEditingTaskId(null);
|
|
2922
|
+
}
|
|
2660
2923
|
return;
|
|
2661
2924
|
}
|
|
2662
2925
|
let cascadedTasksForCallback;
|
|
@@ -2675,8 +2938,21 @@ var GanttChart = (0, import_react12.forwardRef)(({
|
|
|
2675
2938
|
});
|
|
2676
2939
|
onCascade?.(cascadedTasksForCallback);
|
|
2677
2940
|
}
|
|
2678
|
-
}, [tasks, onChange, disableConstraints, onCascade]);
|
|
2679
|
-
const
|
|
2941
|
+
}, [tasks, onChange, disableConstraints, onCascade, editingTaskId]);
|
|
2942
|
+
const handleDelete = (0, import_react13.useCallback)((taskId) => {
|
|
2943
|
+
onChange?.(
|
|
2944
|
+
(currentTasks) => currentTasks.filter((t) => t.id !== taskId).map((t) => ({
|
|
2945
|
+
...t,
|
|
2946
|
+
dependencies: (t.dependencies ?? []).filter((d) => d.taskId !== taskId)
|
|
2947
|
+
}))
|
|
2948
|
+
);
|
|
2949
|
+
onDelete?.(taskId);
|
|
2950
|
+
}, [onChange, onDelete]);
|
|
2951
|
+
const handleInsertAfter = (0, import_react13.useCallback)((taskId, newTask) => {
|
|
2952
|
+
setEditingTaskId(newTask.id);
|
|
2953
|
+
onInsertAfter?.(taskId, newTask);
|
|
2954
|
+
}, [onInsertAfter]);
|
|
2955
|
+
const dependencyOverrides = (0, import_react13.useMemo)(() => {
|
|
2680
2956
|
const map = new Map(cascadeOverrides);
|
|
2681
2957
|
if (draggedTaskOverride) {
|
|
2682
2958
|
map.set(draggedTaskOverride.taskId, {
|
|
@@ -2686,21 +2962,21 @@ var GanttChart = (0, import_react12.forwardRef)(({
|
|
|
2686
2962
|
}
|
|
2687
2963
|
return map;
|
|
2688
2964
|
}, [cascadeOverrides, draggedTaskOverride]);
|
|
2689
|
-
const handleCascadeProgress = (0,
|
|
2965
|
+
const handleCascadeProgress = (0, import_react13.useCallback)((overrides) => {
|
|
2690
2966
|
setCascadeOverrides(new Map(overrides));
|
|
2691
2967
|
}, []);
|
|
2692
|
-
const handleCascade = (0,
|
|
2968
|
+
const handleCascade = (0, import_react13.useCallback)((cascadedTasks) => {
|
|
2693
2969
|
onChange?.((currentTasks) => {
|
|
2694
2970
|
const cascadeMap = new Map(cascadedTasks.map((t) => [t.id, t]));
|
|
2695
2971
|
return currentTasks.map((t) => cascadeMap.get(t.id) ?? t);
|
|
2696
2972
|
});
|
|
2697
2973
|
onCascade?.(cascadedTasks);
|
|
2698
2974
|
}, [onChange, onCascade]);
|
|
2699
|
-
const handleTaskSelect = (0,
|
|
2975
|
+
const handleTaskSelect = (0, import_react13.useCallback)((taskId) => {
|
|
2700
2976
|
setSelectedTaskId(taskId);
|
|
2701
2977
|
}, []);
|
|
2702
|
-
const panStateRef = (0,
|
|
2703
|
-
const handlePanStart = (0,
|
|
2978
|
+
const panStateRef = (0, import_react13.useRef)(null);
|
|
2979
|
+
const handlePanStart = (0, import_react13.useCallback)((e) => {
|
|
2704
2980
|
if (e.button !== 0) return;
|
|
2705
2981
|
const target = e.target;
|
|
2706
2982
|
if (target.closest("[data-taskbar]")) return;
|
|
@@ -2721,7 +2997,7 @@ var GanttChart = (0, import_react12.forwardRef)(({
|
|
|
2721
2997
|
container.style.cursor = "grabbing";
|
|
2722
2998
|
e.preventDefault();
|
|
2723
2999
|
}, []);
|
|
2724
|
-
(0,
|
|
3000
|
+
(0, import_react13.useEffect)(() => {
|
|
2725
3001
|
const handlePanMove = (e) => {
|
|
2726
3002
|
const pan = panStateRef.current;
|
|
2727
3003
|
if (!pan?.active) return;
|
|
@@ -2743,15 +3019,15 @@ var GanttChart = (0, import_react12.forwardRef)(({
|
|
|
2743
3019
|
window.removeEventListener("mouseup", handlePanEnd);
|
|
2744
3020
|
};
|
|
2745
3021
|
}, []);
|
|
2746
|
-
return /* @__PURE__ */ (0,
|
|
3022
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "gantt-container", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2747
3023
|
"div",
|
|
2748
3024
|
{
|
|
2749
3025
|
ref: scrollContainerRef,
|
|
2750
3026
|
className: "gantt-scrollContainer",
|
|
2751
3027
|
style: { height: containerHeight ?? "auto", cursor: "grab" },
|
|
2752
3028
|
onMouseDown: handlePanStart,
|
|
2753
|
-
children: /* @__PURE__ */ (0,
|
|
2754
|
-
/* @__PURE__ */ (0,
|
|
3029
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "gantt-scrollContent", children: [
|
|
3030
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2755
3031
|
TaskList,
|
|
2756
3032
|
{
|
|
2757
3033
|
tasks,
|
|
@@ -2765,11 +3041,15 @@ var GanttChart = (0, import_react12.forwardRef)(({
|
|
|
2765
3041
|
disableTaskNameEditing,
|
|
2766
3042
|
disableDependencyEditing,
|
|
2767
3043
|
onScrollToTask: scrollToTask,
|
|
2768
|
-
onSelectedChipChange: setSelectedChip
|
|
3044
|
+
onSelectedChipChange: setSelectedChip,
|
|
3045
|
+
onAdd,
|
|
3046
|
+
onDelete: handleDelete,
|
|
3047
|
+
onInsertAfter: handleInsertAfter,
|
|
3048
|
+
editingTaskId
|
|
2769
3049
|
}
|
|
2770
3050
|
),
|
|
2771
|
-
/* @__PURE__ */ (0,
|
|
2772
|
-
/* @__PURE__ */ (0,
|
|
3051
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: { minWidth: `${gridWidth}px`, flex: 1 }, children: [
|
|
3052
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "gantt-stickyHeader", style: { width: `${gridWidth}px` }, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2773
3053
|
TimeScaleHeader_default,
|
|
2774
3054
|
{
|
|
2775
3055
|
days: dateRange,
|
|
@@ -2777,7 +3057,7 @@ var GanttChart = (0, import_react12.forwardRef)(({
|
|
|
2777
3057
|
headerHeight
|
|
2778
3058
|
}
|
|
2779
3059
|
) }),
|
|
2780
|
-
/* @__PURE__ */ (0,
|
|
3060
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
2781
3061
|
"div",
|
|
2782
3062
|
{
|
|
2783
3063
|
className: "gantt-taskArea",
|
|
@@ -2786,7 +3066,7 @@ var GanttChart = (0, import_react12.forwardRef)(({
|
|
|
2786
3066
|
width: `${gridWidth}px`
|
|
2787
3067
|
},
|
|
2788
3068
|
children: [
|
|
2789
|
-
/* @__PURE__ */ (0,
|
|
3069
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2790
3070
|
GridBackground_default,
|
|
2791
3071
|
{
|
|
2792
3072
|
dateRange,
|
|
@@ -2794,8 +3074,8 @@ var GanttChart = (0, import_react12.forwardRef)(({
|
|
|
2794
3074
|
totalHeight: totalGridHeight
|
|
2795
3075
|
}
|
|
2796
3076
|
),
|
|
2797
|
-
todayInRange && /* @__PURE__ */ (0,
|
|
2798
|
-
/* @__PURE__ */ (0,
|
|
3077
|
+
todayInRange && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TodayIndicator_default, { monthStart, dayWidth }),
|
|
3078
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2799
3079
|
DependencyLines_default,
|
|
2800
3080
|
{
|
|
2801
3081
|
tasks,
|
|
@@ -2807,7 +3087,7 @@ var GanttChart = (0, import_react12.forwardRef)(({
|
|
|
2807
3087
|
selectedDep: selectedChip
|
|
2808
3088
|
}
|
|
2809
3089
|
),
|
|
2810
|
-
dragGuideLines && /* @__PURE__ */ (0,
|
|
3090
|
+
dragGuideLines && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2811
3091
|
DragGuideLines_default,
|
|
2812
3092
|
{
|
|
2813
3093
|
isDragging: dragGuideLines.isDragging,
|
|
@@ -2817,7 +3097,7 @@ var GanttChart = (0, import_react12.forwardRef)(({
|
|
|
2817
3097
|
totalHeight: totalGridHeight
|
|
2818
3098
|
}
|
|
2819
3099
|
),
|
|
2820
|
-
tasks.map((task, index) => /* @__PURE__ */ (0,
|
|
3100
|
+
tasks.map((task, index) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2821
3101
|
TaskRow_default,
|
|
2822
3102
|
{
|
|
2823
3103
|
task,
|
|
@@ -2856,9 +3136,9 @@ var GanttChart = (0, import_react12.forwardRef)(({
|
|
|
2856
3136
|
GanttChart.displayName = "GanttChart";
|
|
2857
3137
|
|
|
2858
3138
|
// src/components/ui/Button.tsx
|
|
2859
|
-
var
|
|
2860
|
-
var
|
|
2861
|
-
var Button =
|
|
3139
|
+
var import_react14 = __toESM(require("react"));
|
|
3140
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
3141
|
+
var Button = import_react14.default.forwardRef(
|
|
2862
3142
|
({ className, variant = "default", size = "default", children, ...props }, ref) => {
|
|
2863
3143
|
const classes = [
|
|
2864
3144
|
"gantt-btn",
|
|
@@ -2866,7 +3146,7 @@ var Button = import_react13.default.forwardRef(
|
|
|
2866
3146
|
size !== "default" ? `gantt-btn-${size}` : "",
|
|
2867
3147
|
className || ""
|
|
2868
3148
|
].filter(Boolean).join(" ");
|
|
2869
|
-
return /* @__PURE__ */ (0,
|
|
3149
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { ref, className: classes, ...props, children });
|
|
2870
3150
|
}
|
|
2871
3151
|
);
|
|
2872
3152
|
Button.displayName = "Button";
|