gantt-lib 0.128.2 → 0.129.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
@@ -3848,6 +3848,7 @@ var useTaskDrag = (options) => {
3848
3848
  monthStart,
3849
3849
  dayWidth,
3850
3850
  onDragEnd,
3851
+ onScheduleIntent,
3851
3852
  onDragStateChange,
3852
3853
  edgeZoneWidth = 12,
3853
3854
  allTasks = [],
@@ -3991,6 +3992,39 @@ var useTaskDrag = (options) => {
3991
3992
  setCurrentWidth(width);
3992
3993
  return;
3993
3994
  }
3995
+ if (onScheduleIntent) {
3996
+ const toDate = (date) => date.toISOString().split("T")[0];
3997
+ if (finalMode === "move") {
3998
+ onScheduleIntent({
3999
+ type: "move_task",
4000
+ taskId,
4001
+ startDate: toDate(newStartDate)
4002
+ });
4003
+ } else if (currentTask && isTaskParent(taskId, allTasks)) {
4004
+ const anchor = finalMode === "resize-left" ? "end" : "start";
4005
+ const parentRange = computeParentDates(taskId, allTasks);
4006
+ const targetDuration = getTaskDuration(
4007
+ anchor === "start" ? parentRange.startDate : newStartDate,
4008
+ anchor === "start" ? newEndDate : parentRange.endDate,
4009
+ businessDays,
4010
+ weekendPredicate
4011
+ );
4012
+ onScheduleIntent({
4013
+ type: "change_duration",
4014
+ taskId,
4015
+ duration: targetDuration,
4016
+ anchor
4017
+ });
4018
+ } else {
4019
+ const anchor = finalMode === "resize-left" ? "end" : "start";
4020
+ onScheduleIntent({
4021
+ type: "resize_task",
4022
+ taskId,
4023
+ anchor,
4024
+ date: toDate(finalMode === "resize-left" ? newStartDate : newEndDate)
4025
+ });
4026
+ }
4027
+ }
3994
4028
  const isParentResize = currentTask && (finalMode === "resize-left" || finalMode === "resize-right") ? isTaskParent(taskId, allTasks) : false;
3995
4029
  if (!disableConstraints && onCascade && allTasks.length > 0 && !isParentResize) {
3996
4030
  const draggedTaskData = currentTask;
@@ -4045,6 +4079,7 @@ var useTaskDrag = (options) => {
4045
4079
  dayWidth,
4046
4080
  monthStart,
4047
4081
  onDragEnd,
4082
+ onScheduleIntent,
4048
4083
  onDragStateChange,
4049
4084
  taskId,
4050
4085
  disableConstraints,
@@ -4205,7 +4240,7 @@ var arePropsEqual = (prevProps, nextProps) => {
4205
4240
  return prevProps.task.id === nextProps.task.id && prevProps.task.name === nextProps.task.name && prevProps.task.startDate === nextProps.task.startDate && prevProps.task.endDate === nextProps.task.endDate && prevProps.task.baselineStartDate === nextProps.task.baselineStartDate && prevProps.task.baselineEndDate === nextProps.task.baselineEndDate && prevProps.task.type === nextProps.task.type && prevProps.task.color === nextProps.task.color && prevProps.task.progress === nextProps.task.progress && prevProps.task.accepted === nextProps.task.accepted && prevProps.monthStart.getTime() === nextProps.monthStart.getTime() && prevProps.dayWidth === nextProps.dayWidth && prevProps.rowHeight === nextProps.rowHeight && prevProps.overridePosition?.left === nextProps.overridePosition?.left && prevProps.overridePosition?.width === nextProps.overridePosition?.width && prevProps.previewPositionStore === nextProps.previewPositionStore && prevProps.allTasks === nextProps.allTasks && prevProps.disableConstraints === nextProps.disableConstraints && prevProps.task.locked === nextProps.task.locked && prevProps.task.synced === nextProps.task.synced && prevProps.task.divider === nextProps.task.divider && prevProps.highlightExpiredTasks === nextProps.highlightExpiredTasks && prevProps.isCritical === nextProps.isCritical && prevProps.showBaseline === nextProps.showBaseline && prevProps.isFilterMatch === nextProps.isFilterMatch && prevProps.businessDays === nextProps.businessDays && prevProps.customDays === nextProps.customDays && prevProps.isWeekend === nextProps.isWeekend && prevProps.disableTaskDrag === nextProps.disableTaskDrag && prevProps.disableDependencyEditing === nextProps.disableDependencyEditing && prevProps.isDependencyDragActive === nextProps.isDependencyDragActive && prevProps.viewMode === nextProps.viewMode;
4206
4241
  };
4207
4242
  var TaskRow = React2.memo(
4208
- ({ task, monthStart, dayWidth, rowHeight, onTasksChange, onDragStateChange, rowIndex, allTasks, enableAutoSchedule, disableConstraints, overridePosition, previewPositionStore, onCascadeProgress, onCascade, divider, highlightExpiredTasks, isCritical = false, showBaseline = false, isFilterMatch = false, businessDays, customDays, isWeekend: isWeekend3, disableTaskDrag = false, disableDependencyEditing = false, onDependencyPortPointerDown, isDependencyDragActive = false, viewMode = "day" }) => {
4243
+ ({ task, monthStart, dayWidth, rowHeight, onTasksChange, onScheduleIntent, onDragStateChange, rowIndex, allTasks, enableAutoSchedule, disableConstraints, overridePosition, previewPositionStore, onCascadeProgress, onCascade, divider, highlightExpiredTasks, isCritical = false, showBaseline = false, isFilterMatch = false, businessDays, customDays, isWeekend: isWeekend3, disableTaskDrag = false, disableDependencyEditing = false, onDependencyPortPointerDown, isDependencyDragActive = false, viewMode = "day" }) => {
4209
4244
  const defaultParentBarColor = "#782FC4";
4210
4245
  const { divider: taskDivider } = task;
4211
4246
  const normalizedTask = useMemo2(() => normalizeTaskDatesForType(task), [task]);
@@ -4299,7 +4334,9 @@ var TaskRow = React2.memo(
4299
4334
  endDate: result.endDate.toISOString(),
4300
4335
  ...result.updatedDependencies !== void 0 && { dependencies: result.updatedDependencies }
4301
4336
  };
4302
- onTasksChange?.([updatedTask]);
4337
+ if (!onScheduleIntent) {
4338
+ onTasksChange?.([updatedTask]);
4339
+ }
4303
4340
  };
4304
4341
  const weekendPredicate = useMemo2(
4305
4342
  () => createCustomDayPredicate({ customDays, isWeekend: isWeekend3 }),
@@ -4318,6 +4355,7 @@ var TaskRow = React2.memo(
4318
4355
  monthStart,
4319
4356
  dayWidth,
4320
4357
  onDragEnd: handleDragEnd,
4358
+ onScheduleIntent,
4321
4359
  onDragStateChange,
4322
4360
  edgeZoneWidth: 20,
4323
4361
  allTasks,
@@ -6585,6 +6623,7 @@ var TaskListRow = React10.memo(
6585
6623
  taskNumberMap = {},
6586
6624
  rowHeight,
6587
6625
  onTasksChange,
6626
+ onDurationChange,
6588
6627
  selectedTaskId,
6589
6628
  onRowClick,
6590
6629
  disableTaskNameEditing = false,
@@ -6897,12 +6936,14 @@ var TaskListRow = React10.memo(
6897
6936
  const normalizedDuration = Math.max(0, Math.round(nextDuration) || 0);
6898
6937
  setDurationValue(normalizedDuration);
6899
6938
  }, []);
6900
- const handleDurationSave = useCallback5(() => {
6901
- if (durationConfirmedRef.current) {
6902
- durationConfirmedRef.current = false;
6939
+ const emitDurationChange = useCallback5((rounded) => {
6940
+ if (onDurationChange) {
6941
+ onDurationChange(
6942
+ isMilestone && rounded > 0 ? { ...task, type: "task" } : !isMilestone && rounded === 0 ? { ...task, type: "milestone", endDate: task.startDate } : task,
6943
+ rounded
6944
+ );
6903
6945
  return;
6904
6946
  }
6905
- const rounded = Math.round(durationValue) || 0;
6906
6947
  if (isMilestone && rounded > 0) {
6907
6948
  onTasksChange?.([
6908
6949
  { ...task, type: "task", endDate: getEndDate(task.startDate, rounded) }
@@ -6916,8 +6957,16 @@ var TaskListRow = React10.memo(
6916
6957
  { ...task, endDate: getEndDate(task.startDate, rounded) }
6917
6958
  ]);
6918
6959
  }
6960
+ }, [getEndDate, isMilestone, onDurationChange, onTasksChange, task]);
6961
+ const handleDurationSave = useCallback5(() => {
6962
+ if (durationConfirmedRef.current) {
6963
+ durationConfirmedRef.current = false;
6964
+ return;
6965
+ }
6966
+ const rounded = Math.round(durationValue) || 0;
6967
+ emitDurationChange(rounded);
6919
6968
  setEditingColumnId(null);
6920
- }, [durationValue, task, onTasksChange, getEndDate, isMilestone]);
6969
+ }, [durationValue, emitDurationChange]);
6921
6970
  const handleDurationCancel = useCallback5(() => {
6922
6971
  setDurationValue(isMilestone ? 0 : getDuration(normalizedTask.startDate, normalizedTask.endDate));
6923
6972
  setEditingColumnId(null);
@@ -6934,25 +6983,13 @@ var TaskListRow = React10.memo(
6934
6983
  if (e.key === "Enter") {
6935
6984
  durationConfirmedRef.current = true;
6936
6985
  const rounded = Math.round(durationValue) || 0;
6937
- if (isMilestone && rounded > 0) {
6938
- onTasksChange?.([
6939
- { ...task, type: "task", endDate: getEndDate(task.startDate, rounded) }
6940
- ]);
6941
- } else if (!isMilestone && rounded === 0) {
6942
- onTasksChange?.([
6943
- { ...task, type: "milestone", endDate: task.startDate }
6944
- ]);
6945
- } else if (!isMilestone && rounded > 0) {
6946
- onTasksChange?.([
6947
- { ...task, endDate: getEndDate(task.startDate, rounded) }
6948
- ]);
6949
- }
6986
+ emitDurationChange(rounded);
6950
6987
  setEditingColumnId(null);
6951
6988
  } else if (e.key === "Escape") {
6952
6989
  handleDurationCancel();
6953
6990
  }
6954
6991
  },
6955
- [durationValue, task, onTasksChange, handleDurationCancel, getEndDate, isMilestone]
6992
+ [durationValue, emitDurationChange, handleDurationCancel]
6956
6993
  );
6957
6994
  const handleProgressClick = useCallback5(
6958
6995
  (e) => {
@@ -8750,6 +8787,7 @@ var TaskList = ({
8750
8787
  headerHeight,
8751
8788
  taskListWidth,
8752
8789
  onTasksChange,
8790
+ onDurationChange,
8753
8791
  selectedTaskId,
8754
8792
  onTaskSelect,
8755
8793
  show = true,
@@ -9771,6 +9809,7 @@ var TaskList = ({
9771
9809
  taskNumberMap: originalTaskNumberMap,
9772
9810
  rowHeight,
9773
9811
  onTasksChange,
9812
+ onDurationChange,
9774
9813
  selectedTaskId,
9775
9814
  onRowClick: handleRowClick,
9776
9815
  disableTaskNameEditing,
@@ -13773,6 +13812,7 @@ function TaskGanttChartInner(props, ref) {
13773
13812
  headerHeight = 40,
13774
13813
  containerHeight,
13775
13814
  onTasksChange,
13815
+ onScheduleIntent,
13776
13816
  onValidateDependencies,
13777
13817
  enableAutoSchedule,
13778
13818
  disableConstraints,
@@ -14298,7 +14338,7 @@ function TaskGanttChartInner(props, ref) {
14298
14338
  }
14299
14339
  previewPositionStore.clear();
14300
14340
  }, [previewPositionStore]);
14301
- const handleTaskChange = useCallback10((updatedTasks) => {
14341
+ const handleTaskChange = useCallback10((updatedTasks, durationEdit) => {
14302
14342
  const updatedTask = updatedTasks[0];
14303
14343
  if (!updatedTask) return;
14304
14344
  const originalTask = tasks.find((t) => t.id === updatedTask.id);
@@ -14347,12 +14387,18 @@ function TaskGanttChartInner(props, ref) {
14347
14387
  const isUniformMove = deltaStart === deltaEnd && deltaStart !== 0;
14348
14388
  if (!isUniformMove) {
14349
14389
  const anchor = deltaStart === 0 ? "start" : deltaEnd === 0 ? "end" : "start";
14350
- const targetDuration = getTaskDuration(
14390
+ const targetDuration = durationEdit?.duration ?? getTaskDuration(
14351
14391
  anchor === "start" ? origStart : newStart,
14352
14392
  anchor === "start" ? newEnd : origEnd,
14353
14393
  businessDays,
14354
14394
  isCustomWeekend
14355
14395
  );
14396
+ onScheduleIntent?.({
14397
+ type: "change_duration",
14398
+ taskId: updatedTask.id,
14399
+ duration: targetDuration,
14400
+ anchor: durationEdit?.anchor ?? anchor
14401
+ });
14356
14402
  const scaleResult = scaleTaskSubtreeDuration(updatedTask.id, targetDuration, tasks, {
14357
14403
  anchor,
14358
14404
  businessDays,
@@ -14360,7 +14406,7 @@ function TaskGanttChartInner(props, ref) {
14360
14406
  externalDependencyPolicy: "cascade-successors"
14361
14407
  });
14362
14408
  onSubtreeScaleResult?.(scaleResult);
14363
- if (scaleResult.ok && scaleResult.changedTasks.length > 0) {
14409
+ if (!onScheduleIntent && scaleResult.ok && scaleResult.changedTasks.length > 0) {
14364
14410
  onTasksChange?.(scaleResult.changedTasks);
14365
14411
  }
14366
14412
  if (editingTaskId === updatedTask.id) {
@@ -14369,7 +14415,15 @@ function TaskGanttChartInner(props, ref) {
14369
14415
  return;
14370
14416
  }
14371
14417
  const movedParentCascade = disableConstraints ? [updatedTask] : universalCascade(updatedTask, newStart, newEnd, tasks, businessDays, isCustomWeekend);
14372
- onTasksChange?.(movedParentCascade);
14418
+ if (onScheduleIntent) {
14419
+ onScheduleIntent({
14420
+ type: "move_task",
14421
+ taskId: updatedTask.id,
14422
+ startDate: newStart.toISOString().split("T")[0]
14423
+ });
14424
+ } else {
14425
+ onTasksChange?.(movedParentCascade);
14426
+ }
14373
14427
  if (editingTaskId === updatedTask.id) {
14374
14428
  setEditingTaskId(null);
14375
14429
  }
@@ -14377,8 +14431,51 @@ function TaskGanttChartInner(props, ref) {
14377
14431
  }
14378
14432
  const sourceTasks = tasks.map((task) => task.id === updatedTask.id ? updatedTask : task);
14379
14433
  const cascadedTasks = disableConstraints ? [updatedTask] : universalCascade(updatedTask, newStart, newEnd, sourceTasks, businessDays, isCustomWeekend);
14380
- onTasksChange?.(cascadedTasks);
14381
- }, [tasks, onTasksChange, disableConstraints, editingTaskId, businessDays, isCustomWeekend, onSubtreeScaleResult]);
14434
+ if (durationEdit) {
14435
+ if (onScheduleIntent) {
14436
+ onScheduleIntent({
14437
+ type: "change_duration",
14438
+ taskId: updatedTask.id,
14439
+ duration: durationEdit.duration,
14440
+ anchor: durationEdit.anchor
14441
+ });
14442
+ } else {
14443
+ onTasksChange?.(cascadedTasks);
14444
+ }
14445
+ } else if (onScheduleIntent) {
14446
+ const startChanged = origStart.getTime() !== newStart.getTime();
14447
+ const endChanged = origEnd.getTime() !== newEnd.getTime();
14448
+ if (startChanged && endChanged) {
14449
+ onScheduleIntent({
14450
+ type: "move_task",
14451
+ taskId: updatedTask.id,
14452
+ startDate: newStart.toISOString().split("T")[0]
14453
+ });
14454
+ } else {
14455
+ const anchor = startChanged ? "end" : "start";
14456
+ onScheduleIntent({
14457
+ type: "resize_task",
14458
+ taskId: updatedTask.id,
14459
+ anchor,
14460
+ date: (startChanged ? newStart : newEnd).toISOString().split("T")[0]
14461
+ });
14462
+ }
14463
+ } else {
14464
+ onTasksChange?.(cascadedTasks);
14465
+ }
14466
+ }, [tasks, onTasksChange, onScheduleIntent, disableConstraints, editingTaskId, businessDays, isCustomWeekend, onSubtreeScaleResult]);
14467
+ const handleTaskDurationChange = useCallback10((task, duration) => {
14468
+ const updatedTask = {
14469
+ ...task,
14470
+ endDate: task.type === "milestone" ? task.startDate : buildTaskRangeFromStart(
14471
+ parseUTCDate(task.startDate),
14472
+ duration,
14473
+ businessDays,
14474
+ isCustomWeekend
14475
+ ).end.toISOString()
14476
+ };
14477
+ handleTaskChange([updatedTask], { duration, anchor: "start" });
14478
+ }, [businessDays, handleTaskChange, isCustomWeekend]);
14382
14479
  const handleDelete = useCallback10((taskId) => {
14383
14480
  const toDelete = /* @__PURE__ */ new Set([taskId]);
14384
14481
  function collectDescendants(parentId) {
@@ -14526,8 +14623,10 @@ function TaskGanttChartInner(props, ref) {
14526
14623
  [renderedChartTasks]
14527
14624
  );
14528
14625
  const handleCascade = useCallback10((cascadedTasks) => {
14529
- onTasksChange?.(cascadedTasks);
14530
- }, [tasks, onTasksChange]);
14626
+ if (!onScheduleIntent) {
14627
+ onTasksChange?.(cascadedTasks);
14628
+ }
14629
+ }, [onScheduleIntent, onTasksChange]);
14531
14630
  const handleTaskSelect = useCallback10((taskId) => {
14532
14631
  setSelectedTaskId(taskId);
14533
14632
  }, []);
@@ -14862,6 +14961,7 @@ function TaskGanttChartInner(props, ref) {
14862
14961
  headerHeight,
14863
14962
  taskListWidth,
14864
14963
  onTasksChange: handleTaskChange,
14964
+ onDurationChange: handleTaskDurationChange,
14865
14965
  selectedTaskId: selectedTaskId ?? void 0,
14866
14966
  onTaskSelect: handleTaskSelect,
14867
14967
  show: showTaskList,
@@ -15167,6 +15267,7 @@ function TaskGanttChartInner(props, ref) {
15167
15267
  previewPositionStore,
15168
15268
  onCascadeProgress: handleCascadeProgress,
15169
15269
  onCascade: handleCascade,
15270
+ onScheduleIntent,
15170
15271
  highlightExpiredTasks,
15171
15272
  showBaseline,
15172
15273
  isFilterMatch: (filterMode === "highlight" ? matchedTaskIds.has(task.id) : false) || (criticalPathMode === "highlight" ? criticalTaskIds.has(task.id) : false),