gantt-lib 0.17.2 → 0.18.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.js CHANGED
@@ -1,3 +1,5 @@
1
+ "use client";
2
+
1
3
  "use strict";
2
4
  "use client";
3
5
  var __create = Object.create;
@@ -2887,18 +2889,49 @@ var DAY_MS2 = 24 * 60 * 60 * 1e3;
2887
2889
  var getInclusiveDurationDays = (startDate, endDate) => {
2888
2890
  const start = parseUTCDate(startDate);
2889
2891
  const end = parseUTCDate(endDate);
2890
- return Math.max(1, Math.round((end.getTime() - start.getTime()) / DAY_MS2) + 1);
2892
+ return Math.max(
2893
+ 1,
2894
+ Math.round((end.getTime() - start.getTime()) / DAY_MS2) + 1
2895
+ );
2891
2896
  };
2892
2897
  var getEndDateFromDuration = (startDate, durationDays) => {
2893
2898
  const start = parseUTCDate(startDate);
2894
2899
  return new Date(start.getTime() + (durationDays - 1) * DAY_MS2).toISOString().split("T")[0];
2895
2900
  };
2896
- var TrashIcon = () => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
2897
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6" }),
2898
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M3 6h18" }),
2899
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })
2900
- ] });
2901
- 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" }) });
2901
+ var TrashIcon = () => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2902
+ "svg",
2903
+ {
2904
+ xmlns: "http://www.w3.org/2000/svg",
2905
+ width: "12",
2906
+ height: "12",
2907
+ viewBox: "0 0 24 24",
2908
+ fill: "none",
2909
+ stroke: "currentColor",
2910
+ strokeWidth: "2",
2911
+ strokeLinecap: "round",
2912
+ strokeLinejoin: "round",
2913
+ children: [
2914
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6" }),
2915
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M3 6h18" }),
2916
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })
2917
+ ]
2918
+ }
2919
+ );
2920
+ var PlusIcon = () => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2921
+ "svg",
2922
+ {
2923
+ xmlns: "http://www.w3.org/2000/svg",
2924
+ width: "14",
2925
+ height: "14",
2926
+ viewBox: "0 0 24 24",
2927
+ fill: "none",
2928
+ stroke: "currentColor",
2929
+ strokeWidth: "2",
2930
+ strokeLinecap: "round",
2931
+ strokeLinejoin: "round",
2932
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M12 5v14M5 12h14" })
2933
+ }
2934
+ );
2902
2935
  var DragHandleIcon = () => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("svg", { width: "10", height: "14", viewBox: "0 0 10 14", fill: "currentColor", children: [
2903
2936
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("circle", { cx: "2", cy: "2", r: "1.5" }),
2904
2937
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("circle", { cx: "8", cy: "2", r: "1.5" }),
@@ -2907,51 +2940,94 @@ var DragHandleIcon = () => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("svg",
2907
2940
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("circle", { cx: "2", cy: "12", r: "1.5" }),
2908
2941
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("circle", { cx: "8", cy: "12", r: "1.5" })
2909
2942
  ] });
2910
- var ChevronRightIcon = () => /* @__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: "m9 18 6-6-6-6" }) });
2911
- var HierarchyConnectorIcon = ({ isLastChild }) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: `gantt-tl-hierarchy-connector${isLastChild ? " gantt-tl-hierarchy-connector--last" : ""}`, "aria-hidden": "true", children: [
2912
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "gantt-tl-hc-vline" }),
2913
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "gantt-tl-hc-hline" }),
2914
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "gantt-tl-hc-dot" })
2915
- ] });
2943
+ var ChevronRightIcon = () => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2944
+ "svg",
2945
+ {
2946
+ xmlns: "http://www.w3.org/2000/svg",
2947
+ width: "14",
2948
+ height: "14",
2949
+ viewBox: "0 0 24 24",
2950
+ fill: "none",
2951
+ stroke: "currentColor",
2952
+ strokeWidth: "2",
2953
+ strokeLinecap: "round",
2954
+ strokeLinejoin: "round",
2955
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "m9 18 6-6-6-6" })
2956
+ }
2957
+ );
2958
+ var ArrowLeft = () => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2959
+ "svg",
2960
+ {
2961
+ xmlns: "http://www.w3.org/2000/svg",
2962
+ width: "16",
2963
+ height: "16",
2964
+ viewBox: "0 0 24 24",
2965
+ fill: "none",
2966
+ stroke: "currentColor",
2967
+ strokeWidth: "2",
2968
+ strokeLinecap: "round",
2969
+ strokeLinejoin: "round",
2970
+ children: [
2971
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "m12 19-7-7 7-7" }),
2972
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M19 12H5" })
2973
+ ]
2974
+ }
2975
+ );
2976
+ var ArrowRight = () => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2977
+ "svg",
2978
+ {
2979
+ xmlns: "http://www.w3.org/2000/svg",
2980
+ width: "16",
2981
+ height: "16",
2982
+ viewBox: "0 0 24 24",
2983
+ fill: "none",
2984
+ stroke: "currentColor",
2985
+ strokeWidth: "2",
2986
+ strokeLinecap: "round",
2987
+ strokeLinejoin: "round",
2988
+ children: [
2989
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M5 12h14" }),
2990
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "m12 5 7 7-7 7" })
2991
+ ]
2992
+ }
2993
+ );
2916
2994
  var HierarchyButton = ({
2917
2995
  isChild,
2918
- isParent,
2919
- rowIndex,
2996
+ rowIndex: _rowIndex,
2920
2997
  onPromote,
2921
2998
  onDemote
2922
2999
  }) => {
2923
3000
  const canPromote = isChild && onPromote;
2924
- const canDemote = !isParent && onDemote && rowIndex > 0;
2925
- if (!canPromote && !canDemote) {
2926
- return null;
2927
- }
2928
- const handleClick = (e) => {
2929
- e.stopPropagation();
2930
- if (canPromote) {
2931
- onPromote(e);
2932
- } else if (canDemote) {
2933
- onDemote(e);
2934
- }
2935
- };
2936
- const title = canPromote ? "\u041F\u043E\u0432\u044B\u0441\u0438\u0442\u044C (\u0441\u0434\u0435\u043B\u0430\u0442\u044C \u043A\u043E\u0440\u043D\u0435\u0432\u043E\u0439)" : "\u041F\u043E\u043D\u0438\u0437\u0438\u0442\u044C (\u0441\u0434\u0435\u043B\u0430\u0442\u044C \u043F\u043E\u0434\u0447\u0438\u043D\u0435\u043D\u043D\u043E\u0439)";
2937
- const ArrowLeft = () => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
2938
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "m12 19-7-7 7-7" }),
2939
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M19 12H5" })
2940
- ] });
2941
- const ArrowRight = () => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
2942
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M5 12h14" }),
2943
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "m12 5 7 7-7 7" })
3001
+ const canDemote = !!onDemote;
3002
+ if (!canPromote && !canDemote) return null;
3003
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
3004
+ canPromote && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3005
+ "button",
3006
+ {
3007
+ type: "button",
3008
+ className: "gantt-tl-name-action-btn gantt-tl-action-hierarchy",
3009
+ onClick: (e) => {
3010
+ e.stopPropagation();
3011
+ onPromote(e);
3012
+ },
3013
+ title: "\u041F\u043E\u0432\u044B\u0441\u0438\u0442\u044C \u0443\u0440\u043E\u0432\u0435\u043D\u044C",
3014
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ArrowLeft, {})
3015
+ }
3016
+ ),
3017
+ canDemote && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3018
+ "button",
3019
+ {
3020
+ type: "button",
3021
+ className: "gantt-tl-name-action-btn gantt-tl-action-hierarchy",
3022
+ onClick: (e) => {
3023
+ e.stopPropagation();
3024
+ onDemote(e);
3025
+ },
3026
+ title: "\u041F\u043E\u043D\u0438\u0437\u0438\u0442\u044C \u0443\u0440\u043E\u0432\u0435\u043D\u044C",
3027
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ArrowRight, {})
3028
+ }
3029
+ )
2944
3030
  ] });
2945
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2946
- "button",
2947
- {
2948
- type: "button",
2949
- className: "gantt-tl-name-action-btn gantt-tl-action-hierarchy",
2950
- onClick: handleClick,
2951
- title,
2952
- children: canPromote ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ArrowLeft, {}) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ArrowRight, {})
2953
- }
2954
- );
2955
3031
  };
2956
3032
  var DepChip = ({
2957
3033
  lag,
@@ -2983,71 +3059,91 @@ var DepChip = ({
2983
3059
  const nextOpen = !popoverOpen;
2984
3060
  setPopoverOpen(nextOpen);
2985
3061
  if (nextOpen) {
2986
- onChipSelect?.({ successorId: taskId, predecessorId: dep.taskId, linkType: dep.type });
3062
+ onChipSelect?.({
3063
+ successorId: taskId,
3064
+ predecessorId: dep.taskId,
3065
+ linkType: dep.type
3066
+ });
2987
3067
  onScrollToTask?.(dep.taskId);
2988
3068
  } else {
2989
3069
  onChipSelect?.(null);
2990
3070
  }
2991
3071
  };
2992
- const handleOpenChange = (0, import_react10.useCallback)((open) => {
2993
- setPopoverOpen(open);
2994
- if (!open) {
2995
- onChipSelect?.(null);
2996
- }
2997
- }, [onChipSelect]);
3072
+ const handleOpenChange = (0, import_react10.useCallback)(
3073
+ (open) => {
3074
+ setPopoverOpen(open);
3075
+ if (!open) {
3076
+ onChipSelect?.(null);
3077
+ }
3078
+ },
3079
+ [onChipSelect]
3080
+ );
2998
3081
  const handleTrashClick = (e) => {
2999
3082
  e.stopPropagation();
3000
3083
  onRemoveDependency?.(taskId, dep.taskId, dep.type);
3001
3084
  onChipSelectClear();
3002
3085
  setPopoverOpen(false);
3003
3086
  };
3004
- const handleLagChange = (0, import_react10.useCallback)((newLag) => {
3005
- if (!onTasksChange || !allTasks) return;
3006
- const taskById = new Map(allTasks.map((t) => [t.id, t]));
3007
- const predecessor = taskById.get(dep.taskId);
3008
- if (!predecessor) return;
3009
- const predStart = parseUTCDate(predecessor.startDate);
3010
- const predEnd = parseUTCDate(predecessor.endDate);
3011
- const origStart = parseUTCDate(task.startDate);
3012
- const origEnd = parseUTCDate(task.endDate);
3013
- const durationMs = origEnd.getTime() - origStart.getTime();
3014
- const constraintDate = calculateSuccessorDate(predStart, predEnd, dep.type, newLag);
3015
- let newStart, newEnd;
3016
- if (dep.type === "FS" || dep.type === "SS") {
3017
- newStart = constraintDate;
3018
- newEnd = new Date(constraintDate.getTime() + durationMs);
3019
- } else {
3020
- newEnd = constraintDate;
3021
- newStart = new Date(constraintDate.getTime() - durationMs);
3022
- }
3023
- onTasksChange([{
3024
- ...task,
3025
- startDate: newStart.toISOString().split("T")[0],
3026
- endDate: newEnd.toISOString().split("T")[0]
3027
- }]);
3028
- }, [dep, task, allTasks, onTasksChange]);
3029
- const handleInputCommit = (0, import_react10.useCallback)((raw) => {
3030
- if (raw === "") {
3031
- handleLagChange(0);
3032
- return;
3033
- }
3034
- const parsed = parseInt(raw, 10);
3035
- const effectiveLag2 = lag ?? 0;
3036
- if (isNaN(parsed)) {
3037
- const abs = Math.abs(effectiveLag2);
3038
- setInputAbs(abs === 0 ? "" : String(abs));
3039
- return;
3040
- }
3041
- let newLag;
3042
- if (parsed === 0) {
3043
- newLag = 0;
3044
- } else if (dep.type === "SF") {
3045
- newLag = -Math.abs(parsed);
3046
- } else {
3047
- newLag = parsed;
3048
- }
3049
- if (newLag !== effectiveLag2) handleLagChange(newLag);
3050
- }, [lag, dep.type, handleLagChange]);
3087
+ const handleLagChange = (0, import_react10.useCallback)(
3088
+ (newLag) => {
3089
+ if (!onTasksChange || !allTasks) return;
3090
+ const taskById = new Map(allTasks.map((t) => [t.id, t]));
3091
+ const predecessor = taskById.get(dep.taskId);
3092
+ if (!predecessor) return;
3093
+ const predStart = parseUTCDate(predecessor.startDate);
3094
+ const predEnd = parseUTCDate(predecessor.endDate);
3095
+ const origStart = parseUTCDate(task.startDate);
3096
+ const origEnd = parseUTCDate(task.endDate);
3097
+ const durationMs = origEnd.getTime() - origStart.getTime();
3098
+ const constraintDate = calculateSuccessorDate(
3099
+ predStart,
3100
+ predEnd,
3101
+ dep.type,
3102
+ newLag
3103
+ );
3104
+ let newStart, newEnd;
3105
+ if (dep.type === "FS" || dep.type === "SS") {
3106
+ newStart = constraintDate;
3107
+ newEnd = new Date(constraintDate.getTime() + durationMs);
3108
+ } else {
3109
+ newEnd = constraintDate;
3110
+ newStart = new Date(constraintDate.getTime() - durationMs);
3111
+ }
3112
+ onTasksChange([
3113
+ {
3114
+ ...task,
3115
+ startDate: newStart.toISOString().split("T")[0],
3116
+ endDate: newEnd.toISOString().split("T")[0]
3117
+ }
3118
+ ]);
3119
+ },
3120
+ [dep, task, allTasks, onTasksChange]
3121
+ );
3122
+ const handleInputCommit = (0, import_react10.useCallback)(
3123
+ (raw) => {
3124
+ if (raw === "") {
3125
+ handleLagChange(0);
3126
+ return;
3127
+ }
3128
+ const parsed = parseInt(raw, 10);
3129
+ const effectiveLag2 = lag ?? 0;
3130
+ if (isNaN(parsed)) {
3131
+ const abs = Math.abs(effectiveLag2);
3132
+ setInputAbs(abs === 0 ? "" : String(abs));
3133
+ return;
3134
+ }
3135
+ let newLag;
3136
+ if (parsed === 0) {
3137
+ newLag = 0;
3138
+ } else if (dep.type === "SF") {
3139
+ newLag = -Math.abs(parsed);
3140
+ } else {
3141
+ newLag = parsed;
3142
+ }
3143
+ if (newLag !== effectiveLag2) handleLagChange(newLag);
3144
+ },
3145
+ [lag, dep.type, handleLagChange]
3146
+ );
3051
3147
  const Icon = LINK_TYPE_ICONS[dep.type];
3052
3148
  const depName = predecessorName ?? dep.taskId;
3053
3149
  const effectiveLag = lag ?? 0;
@@ -3086,67 +3182,92 @@ var DepChip = ({
3086
3182
  ]
3087
3183
  }
3088
3184
  ) }),
3089
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PopoverContent, { className: "gantt-tl-dep-edit-popover", portal: true, align: "start", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { onClick: (e) => e.stopPropagation(), children: [
3090
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "gantt-tl-dep-edit-task", children: task.name }),
3091
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-dep-edit-row", children: [
3092
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "gantt-tl-dep-edit-label", children: [
3093
- actionVerb,
3094
- preWord ? ` ${preWord}` : ""
3095
- ] }),
3096
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: "gantt-tl-dep-edit-btn", onClick: () => handleLagChange(effectiveLag - 1), children: "\u2212" }),
3097
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3098
- "input",
3099
- {
3100
- type: "number",
3101
- className: "gantt-tl-dep-edit-input",
3102
- value: inputAbs,
3103
- placeholder: zeroPlaceholder,
3104
- min: "0",
3105
- onChange: (e) => setInputAbs(e.target.value),
3106
- onFocus: (e) => e.target.select(),
3107
- onBlur: (e) => handleInputCommit(e.target.value),
3108
- onKeyDown: (e) => {
3109
- if (e.key === "Enter") handleInputCommit(inputAbs);
3110
- }
3111
- }
3112
- ),
3113
- !(dep.type === "SF" && effectiveLag === 0) && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: "gantt-tl-dep-edit-btn", onClick: () => handleLagChange(effectiveLag + 1), children: "+" }),
3114
- effectiveLag !== 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { children: "\u0434." }),
3115
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { children: afterWhat })
3116
- ] }),
3117
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "gantt-tl-dep-edit-pred", children: depName }),
3118
- !disableDependencyEditing && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
3119
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("hr", { className: "gantt-tl-dep-edit-divider" }),
3120
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-dep-edit-actions", children: [
3121
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3122
- "button",
3123
- {
3124
- type: "button",
3125
- className: "gantt-tl-dep-edit-close",
3126
- onClick: () => {
3127
- setPopoverOpen(false);
3128
- onChipSelectClear();
3129
- },
3130
- children: "\u0417\u0430\u043A\u0440\u044B\u0442\u044C"
3131
- }
3132
- ),
3133
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3134
- "button",
3135
- {
3136
- type: "button",
3137
- className: "gantt-tl-dep-edit-delete",
3138
- onClick: handleTrashClick,
3139
- children: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u0432\u044F\u0437\u044C"
3140
- }
3141
- )
3185
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3186
+ PopoverContent,
3187
+ {
3188
+ className: "gantt-tl-dep-edit-popover",
3189
+ portal: true,
3190
+ align: "start",
3191
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { onClick: (e) => e.stopPropagation(), children: [
3192
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "gantt-tl-dep-edit-task", children: task.name }),
3193
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-dep-edit-row", children: [
3194
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "gantt-tl-dep-edit-label", children: [
3195
+ actionVerb,
3196
+ preWord ? ` ${preWord}` : ""
3197
+ ] }),
3198
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3199
+ "button",
3200
+ {
3201
+ type: "button",
3202
+ className: "gantt-tl-dep-edit-btn",
3203
+ onClick: () => handleLagChange(effectiveLag - 1),
3204
+ children: "\u2212"
3205
+ }
3206
+ ),
3207
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3208
+ "input",
3209
+ {
3210
+ type: "number",
3211
+ className: "gantt-tl-dep-edit-input",
3212
+ value: inputAbs,
3213
+ placeholder: zeroPlaceholder,
3214
+ min: "0",
3215
+ onChange: (e) => setInputAbs(e.target.value),
3216
+ onFocus: (e) => e.target.select(),
3217
+ onBlur: (e) => handleInputCommit(e.target.value),
3218
+ onKeyDown: (e) => {
3219
+ if (e.key === "Enter") handleInputCommit(inputAbs);
3220
+ }
3221
+ }
3222
+ ),
3223
+ !(dep.type === "SF" && effectiveLag === 0) && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3224
+ "button",
3225
+ {
3226
+ type: "button",
3227
+ className: "gantt-tl-dep-edit-btn",
3228
+ onClick: () => handleLagChange(effectiveLag + 1),
3229
+ children: "+"
3230
+ }
3231
+ ),
3232
+ effectiveLag !== 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { children: "\u0434." }),
3233
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { children: afterWhat })
3234
+ ] }),
3235
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "gantt-tl-dep-edit-pred", children: depName }),
3236
+ !disableDependencyEditing && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
3237
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("hr", { className: "gantt-tl-dep-edit-divider" }),
3238
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-dep-edit-actions", children: [
3239
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3240
+ "button",
3241
+ {
3242
+ type: "button",
3243
+ className: "gantt-tl-dep-edit-close",
3244
+ onClick: () => {
3245
+ setPopoverOpen(false);
3246
+ onChipSelectClear();
3247
+ },
3248
+ children: "\u0417\u0430\u043A\u0440\u044B\u0442\u044C"
3249
+ }
3250
+ ),
3251
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3252
+ "button",
3253
+ {
3254
+ type: "button",
3255
+ className: "gantt-tl-dep-edit-delete",
3256
+ onClick: handleTrashClick,
3257
+ children: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u0432\u044F\u0437\u044C"
3258
+ }
3259
+ )
3260
+ ] })
3261
+ ] })
3142
3262
  ] })
3143
- ] })
3144
- ] }) })
3263
+ }
3264
+ )
3145
3265
  ] });
3146
3266
  };
3147
3267
  var toISODate = (value) => {
3148
3268
  if (value instanceof Date) return value.toISOString().split("T")[0];
3149
- if (typeof value === "string" && value.includes("T")) return value.split("T")[0];
3269
+ if (typeof value === "string" && value.includes("T"))
3270
+ return value.split("T")[0];
3150
3271
  return value;
3151
3272
  };
3152
3273
  var TaskListRow = import_react10.default.memo(
@@ -3183,13 +3304,17 @@ var TaskListRow = import_react10.default.memo(
3183
3304
  onToggleCollapse,
3184
3305
  onPromoteTask,
3185
3306
  onDemoteTask,
3186
- isLastChild = true
3307
+ isLastChild = true,
3308
+ nestingDepth = 0,
3309
+ ancestorContinues = []
3187
3310
  }) => {
3188
3311
  const [editingName, setEditingName] = (0, import_react10.useState)(false);
3189
3312
  const [nameValue, setNameValue] = (0, import_react10.useState)("");
3190
3313
  const nameInputRef = (0, import_react10.useRef)(null);
3191
3314
  const [editingDuration, setEditingDuration] = (0, import_react10.useState)(false);
3192
- const [durationValue, setDurationValue] = (0, import_react10.useState)(getInclusiveDurationDays(task.startDate, task.endDate));
3315
+ const [durationValue, setDurationValue] = (0, import_react10.useState)(
3316
+ getInclusiveDurationDays(task.startDate, task.endDate)
3317
+ );
3193
3318
  const durationInputRef = (0, import_react10.useRef)(null);
3194
3319
  const [editingProgress, setEditingProgress] = (0, import_react10.useState)(false);
3195
3320
  const [progressValue, setProgressValue] = (0, import_react10.useState)(0);
@@ -3199,11 +3324,16 @@ var TaskListRow = import_react10.default.memo(
3199
3324
  const durationConfirmedRef = (0, import_react10.useRef)(false);
3200
3325
  const progressConfirmedRef = (0, import_react10.useRef)(false);
3201
3326
  const autoEditedForRef = (0, import_react10.useRef)(null);
3202
- const editTriggerRef = (0, import_react10.useRef)("doubleclick");
3327
+ const editTriggerRef = (0, import_react10.useRef)(
3328
+ "doubleclick"
3329
+ );
3203
3330
  const [deletePending, setDeletePending] = (0, import_react10.useState)(false);
3204
3331
  const deleteButtonRef = (0, import_react10.useRef)(null);
3205
3332
  const isSelected = selectedTaskId === task.id;
3206
- const isParent = (0, import_react10.useMemo)(() => isTaskParent(task.id, allTasks), [task.id, allTasks]);
3333
+ const isParent = (0, import_react10.useMemo)(
3334
+ () => isTaskParent(task.id, allTasks),
3335
+ [task.id, allTasks]
3336
+ );
3207
3337
  const isChild = task.parentId !== void 0;
3208
3338
  const isCollapsed = collapsedParentIds.has(task.id);
3209
3339
  const isPicking = selectingPredecessorFor != null;
@@ -3258,31 +3388,40 @@ var TaskListRow = import_react10.default.memo(
3258
3388
  setEditingName(true);
3259
3389
  }
3260
3390
  }, [editingTaskId, task.id, disableTaskNameEditing]);
3261
- const handleNameClick = (0, import_react10.useCallback)((e) => {
3262
- if (disableTaskNameEditing) return;
3263
- e.stopPropagation();
3264
- onRowClick?.(task.id);
3265
- onScrollToTask?.(task.id);
3266
- }, [task.id, disableTaskNameEditing, onRowClick, onScrollToTask]);
3267
- const handleNameDoubleClick = (0, import_react10.useCallback)((e) => {
3268
- if (disableTaskNameEditing) return;
3269
- e.stopPropagation();
3270
- nameConfirmedRef.current = false;
3271
- editTriggerRef.current = "doubleclick";
3272
- setNameValue(task.name);
3273
- setEditingName(true);
3274
- }, [task.name, disableTaskNameEditing]);
3275
- const handleRowKeyDown = (0, import_react10.useCallback)((e) => {
3276
- if (editingProgress) return;
3277
- if (!editingName && !disableTaskNameEditing && e.key === "F2") {
3278
- e.preventDefault();
3391
+ const handleNameClick = (0, import_react10.useCallback)(
3392
+ (e) => {
3393
+ if (disableTaskNameEditing) return;
3394
+ e.stopPropagation();
3395
+ onRowClick?.(task.id);
3396
+ onScrollToTask?.(task.id);
3397
+ },
3398
+ [task.id, disableTaskNameEditing, onRowClick, onScrollToTask]
3399
+ );
3400
+ const handleNameDoubleClick = (0, import_react10.useCallback)(
3401
+ (e) => {
3402
+ if (disableTaskNameEditing) return;
3403
+ e.stopPropagation();
3279
3404
  nameConfirmedRef.current = false;
3280
- editTriggerRef.current = "keypress";
3405
+ editTriggerRef.current = "doubleclick";
3281
3406
  setNameValue(task.name);
3282
3407
  setEditingName(true);
3283
- return;
3284
- }
3285
- }, [editingName, disableTaskNameEditing, task.name]);
3408
+ },
3409
+ [task.name, disableTaskNameEditing]
3410
+ );
3411
+ const handleRowKeyDown = (0, import_react10.useCallback)(
3412
+ (e) => {
3413
+ if (editingProgress) return;
3414
+ if (!editingName && !disableTaskNameEditing && e.key === "F2") {
3415
+ e.preventDefault();
3416
+ nameConfirmedRef.current = false;
3417
+ editTriggerRef.current = "keypress";
3418
+ setNameValue(task.name);
3419
+ setEditingName(true);
3420
+ return;
3421
+ }
3422
+ },
3423
+ [editingName, disableTaskNameEditing, task.name]
3424
+ );
3286
3425
  const handleNameSave = (0, import_react10.useCallback)(() => {
3287
3426
  if (nameConfirmedRef.current) {
3288
3427
  nameConfirmedRef.current = false;
@@ -3296,24 +3435,32 @@ var TaskListRow = import_react10.default.memo(
3296
3435
  const handleNameCancel = (0, import_react10.useCallback)(() => {
3297
3436
  setEditingName(false);
3298
3437
  }, []);
3299
- const handleNameKeyDown = (0, import_react10.useCallback)((e) => {
3300
- if (e.key === "Enter") {
3301
- nameConfirmedRef.current = true;
3302
- if (nameValue.trim()) {
3303
- onTasksChange?.([{ ...task, name: nameValue.trim() }]);
3438
+ const handleNameKeyDown = (0, import_react10.useCallback)(
3439
+ (e) => {
3440
+ if (e.key === "Enter") {
3441
+ nameConfirmedRef.current = true;
3442
+ if (nameValue.trim()) {
3443
+ onTasksChange?.([{ ...task, name: nameValue.trim() }]);
3444
+ }
3445
+ setEditingName(false);
3446
+ } else if (e.key === "Escape") {
3447
+ handleNameCancel();
3304
3448
  }
3305
- setEditingName(false);
3306
- } else if (e.key === "Escape") {
3307
- handleNameCancel();
3308
- }
3309
- }, [nameValue, task, onTasksChange, handleNameCancel]);
3310
- const handleDurationClick = (0, import_react10.useCallback)((e) => {
3311
- if (task.locked) return;
3312
- e.stopPropagation();
3313
- durationConfirmedRef.current = false;
3314
- setDurationValue(getInclusiveDurationDays(task.startDate, task.endDate));
3315
- setEditingDuration(true);
3316
- }, [task.locked, task.startDate, task.endDate]);
3449
+ },
3450
+ [nameValue, task, onTasksChange, handleNameCancel]
3451
+ );
3452
+ const handleDurationClick = (0, import_react10.useCallback)(
3453
+ (e) => {
3454
+ if (task.locked) return;
3455
+ e.stopPropagation();
3456
+ durationConfirmedRef.current = false;
3457
+ setDurationValue(
3458
+ getInclusiveDurationDays(task.startDate, task.endDate)
3459
+ );
3460
+ setEditingDuration(true);
3461
+ },
3462
+ [task.locked, task.startDate, task.endDate]
3463
+ );
3317
3464
  const applyDurationChange = (0, import_react10.useCallback)((nextDuration) => {
3318
3465
  const normalizedDuration = Math.max(1, Math.round(nextDuration) || 1);
3319
3466
  setDurationValue(normalizedDuration);
@@ -3324,34 +3471,59 @@ var TaskListRow = import_react10.default.memo(
3324
3471
  return;
3325
3472
  }
3326
3473
  const normalizedDuration = Math.max(1, Math.round(durationValue) || 1);
3327
- onTasksChange?.([{ ...task, endDate: getEndDateFromDuration(task.startDate, normalizedDuration) }]);
3474
+ onTasksChange?.([
3475
+ {
3476
+ ...task,
3477
+ endDate: getEndDateFromDuration(task.startDate, normalizedDuration)
3478
+ }
3479
+ ]);
3328
3480
  setEditingDuration(false);
3329
3481
  }, [durationValue, task, onTasksChange]);
3330
3482
  const handleDurationCancel = (0, import_react10.useCallback)(() => {
3331
3483
  setDurationValue(getInclusiveDurationDays(task.startDate, task.endDate));
3332
3484
  setEditingDuration(false);
3333
3485
  }, [task.startDate, task.endDate]);
3334
- const handleDurationAdjust = (0, import_react10.useCallback)((delta) => {
3335
- applyDurationChange(durationValue + delta);
3336
- }, [applyDurationChange, durationValue]);
3337
- const handleDurationKeyDown = (0, import_react10.useCallback)((e) => {
3338
- e.stopPropagation();
3339
- if (e.key === "Enter") {
3340
- durationConfirmedRef.current = true;
3341
- const normalizedDuration = Math.max(1, Math.round(durationValue) || 1);
3342
- onTasksChange?.([{ ...task, endDate: getEndDateFromDuration(task.startDate, normalizedDuration) }]);
3343
- setEditingDuration(false);
3344
- } else if (e.key === "Escape") {
3345
- handleDurationCancel();
3346
- }
3347
- }, [durationValue, task, onTasksChange, handleDurationCancel]);
3348
- const handleProgressClick = (0, import_react10.useCallback)((e) => {
3349
- if (task.locked) return;
3350
- e.stopPropagation();
3351
- progressConfirmedRef.current = false;
3352
- setProgressValue(task.progress ?? 0);
3353
- setEditingProgress(true);
3354
- }, [task.progress, task.locked]);
3486
+ const handleDurationAdjust = (0, import_react10.useCallback)(
3487
+ (delta) => {
3488
+ applyDurationChange(durationValue + delta);
3489
+ },
3490
+ [applyDurationChange, durationValue]
3491
+ );
3492
+ const handleDurationKeyDown = (0, import_react10.useCallback)(
3493
+ (e) => {
3494
+ e.stopPropagation();
3495
+ if (e.key === "Enter") {
3496
+ durationConfirmedRef.current = true;
3497
+ const normalizedDuration = Math.max(
3498
+ 1,
3499
+ Math.round(durationValue) || 1
3500
+ );
3501
+ onTasksChange?.([
3502
+ {
3503
+ ...task,
3504
+ endDate: getEndDateFromDuration(
3505
+ task.startDate,
3506
+ normalizedDuration
3507
+ )
3508
+ }
3509
+ ]);
3510
+ setEditingDuration(false);
3511
+ } else if (e.key === "Escape") {
3512
+ handleDurationCancel();
3513
+ }
3514
+ },
3515
+ [durationValue, task, onTasksChange, handleDurationCancel]
3516
+ );
3517
+ const handleProgressClick = (0, import_react10.useCallback)(
3518
+ (e) => {
3519
+ if (task.locked) return;
3520
+ e.stopPropagation();
3521
+ progressConfirmedRef.current = false;
3522
+ setProgressValue(task.progress ?? 0);
3523
+ setEditingProgress(true);
3524
+ },
3525
+ [task.progress, task.locked]
3526
+ );
3355
3527
  const handleProgressSave = (0, import_react10.useCallback)(() => {
3356
3528
  if (progressConfirmedRef.current) {
3357
3529
  progressConfirmedRef.current = false;
@@ -3374,28 +3546,36 @@ var TaskListRow = import_react10.default.memo(
3374
3546
  setEditingProgress(false);
3375
3547
  }, []);
3376
3548
  const handleProgressAdjust = (0, import_react10.useCallback)((delta) => {
3377
- setProgressValue((current) => Math.max(0, Math.min(100, current + delta)));
3549
+ setProgressValue(
3550
+ (current) => Math.max(0, Math.min(100, current + delta))
3551
+ );
3378
3552
  }, []);
3379
- const handleProgressKeyDown = (0, import_react10.useCallback)((e) => {
3380
- e.stopPropagation();
3381
- if (e.key === "Enter") {
3382
- progressConfirmedRef.current = true;
3383
- const clampedValue = Math.max(0, Math.min(100, progressValue));
3384
- if ((clampedValue === 100 || clampedValue === 0) && isTaskParent(task.id, allTasks)) {
3385
- const children = getChildren(task.id, allTasks);
3386
- const updatedTasks = [
3387
- { ...task, progress: clampedValue },
3388
- ...children.map((child) => ({ ...child, progress: clampedValue }))
3389
- ];
3390
- onTasksChange?.(updatedTasks);
3391
- } else {
3392
- onTasksChange?.([{ ...task, progress: clampedValue }]);
3553
+ const handleProgressKeyDown = (0, import_react10.useCallback)(
3554
+ (e) => {
3555
+ e.stopPropagation();
3556
+ if (e.key === "Enter") {
3557
+ progressConfirmedRef.current = true;
3558
+ const clampedValue = Math.max(0, Math.min(100, progressValue));
3559
+ if ((clampedValue === 100 || clampedValue === 0) && isTaskParent(task.id, allTasks)) {
3560
+ const children = getChildren(task.id, allTasks);
3561
+ const updatedTasks = [
3562
+ { ...task, progress: clampedValue },
3563
+ ...children.map((child) => ({
3564
+ ...child,
3565
+ progress: clampedValue
3566
+ }))
3567
+ ];
3568
+ onTasksChange?.(updatedTasks);
3569
+ } else {
3570
+ onTasksChange?.([{ ...task, progress: clampedValue }]);
3571
+ }
3572
+ setEditingProgress(false);
3573
+ } else if (e.key === "Escape") {
3574
+ handleProgressCancel();
3393
3575
  }
3394
- setEditingProgress(false);
3395
- } else if (e.key === "Escape") {
3396
- handleProgressCancel();
3397
- }
3398
- }, [progressValue, task, onTasksChange, handleProgressCancel, allTasks]);
3576
+ },
3577
+ [progressValue, task, onTasksChange, handleProgressCancel, allTasks]
3578
+ );
3399
3579
  (0, import_react10.useEffect)(() => {
3400
3580
  if (editingProgress && progressInputRef.current) {
3401
3581
  progressInputRef.current.focus();
@@ -3411,77 +3591,111 @@ var TaskListRow = import_react10.default.memo(
3411
3591
  durationInputRef.current.select();
3412
3592
  }
3413
3593
  }, [editingDuration]);
3414
- const handleStartDateChange = (0, import_react10.useCallback)((newDateISO) => {
3415
- if (!newDateISO) return;
3416
- const origStart = parseUTCDate(task.startDate);
3417
- const origEnd = parseUTCDate(task.endDate);
3418
- const durationMs = origEnd.getTime() - origStart.getTime();
3419
- const newStart = /* @__PURE__ */ new Date(newDateISO + "T00:00:00Z");
3420
- const newEnd = new Date(newStart.getTime() + durationMs);
3421
- const { startDate: normalizedStart, endDate: normalizedEnd } = normalizeTaskDates(
3422
- newDateISO,
3423
- newEnd.toISOString().split("T")[0]
3424
- );
3425
- onTasksChange?.([{ ...task, startDate: normalizedStart, endDate: normalizedEnd }]);
3426
- }, [task, onTasksChange]);
3427
- const handleEndDateChange = (0, import_react10.useCallback)((newDateISO) => {
3428
- if (!newDateISO) return;
3429
- const origStart = parseUTCDate(task.startDate);
3430
- const origEnd = parseUTCDate(task.endDate);
3431
- const durationMs = origEnd.getTime() - origStart.getTime();
3432
- const newEnd = /* @__PURE__ */ new Date(newDateISO + "T00:00:00Z");
3433
- const newStart = new Date(newEnd.getTime() - durationMs);
3434
- const { startDate: normalizedStart, endDate: normalizedEnd } = normalizeTaskDates(
3435
- newStart.toISOString().split("T")[0],
3436
- newDateISO
3437
- );
3438
- onTasksChange?.([{ ...task, startDate: normalizedStart, endDate: normalizedEnd }]);
3439
- }, [task, onTasksChange]);
3594
+ const handleStartDateChange = (0, import_react10.useCallback)(
3595
+ (newDateISO) => {
3596
+ if (!newDateISO) return;
3597
+ const origStart = parseUTCDate(task.startDate);
3598
+ const origEnd = parseUTCDate(task.endDate);
3599
+ const durationMs = origEnd.getTime() - origStart.getTime();
3600
+ const newStart = /* @__PURE__ */ new Date(newDateISO + "T00:00:00Z");
3601
+ const newEnd = new Date(newStart.getTime() + durationMs);
3602
+ const { startDate: normalizedStart, endDate: normalizedEnd } = normalizeTaskDates(newDateISO, newEnd.toISOString().split("T")[0]);
3603
+ onTasksChange?.([
3604
+ { ...task, startDate: normalizedStart, endDate: normalizedEnd }
3605
+ ]);
3606
+ },
3607
+ [task, onTasksChange]
3608
+ );
3609
+ const handleEndDateChange = (0, import_react10.useCallback)(
3610
+ (newDateISO) => {
3611
+ if (!newDateISO) return;
3612
+ const origStart = parseUTCDate(task.startDate);
3613
+ const origEnd = parseUTCDate(task.endDate);
3614
+ const durationMs = origEnd.getTime() - origStart.getTime();
3615
+ const newEnd = /* @__PURE__ */ new Date(newDateISO + "T00:00:00Z");
3616
+ const newStart = new Date(newEnd.getTime() - durationMs);
3617
+ const { startDate: normalizedStart, endDate: normalizedEnd } = normalizeTaskDates(newStart.toISOString().split("T")[0], newDateISO);
3618
+ onTasksChange?.([
3619
+ { ...task, startDate: normalizedStart, endDate: normalizedEnd }
3620
+ ]);
3621
+ },
3622
+ [task, onTasksChange]
3623
+ );
3440
3624
  const handleRowClickInternal = (0, import_react10.useCallback)(() => {
3441
3625
  onRowClick?.(task.id);
3442
3626
  }, [task.id, onRowClick]);
