gantt-lib 0.6.2 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -72,6 +72,7 @@ __export(index_exports, {
72
72
  getMultiMonthDays: () => getMultiMonthDays,
73
73
  getSuccessorChain: () => getSuccessorChain,
74
74
  getTransitiveCascadeChain: () => getTransitiveCascadeChain,
75
+ getVisibleReorderPosition: () => getVisibleReorderPosition,
75
76
  isTaskParent: () => isTaskParent,
76
77
  isToday: () => isToday,
77
78
  isWeekend: () => isWeekend,
@@ -281,33 +282,33 @@ function detectCycles(tasks) {
281
282
  return { hasCycle: false };
282
283
  }
283
284
  function computeLagFromDates(linkType, predStart, predEnd, succStart, succEnd) {
284
- const DAY_MS = 24 * 60 * 60 * 1e3;
285
+ const DAY_MS2 = 24 * 60 * 60 * 1e3;
285
286
  const pS = Date.UTC(predStart.getUTCFullYear(), predStart.getUTCMonth(), predStart.getUTCDate());
286
287
  const pE = Date.UTC(predEnd.getUTCFullYear(), predEnd.getUTCMonth(), predEnd.getUTCDate());
287
288
  const sS = Date.UTC(succStart.getUTCFullYear(), succStart.getUTCMonth(), succStart.getUTCDate());
288
289
  const sE = Date.UTC(succEnd.getUTCFullYear(), succEnd.getUTCMonth(), succEnd.getUTCDate());
289
290
  switch (linkType) {
290
291
  case "FS":
291
- return Math.round((sS - pE) / DAY_MS) - 1;
292
+ return Math.round((sS - pE) / DAY_MS2) - 1;
292
293
  case "SS":
293
- return Math.round((sS - pS) / DAY_MS);
294
+ return Math.round((sS - pS) / DAY_MS2);
294
295
  case "FF":
295
- return Math.round((sE - pE) / DAY_MS);
296
+ return Math.round((sE - pE) / DAY_MS2);
296
297
  case "SF":
297
- return Math.round((sE - pS) / DAY_MS) + 1;
298
+ return Math.round((sE - pS) / DAY_MS2) + 1;
298
299
  }
299
300
  }
300
301
  function calculateSuccessorDate(predecessorStart, predecessorEnd, linkType, lag = 0) {
301
- const DAY_MS = 24 * 60 * 60 * 1e3;
302
+ const DAY_MS2 = 24 * 60 * 60 * 1e3;
302
303
  switch (linkType) {
303
304
  case "FS":
304
- return new Date(predecessorEnd.getTime() + (lag + 1) * DAY_MS);
305
+ return new Date(predecessorEnd.getTime() + (lag + 1) * DAY_MS2);
305
306
  case "SS":
306
- return new Date(predecessorStart.getTime() + lag * DAY_MS);
307
+ return new Date(predecessorStart.getTime() + lag * DAY_MS2);
307
308
  case "FF":
308
- return new Date(predecessorEnd.getTime() + lag * DAY_MS);
309
+ return new Date(predecessorEnd.getTime() + lag * DAY_MS2);
309
310
  case "SF":
310
- return new Date(predecessorStart.getTime() + (lag - 1) * DAY_MS);
311
+ return new Date(predecessorStart.getTime() + (lag - 1) * DAY_MS2);
311
312
  }
312
313
  }
313
314
  function validateDependencies(tasks) {
@@ -539,13 +540,13 @@ function computeParentProgress(parentId, tasks) {
539
540
  if (children.length === 0) {
540
541
  return 0;
541
542
  }
542
- const DAY_MS = 24 * 60 * 60 * 1e3;
543
+ const DAY_MS2 = 24 * 60 * 60 * 1e3;
543
544
  let totalWeight = 0;
544
545
  let weightedSum = 0;
545
546
  for (const child of children) {
546
547
  const start = new Date(child.startDate).getTime();
547
548
  const end = new Date(child.endDate).getTime();
548
- const duration = (end - start + DAY_MS) / DAY_MS;
549
+ const duration = (end - start + DAY_MS2) / DAY_MS2;
549
550
  const progress = child.progress ?? 0;
550
551
  totalWeight += duration;
551
552
  weightedSum += duration * progress;
@@ -2082,6 +2083,36 @@ var DependencyLines_default = DependencyLines;
2082
2083
  // src/components/TaskList/TaskList.tsx
2083
2084
  var import_react12 = __toESM(require("react"));
2084
2085
 
2086
+ // src/utils/taskListReorder.ts
2087
+ function getVisibleReorderPosition(orderedTasks, visibleTasks, movedTaskId, originVisibleIndex, dropVisibleIndex) {
2088
+ const originOrderedIndex = orderedTasks.findIndex((task) => task.id === movedTaskId);
2089
+ if (originOrderedIndex === -1) {
2090
+ return null;
2091
+ }
2092
+ const reorderedWithoutMoved = orderedTasks.filter((task) => task.id !== movedTaskId);
2093
+ const visibleWithoutMoved = visibleTasks.filter((task) => task.id !== movedTaskId);
2094
+ const visibleInsertIndex = originVisibleIndex < dropVisibleIndex ? dropVisibleIndex - 1 : dropVisibleIndex;
2095
+ if (visibleWithoutMoved.length === 0) {
2096
+ return { originOrderedIndex, insertIndex: 0 };
2097
+ }
2098
+ if (visibleInsertIndex <= 0) {
2099
+ return {
2100
+ originOrderedIndex,
2101
+ insertIndex: reorderedWithoutMoved.findIndex((task) => task.id === visibleWithoutMoved[0].id)
2102
+ };
2103
+ }
2104
+ if (visibleInsertIndex >= visibleWithoutMoved.length) {
2105
+ return {
2106
+ originOrderedIndex,
2107
+ insertIndex: reorderedWithoutMoved.length
2108
+ };
2109
+ }
2110
+ return {
2111
+ originOrderedIndex,
2112
+ insertIndex: reorderedWithoutMoved.findIndex((task) => task.id === visibleWithoutMoved[visibleInsertIndex].id)
2113
+ };
2114
+ }
2115
+
2085
2116
  // src/components/ui/Popover.tsx
2086
2117
  var RadixPopover = __toESM(require("@radix-ui/react-popover"));
2087
2118
  var import_jsx_runtime7 = require("react/jsx-runtime");
@@ -2418,6 +2449,16 @@ var LINK_TYPE_LABELS = {
2418
2449
 
2419
2450
  // src/components/TaskList/TaskListRow.tsx
2420
2451
  var import_jsx_runtime12 = require("react/jsx-runtime");
2452
+ var DAY_MS = 24 * 60 * 60 * 1e3;
2453
+ var getInclusiveDurationDays = (startDate, endDate) => {
2454
+ const start = parseUTCDate(startDate);
2455
+ const end = parseUTCDate(endDate);
2456
+ return Math.max(1, Math.round((end.getTime() - start.getTime()) / DAY_MS) + 1);
2457
+ };
2458
+ var getEndDateFromDuration = (startDate, durationDays) => {
2459
+ const start = parseUTCDate(startDate);
2460
+ return new Date(start.getTime() + (durationDays - 1) * DAY_MS).toISOString().split("T")[0];
2461
+ };
2421
2462
  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: [
2422
2463
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6" }),
2423
2464
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M3 6h18" }),
@@ -2432,6 +2473,7 @@ var DragHandleIcon = () => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("svg",
2432
2473
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("circle", { cx: "2", cy: "12", r: "1.5" }),
2433
2474
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("circle", { cx: "8", cy: "12", r: "1.5" })
2434
2475
  ] });
2476
+ 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" }) });
2435
2477
  var HierarchyButton = ({
2436
2478
  isChild,
2437
2479
  isParent,
@@ -2600,11 +2642,16 @@ var TaskListRow = import_react10.default.memo(
2600
2642
  const [editingName, setEditingName] = (0, import_react10.useState)(false);
2601
2643
  const [nameValue, setNameValue] = (0, import_react10.useState)("");
2602
2644
  const nameInputRef = (0, import_react10.useRef)(null);
2645
+ const [editingDuration, setEditingDuration] = (0, import_react10.useState)(false);
2646
+ const [durationValue, setDurationValue] = (0, import_react10.useState)(getInclusiveDurationDays(task.startDate, task.endDate));
2647
+ const durationInputRef = (0, import_react10.useRef)(null);
2603
2648
  const [editingProgress, setEditingProgress] = (0, import_react10.useState)(false);
2604
2649
  const [progressValue, setProgressValue] = (0, import_react10.useState)(0);
2605
2650
  const progressInputRef = (0, import_react10.useRef)(null);
2606
2651
  const [overflowOpen, setOverflowOpen] = (0, import_react10.useState)(false);
2607
- const confirmedRef = (0, import_react10.useRef)(false);
2652
+ const nameConfirmedRef = (0, import_react10.useRef)(false);
2653
+ const durationConfirmedRef = (0, import_react10.useRef)(false);
2654
+ const progressConfirmedRef = (0, import_react10.useRef)(false);
2608
2655
  const autoEditedForRef = (0, import_react10.useRef)(null);
2609
2656
  const editTriggerRef = (0, import_react10.useRef)("doubleclick");
2610
2657
  const [deletePending, setDeletePending] = (0, import_react10.useState)(false);
@@ -2659,7 +2706,7 @@ var TaskListRow = import_react10.default.memo(
2659
2706
  (0, import_react10.useEffect)(() => {
2660
2707
  if (editingTaskId === task.id && !disableTaskNameEditing && autoEditedForRef.current !== editingTaskId) {
2661
2708
  autoEditedForRef.current = editingTaskId;
2662
- confirmedRef.current = false;
2709
+ nameConfirmedRef.current = false;
2663
2710
  editTriggerRef.current = "autoedit";
2664
2711
  setNameValue(task.name);
2665
2712
  setEditingName(true);
@@ -2674,7 +2721,7 @@ var TaskListRow = import_react10.default.memo(
2674
2721
  const handleNameDoubleClick = (0, import_react10.useCallback)((e) => {
2675
2722
  if (disableTaskNameEditing) return;
2676
2723
  e.stopPropagation();
2677
- confirmedRef.current = false;
2724
+ nameConfirmedRef.current = false;
2678
2725
  editTriggerRef.current = "doubleclick";
2679
2726
  setNameValue(task.name);
2680
2727
  setEditingName(true);
@@ -2683,7 +2730,7 @@ var TaskListRow = import_react10.default.memo(
2683
2730
  if (editingProgress) return;
2684
2731
  if (!editingName && !disableTaskNameEditing && e.key === "F2") {
2685
2732
  e.preventDefault();
2686
- confirmedRef.current = false;
2733
+ nameConfirmedRef.current = false;
2687
2734
  editTriggerRef.current = "keypress";
2688
2735
  setNameValue(task.name);
2689
2736
  setEditingName(true);
@@ -2691,15 +2738,15 @@ var TaskListRow = import_react10.default.memo(
2691
2738
  }
2692
2739
  if (!editingName && !disableTaskNameEditing && e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
2693
2740
  e.preventDefault();
2694
- confirmedRef.current = false;
2741
+ nameConfirmedRef.current = false;
2695
2742
  editTriggerRef.current = "keypress";
2696
2743
  setNameValue(e.key);
2697
2744
  setEditingName(true);
2698
2745
  }
2699
2746
  }, [editingName, disableTaskNameEditing, task.name]);
2700
2747
  const handleNameSave = (0, import_react10.useCallback)(() => {
2701
- if (confirmedRef.current) {
2702
- confirmedRef.current = false;
2748
+ if (nameConfirmedRef.current) {
2749
+ nameConfirmedRef.current = false;
2703
2750
  return;
2704
2751
  }
2705
2752
  if (nameValue.trim()) {
@@ -2712,7 +2759,7 @@ var TaskListRow = import_react10.default.memo(
2712
2759
  }, []);
2713
2760
  const handleNameKeyDown = (0, import_react10.useCallback)((e) => {
2714
2761
  if (e.key === "Enter") {
2715
- confirmedRef.current = true;
2762
+ nameConfirmedRef.current = true;
2716
2763
  if (nameValue.trim()) {
2717
2764
  onTaskChange?.({ ...task, name: nameValue.trim() });
2718
2765
  }
@@ -2721,15 +2768,54 @@ var TaskListRow = import_react10.default.memo(
2721
2768
  handleNameCancel();
2722
2769
  }
2723
2770
  }, [nameValue, task, onTaskChange, handleNameCancel]);
2771
+ const handleDurationClick = (0, import_react10.useCallback)((e) => {
2772
+ if (task.locked) return;
2773
+ e.stopPropagation();
2774
+ durationConfirmedRef.current = false;
2775
+ setDurationValue(getInclusiveDurationDays(task.startDate, task.endDate));
2776
+ setEditingDuration(true);
2777
+ }, [task.locked, task.startDate, task.endDate]);
2778
+ const applyDurationChange = (0, import_react10.useCallback)((nextDuration) => {
2779
+ const normalizedDuration = Math.max(1, Math.round(nextDuration) || 1);
2780
+ setDurationValue(normalizedDuration);
2781
+ }, []);
2782
+ const handleDurationSave = (0, import_react10.useCallback)(() => {
2783
+ if (durationConfirmedRef.current) {
2784
+ durationConfirmedRef.current = false;
2785
+ return;
2786
+ }
2787
+ const normalizedDuration = Math.max(1, Math.round(durationValue) || 1);
2788
+ onTaskChange?.({ ...task, endDate: getEndDateFromDuration(task.startDate, normalizedDuration) });
2789
+ setEditingDuration(false);
2790
+ }, [durationValue, task, onTaskChange]);
2791
+ const handleDurationCancel = (0, import_react10.useCallback)(() => {
2792
+ setDurationValue(getInclusiveDurationDays(task.startDate, task.endDate));
2793
+ setEditingDuration(false);
2794
+ }, [task.startDate, task.endDate]);
2795
+ const handleDurationAdjust = (0, import_react10.useCallback)((delta) => {
2796
+ applyDurationChange(durationValue + delta);
2797
+ }, [applyDurationChange, durationValue]);
2798
+ const handleDurationKeyDown = (0, import_react10.useCallback)((e) => {
2799
+ e.stopPropagation();
2800
+ if (e.key === "Enter") {
2801
+ durationConfirmedRef.current = true;
2802
+ const normalizedDuration = Math.max(1, Math.round(durationValue) || 1);
2803
+ onTaskChange?.({ ...task, endDate: getEndDateFromDuration(task.startDate, normalizedDuration) });
2804
+ setEditingDuration(false);
2805
+ } else if (e.key === "Escape") {
2806
+ handleDurationCancel();
2807
+ }
2808
+ }, [durationValue, task, onTaskChange, handleDurationCancel]);
2724
2809
  const handleProgressClick = (0, import_react10.useCallback)((e) => {
2810
+ if (task.locked) return;
2725
2811
  e.stopPropagation();
2726
- confirmedRef.current = false;
2812
+ progressConfirmedRef.current = false;
2727
2813
  setProgressValue(task.progress ?? 0);
2728
2814
  setEditingProgress(true);
2729
- }, [task.progress]);
2815
+ }, [task.progress, task.locked]);
2730
2816
  const handleProgressSave = (0, import_react10.useCallback)(() => {
2731
- if (confirmedRef.current) {
2732
- confirmedRef.current = false;
2817
+ if (progressConfirmedRef.current) {
2818
+ progressConfirmedRef.current = false;
2733
2819
  return;
2734
2820
  }
2735
2821
  const clampedValue = Math.max(0, Math.min(100, progressValue));
@@ -2739,10 +2825,13 @@ var TaskListRow = import_react10.default.memo(
2739
2825
  const handleProgressCancel = (0, import_react10.useCallback)(() => {
2740
2826
  setEditingProgress(false);
2741
2827
  }, []);
2828
+ const handleProgressAdjust = (0, import_react10.useCallback)((delta) => {
2829
+ setProgressValue((current) => Math.max(0, Math.min(100, current + delta)));
2830
+ }, []);
2742
2831
  const handleProgressKeyDown = (0, import_react10.useCallback)((e) => {
2743
2832
  e.stopPropagation();
2744
2833
  if (e.key === "Enter") {
2745
- confirmedRef.current = true;
2834
+ progressConfirmedRef.current = true;
2746
2835
  const clampedValue = Math.max(0, Math.min(100, progressValue));
2747
2836
  onTaskChange?.({ ...task, progress: clampedValue });
2748
2837
  setEditingProgress(false);
@@ -2756,6 +2845,15 @@ var TaskListRow = import_react10.default.memo(
2756
2845
  progressInputRef.current.select();
2757
2846
  }
2758
2847
  }, [editingProgress]);
2848
+ (0, import_react10.useEffect)(() => {
2849
+ setDurationValue(getInclusiveDurationDays(task.startDate, task.endDate));
2850
+ }, [task.startDate, task.endDate]);
2851
+ (0, import_react10.useEffect)(() => {
2852
+ if (editingDuration && durationInputRef.current) {
2853
+ durationInputRef.current.focus();
2854
+ durationInputRef.current.select();
2855
+ }
2856
+ }, [editingDuration]);
2759
2857
  const handleStartDateChange = (0, import_react10.useCallback)((newDateISO) => {
2760
2858
  if (!newDateISO) return;
2761
2859
  const origStart = parseUTCDate(task.startDate);
@@ -2820,7 +2918,7 @@ var TaskListRow = import_react10.default.memo(
2820
2918
  onChipSelect?.(null);
2821
2919
  }, [selectedChip, onRemoveDependency, onChipSelect]);
2822
2920
  const startDateISO = toISODate(task.startDate);
2823
- const endDateISO = toISODate(task.endDate);
2921
+ const endDateISO = editingDuration ? getEndDateFromDuration(task.startDate, durationValue) : toISODate(task.endDate);
2824
2922
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2825
2923
  "div",
2826
2924
  {
@@ -2846,21 +2944,12 @@ var TaskListRow = import_react10.default.memo(
2846
2944
  },
2847
2945
  tabIndex: isSelected ? 0 : -1,
2848
2946
  children: [
2849
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2947
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2850
2948
  "div",
2851
2949
  {
2852
2950
  className: "gantt-tl-cell gantt-tl-cell-number",
2853
2951
  onClick: handleNumberClick,
2854
- children: isParent ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2855
- "button",
2856
- {
2857
- type: "button",
2858
- className: "gantt-tl-collapse-btn",
2859
- onClick: handleToggleCollapse,
2860
- "aria-label": isCollapsed ? "\u0420\u0430\u0437\u0432\u0435\u0440\u043D\u0443\u0442\u044C" : "\u0421\u0432\u0435\u0440\u043D\u0443\u0442\u044C",
2861
- children: isCollapsed ? "+" : "-"
2862
- }
2863
- ) : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
2952
+ children: [
2864
2953
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2865
2954
  "span",
2866
2955
  {
@@ -2876,10 +2965,20 @@ var TaskListRow = import_react10.default.memo(
2876
2965
  }
2877
2966
  ),
2878
2967
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "gantt-tl-num-label", children: rowIndex + 1 })
2879
- ] })
2968
+ ]
2880
2969
  }
2881
2970
  ),
2882
2971
  /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-cell gantt-tl-cell-name", children: [
2972
+ isParent && !editingName && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2973
+ "button",
2974
+ {
2975
+ type: "button",
2976
+ className: `gantt-tl-collapse-btn ${isCollapsed ? "gantt-tl-collapse-btn-collapsed" : ""}`,
2977
+ onClick: handleToggleCollapse,
2978
+ "aria-label": isCollapsed ? "Expand children" : "Collapse children",
2979
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ChevronRightIcon, {})
2980
+ }
2981
+ ),
2883
2982
  editingName && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2884
2983
  Input,
2885
2984
  {
@@ -2889,7 +2988,7 @@ var TaskListRow = import_react10.default.memo(
2889
2988
  onChange: (e) => setNameValue(e.target.value),
2890
2989
  onBlur: handleNameSave,
2891
2990
  onKeyDown: handleNameKeyDown,
2892
- className: "gantt-tl-name-input",
2991
+ className: ["gantt-tl-name-input", isChild ? "gantt-tl-name-input-child" : ""].filter(Boolean).join(" "),
2893
2992
  onClick: (e) => e.stopPropagation()
2894
2993
  }
2895
2994
  ),
@@ -2897,7 +2996,13 @@ var TaskListRow = import_react10.default.memo(
2897
2996
  "button",
2898
2997
  {
2899
2998
  type: "button",
2900
- className: `gantt-tl-name-trigger ${disableTaskNameEditing ? "gantt-tl-name-locked" : ""}`,
2999
+ className: [
3000
+ "gantt-tl-name-trigger",
3001
+ disableTaskNameEditing ? "gantt-tl-name-locked" : "",
3002
+ isParent ? "gantt-tl-name-trigger-parent" : "",
3003
+ isChild ? "gantt-tl-name-trigger-child" : ""
3004
+ ].filter(Boolean).join(" "),
3005
+ title: task.name,
2901
3006
  onClick: handleNameClick,
2902
3007
  onDoubleClick: handleNameDoubleClick,
2903
3008
  style: editingName ? { visibility: "hidden", pointerEvents: "none" } : void 0,
@@ -2986,22 +3091,91 @@ var TaskListRow = import_react10.default.memo(
2986
3091
  disabled: task.locked
2987
3092
  }
2988
3093
  ) }),
3094
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-cell gantt-tl-cell-duration", onClick: handleDurationClick, children: [
3095
+ editingDuration && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-number-editor", onClick: (e) => e.stopPropagation(), children: [
3096
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3097
+ Input,
3098
+ {
3099
+ ref: durationInputRef,
3100
+ type: "number",
3101
+ min: 1,
3102
+ step: 1,
3103
+ value: durationValue,
3104
+ onChange: (e) => applyDurationChange(parseInt(e.target.value, 10) || 1),
3105
+ onBlur: handleDurationSave,
3106
+ onKeyDown: handleDurationKeyDown,
3107
+ className: "gantt-tl-number-input"
3108
+ }
3109
+ ),
3110
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-number-steppers", "aria-hidden": "true", children: [
3111
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3112
+ "button",
3113
+ {
3114
+ type: "button",
3115
+ className: "gantt-tl-number-stepper",
3116
+ tabIndex: -1,
3117
+ onMouseDown: (e) => e.preventDefault(),
3118
+ onClick: () => handleDurationAdjust(1),
3119
+ 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" }) })
3120
+ }
3121
+ ),
3122
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3123
+ "button",
3124
+ {
3125
+ type: "button",
3126
+ className: "gantt-tl-number-stepper",
3127
+ tabIndex: -1,
3128
+ onMouseDown: (e) => e.preventDefault(),
3129
+ onClick: () => handleDurationAdjust(-1),
3130
+ 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" }) })
3131
+ }
3132
+ )
3133
+ ] })
3134
+ ] }),
3135
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: editingDuration ? { visibility: "hidden", pointerEvents: "none" } : void 0, children: getInclusiveDurationDays(task.startDate, task.endDate) })
3136
+ ] }),
2989
3137
  /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-cell gantt-tl-cell-progress", onClick: handleProgressClick, children: [
2990
- editingProgress && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2991
- Input,
2992
- {
2993
- ref: progressInputRef,
2994
- type: "number",
2995
- min: 0,
2996
- max: 100,
2997
- value: progressValue,
2998
- onChange: (e) => setProgressValue(parseInt(e.target.value) || 0),
2999
- onBlur: handleProgressSave,
3000
- onKeyDown: handleProgressKeyDown,
3001
- className: "gantt-tl-progress-input",
3002
- onClick: (e) => e.stopPropagation()
3003
- }
3004
- ),
3138
+ editingProgress && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-number-editor", onClick: (e) => e.stopPropagation(), children: [
3139
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3140
+ Input,
3141
+ {
3142
+ ref: progressInputRef,
3143
+ type: "number",
3144
+ min: 0,
3145
+ max: 100,
3146
+ step: 1,
3147
+ value: progressValue,
3148
+ onChange: (e) => setProgressValue(parseInt(e.target.value, 10) || 0),
3149
+ onBlur: handleProgressSave,
3150
+ onKeyDown: handleProgressKeyDown,
3151
+ className: "gantt-tl-number-input"
3152
+ }
3153
+ ),
3154
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-number-steppers", "aria-hidden": "true", children: [
3155
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3156
+ "button",
3157
+ {
3158
+ type: "button",
3159
+ className: "gantt-tl-number-stepper",
3160
+ tabIndex: -1,
3161
+ onMouseDown: (e) => e.preventDefault(),
3162
+ onClick: () => handleProgressAdjust(1),
3163
+ 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" }) })
3164
+ }
3165
+ ),
3166
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3167
+ "button",
3168
+ {
3169
+ type: "button",
3170
+ className: "gantt-tl-number-stepper",
3171
+ tabIndex: -1,
3172
+ onMouseDown: (e) => e.preventDefault(),
3173
+ onClick: () => handleProgressAdjust(-1),
3174
+ 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" }) })
3175
+ }
3176
+ )
3177
+ ] })
3178
+ ] }),
3005
3179
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: editingProgress ? { visibility: "hidden", pointerEvents: "none" } : void 0, children: task.progress ? `${Math.round(task.progress)}%` : "0%" })
3006
3180
  ] }),
