gantt-lib 0.4.0 → 0.5.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
@@ -1972,6 +1972,14 @@ var TrashIcon = () => /* @__PURE__ */ jsxs9("svg", { xmlns: "http://www.w3.org/2
1972
1972
  /* @__PURE__ */ jsx12("path", { d: "M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })
1973
1973
  ] });
1974
1974
  var PlusIcon = () => /* @__PURE__ */ jsx12("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx12("path", { d: "M12 5v14M5 12h14" }) });
1975
+ var DragHandleIcon = () => /* @__PURE__ */ jsxs9("svg", { width: "10", height: "14", viewBox: "0 0 10 14", fill: "currentColor", children: [
1976
+ /* @__PURE__ */ jsx12("circle", { cx: "2", cy: "2", r: "1.5" }),
1977
+ /* @__PURE__ */ jsx12("circle", { cx: "8", cy: "2", r: "1.5" }),
1978
+ /* @__PURE__ */ jsx12("circle", { cx: "2", cy: "7", r: "1.5" }),
1979
+ /* @__PURE__ */ jsx12("circle", { cx: "8", cy: "7", r: "1.5" }),
1980
+ /* @__PURE__ */ jsx12("circle", { cx: "2", cy: "12", r: "1.5" }),
1981
+ /* @__PURE__ */ jsx12("circle", { cx: "8", cy: "12", r: "1.5" })
1982
+ ] });
1975
1983
  function formatDepDescription(type, lag) {
1976
1984
  const effectiveLag = lag ?? 0;
1977
1985
  if (type === "FS") {
@@ -2085,7 +2093,13 @@ var TaskListRow = React9.memo(
2085
2093
  onDelete,
2086
2094
  onAdd,
2087
2095
  onInsertAfter,
2088
- editingTaskId
2096
+ editingTaskId,
2097
+ isDragging = false,
2098
+ isDragOver = false,
2099
+ onDragStart,
2100
+ onDragOver,
2101
+ onDrop,
2102
+ onDragEnd
2089
2103
  }) => {
2090
2104
  const [editingName, setEditingName] = useState4(false);
2091
2105
  const [nameValue, setNameValue] = useState4("");
@@ -2094,6 +2108,8 @@ var TaskListRow = React9.memo(
2094
2108
  const confirmedRef = useRef3(false);
2095
2109
  const autoEditedForRef = useRef3(null);
2096
2110
  const editTriggerRef = useRef3("doubleclick");
2111
+ const [deletePending, setDeletePending] = useState4(false);
2112
+ const deleteButtonRef = useRef3(null);
2097
2113
  const isSelected = selectedTaskId === task.id;
2098
2114
  const isPicking = selectingPredecessorFor != null;
2099
2115
  const isSourceRow = isPicking && selectingPredecessorFor === task.id;
@@ -2125,6 +2141,19 @@ var TaskListRow = React9.memo(
2125
2141
  }
2126
2142
  }
2127
2143
  }, [editingName]);
2144
+ useEffect3(() => {
2145
+ const handleMouseDownOutside = (event) => {
2146
+ if (deletePending && deleteButtonRef.current && !deleteButtonRef.current.contains(event.target)) {
2147
+ setDeletePending(false);
2148
+ }
2149
+ };
2150
+ if (deletePending) {
2151
+ document.addEventListener("mousedown", handleMouseDownOutside);
2152
+ }
2153
+ return () => {
2154
+ document.removeEventListener("mousedown", handleMouseDownOutside);
2155
+ };
2156
+ }, [deletePending]);
2128
2157
  useEffect3(() => {
2129
2158
  if (editingTaskId === task.id && !disableTaskNameEditing && autoEditedForRef.current !== editingTaskId) {
2130
2159
  autoEditedForRef.current = editingTaskId;
@@ -2244,19 +2273,44 @@ var TaskListRow = React9.memo(
2244
2273
  "gantt-tl-row",
2245
2274
  isSelected ? "gantt-tl-row-selected" : "",
2246
2275
  isPicking && !isSourceRow ? "gantt-tl-row-picking" : "",
2247
- isSourceRow ? "gantt-tl-row-picking-self" : ""
2276
+ isSourceRow ? "gantt-tl-row-picking-self" : "",
2277
+ isDragging ? "gantt-tl-row-dragging" : "",
2278
+ isDragOver ? "gantt-tl-row-drag-over" : ""
2248
2279
  ].filter(Boolean).join(" "),
2249
2280
  style: { minHeight: `${rowHeight}px`, position: "relative" },
2250
2281
  onClick: handleRowClickInternal,
2251
2282
  onKeyDown: handleRowKeyDown,
2283
+ onDragOver: (e) => onDragOver?.(rowIndex, e),
2284
+ onDrop: (e) => onDrop?.(rowIndex, e),
2285
+ onMouseLeave: () => {
2286
+ if (deletePending) {
2287
+ setDeletePending(false);
2288
+ }
2289
+ },
2252
2290
  tabIndex: isSelected ? 0 : -1,
2253
2291
  children: [
2254
- /* @__PURE__ */ jsx12(
2292
+ /* @__PURE__ */ jsxs9(
2255
2293
  "div",
2256
2294
  {
2257
2295
  className: "gantt-tl-cell gantt-tl-cell-number",
2258
2296
  onClick: handleNumberClick,
2259
- children: /* @__PURE__ */ jsx12("span", { className: "gantt-tl-num-label", children: rowIndex + 1 })
2297
+ children: [
2298
+ /* @__PURE__ */ jsx12(
2299
+ "span",
2300
+ {
2301
+ className: "gantt-tl-drag-handle",
2302
+ draggable: true,
2303
+ onDragStart: (e) => {
2304
+ e.stopPropagation();
2305
+ onDragStart?.(rowIndex, e);
2306
+ },
2307
+ onDragEnd: (e) => onDragEnd?.(e),
2308
+ onClick: (e) => e.stopPropagation(),
2309
+ children: /* @__PURE__ */ jsx12(DragHandleIcon, {})
2310
+ }
2311
+ ),
2312
+ /* @__PURE__ */ jsx12("span", { className: "gantt-tl-num-label", children: rowIndex + 1 })
2313
+ ]
2260
2314
  }
2261
2315
  ),
2262
2316
  /* @__PURE__ */ jsxs9("div", { className: "gantt-tl-cell gantt-tl-cell-name", children: [
@@ -2319,13 +2373,19 @@ var TaskListRow = React9.memo(
2319
2373
  "button",
2320
2374
  {
2321
2375
  type: "button",
2322
- className: "gantt-tl-name-action-btn gantt-tl-action-delete",
2376
+ ref: deleteButtonRef,
2377
+ className: `gantt-tl-name-action-btn gantt-tl-action-delete${deletePending ? " gantt-tl-action-delete-confirm" : ""}`,
2323
2378
  onClick: (e) => {
2324
2379
  e.stopPropagation();
2325
- onDelete(task.id);
2380
+ if (!deletePending) {
2381
+ setDeletePending(true);
2382
+ } else {
2383
+ setDeletePending(false);
2384
+ onDelete(task.id);
2385
+ }
2326
2386
  },
2327
2387
  "aria-label": "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0437\u0430\u0434\u0430\u0447\u0443",
2328
- children: /* @__PURE__ */ jsx12(TrashIcon, {})
2388
+ children: deletePending ? "\u0423\u0434\u0430\u043B\u0438\u0442\u044C?" : /* @__PURE__ */ jsx12(TrashIcon, {})
2329
2389
  }
2330
2390
  )
2331
2391
  ] })
@@ -2520,6 +2580,7 @@ var TaskList = ({
2520
2580
  onAdd,
2521
2581
  onDelete,
2522
2582
  onInsertAfter,
2583
+ onReorder,
2523
2584
  editingTaskId: propEditingTaskId
2524
2585
  }) => {
2525
2586
  const totalHeight = useMemo8(
@@ -2621,6 +2682,43 @@ var TaskList = ({
2621
2682
  onTaskChange?.({ ...task, dependencies: updatedDeps });
2622
2683
  }, [tasks, onTaskChange]);
2623
2684
  const [isCreating, setIsCreating] = useState6(false);
2685
+ const [draggingIndex, setDraggingIndex] = useState6(null);
2686
+ const [dragOverIndex, setDragOverIndex] = useState6(null);
2687
+ const dragOriginIndexRef = useRef5(null);
2688
+ const handleDragStart = useCallback5((index, e) => {
2689
+ e.dataTransfer.effectAllowed = "move";
2690
+ setDraggingIndex(index);
2691
+ dragOriginIndexRef.current = index;
2692
+ }, []);
2693
+ const handleDragOver = useCallback5((index, e) => {
2694
+ e.preventDefault();
2695
+ e.dataTransfer.dropEffect = "move";
2696
+ setDragOverIndex(index);
2697
+ }, []);
2698
+ const handleDrop = useCallback5((dropIndex, e) => {
2699
+ e.preventDefault();
2700
+ const originIndex = dragOriginIndexRef.current;
2701
+ if (originIndex === null || originIndex === dropIndex) {
2702
+ setDraggingIndex(null);
2703
+ setDragOverIndex(null);
2704
+ dragOriginIndexRef.current = null;
2705
+ return;
2706
+ }
2707
+ const reordered = [...tasks];
2708
+ const [moved] = reordered.splice(originIndex, 1);
2709
+ const insertIndex = originIndex < dropIndex ? dropIndex - 1 : dropIndex;
2710
+ reordered.splice(insertIndex, 0, moved);
2711
+ onReorder?.(reordered);
2712
+ onTaskSelect?.(moved.id);
2713
+ setDraggingIndex(null);
2714
+ setDragOverIndex(null);
2715
+ dragOriginIndexRef.current = null;
2716
+ }, [tasks, onReorder, onTaskSelect]);
2717
+ const handleDragEnd = useCallback5(() => {
2718
+ setDraggingIndex(null);
2719
+ setDragOverIndex(null);
2720
+ dragOriginIndexRef.current = null;
2721
+ }, []);
2624
2722
  const handleConfirmNewTask = useCallback5((name) => {
2625
2723
  const now = /* @__PURE__ */ new Date();
2626
2724
  const todayISO = new Date(Date.UTC(
@@ -2712,7 +2810,13 @@ var TaskList = ({
2712
2810
  onDelete,
2713
2811
  onAdd,
2714
2812
  onInsertAfter,
2715
- editingTaskId: propEditingTaskId
2813
+ editingTaskId: propEditingTaskId,
2814
+ isDragging: draggingIndex === index,
2815
+ isDragOver: dragOverIndex === index,
2816
+ onDragStart: handleDragStart,
2817
+ onDragOver: handleDragOver,
2818
+ onDrop: handleDrop,
2819
+ onDragEnd: handleDragEnd
2716
2820
  },
2717
2821
  task.id
2718
2822
  )) }),
@@ -2759,11 +2863,12 @@ var GanttChart = forwardRef(({
2759
2863
  onAdd,
2760
2864
  onDelete,
2761
2865
  onInsertAfter,
2762
- editingTaskId
2866
+ onReorder
2763
2867
  }, ref) => {
2764
2868
  const scrollContainerRef = useRef6(null);
2765
2869
  const [selectedTaskId, setSelectedTaskId] = useState7(null);
2766
2870
  const [selectedChip, setSelectedChip] = useState7(null);
2871
+ const [editingTaskId, setEditingTaskId] = useState7(null);
2767
2872
  const dateRange = useMemo9(() => getMultiMonthDays(tasks), [tasks]);
2768
2873
  const [validationResult, setValidationResult] = useState7(null);
2769
2874
  const [cascadeOverrides, setCascadeOverrides] = useState7(/* @__PURE__ */ new Map());
@@ -2847,6 +2952,9 @@ var GanttChart = forwardRef(({
2847
2952
  const originalTask = tasks.find((t) => t.id === updatedTask.id);
2848
2953
  if (!originalTask) {
2849
2954
  onChange?.((currentTasks) => currentTasks.map((t) => t.id === updatedTask.id ? updatedTask : t));
2955
+ if (editingTaskId === updatedTask.id) {
2956
+ setEditingTaskId(null);
2957
+ }
2850
2958
  return;
2851
2959
  }
2852
2960
  const origStart = new Date(originalTask.startDate);
@@ -2856,6 +2964,9 @@ var GanttChart = forwardRef(({
2856
2964
  const datesChanged = origStart.getTime() !== newStart.getTime() || origEnd.getTime() !== newEnd.getTime();
2857
2965
  if (!datesChanged) {
2858
2966
  onChange?.((currentTasks) => currentTasks.map((t) => t.id === updatedTask.id ? updatedTask : t));
2967
+ if (editingTaskId === updatedTask.id) {
2968
+ setEditingTaskId(null);
2969
+ }
2859
2970
  return;
2860
2971
  }
2861
2972
  let cascadedTasksForCallback;
@@ -2874,7 +2985,7 @@ var GanttChart = forwardRef(({
2874
2985
  });
2875
2986
  onCascade?.(cascadedTasksForCallback);
2876
2987
  }
2877
- }, [tasks, onChange, disableConstraints, onCascade]);
2988
+ }, [tasks, onChange, disableConstraints, onCascade, editingTaskId]);
2878
2989
  const handleDelete = useCallback6((taskId) => {
2879
2990
  onChange?.(
2880
2991
  (currentTasks) => currentTasks.filter((t) => t.id !== taskId).map((t) => ({
@@ -2884,6 +2995,14 @@ var GanttChart = forwardRef(({
2884
2995
  );
2885
2996
  onDelete?.(taskId);
2886
2997
  }, [onChange, onDelete]);
2998
+ const handleInsertAfter = useCallback6((taskId, newTask) => {
2999
+ setEditingTaskId(newTask.id);
3000
+ onInsertAfter?.(taskId, newTask);
3001
+ }, [onInsertAfter]);
3002
+ const handleReorder = useCallback6((reorderedTasks) => {
3003
+ onChange?.(reorderedTasks);
3004
+ onReorder?.(reorderedTasks);
3005
+ }, [onChange, onReorder]);
2887
3006
  const dependencyOverrides = useMemo9(() => {
2888
3007
  const map = new Map(cascadeOverrides);
2889
3008
  if (draggedTaskOverride) {
@@ -2976,7 +3095,8 @@ var GanttChart = forwardRef(({
2976
3095
  onSelectedChipChange: setSelectedChip,
2977
3096
  onAdd,
2978
3097
  onDelete: handleDelete,
2979
- onInsertAfter,
3098
+ onInsertAfter: handleInsertAfter,
3099
+ onReorder: handleReorder,
2980
3100
  editingTaskId
2981
3101
  }
2982
3102
  ),