gantt-task-react-v 1.3.5 → 1.4.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.
@@ -4688,9 +4688,9 @@ const getStartAndEnd = (containerEl, property, cellSize) => {
4688
4688
  const scrollValue = property === "scrollLeft" ? el.scrollLeft : el.scrollTop;
4689
4689
  const maxScrollValue = property === "scrollLeft" ? el.scrollWidth : el.scrollHeight;
4690
4690
  const fullValue = property === "scrollLeft" ? el.clientWidth : el.clientHeight;
4691
- const firstIndex = Math.max(0, Math.floor(scrollValue / cellSize));
4692
4691
  const visibleCount = Math.max(1, Math.ceil(fullValue / cellSize));
4693
4692
  const overscan = Math.min(100, Math.max(10, Math.ceil(visibleCount * 0.5)));
4693
+ const firstIndex = Math.max(0, Math.floor(scrollValue / cellSize) - overscan);
4694
4694
  const lastIndex = Math.floor((scrollValue + fullValue) / cellSize) + overscan;
4695
4695
  const isStartOfScroll = scrollValue < DELTA;
4696
4696
  const isEndOfScroll = scrollValue + fullValue > maxScrollValue - DELTA;
@@ -5536,6 +5536,37 @@ const TaskListTableHeadersDefaultInner = ({
5536
5536
  canMoveTasks,
5537
5537
  onColumnResizeStart
5538
5538
  }) => {
5539
+ const pinnedStyles = useMemo(() => {
5540
+ const result = {};
5541
+ let leftOffset = 0;
5542
+ if (canMoveTasks) {
5543
+ leftOffset = 24;
5544
+ }
5545
+ for (let i = 0; i < columns.length; i++) {
5546
+ if (columns[i].pinned === "left") {
5547
+ result[i] = {
5548
+ position: "sticky",
5549
+ left: leftOffset,
5550
+ zIndex: 2,
5551
+ backgroundColor: "var(--gantt-table-header-background-color, #fff)"
5552
+ };
5553
+ leftOffset += columns[i].width;
5554
+ }
5555
+ }
5556
+ let rightOffset = 0;
5557
+ for (let i = columns.length - 1; i >= 0; i--) {
5558
+ if (columns[i].pinned === "right") {
5559
+ result[i] = {
5560
+ position: "sticky",
5561
+ right: rightOffset,
5562
+ zIndex: 2,
5563
+ backgroundColor: "var(--gantt-table-header-background-color, #fff)"
5564
+ };
5565
+ rightOffset += columns[i].width;
5566
+ }
5567
+ }
5568
+ return result;
5569
+ }, [columns, canMoveTasks]);
5539
5570
  return /* @__PURE__ */ jsx(
5540
5571
  "div",
5541
5572
  {
@@ -5572,7 +5603,8 @@ const TaskListTableHeadersDefaultInner = ({
5572
5603
  className: styles$h.ganttTable_HeaderItem,
5573
5604
  style: {
5574
5605
  minWidth: width,
5575
- maxWidth: width
5606
+ maxWidth: width,
5607
+ ...pinnedStyles[index2]
5576
5608
  },
5577
5609
  children: [
5578
5610
  title,
@@ -10135,6 +10167,37 @@ const TaskListTableRowInner = forwardRef(
10135
10167
  }
10136
10168
  return classNames.join(" ");
10137
10169
  }, [isCut2, moveOverPosition, isOverlay2, isDragging]);
10170
+ const pinnedStyles = useMemo(() => {
10171
+ const result = {};
10172
+ let leftOffset = 0;
10173
+ if (moveHandleProps || !isOverlay2 && task.type !== "project" && task.id !== "no-project-asigned") {
10174
+ leftOffset = 24;
10175
+ }
10176
+ for (let i = 0; i < columns.length; i++) {
10177
+ if (columns[i].pinned === "left") {
10178
+ result[i] = {
10179
+ position: "sticky",
10180
+ left: leftOffset,
10181
+ zIndex: 1,
10182
+ backgroundColor: "inherit"
10183
+ };
10184
+ leftOffset += columns[i].width;
10185
+ }
10186
+ }
10187
+ let rightOffset = 0;
10188
+ for (let i = columns.length - 1; i >= 0; i--) {
10189
+ if (columns[i].pinned === "right") {
10190
+ result[i] = {
10191
+ position: "sticky",
10192
+ right: rightOffset,
10193
+ zIndex: 1,
10194
+ backgroundColor: "inherit"
10195
+ };
10196
+ rightOffset += columns[i].width;
10197
+ }
10198
+ }
10199
+ return result;
10200
+ }, [columns, moveHandleProps, isOverlay2, task.type, task.id]);
10138
10201
  return /* @__PURE__ */ jsxs(
10139
10202
  "div",
10140
10203
  {
@@ -10156,7 +10219,8 @@ const TaskListTableRowInner = forwardRef(
10156
10219
  className: styles$f.taskListCell,
10157
10220
  style: {
10158
10221
  minWidth: width,
10159
- maxWidth: width
10222
+ maxWidth: width,
10223
+ ...pinnedStyles[index2]
10160
10224
  },
10161
10225
  children: /* @__PURE__ */ jsx(Component, { data: columnData })
10162
10226
  },
@@ -13168,47 +13232,40 @@ const TaskGanttContentInner = (props) => {
13168
13232
  )
13169
13233
  );
13170
13234
  if (task.comparisonDates && comparisonDates) {
13171
- console.log(`Comparison bar for task ${task.id}:`, {
13172
- originalCoords: comparisonDates,
13173
- taskComparisonDates: task.comparisonDates
13174
- });
13175
13235
  const safeComparisonX = isNaN(comparisonDates.x) || !isFinite(comparisonDates.x) ? 0 : comparisonDates.x;
13176
- const safeComparisonWidth = isNaN(comparisonDates.width) || !isFinite(comparisonDates.width) ? 10 : Math.max(comparisonDates.width, 3);
13177
- const safeComparisonHeight = isNaN(comparisonDates.height) || !isFinite(comparisonDates.height) ? 6 : Math.max(comparisonDates.height, 3);
13178
- const comparisonRight = safeComparisonX + safeComparisonWidth;
13179
- const isVisible = comparisonRight >= 0 && safeComparisonX <= 1e4;
13180
- if (isVisible) {
13181
- tasksRes.push(
13182
- /* @__PURE__ */ jsx(
13183
- "svg",
13184
- {
13185
- id: task.id + "_comparison",
13186
- className: "TaskItemWrapperComparison",
13187
- x: Math.max(safeComparisonX + (additionalLeftSpace || 0), 0),
13188
- y: safeLevelY + taskHeight + 2,
13189
- width: safeComparisonWidth,
13190
- height: safeComparisonHeight,
13191
- children: /* @__PURE__ */ jsx(
13192
- BarComparison,
13193
- {
13194
- inProgress: !task.comparisonDates.end,
13195
- isPlan: task.comparisonDates.start.getTime() >= task.start.getTime() && !!task.comparisonDates.end && task.comparisonDates.end.getTime() <= task.end.getTime() || task.comparisonDates.start.getTime() <= task.start.getTime() && !!task.comparisonDates.end && task.comparisonDates.end.getTime() <= task.start.getTime(),
13196
- isWarning: !!task.comparisonDates.end && task.comparisonDates.end.getTime() >= task.end.getTime(),
13197
- isCritical: task.comparisonDates.start.getTime() > task.start.getTime(),
13198
- barCornerRadius: distances.barCornerRadius,
13199
- height: safeComparisonHeight,
13200
- width: safeComparisonWidth,
13201
- borderHeight: distances.barComparisonTaskBorderHeight,
13202
- yOffset: distances.barComparisonTaskYOffset,
13203
- task,
13204
- onTooltipTask
13205
- }
13206
- )
13207
- },
13208
- key2 + "_comparison"
13209
- )
13210
- );
13211
- }
13236
+ const safeComparisonY = isNaN(comparisonDates.y) || !isFinite(comparisonDates.y) ? safeLevelY : comparisonDates.y;
13237
+ const safeComparisonWidth = isNaN(comparisonDates.width) || !isFinite(comparisonDates.width) ? 0 : Math.max(comparisonDates.width, 0);
13238
+ const safeComparisonHeight = isNaN(comparisonDates.height) || !isFinite(comparisonDates.height) ? 0 : Math.max(comparisonDates.height, 0);
13239
+ tasksRes.push(
13240
+ /* @__PURE__ */ jsx(
13241
+ "svg",
13242
+ {
13243
+ id: task.id + "_comparison",
13244
+ className: "TaskItemWrapperComparison",
13245
+ x: Math.max(safeComparisonX + (additionalLeftSpace || 0), 0),
13246
+ y: safeComparisonY,
13247
+ width: safeComparisonWidth,
13248
+ height: safeComparisonHeight * 2,
13249
+ children: /* @__PURE__ */ jsx(
13250
+ BarComparison,
13251
+ {
13252
+ inProgress: !task.comparisonDates.end,
13253
+ isPlan: task.comparisonDates.start.getTime() >= task.start.getTime() && !!task.comparisonDates.end && task.comparisonDates.end.getTime() <= task.end.getTime() || task.comparisonDates.start.getTime() <= task.start.getTime() && !!task.comparisonDates.end && task.comparisonDates.end.getTime() <= task.start.getTime(),
13254
+ isWarning: !!task.comparisonDates.end && task.comparisonDates.end.getTime() >= task.end.getTime(),
13255
+ isCritical: task.comparisonDates.start.getTime() > task.start.getTime(),
13256
+ barCornerRadius: distances.barCornerRadius,
13257
+ height: safeComparisonHeight,
13258
+ width: safeComparisonWidth,
13259
+ borderHeight: distances.barComparisonTaskBorderHeight,
13260
+ yOffset: distances.barComparisonTaskYOffset,
13261
+ task,
13262
+ onTooltipTask
13263
+ }
13264
+ )
13265
+ },
13266
+ key2 + "_comparison"
13267
+ )
13268
+ );
13212
13269
  }
13213
13270
  const addedDependenciesAtLevel = addedDependencies[comparisonLevel] || {};
13214
13271
  if (!addedDependencies[comparisonLevel]) {
@@ -13867,12 +13924,10 @@ const countTaskCoordinates = (task, taskToRowIndexMap, startDate, viewMode, rtl,
13867
13924
  );
13868
13925
  cx1 = isNaN(cx1) || !isFinite(cx1) ? x1 : cx1;
13869
13926
  cx2 = isNaN(cx2) || !isFinite(cx2) ? x2 : cx2;
13870
- const comparisonWidth = Math.max(Math.abs(cx2 - cx1), 3);
13871
- const comparisonX = Math.min(cx1, cx2);
13872
13927
  comparisonDates = {
13873
- x: comparisonX,
13928
+ x: cx1,
13874
13929
  y: y + taskHeight,
13875
- width: comparisonWidth,
13930
+ width: Math.max(cx2 - cx1, 0),
13876
13931
  height: barComparisonTaskHeight
13877
13932
  };
13878
13933
  }
@@ -19066,7 +19121,8 @@ const Gantt = (props) => {
19066
19121
  todayLabel = "Today",
19067
19122
  dataDateLabel = "Data Date",
19068
19123
  showProgress = true,
19069
- progressColor
19124
+ progressColor,
19125
+ scrollToTaskId
19070
19126
  } = props;
19071
19127
  const ganttSVGRef = useRef(null);
19072
19128
  const wrapperRef = useRef(null);
@@ -19374,6 +19430,44 @@ const Gantt = (props) => {
19374
19430
  },
19375
19431
  [mapTaskToCoordinates, setScrollXProgrammatically]
19376
19432
  );
19433
+ const prevScrollToTaskIdRef = useRef(void 0);
19434
+ useEffect(() => {
19435
+ if (!scrollToTaskId || scrollToTaskId === prevScrollToTaskIdRef.current) {
19436
+ return;
19437
+ }
19438
+ prevScrollToTaskIdRef.current = scrollToTaskId;
19439
+ for (const [comparisonLevel, levelMap] of tasksMap) {
19440
+ const task = levelMap.get(scrollToTaskId);
19441
+ if (!task || task.type === "empty") {
19442
+ continue;
19443
+ }
19444
+ const { x1 } = getTaskCoordinates(task, mapTaskToCoordinates);
19445
+ setScrollXProgrammatically(Math.max(0, x1 - 100));
19446
+ const rowIndexMap = taskToRowIndexMap.get(comparisonLevel);
19447
+ if (rowIndexMap) {
19448
+ const rowIndex = rowIndexMap.get(scrollToTaskId);
19449
+ if (typeof rowIndex === "number") {
19450
+ const targetScrollY = rowIndex * fullRowHeight - ganttHeight / 2 + fullRowHeight / 2;
19451
+ setScrollYProgrammatically(
19452
+ Math.max(0, Math.min(targetScrollY, ganttFullHeight - ganttHeight))
19453
+ );
19454
+ }
19455
+ }
19456
+ selectTask(scrollToTaskId);
19457
+ break;
19458
+ }
19459
+ }, [
19460
+ scrollToTaskId,
19461
+ tasksMap,
19462
+ mapTaskToCoordinates,
19463
+ taskToRowIndexMap,
19464
+ fullRowHeight,
19465
+ ganttHeight,
19466
+ ganttFullHeight,
19467
+ setScrollXProgrammatically,
19468
+ setScrollYProgrammatically,
19469
+ selectTask
19470
+ ]);
19377
19471
  const { contextMenu, handleCloseContextMenu, handleOpenContextMenu } = useContextMenu(wrapperRef, scrollToTask);
19378
19472
  const [ganttContextMenu, setGanttContextMenu] = useState({
19379
19473
  task: null,
@@ -4705,9 +4705,9 @@
4705
4705
  const scrollValue = property === "scrollLeft" ? el.scrollLeft : el.scrollTop;
4706
4706
  const maxScrollValue = property === "scrollLeft" ? el.scrollWidth : el.scrollHeight;
4707
4707
  const fullValue = property === "scrollLeft" ? el.clientWidth : el.clientHeight;
4708
- const firstIndex = Math.max(0, Math.floor(scrollValue / cellSize));
4709
4708
  const visibleCount = Math.max(1, Math.ceil(fullValue / cellSize));
4710
4709
  const overscan = Math.min(100, Math.max(10, Math.ceil(visibleCount * 0.5)));
4710
+ const firstIndex = Math.max(0, Math.floor(scrollValue / cellSize) - overscan);
4711
4711
  const lastIndex = Math.floor((scrollValue + fullValue) / cellSize) + overscan;
4712
4712
  const isStartOfScroll = scrollValue < DELTA;
4713
4713
  const isEndOfScroll = scrollValue + fullValue > maxScrollValue - DELTA;
@@ -5553,6 +5553,37 @@
5553
5553
  canMoveTasks,
5554
5554
  onColumnResizeStart
5555
5555
  }) => {
5556
+ const pinnedStyles = React.useMemo(() => {
5557
+ const result = {};
5558
+ let leftOffset = 0;
5559
+ if (canMoveTasks) {
5560
+ leftOffset = 24;
5561
+ }
5562
+ for (let i = 0; i < columns.length; i++) {
5563
+ if (columns[i].pinned === "left") {
5564
+ result[i] = {
5565
+ position: "sticky",
5566
+ left: leftOffset,
5567
+ zIndex: 2,
5568
+ backgroundColor: "var(--gantt-table-header-background-color, #fff)"
5569
+ };
5570
+ leftOffset += columns[i].width;
5571
+ }
5572
+ }
5573
+ let rightOffset = 0;
5574
+ for (let i = columns.length - 1; i >= 0; i--) {
5575
+ if (columns[i].pinned === "right") {
5576
+ result[i] = {
5577
+ position: "sticky",
5578
+ right: rightOffset,
5579
+ zIndex: 2,
5580
+ backgroundColor: "var(--gantt-table-header-background-color, #fff)"
5581
+ };
5582
+ rightOffset += columns[i].width;
5583
+ }
5584
+ }
5585
+ return result;
5586
+ }, [columns, canMoveTasks]);
5556
5587
  return /* @__PURE__ */ jsxRuntime.jsx(
5557
5588
  "div",
5558
5589
  {
@@ -5589,7 +5620,8 @@
5589
5620
  className: styles$h.ganttTable_HeaderItem,
5590
5621
  style: {
5591
5622
  minWidth: width,
5592
- maxWidth: width
5623
+ maxWidth: width,
5624
+ ...pinnedStyles[index2]
5593
5625
  },
5594
5626
  children: [
5595
5627
  title,
@@ -10152,6 +10184,37 @@
10152
10184
  }
10153
10185
  return classNames.join(" ");
10154
10186
  }, [isCut2, moveOverPosition, isOverlay2, isDragging]);
10187
+ const pinnedStyles = React.useMemo(() => {
10188
+ const result = {};
10189
+ let leftOffset = 0;
10190
+ if (moveHandleProps || !isOverlay2 && task.type !== "project" && task.id !== "no-project-asigned") {
10191
+ leftOffset = 24;
10192
+ }
10193
+ for (let i = 0; i < columns.length; i++) {
10194
+ if (columns[i].pinned === "left") {
10195
+ result[i] = {
10196
+ position: "sticky",
10197
+ left: leftOffset,
10198
+ zIndex: 1,
10199
+ backgroundColor: "inherit"
10200
+ };
10201
+ leftOffset += columns[i].width;
10202
+ }
10203
+ }
10204
+ let rightOffset = 0;
10205
+ for (let i = columns.length - 1; i >= 0; i--) {
10206
+ if (columns[i].pinned === "right") {
10207
+ result[i] = {
10208
+ position: "sticky",
10209
+ right: rightOffset,
10210
+ zIndex: 1,
10211
+ backgroundColor: "inherit"
10212
+ };
10213
+ rightOffset += columns[i].width;
10214
+ }
10215
+ }
10216
+ return result;
10217
+ }, [columns, moveHandleProps, isOverlay2, task.type, task.id]);
10155
10218
  return /* @__PURE__ */ jsxRuntime.jsxs(
10156
10219
  "div",
10157
10220
  {
@@ -10173,7 +10236,8 @@
10173
10236
  className: styles$f.taskListCell,
10174
10237
  style: {
10175
10238
  minWidth: width,
10176
- maxWidth: width
10239
+ maxWidth: width,
10240
+ ...pinnedStyles[index2]
10177
10241
  },
10178
10242
  children: /* @__PURE__ */ jsxRuntime.jsx(Component, { data: columnData })
10179
10243
  },
@@ -13185,47 +13249,40 @@
13185
13249
  )
13186
13250
  );
13187
13251
  if (task.comparisonDates && comparisonDates) {
13188
- console.log(`Comparison bar for task ${task.id}:`, {
13189
- originalCoords: comparisonDates,
13190
- taskComparisonDates: task.comparisonDates
13191
- });
13192
13252
  const safeComparisonX = isNaN(comparisonDates.x) || !isFinite(comparisonDates.x) ? 0 : comparisonDates.x;
13193
- const safeComparisonWidth = isNaN(comparisonDates.width) || !isFinite(comparisonDates.width) ? 10 : Math.max(comparisonDates.width, 3);
13194
- const safeComparisonHeight = isNaN(comparisonDates.height) || !isFinite(comparisonDates.height) ? 6 : Math.max(comparisonDates.height, 3);
13195
- const comparisonRight = safeComparisonX + safeComparisonWidth;
13196
- const isVisible = comparisonRight >= 0 && safeComparisonX <= 1e4;
13197
- if (isVisible) {
13198
- tasksRes.push(
13199
- /* @__PURE__ */ jsxRuntime.jsx(
13200
- "svg",
13201
- {
13202
- id: task.id + "_comparison",
13203
- className: "TaskItemWrapperComparison",
13204
- x: Math.max(safeComparisonX + (additionalLeftSpace || 0), 0),
13205
- y: safeLevelY + taskHeight + 2,
13206
- width: safeComparisonWidth,
13207
- height: safeComparisonHeight,
13208
- children: /* @__PURE__ */ jsxRuntime.jsx(
13209
- BarComparison,
13210
- {
13211
- inProgress: !task.comparisonDates.end,
13212
- isPlan: task.comparisonDates.start.getTime() >= task.start.getTime() && !!task.comparisonDates.end && task.comparisonDates.end.getTime() <= task.end.getTime() || task.comparisonDates.start.getTime() <= task.start.getTime() && !!task.comparisonDates.end && task.comparisonDates.end.getTime() <= task.start.getTime(),
13213
- isWarning: !!task.comparisonDates.end && task.comparisonDates.end.getTime() >= task.end.getTime(),
13214
- isCritical: task.comparisonDates.start.getTime() > task.start.getTime(),
13215
- barCornerRadius: distances.barCornerRadius,
13216
- height: safeComparisonHeight,
13217
- width: safeComparisonWidth,
13218
- borderHeight: distances.barComparisonTaskBorderHeight,
13219
- yOffset: distances.barComparisonTaskYOffset,
13220
- task,
13221
- onTooltipTask
13222
- }
13223
- )
13224
- },
13225
- key2 + "_comparison"
13226
- )
13227
- );
13228
- }
13253
+ const safeComparisonY = isNaN(comparisonDates.y) || !isFinite(comparisonDates.y) ? safeLevelY : comparisonDates.y;
13254
+ const safeComparisonWidth = isNaN(comparisonDates.width) || !isFinite(comparisonDates.width) ? 0 : Math.max(comparisonDates.width, 0);
13255
+ const safeComparisonHeight = isNaN(comparisonDates.height) || !isFinite(comparisonDates.height) ? 0 : Math.max(comparisonDates.height, 0);
13256
+ tasksRes.push(
13257
+ /* @__PURE__ */ jsxRuntime.jsx(
13258
+ "svg",
13259
+ {
13260
+ id: task.id + "_comparison",
13261
+ className: "TaskItemWrapperComparison",
13262
+ x: Math.max(safeComparisonX + (additionalLeftSpace || 0), 0),
13263
+ y: safeComparisonY,
13264
+ width: safeComparisonWidth,
13265
+ height: safeComparisonHeight * 2,
13266
+ children: /* @__PURE__ */ jsxRuntime.jsx(
13267
+ BarComparison,
13268
+ {
13269
+ inProgress: !task.comparisonDates.end,
13270
+ isPlan: task.comparisonDates.start.getTime() >= task.start.getTime() && !!task.comparisonDates.end && task.comparisonDates.end.getTime() <= task.end.getTime() || task.comparisonDates.start.getTime() <= task.start.getTime() && !!task.comparisonDates.end && task.comparisonDates.end.getTime() <= task.start.getTime(),
13271
+ isWarning: !!task.comparisonDates.end && task.comparisonDates.end.getTime() >= task.end.getTime(),
13272
+ isCritical: task.comparisonDates.start.getTime() > task.start.getTime(),
13273
+ barCornerRadius: distances.barCornerRadius,
13274
+ height: safeComparisonHeight,
13275
+ width: safeComparisonWidth,
13276
+ borderHeight: distances.barComparisonTaskBorderHeight,
13277
+ yOffset: distances.barComparisonTaskYOffset,
13278
+ task,
13279
+ onTooltipTask
13280
+ }
13281
+ )
13282
+ },
13283
+ key2 + "_comparison"
13284
+ )
13285
+ );
13229
13286
  }
13230
13287
  const addedDependenciesAtLevel = addedDependencies[comparisonLevel] || {};
13231
13288
  if (!addedDependencies[comparisonLevel]) {
@@ -13884,12 +13941,10 @@
13884
13941
  );
13885
13942
  cx1 = isNaN(cx1) || !isFinite(cx1) ? x1 : cx1;
13886
13943
  cx2 = isNaN(cx2) || !isFinite(cx2) ? x2 : cx2;
13887
- const comparisonWidth = Math.max(Math.abs(cx2 - cx1), 3);
13888
- const comparisonX = Math.min(cx1, cx2);
13889
13944
  comparisonDates = {
13890
- x: comparisonX,
13945
+ x: cx1,
13891
13946
  y: y + taskHeight,
13892
- width: comparisonWidth,
13947
+ width: Math.max(cx2 - cx1, 0),
13893
13948
  height: barComparisonTaskHeight
13894
13949
  };
13895
13950
  }
@@ -19083,7 +19138,8 @@
19083
19138
  todayLabel = "Today",
19084
19139
  dataDateLabel = "Data Date",
19085
19140
  showProgress = true,
19086
- progressColor
19141
+ progressColor,
19142
+ scrollToTaskId
19087
19143
  } = props;
19088
19144
  const ganttSVGRef = React.useRef(null);
19089
19145
  const wrapperRef = React.useRef(null);
@@ -19391,6 +19447,44 @@
19391
19447
  },
19392
19448
  [mapTaskToCoordinates, setScrollXProgrammatically]
19393
19449
  );
19450
+ const prevScrollToTaskIdRef = React.useRef(void 0);
19451
+ React.useEffect(() => {
19452
+ if (!scrollToTaskId || scrollToTaskId === prevScrollToTaskIdRef.current) {
19453
+ return;
19454
+ }
19455
+ prevScrollToTaskIdRef.current = scrollToTaskId;
19456
+ for (const [comparisonLevel, levelMap] of tasksMap) {
19457
+ const task = levelMap.get(scrollToTaskId);
19458
+ if (!task || task.type === "empty") {
19459
+ continue;
19460
+ }
19461
+ const { x1 } = getTaskCoordinates(task, mapTaskToCoordinates);
19462
+ setScrollXProgrammatically(Math.max(0, x1 - 100));
19463
+ const rowIndexMap = taskToRowIndexMap.get(comparisonLevel);
19464
+ if (rowIndexMap) {
19465
+ const rowIndex = rowIndexMap.get(scrollToTaskId);
19466
+ if (typeof rowIndex === "number") {
19467
+ const targetScrollY = rowIndex * fullRowHeight - ganttHeight / 2 + fullRowHeight / 2;
19468
+ setScrollYProgrammatically(
19469
+ Math.max(0, Math.min(targetScrollY, ganttFullHeight - ganttHeight))
19470
+ );
19471
+ }
19472
+ }
19473
+ selectTask(scrollToTaskId);
19474
+ break;
19475
+ }
19476
+ }, [
19477
+ scrollToTaskId,
19478
+ tasksMap,
19479
+ mapTaskToCoordinates,
19480
+ taskToRowIndexMap,
19481
+ fullRowHeight,
19482
+ ganttHeight,
19483
+ ganttFullHeight,
19484
+ setScrollXProgrammatically,
19485
+ setScrollYProgrammatically,
19486
+ selectTask
19487
+ ]);
19394
19488
  const { contextMenu, handleCloseContextMenu, handleOpenContextMenu } = useContextMenu(wrapperRef, scrollToTask);
19395
19489
  const [ganttContextMenu, setGanttContextMenu] = React.useState({
19396
19490
  task: null,
@@ -368,6 +368,11 @@ export interface GanttProps {
368
368
  * Custom color for progress bars. If not provided, theme progress colors are used.
369
369
  */
370
370
  progressColor?: string;
371
+ /**
372
+ * When set (or changed), the gantt will scroll to reveal and select this task.
373
+ * Set to a task id to scroll both horizontally and vertically to that task.
374
+ */
375
+ scrollToTaskId?: TaskId;
371
376
  }
372
377
  export interface GanttTaskBarActions {
373
378
  allowMoveTaskBar?: (action: TaskBarMoveAction, task: RenderTask) => boolean;
@@ -397,6 +402,11 @@ export type Column = {
397
402
  width: number;
398
403
  title?: ReactNode;
399
404
  canResize?: boolean;
405
+ /**
406
+ * Pin column to the left or right side of the table.
407
+ * Pinned columns stay visible while scrolling horizontally.
408
+ */
409
+ pinned?: "left" | "right";
400
410
  };
401
411
  export type OnResizeColumn = (nextColumns: readonly Column[], columnIndex: number, deltaWidth: number) => void;
402
412
  export type ChangeAction = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gantt-task-react-v",
3
- "version": "1.3.5",
3
+ "version": "1.4.0",
4
4
  "description": "Interactive Gantt Chart for React with TypeScript.",
5
5
  "author": "aguilanbon",
6
6
  "homepage": "https://github.com/aguilanbon/gantt-task-react-v",