3443
- const handleNumberClick = (0, import_react10.useCallback)((e) => {
3444
- e.stopPropagation();
3445
- onRowClick?.(task.id);
3446
- }, [task.id, onRowClick]);
3447
- const handleToggleCollapse = (0, import_react10.useCallback)((e) => {
3448
- e.stopPropagation();
3449
- onToggleCollapse?.(task.id);
3450
- }, [task.id, onToggleCollapse]);
3451
- const handlePromote = (0, import_react10.useCallback)((e) => {
3452
- e.stopPropagation();
3453
- onPromoteTask?.(task.id);
3454
- }, [task.id, onPromoteTask]);
3455
- const handleDemote = (0, import_react10.useCallback)((e) => {
3456
- e.stopPropagation();
3457
- const currentIndex = allTasks.findIndex((t) => t.id === task.id);
3458
- if (currentIndex > 0) {
3459
- const previousTask = allTasks[currentIndex - 1];
3460
- const targetParentId = previousTask.parentId || previousTask.id;
3461
- onDemoteTask?.(task.id, targetParentId);
3462
- }
3463
- }, [task.id, allTasks, onDemoteTask]);
3464
- const handleAddClick = (0, import_react10.useCallback)((e) => {
3465
- e.stopPropagation();
3466
- onSetSelectingPredecessorFor?.(task.id);
3467
- }, [task.id, onSetSelectingPredecessorFor]);
3468
- const handlePredecessorPick = (0, import_react10.useCallback)((e) => {
3469
- e.stopPropagation();
3470
- if (!isPicking || isSourceRow) return;
3471
- if (!selectingPredecessorFor || !activeLinkType) return;
3472
- onAddDependency?.(task.id, selectingPredecessorFor, activeLinkType);
3473
- }, [isPicking, isSourceRow, selectingPredecessorFor, task.id, activeLinkType, onAddDependency]);
3474
- const handleCancelPicking = (0, import_react10.useCallback)((e) => {
3475
- e.stopPropagation();
3476
- onSetSelectingPredecessorFor?.(null);
3477
- }, [onSetSelectingPredecessorFor]);
3627
+ const handleNumberClick = (0, import_react10.useCallback)(
3628
+ (e) => {
3629
+ e.stopPropagation();
3630
+ onRowClick?.(task.id);
3631
+ },
3632
+ [task.id, onRowClick]
3633
+ );
3634
+ const handleToggleCollapse = (0, import_react10.useCallback)(
3635
+ (e) => {
3636
+ e.stopPropagation();
3637
+ onToggleCollapse?.(task.id);
3638
+ },
3639
+ [task.id, onToggleCollapse]
3640
+ );
3641
+ const handlePromote = (0, import_react10.useCallback)(
3642
+ (e) => {
3643
+ e.stopPropagation();
3644
+ onPromoteTask?.(task.id);
3645
+ },
3646
+ [task.id, onPromoteTask]
3647
+ );
3648
+ const handleDemote = (0, import_react10.useCallback)(
3649
+ (e) => {
3650
+ e.stopPropagation();
3651
+ onDemoteTask?.(task.id, "");
3652
+ },
3653
+ [task.id, onDemoteTask]
3654
+ );
3655
+ const handleAddClick = (0, import_react10.useCallback)(
3656
+ (e) => {
3657
+ e.stopPropagation();
3658
+ onSetSelectingPredecessorFor?.(task.id);
3659
+ },
3660
+ [task.id, onSetSelectingPredecessorFor]
3661
+ );
3662
+ const handlePredecessorPick = (0, import_react10.useCallback)(
3663
+ (e) => {
3664
+ e.stopPropagation();
3665
+ if (!isPicking || isSourceRow) return;
3666
+ if (!selectingPredecessorFor || !activeLinkType) return;
3667
+ onAddDependency?.(task.id, selectingPredecessorFor, activeLinkType);
3668
+ },
3669
+ [
3670
+ isPicking,
3671
+ isSourceRow,
3672
+ selectingPredecessorFor,
3673
+ task.id,
3674
+ activeLinkType,
3675
+ onAddDependency
3676
+ ]
3677
+ );
3678
+ const handleCancelPicking = (0, import_react10.useCallback)(
3679
+ (e) => {
3680
+ e.stopPropagation();
3681
+ onSetSelectingPredecessorFor?.(null);
3682
+ },
3683
+ [onSetSelectingPredecessorFor]
3684
+ );
3478
3685
  const isSelectedPredecessor = selectedChip != null && selectedChip.predecessorId === task.id;