3007
3181
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
@@ -3158,15 +3332,17 @@ var NewTaskRow = ({ rowHeight, onConfirm, onCancel }) => {
3158
3332
  // src/components/TaskList/TaskList.tsx
3159
3333
  var import_jsx_runtime14 = require("react/jsx-runtime");
3160
3334
  var LINK_TYPE_ORDER = ["FS", "SS", "FF", "SF"];
3335
+ var MIN_TASK_LIST_WIDTH = 640;
3161
3336
  var TaskList = ({
3162
3337
  tasks,
3163
3338
  rowHeight,
3164
3339
  headerHeight,
3165
- taskListWidth = 542,
3340
+ taskListWidth = 640,
3166
3341
  onTaskChange,
3167
3342
  selectedTaskId,
3168
3343
  onTaskSelect,
3169
3344
  show = true,
3345
+ hasRightShadow = false,
3170
3346
  disableTaskNameEditing = false,
3171
3347
  disableDependencyEditing = false,
3172
3348
  onScrollToTask,
@@ -3305,11 +3481,13 @@ var TaskList = ({
3305
3481
  const [draggingIndex, setDraggingIndex] = (0, import_react12.useState)(null);
3306
3482
  const [dragOverIndex, setDragOverIndex] = (0, import_react12.useState)(null);
3307
3483
  const dragOriginIndexRef = (0, import_react12.useRef)(null);
3484
+ const dragTaskIdRef = (0, import_react12.useRef)(null);
3308
3485
  const handleDragStart = (0, import_react12.useCallback)((index, e) => {
3309
3486
  e.dataTransfer.effectAllowed = "move";
3310
3487
  setDraggingIndex(index);
3311
3488
  dragOriginIndexRef.current = index;
3312
- }, []);
3489
+ dragTaskIdRef.current = visibleTasks[index]?.id ?? null;
3490
+ }, [visibleTasks]);
3313
3491
  const handleDragOver = (0, import_react12.useCallback)((index, e) => {
3314
3492
  e.preventDefault();
3315
3493
  e.dataTransfer.dropEffect = "move";
@@ -3317,16 +3495,32 @@ var TaskList = ({
3317
3495
  }, []);
3318
3496
  const handleDrop = (0, import_react12.useCallback)((dropIndex, e) => {
3319
3497
  e.preventDefault();
3320
- const originIndex = dragOriginIndexRef.current;
3321
- if (originIndex === null || originIndex === dropIndex) {
3498
+ const originVisibleIndex = dragOriginIndexRef.current;
3499
+ const movedTaskId = dragTaskIdRef.current;
3500
+ if (originVisibleIndex === null || movedTaskId === null || originVisibleIndex === dropIndex) {
3501
+ setDraggingIndex(null);
3502
+ setDragOverIndex(null);
3503
+ dragOriginIndexRef.current = null;
3504
+ dragTaskIdRef.current = null;
3505
+ return;
3506
+ }
3507
+ const reorderPosition = getVisibleReorderPosition(
3508
+ orderedTasks,
3509
+ visibleTasks,
3510
+ movedTaskId,
3511
+ originVisibleIndex,
3512
+ dropIndex
3513
+ );
3514
+ if (!reorderPosition) {
3322
3515
  setDraggingIndex(null);
3323
3516
  setDragOverIndex(null);
3324
3517
  dragOriginIndexRef.current = null;
3518
+ dragTaskIdRef.current = null;
3325
3519
  return;
3326
3520
  }
3521
+ const { originOrderedIndex, insertIndex } = reorderPosition;
3327
3522
  const reordered = [...orderedTasks];
3328
- const [moved] = reordered.splice(originIndex, 1);
3329
- const insertIndex = dropIndex === visibleTasks.length ? visibleTasks.length - 1 : originIndex < dropIndex ? dropIndex - 1 : dropIndex;
3523
+ const [moved] = reordered.splice(originOrderedIndex, 1);
3330
3524
  const isChild = !!moved.parentId;
3331
3525
  const isParent = tasks.some((t) => t.parentId === moved.id);
3332
3526
  const taskType = isParent ? "PARENT" : isChild ? "CHILD" : "ROOT";
@@ -3336,10 +3530,11 @@ var TaskList = ({
3336
3530
  name: moved.name,
3337
3531
  type: taskType,
3338
3532
  parentId: moved.parentId,
3339
- originIndex,
3533
+ originIndex: originOrderedIndex,
3534
+ originVisibleIndex,
3340
3535
  dropIndex,
3341
3536
  insertIndex,
3342
- direction: originIndex < dropIndex ? "DOWN" : "UP"
3537
+ direction: originVisibleIndex < dropIndex ? "DOWN" : "UP"
3343
3538
  });
3344
3539
  console.log("[TASKS ARRAY LENGTH]", orderedTasks.length);
3345
3540
  let inferredParentId;
@@ -3426,11 +3621,13 @@ var TaskList = ({
3426
3621
  setDraggingIndex(null);
3427
3622
  setDragOverIndex(null);
3428
3623
  dragOriginIndexRef.current = null;
3429
- }, [orderedTasks, visibleTasks.length, onReorder, onTaskSelect]);
3624
+ dragTaskIdRef.current = null;
3625
+ }, [orderedTasks, visibleTasks, onReorder, onTaskSelect]);
3430
3626
  const handleDragEnd = (0, import_react12.useCallback)(() => {
3431
3627
  setDraggingIndex(null);
3432
3628
  setDragOverIndex(null);
3433
3629
  dragOriginIndexRef.current = null;
3630
+ dragTaskIdRef.current = null;
3434
3631
  }, []);
3435
3632
  const handleConfirmNewTask = (0, import_react12.useCallback)((name) => {
3436
3633
  const now = /* @__PURE__ */ new Date();
@@ -3454,18 +3651,20 @@ var TaskList = ({
3454
3651
  setIsCreating(false);
3455
3652
  }, [onAdd]);
3456
3653
  const handleCancelNewTask = (0, import_react12.useCallback)(() => setIsCreating(false), []);
3654
+ const effectiveTaskListWidth = Math.max(taskListWidth, MIN_TASK_LIST_WIDTH);
3457
3655
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3458
3656
  "div",
3459
3657
  {
3460
3658
  ref: overlayRef,
3461
- className: `gantt-tl-overlay${show ? "" : " gantt-tl-hidden"}`,
3462
- style: { width: `${taskListWidth}px` },
3659
+ className: `gantt-tl-overlay${show ? "" : " gantt-tl-hidden"}${hasRightShadow ? " gantt-tl-overlay-shadowed" : ""}`,
3660
+ style: { width: `${effectiveTaskListWidth}px`, minWidth: `${MIN_TASK_LIST_WIDTH}px` },
3463
3661
  children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "gantt-tl-table", children: [
3464
3662
  /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "gantt-tl-header", style: { height: `${headerHeight + 0.5}px` }, children: [
3465
3663
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "gantt-tl-headerCell gantt-tl-cell-number", children: "\u2116" }),
3466
3664
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "gantt-tl-headerCell gantt-tl-cell-name", children: "\u0418\u043C\u044F" }),
3467
3665
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "gantt-tl-headerCell gantt-tl-cell-date", children: "\u041D\u0430\u0447\u0430\u043B\u043E" }),
3468
3666
  /* @__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" }),
3667
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "gantt-tl-headerCell gantt-tl-cell-duration", children: "\u0414\u043D." }),
3469
3668
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "gantt-tl-headerCell gantt-tl-cell-progress", children: "%" }),
3470
3669
  /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "gantt-tl-headerCell gantt-tl-cell-deps", style: { position: "relative" }, children: [
3471
3670
  /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(Popover, { open: typeMenuOpen, onOpenChange: setTypeMenuOpen, children: [
@@ -3591,7 +3790,7 @@ var GanttChart = (0, import_react13.forwardRef)(({
3591
3790
  disableConstraints,
3592
3791
  onCascade,
3593
3792
  showTaskList = false,
3594
- taskListWidth = 520,
3793
+ taskListWidth = 660,
3595
3794
  disableTaskNameEditing = false,
3596
3795
  disableDependencyEditing = false,
3597
3796
  highlightExpiredTasks = false,
@@ -3603,6 +3802,7 @@ var GanttChart = (0, import_react13.forwardRef)(({
3603
3802
  }, ref) => {
3604
3803
  const scrollContainerRef = (0, import_react13.useRef)(null);
3605
3804
  const [selectedTaskId, setSelectedTaskId] = (0, import_react13.useState)(null);
3805
+ const [taskListHasRightShadow, setTaskListHasRightShadow] = (0, import_react13.useState)(false);
3606
3806
  const [selectedChip, setSelectedChip] = (0, import_react13.useState)(null);
3607
3807
  const [collapsedParentIds, setCollapsedParentIds] = (0, import_react13.useState)(/* @__PURE__ */ new Set());
3608
3808
  const [editingTaskId, setEditingTaskId] = (0, import_react13.useState)(null);
@@ -3649,6 +3849,18 @@ var GanttChart = (0, import_react13.forwardRef)(({
3649
3849
  const scrollLeft = Math.round(todayOffset - containerWidth / 2 + dayWidth / 2);
3650
3850
  container.scrollLeft = Math.max(0, scrollLeft);
3651
3851
  }, []);
3852
+ (0, import_react13.useEffect)(() => {
3853
+ const container = scrollContainerRef.current;
3854
+ if (!container) return;
3855
+ const updateShadow = () => {
3856
+ setTaskListHasRightShadow(container.scrollLeft > 0);
3857
+ };
3858
+ updateShadow();
3859
+ container.addEventListener("scroll", updateShadow, { passive: true });
3860
+ return () => {
3861
+ container.removeEventListener("scroll", updateShadow);
3862
+ };
3863
+ }, []);
3652
3864
  const scrollToToday = (0, import_react13.useCallback)(() => {
3653
3865
  const container = scrollContainerRef.current;
3654
3866
  if (!container || dateRange.length === 0) return;
@@ -4052,6 +4264,7 @@ var GanttChart = (0, import_react13.forwardRef)(({
4052
4264
  selectedTaskId: selectedTaskId ?? void 0,
4053
4265
  onTaskSelect: handleTaskSelect,
4054
4266
  show: showTaskList,
4267
+ hasRightShadow: taskListHasRightShadow,
4055
4268
  disableTaskNameEditing,
4056
4269
  disableDependencyEditing,
4057
4270
  onScrollToTask: scrollToTask,
@@ -4215,6 +4428,7 @@ Button.displayName = "Button";
4215
4428
  getMultiMonthDays,
4216
4429
  getSuccessorChain,
4217
4430
  getTransitiveCascadeChain,
4431
+ getVisibleReorderPosition,
4218
4432
  isTaskParent,
4219
4433
  isToday,
4220
4434
  isWeekend,