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