3479
- const handleDeleteSelected = (0, import_react10.useCallback)((e) => {
3480
- e.stopPropagation();
3481
- if (!selectedChip) return;
3482
- onRemoveDependency?.(selectedChip.successorId, selectedChip.predecessorId, selectedChip.linkType);
3483
- onChipSelect?.(null);
3484
- }, [selectedChip, onRemoveDependency, onChipSelect]);
3686
+ const handleDeleteSelected = (0, import_react10.useCallback)(
3687
+ (e) => {
3688
+ e.stopPropagation();
3689
+ if (!selectedChip) return;
3690
+ onRemoveDependency?.(
3691
+ selectedChip.successorId,
3692
+ selectedChip.predecessorId,
3693
+ selectedChip.linkType
3694
+ );
3695
+ onChipSelect?.(null);
3696
+ },
3697
+ [selectedChip, onRemoveDependency, onChipSelect]
3698
+ );
3485
3699
  const startDateISO = toISODate(task.startDate);
3486
3700
  const endDateISO = editingDuration ? getEndDateFromDuration(task.startDate, durationValue) : toISODate(task.endDate);
3487
3701
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
@@ -3534,13 +3748,78 @@ var TaskListRow = import_react10.default.memo(
3534
3748
  }
3535
3749
  ),
3536
3750
  /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-cell gantt-tl-cell-name", children: [
3537
- isChild && !editingName && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(HierarchyConnectorIcon, { isLastChild }),
3751
+ isChild && !editingName && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
3752
+ ancestorContinues.map(
3753
+ (continues, idx) => continues ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3754
+ "span",
3755
+ {
3756
+ style: {
3757
+ position: "absolute",
3758
+ left: `${idx * 20 + 9}px`,
3759
+ top: 0,
3760
+ height: `${rowHeight}px`,
3761
+ width: "1.5px",
3762
+ background: "#d4bceb",
3763
+ borderRadius: "1px",
3764
+ pointerEvents: "none"
3765
+ }
3766
+ },
3767
+ idx
3768
+ ) : null
3769
+ ),
3770
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3771
+ "span",
3772
+ {
3773
+ style: {
3774
+ position: "absolute",
3775
+ left: `${(nestingDepth - 1) * 20 + 9}px`,
3776
+ top: 0,
3777
+ height: isLastChild ? `${rowHeight / 2}px` : `${rowHeight}px`,
3778
+ width: "1.5px",
3779
+ background: "#d4bceb",
3780
+ borderRadius: "1px",
3781
+ pointerEvents: "none"
3782
+ }
3783
+ }
3784
+ ),
3785
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3786
+ "span",
3787
+ {
3788
+ style: {
3789
+ position: "absolute",
3790
+ left: `${(nestingDepth - 1) * 20 + 9}px`,
3791
+ top: `${rowHeight / 2 - 0.75}px`,
3792
+ width: "8px",
3793
+ height: "1.5px",
3794
+ background: "#d4bceb",
3795
+ borderRadius: "1px",
3796
+ pointerEvents: "none"
3797
+ }
3798
+ }
3799
+ ),
3800
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3801
+ "span",
3802
+ {
3803
+ style: {
3804
+ position: "absolute",
3805
+ left: `${(nestingDepth - 1) * 20 + 15}px`,
3806
+ top: `${rowHeight / 2 - 2}px`,
3807
+ width: "4px",
3808
+ height: "4px",
3809
+ borderRadius: "50%",
3810
+ background: "#d4bceb",
3811
+ pointerEvents: "none"
3812
+ }
3813
+ }
3814
+ )
3815
+ ] }),
3538
3816
  isParent && !editingName && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3539
3817
  "button",
3540
3818
  {
3541
3819
  type: "button",
3542
3820
  className: `gantt-tl-collapse-btn ${isCollapsed ? "gantt-tl-collapse-btn-collapsed" : ""}`,
3543
3821
  onClick: handleToggleCollapse,
3822
+ style: { left: `${nestingDepth * 20 + 4}px` },
3544
3823
  "aria-label": isCollapsed ? "Expand children" : "Collapse children",
3545
3824
  children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ChevronRightIcon, {})
3546
3825
  }
@@ -3554,7 +3833,10 @@ var TaskListRow = import_react10.default.memo(
3554
3833
  onChange: (e) => setNameValue(e.target.value),
3555
3834
  onBlur: handleNameSave,
3556
3835
  onKeyDown: handleNameKeyDown,
3557
- className: ["gantt-tl-name-input", isChild ? "gantt-tl-name-input-child" : ""].filter(Boolean).join(" "),
3836
+ className: "gantt-tl-name-input",
3837
+ style: {
3838
+ paddingLeft: nestingDepth > 0 ? `${nestingDepth * 20 + 24}px` : void 0
3839
+ },
3558
3840
  onClick: (e) => e.stopPropagation()
3559
3841
  }
3560
3842
  ),
@@ -3564,14 +3846,15 @@ var TaskListRow = import_react10.default.memo(
3564
3846
  type: "button",
3565
3847
  className: [
3566
3848
  "gantt-tl-name-trigger",
3567
- disableTaskNameEditing ? "gantt-tl-name-locked" : "",
3568
- isParent ? "gantt-tl-name-trigger-parent" : "",
3569
- isChild ? "gantt-tl-name-trigger-child" : ""
3849
+ disableTaskNameEditing ? "gantt-tl-name-locked" : ""
3570
3850
  ].filter(Boolean).join(" "),
3571
3851
  title: task.name,
3572
3852
  onClick: handleNameClick,
3573
3853
  onDoubleClick: handleNameDoubleClick,
3574
- style: editingName ? { visibility: "hidden", pointerEvents: "none" } : void 0,
3854
+ style: {
3855
+ paddingLeft: nestingDepth > 0 ? `${nestingDepth * 20 + (isParent ? 26 : 8)}px` : isParent ? "26px" : void 0,
3856
+ ...editingName ? { visibility: "hidden", pointerEvents: "none" } : void 0
3857
+ },
3575
3858
  children: task.name
3576
3859
  }
3577
3860
  ),
@@ -3584,16 +3867,20 @@ var TaskListRow = import_react10.default.memo(
3584
3867
  onClick: (e) => {
3585
3868
  e.stopPropagation();
3586
3869
  const now = /* @__PURE__ */ new Date();
3587
- const todayISO = new Date(Date.UTC(
3588
- now.getUTCFullYear(),
3589
- now.getUTCMonth(),
3590
- now.getUTCDate()
3591
- )).toISOString().split("T")[0];
3592
- const endISO = new Date(Date.UTC(
3593
- now.getUTCFullYear(),
3594
- now.getUTCMonth(),
3595
- now.getUTCDate() + 7
3596
- )).toISOString().split("T")[0];
3870
+ const todayISO = new Date(
3871
+ Date.UTC(
3872
+ now.getUTCFullYear(),
3873
+ now.getUTCMonth(),
3874
+ now.getUTCDate()
3875
+ )
3876
+ ).toISOString().split("T")[0];
3877
+ const endISO = new Date(
3878
+ Date.UTC(
3879
+ now.getUTCFullYear(),
3880
+ now.getUTCMonth(),
3881
+ now.getUTCDate() + 7
3882
+ )
3883
+ ).toISOString().split("T")[0];
3597
3884
  const newTask = {
3598
3885
  id: crypto.randomUUID(),
3599
3886
  name: "\u041D\u043E\u0432\u0430\u044F \u0437\u0430\u0434\u0430\u0447\u0430",
@@ -3629,7 +3916,6 @@ var TaskListRow = import_react10.default.memo(
3629
3916
  HierarchyButton,
3630
3917
  {
3631
3918
  isChild,
3632
- isParent,
3633
3919
  rowIndex,
3634
3920
  onPromote: onPromoteTask ? handlePromote : void 0,
3635
3921
  onDemote: onDemoteTask ? handleDemote : void 0
@@ -3637,113 +3923,228 @@ var TaskListRow = import_react10.default.memo(
3637
3923
  )
3638
3924
  ] })
3639
3925
  ] }),
3640
- /* @__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)(
3641
- DatePicker,
3926
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3927
+ "div",
3642
3928
  {
3643
- value: startDateISO,
3644
- onChange: handleStartDateChange,
3645
- format: "dd.MM.yy",
3646
- portal: true,
3647
- disabled: task.locked
3929
+ className: "gantt-tl-cell gantt-tl-cell-date",
3930
+ onClick: (e) => e.stopPropagation(),
3931
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3932
+ DatePicker,
3933
+ {
3934
+ value: startDateISO,
3935
+ onChange: handleStartDateChange,
3936
+ format: "dd.MM.yy",
3937
+ portal: true,
3938
+ disabled: task.locked
3939
+ }
3940
+ )
3648
3941
  }
3649
- ) }),
3650
- /* @__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)(
3651
- DatePicker,
3942
+ ),
3943
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3944
+ "div",
3652
3945
  {
3653
- value: endDateISO,
3654
- onChange: handleEndDateChange,
3655
- format: "dd.MM.yy",
3656
- portal: true,
3657
- disabled: task.locked
3658
- }
3659
- ) }),
3660
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-cell gantt-tl-cell-duration", onClick: handleDurationClick, children: [
3661
- editingDuration && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-number-editor", onClick: (e) => e.stopPropagation(), children: [
3662
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3663
- Input,
3946
+ className: "gantt-tl-cell gantt-tl-cell-date",
3947
+ onClick: (e) => e.stopPropagation(),
3948
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3949
+ DatePicker,
3664
3950
  {
3665
- ref: durationInputRef,
3666
- type: "number",
3667
- min: 1,
3668
- step: 1,
3669
- value: durationValue,
3670
- onChange: (e) => applyDurationChange(parseInt(e.target.value, 10) || 1),
3671
- onBlur: handleDurationSave,
3672
- onKeyDown: handleDurationKeyDown,
3673
- className: "gantt-tl-number-input"
3951
+ value: endDateISO,
3952
+ onChange: handleEndDateChange,
3953
+ format: "dd.MM.yy",
3954
+ portal: true,
3955
+ disabled: task.locked
3674
3956
  }
3675
- ),
3676
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-number-steppers", "aria-hidden": "true", children: [
3677
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3678
- "button",
3957
+ )
3958
+ }
3959
+ ),
3960
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3961
+ "div",
3962
+ {
3963
+ className: "gantt-tl-cell gantt-tl-cell-duration",
3964
+ onClick: handleDurationClick,
3965
+ children: [
3966
+ editingDuration && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3967
+ "div",
3679
3968
  {
3680
- type: "button",
3681
- className: "gantt-tl-number-stepper",
3682
- tabIndex: -1,
3683
- onMouseDown: (e) => e.preventDefault(),
3684
- onClick: () => handleDurationAdjust(1),
3685
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "10", height: "10", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "m18 15-6-6-6 6" }) })
3969
+ className: "gantt-tl-number-editor",
3970
+ onClick: (e) => e.stopPropagation(),
3971
+ children: [
3972
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3973
+ Input,
3974
+ {
3975
+ ref: durationInputRef,
3976
+ type: "number",
3977
+ min: 1,
3978
+ step: 1,
3979
+ value: durationValue,
3980
+ onChange: (e) => applyDurationChange(parseInt(e.target.value, 10) || 1),
3981
+ onBlur: handleDurationSave,
3982
+ onKeyDown: handleDurationKeyDown,
3983
+ className: "gantt-tl-number-input"
3984
+ }
3985
+ ),
3986
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-number-steppers", "aria-hidden": "true", children: [
3987
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3988
+ "button",
3989
+ {
3990
+ type: "button",
3991
+ className: "gantt-tl-number-stepper",
3992
+ tabIndex: -1,
3993
+ onMouseDown: (e) => e.preventDefault(),
3994
+ onClick: () => handleDurationAdjust(1),
3995
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3996
+ "svg",
3997
+ {
3998
+ xmlns: "http://www.w3.org/2000/svg",
3999
+ width: "10",
4000
+ height: "10",
4001
+ viewBox: "0 0 24 24",
4002
+ fill: "none",
4003
+ stroke: "currentColor",
4004
+ strokeWidth: "2",
4005
+ strokeLinecap: "round",
4006
+ strokeLinejoin: "round",
4007
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "m18 15-6-6-6 6" })
4008
+ }
4009
+ )
4010
+ }
4011
+ ),
4012
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4013
+ "button",
4014
+ {
4015
+ type: "button",
4016
+ className: "gantt-tl-number-stepper",
4017
+ tabIndex: -1,
4018
+ onMouseDown: (e) => e.preventDefault(),
4019
+ onClick: () => handleDurationAdjust(-1),
4020
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4021
+ "svg",
4022
+ {
4023
+ xmlns: "http://www.w3.org/2000/svg",
4024
+ width: "10",
4025
+ height: "10",
4026
+ viewBox: "0 0 24 24",
4027
+ fill: "none",
4028
+ stroke: "currentColor",
4029
+ strokeWidth: "2",
4030
+ strokeLinecap: "round",
4031
+ strokeLinejoin: "round",
4032
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "m6 9 6 6 6-6" })
4033
+ }
4034
+ )
4035
+ }
4036
+ )
4037
+ ] })
4038
+ ]
3686
4039
  }
3687
4040
  ),
3688
4041
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3689
- "button",
4042
+ "span",
3690
4043
  {
3691
- type: "button",
3692
- className: "gantt-tl-number-stepper",
3693
- tabIndex: -1,
3694
- onMouseDown: (e) => e.preventDefault(),
3695
- onClick: () => handleDurationAdjust(-1),
3696
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "10", height: "10", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "m6 9 6 6 6-6" }) })
4044
+ style: editingDuration ? { visibility: "hidden", pointerEvents: "none" } : void 0,
4045
+ children: getInclusiveDurationDays(task.startDate, task.endDate)
3697
4046
  }
3698
4047
  )
3699
- ] })
3700
- ] }),
3701
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: editingDuration ? { visibility: "hidden", pointerEvents: "none" } : void 0, children: getInclusiveDurationDays(task.startDate, task.endDate) })
3702
- ] }),
3703
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-cell gantt-tl-cell-progress", onClick: handleProgressClick, children: [
3704
- editingProgress && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-number-editor", onClick: (e) => e.stopPropagation(), children: [
3705
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3706
- Input,
3707
- {
3708
- ref: progressInputRef,
3709
- type: "number",
3710
- min: 0,
3711
- max: 100,
3712
- step: 1,
3713
- value: progressValue,
3714
- onChange: (e) => setProgressValue(parseInt(e.target.value, 10) || 0),
3715
- onBlur: handleProgressSave,
3716
- onKeyDown: handleProgressKeyDown,
3717
- className: "gantt-tl-number-input"
3718
- }
3719
- ),
3720
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-number-steppers", "aria-hidden": "true", children: [
3721
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3722
- "button",
4048
+ ]
4049
+ }
4050
+ ),
4051
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
4052
+ "div",
4053
+ {
4054
+ className: "gantt-tl-cell gantt-tl-cell-progress",
4055
+ onClick: handleProgressClick,
4056
+ children: [
4057
+ editingProgress && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
4058
+ "div",
3723
4059
  {
3724
- type: "button",
3725
- className: "gantt-tl-number-stepper",
3726
- tabIndex: -1,
3727
- onMouseDown: (e) => e.preventDefault(),
3728
- onClick: () => handleProgressAdjust(1),
3729
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "10", height: "10", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "m18 15-6-6-6 6" }) })
4060
+ className: "gantt-tl-number-editor",
4061
+ onClick: (e) => e.stopPropagation(),
4062
+ children: [
4063
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4064
+ Input,
4065
+ {
4066
+ ref: progressInputRef,
4067
+ type: "number",
4068
+ min: 0,
4069
+ max: 100,
4070
+ step: 1,
4071
+ value: progressValue,
4072
+ onChange: (e) => setProgressValue(parseInt(e.target.value, 10) || 0),
4073
+ onBlur: handleProgressSave,
4074
+ onKeyDown: handleProgressKeyDown,
4075
+ className: "gantt-tl-number-input"
4076
+ }
4077
+ ),
4078
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-number-steppers", "aria-hidden": "true", children: [
4079
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4080
+ "button",
4081
+ {
4082
+ type: "button",
4083
+ className: "gantt-tl-number-stepper",
4084
+ tabIndex: -1,
4085
+ onMouseDown: (e) => e.preventDefault(),
4086
+ onClick: () => handleProgressAdjust(1),
4087
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4088
+ "svg",
4089
+ {
4090
+ xmlns: "http://www.w3.org/2000/svg",
4091
+ width: "10",
4092
+ height: "10",
4093
+ viewBox: "0 0 24 24",
4094
+ fill: "none",
4095
+ stroke: "currentColor",
4096
+ strokeWidth: "2",
4097
+ strokeLinecap: "round",
4098
+ strokeLinejoin: "round",
4099
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "m18 15-6-6-6 6" })
4100
+ }
4101
+ )
4102
+ }
4103
+ ),
4104
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4105
+ "button",
4106
+ {
4107
+ type: "button",
4108
+ className: "gantt-tl-number-stepper",
4109
+ tabIndex: -1,
4110
+ onMouseDown: (e) => e.preventDefault(),
4111
+ onClick: () => handleProgressAdjust(-1),
4112
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4113
+ "svg",
4114
+ {
4115
+ xmlns: "http://www.w3.org/2000/svg",
4116
+ width: "10",
4117
+ height: "10",
4118
+ viewBox: "0 0 24 24",
4119
+ fill: "none",
4120
+ stroke: "currentColor",
4121
+ strokeWidth: "2",
4122
+ strokeLinecap: "round",
4123
+ strokeLinejoin: "round",
4124
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "m6 9 6 6 6-6" })
4125
+ }
4126
+ )
4127
+ }
4128
+ )
4129
+ ] })
4130
+ ]
3730
4131
  }
3731
4132
  ),
3732
4133
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3733
- "button",
4134
+ "span",
3734
4135
  {
3735
- type: "button",
3736
- className: "gantt-tl-number-stepper",
3737
- tabIndex: -1,
3738
- onMouseDown: (e) => e.preventDefault(),
3739
- onClick: () => handleProgressAdjust(-1),
3740
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "10", height: "10", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "m6 9 6 6 6-6" }) })
4136
+ style: editingProgress ? { visibility: "hidden", pointerEvents: "none" } : task.progress === 100 ? {
4137
+ backgroundColor: "#17c864",
4138
+ borderRadius: "4px",
4139
+ padding: "2px 4px",
4140
+ color: "#ffffff"
4141
+ } : void 0,
4142
+ children: task.progress ? Math.round(task.progress) === 100 ? "100" : `${Math.round(task.progress)}%` : "0%"
3741
4143
  }
3742
4144
  )
3743
- ] })
3744
- ] }),
3745
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: editingProgress ? { visibility: "hidden", pointerEvents: "none" } : void 0, children: task.progress ? `${Math.round(task.progress)}%` : "0%" })
3746
- ] }),
4145
+ ]
4146
+ }
4147
+ ),
3747
4148
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3748
4149
  "div",
3749
4150
  {
@@ -3784,26 +4185,33 @@ var TaskListRow = import_react10.default.memo(
3784
4185
  ]
3785
4186
  }
3786
4187
  ) }),
3787
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PopoverContent, { portal: true, align: "start", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "gantt-tl-dep-overflow-list", onClick: (e) => e.stopPropagation(), children: chips.map(({ dep, lag, predecessorName }) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3788
- DepChip,
4188
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PopoverContent, { portal: true, align: "start", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4189
+ "div",
3789
4190
  {
3790
- lag,
3791
- dep,
3792
- taskId: task.id,
3793
- predecessorName,
3794
- selectedChip,
3795
- disableDependencyEditing,
3796
- onChipSelect,
3797
- onRowClick,
3798
- onScrollToTask,
3799
- onRemoveDependency,
3800
- onChipSelectClear: () => onChipSelect?.(null),
3801
- task,
3802
- allTasks,
3803
- onTasksChange
3804
- },
3805
- `${dep.taskId}-${dep.type}`
3806
- )) }) })
4191
+ className: "gantt-tl-dep-overflow-list",
4192
+ onClick: (e) => e.stopPropagation(),
4193
+ children: chips.map(({ dep, lag, predecessorName }) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4194
+ DepChip,
4195
+ {
4196
+ lag,
4197
+ dep,
4198
+ taskId: task.id,
4199
+ predecessorName,
4200
+ selectedChip,
4201
+ disableDependencyEditing,
4202
+ onChipSelect,
4203
+ onRowClick,
4204
+ onScrollToTask,
4205
+ onRemoveDependency,
4206
+ onChipSelectClear: () => onChipSelect?.(null),
4207
+ task,
4208
+ allTasks,
4209
+ onTasksChange
4210
+ },
4211
+ `${dep.taskId}-${dep.type}`
4212
+ ))
4213
+ }
4214
+ ) })
3807
4215
  ] })
3808
4216
  ) : chips.length === 1 ? (
3809
4217
  /* Single chip — unified DepChip */
@@ -4002,6 +4410,25 @@ var TaskList = ({
4002
4410
  () => visibleTasks.length * rowHeight,
4003
4411
  [visibleTasks.length, rowHeight]
4004
4412
  );
4413
+ const nestingDepthMap = (0, import_react12.useMemo)(() => {
4414
+ const depthMap = /* @__PURE__ */ new Map();
4415
+ const taskById = new Map(tasks.map((t) => [t.id, t]));
4416
+ function getDepth(taskId) {
4417
+ if (depthMap.has(taskId)) return depthMap.get(taskId);
4418
+ const task = taskById.get(taskId);
4419
+ if (!task || !task.parentId || !taskById.has(task.parentId)) {
4420
+ depthMap.set(taskId, 0);
4421
+ return 0;
4422
+ }
4423
+ const depth = getDepth(task.parentId) + 1;
4424
+ depthMap.set(taskId, depth);
4425
+ return depth;
4426
+ }
4427
+ for (const task of tasks) {
4428
+ getDepth(task.id);
4429
+ }
4430
+ return depthMap;
4431
+ }, [tasks]);
4005
4432
  const lastChildIds = (0, import_react12.useMemo)(() => {
4006
4433
  const last = /* @__PURE__ */ new Set();
4007
4434
  const seenParents = /* @__PURE__ */ new Set();
@@ -4014,6 +4441,20 @@ var TaskList = ({
4014
4441
  }
4015
4442
  return last;
4016
4443
  }, [visibleTasks]);
4444
+ const ancestorContinuesMap = (0, import_react12.useMemo)(() => {
4445
+ const taskById = new Map(tasks.map((t) => [t.id, t]));
4446
+ const map = /* @__PURE__ */ new Map();
4447
+ for (const task of visibleTasks) {
4448
+ const continues = [];
4449
+ let current = taskById.get(task.id);
4450
+ while (current?.parentId && taskById.has(current.parentId)) {
4451
+ continues.unshift(!lastChildIds.has(current.id));
4452
+ current = taskById.get(current.parentId);
4453
+ }
4454
+ map.set(task.id, continues.slice(0, -1));
4455
+ }
4456
+ return map;
4457
+ }, [tasks, visibleTasks, lastChildIds]);
4017
4458
  const handleRowClick = (0, import_react12.useCallback)((taskId) => {
4018
4459
  onTaskSelect?.(taskId);
4019
4460
  }, [onTaskSelect]);
@@ -4124,9 +4565,6 @@ var TaskList = ({
4124
4565
  if (dropTarget.parentId === draggedTaskId) {
4125
4566
  return false;
4126
4567
  }
4127
- if (dropTarget.parentId) {
4128
- return false;
4129
- }
4130
4568
  const draggedTask = orderedTasks.find((t) => t.id === draggedTaskId);
4131
4569
  if (!draggedTask) return true;
4132
4570
  const descendants = getAllDescendants(draggedTaskId, orderedTasks);
@@ -4272,6 +4710,52 @@ var TaskList = ({
4272
4710
  setIsCreating(false);
4273
4711
  }, [onAdd]);
4274
4712
  const handleCancelNewTask = (0, import_react12.useCallback)(() => setIsCreating(false), []);
4713
+ function getTaskDepth(task, tasks2) {
4714
+ if (!task) return 0;
4715
+ let depth = 0;
4716
+ let current = task;
4717
+ while (current) {
4718
+ if (!current.parentId) break;
4719
+ depth++;
4720
+ const parentId = current.parentId;
4721
+ current = tasks2.find((t) => t.id === parentId);
4722
+ }
4723
+ return depth;
4724
+ }
4725
+ const handleDemoteWrapper = (0, import_react12.useCallback)((taskId, _newParentId) => {
4726
+ const taskIndex = visibleTasks.findIndex((t) => t.id === taskId);
4727
+ const currentTask = visibleTasks[taskIndex];
4728
+ const currentDepth = getTaskDepth(currentTask, orderedTasks);
4729
+ if (taskIndex > 0) {
4730
+ for (let i = taskIndex - 1; i >= 0; i--) {
4731
+ const previousTask = visibleTasks[i];
4732
+ const previousDepth = getTaskDepth(previousTask, orderedTasks);
4733
+ if (previousDepth === currentDepth) {
4734
+ onDemoteTask?.(taskId, previousTask.id);
4735
+ return;
4736
+ }
4737
+ if (previousDepth < currentDepth) {
4738
+ break;
4739
+ }
4740
+ }
4741
+ return;
4742
+ }
4743
+ const demotedTask = orderedTasks.find((t) => t.id === taskId);
4744
+ if (!demotedTask) return;
4745
+ const newSectionTask = {
4746
+ id: crypto.randomUUID(),
4747
+ name: "\u041D\u043E\u0432\u044B\u0439 \u0440\u0430\u0437\u0434\u0435\u043B",
4748
+ startDate: demotedTask.startDate,
4749
+ endDate: demotedTask.endDate
4750
+ };
4751
+ const updatedTasks = [
4752
+ newSectionTask,
4753
+ ...orderedTasks.map(
4754
+ (t) => t.id === taskId ? { ...t, parentId: newSectionTask.id } : t
4755
+ )
4756
+ ];
4757
+ onReorder?.(updatedTasks, taskId, newSectionTask.id);
4758
+ }, [visibleTasks, orderedTasks, onDemoteTask, onReorder]);
4275
4759
  const effectiveTaskListWidth = Math.max(taskListWidth, MIN_TASK_LIST_WIDTH);
4276
4760
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4277
4761
  "div",
@@ -4355,8 +4839,10 @@ var TaskList = ({
4355
4839
  collapsedParentIds,
4356
4840
  onToggleCollapse: handleToggleCollapse,
4357
4841
  onPromoteTask,
4358
- onDemoteTask,
4359
- isLastChild: lastChildIds.has(task.id)
4842
+ onDemoteTask: onDemoteTask ? handleDemoteWrapper : void 0,
4843
+ isLastChild: lastChildIds.has(task.id),
4844
+ nestingDepth: nestingDepthMap.get(task.id) ?? 0,
4845
+ ancestorContinues: ancestorContinuesMap.get(task.id) ?? []
4360
4846
  },
4361
4847
  task.id
4362
4848
  )) }),
@@ -4665,6 +5151,17 @@ var GanttChart = (0, import_react13.forwardRef)(({
4665
5151
  }),
4666
5152
  [scrollToToday, scrollToTask, handleCollapseAll, handleExpandAll]
4667
5153
  );
5154
+ function getTaskDepth(taskId, tasks2) {
5155
+ let depth = 0;
5156
+ let current = tasks2.find((t) => t.id === taskId);
5157
+ while (current) {
5158
+ if (!current.parentId) break;
5159
+ depth++;
5160
+ const parentId = current.parentId;
5161
+ current = tasks2.find((t) => t.id === parentId);
5162
+ }
5163
+ return depth;
5164
+ }
4668
5165
  const handlePromoteTask = (0, import_react13.useCallback)((taskId) => {
4669
5166
  if (onPromoteTask) {
4670
5167
  onPromoteTask(taskId);
@@ -4674,20 +5171,20 @@ var GanttChart = (0, import_react13.forwardRef)(({
4674
5171
  if (!taskToPromote || !taskToPromote.parentId) {
4675
5172
  return;
4676
5173
  }
4677
- const parentId = taskToPromote.parentId;
4678
- const siblings = tasks.filter((t) => t.parentId === parentId);
5174
+ const depth = getTaskDepth(taskId, tasks);
5175
+ const grandparentId = depth > 1 ? tasks.find((t) => t.id === taskToPromote.parentId)?.parentId : void 0;
5176
+ const currentParentId = taskToPromote.parentId;
5177
+ const siblings = tasks.filter((t) => t.parentId === currentParentId);
5178
+ const promotedTask = { ...taskToPromote, parentId: grandparentId };
4679
5179
  if (siblings.length <= 1) {
4680
- const promotedTask2 = { ...taskToPromote, parentId: void 0 };
4681
- onTasksChange?.([promotedTask2]);
5180
+ onTasksChange?.([promotedTask]);
4682
5181
  return;
4683
5182
  }
4684
- const lastSiblingIndex = tasks.map((t, i) => ({ task: t, index: i })).filter(({ task }) => task.parentId === parentId).sort((a, b) => b.index - a.index)[0];
5183
+ const lastSiblingIndex = tasks.map((t, i) => ({ task: t, index: i })).filter(({ task }) => task.parentId === currentParentId).sort((a, b) => b.index - a.index)[0];
4685
5184
  if (!lastSiblingIndex) {
4686
- const promotedTask2 = { ...taskToPromote, parentId: void 0 };
4687
- onTasksChange?.([promotedTask2]);
5185
+ onTasksChange?.([promotedTask]);
4688
5186
  return;
4689
5187
  }
4690
- const promotedTask = { ...taskToPromote, parentId: void 0 };
4691
5188
  const reorderedTasks = normalizeHierarchyTasks([
4692
5189
  ...tasks.filter((t) => t.id !== taskId).slice(0, lastSiblingIndex.index + 1),
4693
5190
  promotedTask,