gantt-lib 0.91.0 → 0.101.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
@@ -3,7 +3,7 @@
3
3
  "use client";
4
4
 
5
5
  // src/components/GanttChart/GanttChart.tsx
6
- import { useMemo as useMemo10, useCallback as useCallback8, useRef as useRef9, useState as useState9, useEffect as useEffect9, useImperativeHandle, forwardRef } from "react";
6
+ import { useMemo as useMemo11, useCallback as useCallback8, useRef as useRef9, useState as useState9, useEffect as useEffect9, useImperativeHandle, forwardRef } from "react";
7
7
 
8
8
  // src/core/scheduling/dateMath.ts
9
9
  var DAY_MS = 24 * 60 * 60 * 1e3;
@@ -4729,11 +4729,15 @@ var TaskListRow = React9.memo(
4729
4729
  resolvedColumns,
4730
4730
  isTaskSelected = false,
4731
4731
  onTaskSelectionChange,
4732
+ activeCustomCell,
4733
+ onActiveCustomCellChange,
4732
4734
  taskListMenuCommands = [],
4735
+ hideTaskListRowActions = false,
4733
4736
  taskDateChangeMode = "preserve-duration",
4734
4737
  onTaskDateChangeModeChange
4735
4738
  }) => {
4736
4739
  const [editingColumnId, setEditingColumnId] = useState4(null);
4740
+ const [editingColumnStartValue, setEditingColumnStartValue] = useState4(void 0);
4737
4741
  const editingName = editingColumnId === "name";
4738
4742
  const editingDuration = editingColumnId === "duration";
4739
4743
  const editingProgress = editingColumnId === "progress";
@@ -4759,12 +4763,15 @@ var TaskListRow = React9.memo(
4759
4763
  const editTriggerRef = useRef4(
4760
4764
  "doubleclick"
4761
4765
  );
4766
+ const rowRef = useRef4(null);
4762
4767
  const isSelected = selectedTaskId === task.id;
4763
4768
  const isParent = useMemo7(
4764
4769
  () => isTaskParent(task.id, allTasks),
4765
4770
  [task.id, allTasks]
4766
4771
  );
4767
4772
  const isChild = task.parentId !== void 0;
4773
+ const rowFillLevel = Math.min(nestingDepth, 2);
4774
+ const isTotalRow = Boolean(task.isTotal);
4768
4775
  const isMilestoneRow = normalizedTask.type === "milestone";
4769
4776
  const weekendPredicate = useMemo7(
4770
4777
  () => createCustomDayPredicate({ customDays, isWeekend: isWeekend3 }),
@@ -5311,7 +5318,7 @@ var TaskListRow = React9.memo(
5311
5318
  ),
5312
5319
  [taskListMenuCommands, task, isParent, isMilestoneRow]
5313
5320
  );
5314
- const hasContextMenu = visibleCustomMenuCommands.length > 0 || !!onDuplicateTask || !!onDelete || !!onTasksChange || isParent && !!onUngroupTask;
5321
+ const hasContextMenu = !hideTaskListRowActions && (visibleCustomMenuCommands.length > 0 || !!onDuplicateTask || !!onDelete || !!onTasksChange || isParent && !!onUngroupTask);
5315
5322
  const handleCustomMenuCommandClick = useCallback4(
5316
5323
  (command) => (e) => {
5317
5324
  e.stopPropagation();
@@ -5550,14 +5557,14 @@ var TaskListRow = React9.memo(
5550
5557
  className: "gantt-tl-cell gantt-tl-cell-number",
5551
5558
  onClick: handleNumberClick,
5552
5559
  children: [
5553
- /* @__PURE__ */ jsx12(
5560
+ onDragStart && /* @__PURE__ */ jsx12(
5554
5561
  "span",
5555
5562
  {
5556
5563
  className: "gantt-tl-drag-handle",
5557
5564
  draggable: true,
5558
5565
  onDragStart: (e) => {
5559
5566
  e.stopPropagation();
5560
- onDragStart?.(rowIndex, e);
5567
+ onDragStart(rowIndex, e);
5561
5568
  },
5562
5569
  onDragEnd: (e) => onDragEnd?.(e),
5563
5570
  onClick: (e) => e.stopPropagation(),
@@ -5753,7 +5760,7 @@ var TaskListRow = React9.memo(
5753
5760
  "aria-hidden": "true"
5754
5761
  }
5755
5762
  ),
5756
- !editingName && (onInsertAfter || onDelete || onPromoteTask || onDemoteTask || onUngroupTask || onDuplicateTask || onTasksChange || hasContextMenu) && /* @__PURE__ */ jsxs9("div", { className: `gantt-tl-name-actions${contextMenuOpen ? " gantt-tl-name-actions-open" : ""}`, children: [
5763
+ !editingName && !hideTaskListRowActions && (onInsertAfter || onDelete || onPromoteTask || onDemoteTask || onUngroupTask || onDuplicateTask || onTasksChange || hasContextMenu) && /* @__PURE__ */ jsxs9("div", { className: `gantt-tl-name-actions${contextMenuOpen ? " gantt-tl-name-actions-open" : ""}`, children: [
5757
5764
  onInsertAfter && /* @__PURE__ */ jsx12(
5758
5765
  "button",
5759
5766
  {
@@ -6272,9 +6279,52 @@ var TaskListRow = React9.memo(
6272
6279
  progress: progressCell,
6273
6280
  dependencies: dependenciesCell
6274
6281
  };
6282
+ const focusCustomCell = useCallback4((taskId, columnId) => {
6283
+ const overlay = rowRef.current?.closest(".gantt-tl-overlay");
6284
+ if (!overlay) {
6285
+ return;
6286
+ }
6287
+ const selector = `[data-gantt-task-row-id="${taskId}"] [data-custom-column-id="${columnId}"]`;
6288
+ const nextCell = overlay.querySelector(selector);
6289
+ nextCell?.focus();
6290
+ }, []);
6291
+ const moveActiveCustomCell = useCallback4((columnId, direction) => {
6292
+ const overlay = rowRef.current?.closest(".gantt-tl-overlay");
6293
+ if (!overlay || !resolvedColumns) {
6294
+ return;
6295
+ }
6296
+ const customColumnIds = resolvedColumns.filter((column) => !["selection", "number", "name", "startDate", "endDate", "duration", "progress", "dependencies"].includes(column.id)).map((column) => column.id);
6297
+ const columnIndex = customColumnIds.indexOf(columnId);
6298
+ if (columnIndex === -1) {
6299
+ return;
6300
+ }
6301
+ const rowElements = Array.from(
6302
+ overlay.querySelectorAll(".gantt-tl-row[data-gantt-task-row-id]")
6303
+ );
6304
+ const rowIds = rowElements.map((element) => element.dataset.ganttTaskRowId).filter((value) => Boolean(value));
6305
+ const rowIndex2 = rowIds.indexOf(task.id);
6306
+ if (rowIndex2 === -1) {
6307
+ return;
6308
+ }
6309
+ let nextRowIndex = rowIndex2;
6310
+ let nextColumnIndex = columnIndex;
6311
+ if (direction === "left") nextColumnIndex -= 1;
6312
+ if (direction === "right") nextColumnIndex += 1;
6313
+ if (direction === "up") nextRowIndex -= 1;
6314
+ if (direction === "down") nextRowIndex += 1;
6315
+ if (nextRowIndex < 0 || nextRowIndex >= rowIds.length || nextColumnIndex < 0 || nextColumnIndex >= customColumnIds.length) {
6316
+ return;
6317
+ }
6318
+ const nextCell = { taskId: rowIds[nextRowIndex], columnId: customColumnIds[nextColumnIndex] };
6319
+ onActiveCustomCellChange?.(nextCell);
6320
+ window.requestAnimationFrame(() => {
6321
+ focusCustomCell(nextCell.taskId, nextCell.columnId);
6322
+ });
6323
+ }, [focusCustomCell, onActiveCustomCellChange, resolvedColumns, task.id]);
6275
6324
  return /* @__PURE__ */ jsx12(
6276
6325
  "div",
6277
6326
  {
6327
+ ref: rowRef,
6278
6328
  "data-filter-match": isFilterMatch ? "true" : "false",
6279
6329
  className: [
6280
6330
  "gantt-tl-row",
@@ -6287,9 +6337,11 @@ var TaskListRow = React9.memo(
6287
6337
  isDragging ? "gantt-tl-row-dragging" : "",
6288
6338
  isDragOver ? "gantt-tl-row-drag-over" : "",
6289
6339
  isChild ? "gantt-tl-row-child" : "",
6290
- isParent ? "gantt-tl-row-parent" : ""
6340
+ isParent ? "gantt-tl-row-parent" : "",
6341
+ `gantt-tl-row-level-${rowFillLevel}`,
6342
+ isTotalRow ? "gantt-tl-row-total" : ""
6291
6343
  ].filter(Boolean).join(" "),
6292
- style: { minHeight: `${rowHeight}px`, position: "relative" },
6344
+ style: { height: `${rowHeight}px`, position: "relative" },
6293
6345
  "data-gantt-task-row-id": task.id,
6294
6346
  onClick: handleRowClickInternal,
6295
6347
  onKeyDown: handleRowKeyDown,
@@ -6301,43 +6353,120 @@ var TaskListRow = React9.memo(
6301
6353
  if (builtIn) return /* @__PURE__ */ jsx12(React9.Fragment, { children: builtIn }, col.id);
6302
6354
  const isEditing = editingColumnId === col.id;
6303
6355
  const editorFn = col.renderEditor;
6356
+ const isActiveCustomCell = activeCustomCell?.taskId === task.id && activeCustomCell?.columnId === col.id;
6357
+ const startEditingCustomCell = (startValue) => {
6358
+ if (!editorFn) return;
6359
+ onActiveCustomCellChange?.({ taskId: task.id, columnId: col.id });
6360
+ setEditingColumnStartValue(startValue);
6361
+ setEditingColumnId(col.id);
6362
+ };
6304
6363
  const columnContext = {
6305
6364
  task,
6306
6365
  rowIndex,
6307
6366
  isEditing,
6367
+ editStartValue: isEditing ? editingColumnStartValue : void 0,
6308
6368
  openEditor: () => {
6309
- if (editorFn) setEditingColumnId(col.id);
6369
+ startEditingCustomCell();
6310
6370
  },
6311
6371
  closeEditor: () => {
6312
- if (editingColumnId === col.id) setEditingColumnId(null);
6372
+ if (editingColumnId === col.id) {
6373
+ setEditingColumnId(null);
6374
+ setEditingColumnStartValue(void 0);
6375
+ onActiveCustomCellChange?.({ taskId: task.id, columnId: col.id });
6376
+ window.requestAnimationFrame(() => {
6377
+ focusCustomCell(task.id, col.id);
6378
+ });
6379
+ }
6313
6380
  },
6314
6381
  updateTask: (patch) => {
6315
6382
  onTasksChange?.([{ ...task, ...patch }]);
6383
+ onActiveCustomCellChange?.({ taskId: task.id, columnId: col.id });
6384
+ setEditingColumnStartValue(void 0);
6316
6385
  setEditingColumnId(null);
6386
+ window.requestAnimationFrame(() => {
6387
+ focusCustomCell(task.id, col.id);
6388
+ });
6317
6389
  }
6318
6390
  };
6319
6391
  return /* @__PURE__ */ jsx12(
6320
6392
  "div",
6321
6393
  {
6322
- className: "gantt-tl-cell gantt-tl-cell-custom",
6394
+ className: `gantt-tl-cell gantt-tl-cell-custom gantt-tl-cell-align-${col.align ?? "left"}`,
6323
6395
  "data-column-id": `custom:${col.id}`,
6324
6396
  "data-custom-column-id": col.id,
6397
+ "data-custom-column-active": isActiveCustomCell ? "true" : "false",
6325
6398
  "data-custom-column-editing": isEditing ? "true" : "false",
6326
6399
  "data-testid": `custom-cell-${col.id}`,
6327
- onClick: editorFn && !isEditing ? (e) => {
6400
+ tabIndex: editorFn ? 0 : -1,
6401
+ onFocus: editorFn ? () => {
6402
+ onActiveCustomCellChange?.({ taskId: task.id, columnId: col.id });
6403
+ } : void 0,
6404
+ onClick: editorFn ? (e) => {
6405
+ e.stopPropagation();
6406
+ onActiveCustomCellChange?.({ taskId: task.id, columnId: col.id });
6407
+ if (isEditing) {
6408
+ return;
6409
+ }
6410
+ e.currentTarget.focus();
6411
+ } : void 0,
6412
+ onDoubleClick: editorFn && !isEditing ? (e) => {
6328
6413
  e.stopPropagation();
6329
- setEditingColumnId(col.id);
6414
+ startEditingCustomCell();
6415
+ } : void 0,
6416
+ onKeyDown: editorFn && !isEditing ? (e) => {
6417
+ if (e.key === "ArrowLeft") {
6418
+ e.preventDefault();
6419
+ e.stopPropagation();
6420
+ moveActiveCustomCell(col.id, "left");
6421
+ return;
6422
+ }
6423
+ if (e.key === "ArrowRight") {
6424
+ e.preventDefault();
6425
+ e.stopPropagation();
6426
+ moveActiveCustomCell(col.id, "right");
6427
+ return;
6428
+ }
6429
+ if (e.key === "ArrowUp") {
6430
+ e.preventDefault();
6431
+ e.stopPropagation();
6432
+ moveActiveCustomCell(col.id, "up");
6433
+ return;
6434
+ }
6435
+ if (e.key === "ArrowDown") {
6436
+ e.preventDefault();
6437
+ e.stopPropagation();
6438
+ moveActiveCustomCell(col.id, "down");
6439
+ return;
6440
+ }
6441
+ if (e.key === "Enter" || e.key === "F2") {
6442
+ e.preventDefault();
6443
+ e.stopPropagation();
6444
+ startEditingCustomCell();
6445
+ return;
6446
+ }
6447
+ if (e.key === "Backspace" || e.key === "Delete") {
6448
+ e.preventDefault();
6449
+ e.stopPropagation();
6450
+ startEditingCustomCell("");
6451
+ return;
6452
+ }
6453
+ if (e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
6454
+ e.preventDefault();
6455
+ e.stopPropagation();
6456
+ startEditingCustomCell(e.key);
6457
+ }
6330
6458
  } : void 0,
6331
6459
  style: { width: col.width ?? 120, minWidth: col.width ?? 120, flexShrink: 0 },
6332
6460
  children: isEditing && editorFn ? /* @__PURE__ */ jsx12(
6333
6461
  "div",
6334
6462
  {
6463
+ className: "gantt-tl-cell-custom-editor",
6335
6464
  "data-custom-column-editor": col.id,
6336
6465
  onMouseDown: (e) => e.stopPropagation(),
6337
6466
  onClick: (e) => e.stopPropagation(),
6338
6467
  children: editorFn(columnContext)
6339
6468
  }
6340
- ) : col.renderCell(columnContext)
6469
+ ) : /* @__PURE__ */ jsx12("div", { className: "gantt-tl-cell-custom-content", children: col.renderCell(columnContext) })
6341
6470
  },
6342
6471
  col.id
6343
6472
  );
@@ -6389,7 +6518,7 @@ var NewTaskRow = ({
6389
6518
  onCancel();
6390
6519
  }
6391
6520
  };
6392
- return /* @__PURE__ */ jsxs10("div", { className: "gantt-tl-row gantt-tl-row-new", style: { minHeight: `${rowHeight}px` }, children: [
6521
+ return /* @__PURE__ */ jsxs10("div", { className: "gantt-tl-row gantt-tl-row-new", style: { height: `${rowHeight}px` }, children: [
6393
6522
  /* @__PURE__ */ jsx13("div", { className: "gantt-tl-cell gantt-tl-cell-number" }),
6394
6523
  /* @__PURE__ */ jsx13("div", { className: "gantt-tl-cell gantt-tl-cell-name gantt-tl-cell-new-name", children: /* @__PURE__ */ jsx13(
6395
6524
  Input,
@@ -6623,6 +6752,7 @@ var TaskList = ({
6623
6752
  onDelete,
6624
6753
  onInsertAfter,
6625
6754
  onReorder,
6755
+ disableTaskDrag = false,
6626
6756
  editingTaskId: propEditingTaskId,
6627
6757
  enableAddTask = true,
6628
6758
  defaultTaskDurationDays = DEFAULT_TASK_DURATION_DAYS,
@@ -6644,10 +6774,14 @@ var TaskList = ({
6644
6774
  additionalColumns,
6645
6775
  hiddenTaskListColumns,
6646
6776
  taskListMenuCommands,
6777
+ hideTaskListRowActions = false,
6778
+ rowContentLines = 1,
6779
+ bodyMinHeight,
6647
6780
  taskDateChangeMode = "preserve-duration",
6648
6781
  onTaskDateChangeModeChange
6649
6782
  }) => {
6650
6783
  const [internalSelectedTaskIds, setInternalSelectedTaskIds] = useState6(/* @__PURE__ */ new Set());
6784
+ const [activeCustomCell, setActiveCustomCell] = useState6(null);
6651
6785
  const effectiveSelectedTaskIds = selectedTaskIds ?? internalSelectedTaskIds;
6652
6786
  const emitSelectedTaskIdsChange = useCallback5((nextSelectedTaskIds) => {
6653
6787
  if (!selectedTaskIds) {
@@ -6819,21 +6953,28 @@ var TaskList = ({
6819
6953
  onSelectedChipChange?.(chip);
6820
6954
  }, [onSelectedChipChange]);
6821
6955
  useEffect6(() => {
6822
- if (!selectingPredecessorFor && !selectedChip && !selectedTaskId) return;
6956
+ if (!selectingPredecessorFor && !selectedChip && !selectedTaskId && !activeCustomCell) return;
6823
6957
  const handleKeyDown = (e) => {
6824
6958
  if (e.key === "Escape") {
6825
6959
  setSelectingPredecessorFor(null);
6826
6960
  setSelectedChip(null);
6961
+ setActiveCustomCell(null);
6827
6962
  onSelectedChipChange?.(null);
6828
6963
  onTaskSelect?.(null);
6829
6964
  }
6830
6965
  };
6831
6966
  const handleMouseDown = (e) => {
6832
6967
  const target = e.target;
6833
- if (overlayRef.current?.contains(target)) return;
6968
+ if (overlayRef.current?.contains(target)) {
6969
+ if (activeCustomCell && !target.closest?.("[data-custom-column-id]")) {
6970
+ setActiveCustomCell(null);
6971
+ }
6972
+ return;
6973
+ }
6834
6974
  if (target.closest?.(".gantt-popover")) return;
6835
6975
  setSelectingPredecessorFor(null);
6836
6976
  setSelectedChip(null);
6977
+ setActiveCustomCell(null);
6837
6978
  onSelectedChipChange?.(null);
6838
6979
  onTaskSelect?.(null);
6839
6980
  };
@@ -6843,7 +6984,7 @@ var TaskList = ({
6843
6984
  document.removeEventListener("keydown", handleKeyDown);
6844
6985
  document.removeEventListener("mousedown", handleMouseDown, true);
6845
6986
  };
6846
- }, [selectingPredecessorFor, selectedChip, selectedTaskId, onTaskSelect, onSelectedChipChange]);
6987
+ }, [selectingPredecessorFor, selectedChip, selectedTaskId, activeCustomCell, onTaskSelect, onSelectedChipChange]);
6847
6988
  const handleAddDependency = useCallback5((successorTaskId, predecessorTaskId, linkType) => {
6848
6989
  if (successorTaskId === predecessorTaskId) return;
6849
6990
  if (areTasksHierarchicallyRelated(successorTaskId, predecessorTaskId, tasks)) {
@@ -7233,7 +7374,10 @@ var TaskList = ({
7233
7374
  {
7234
7375
  ref: overlayRef,
7235
7376
  className: `gantt-tl-overlay${show ? "" : " gantt-tl-hidden"}${hasRightShadow ? " gantt-tl-overlay-shadowed" : ""}`,
7236
- style: { "--tasklist-width": `${effectiveTaskListWidth}px` },
7377
+ style: {
7378
+ "--tasklist-width": `${effectiveTaskListWidth}px`,
7379
+ "--gantt-row-content-lines": String(Math.max(2, Math.floor(rowContentLines)))
7380
+ },
7237
7381
  children: /* @__PURE__ */ jsxs11("div", { className: "gantt-tl-table", children: [
7238
7382
  /* @__PURE__ */ jsx14("div", { className: "gantt-tl-header", style: { height: `${tableHeaderHeight}px` }, children: resolvedColumns.map((col) => {
7239
7383
  if (col.id === "selection") {
@@ -7313,7 +7457,7 @@ var TaskList = ({
7313
7457
  return /* @__PURE__ */ jsx14(
7314
7458
  "div",
7315
7459
  {
7316
- className: "gantt-tl-headerCell gantt-tl-headerCell-custom",
7460
+ className: `gantt-tl-headerCell gantt-tl-headerCell-custom gantt-tl-cell-align-${col.align ?? "left"}`,
7317
7461
  "data-column-id": `custom:${col.id}`,
7318
7462
  "data-custom-column-id": col.id,
7319
7463
  style: { width: col.width, minWidth: col.width, flexShrink: 0 },
@@ -7322,81 +7466,94 @@ var TaskList = ({
7322
7466
  col.id
7323
7467
  );
7324
7468
  }) }),
7325
- /* @__PURE__ */ jsx14("div", { className: "gantt-tl-body", style: { height: `${totalHeight}px` }, children: visibleTasks.map((task, index) => {
7326
- const previousVisibleTask = index > 0 ? visibleTasks[index - 1] : void 0;
7327
- const canDemoteTask = index === 0 || !task.parentId || previousVisibleTask?.id !== task.parentId;
7328
- return /* @__PURE__ */ jsxs11(React11.Fragment, { children: [
7329
- /* @__PURE__ */ jsx14(
7330
- TaskListRow,
7331
- {
7332
- task,
7333
- rowIndex: index,
7334
- taskNumber: originalTaskNumberMap[task.id] || "",
7335
- taskNumberMap: originalTaskNumberMap,
7336
- rowHeight,
7337
- onTasksChange,
7338
- selectedTaskId,
7339
- onRowClick: handleRowClick,
7340
- disableTaskNameEditing,
7341
- disableDependencyEditing,
7342
- allTasks: tasks,
7343
- activeLinkType,
7344
- onSetActiveLinkType: setActiveLinkType,
7345
- selectingPredecessorFor,
7346
- dependencyPickMode,
7347
- onSetDependencyPickMode: setDependencyPickMode,
7348
- onSetSelectingPredecessorFor: setSelectingPredecessorFor,
7349
- onAddDependency: handleAddDependency,
7350
- onRemoveDependency: handleRemoveDependency,
7351
- selectedChip,
7352
- onChipSelect: handleChipSelect,
7353
- onScrollToTask,
7354
- onDelete,
7355
- onAdd,
7356
- onInsertAfter: handleStartInsertAfter,
7357
- editingTaskId: propEditingTaskId,
7358
- isDragging: draggingIndex === index,
7359
- isDragOver: dragOverIndex === index,
7360
- onDragStart: handleDragStart,
7361
- onDragOver: handleDragOver,
7362
- onDrop: handleDrop,
7363
- onDragEnd: handleDragEnd,
7364
- collapsedParentIds,
7365
- onToggleCollapse: handleToggleCollapse,
7366
- onPromoteTask,
7367
- onDemoteTask: onDemoteTask ? handleDemoteWrapper : void 0,
7368
- onUngroupTask,
7369
- onDuplicateTask: onReorder ? handleDuplicateTask : void 0,
7370
- canDemoteTask,
7371
- isLastChild: lastChildIds.has(task.id),
7372
- nestingDepth: nestingDepthMap.get(task.id) ?? 0,
7373
- hasVisibleChildren: visibleParentIds.has(task.id),
7374
- ancestorLineModes: ancestorLineModesMap.get(task.id) ?? [],
7375
- customDays,
7376
- isWeekend: isWeekend3,
7377
- businessDays,
7378
- defaultTaskDurationDays,
7379
- isFilterMatch: filterMode === "highlight" ? highlightedTaskIds.has(task.id) : false,
7380
- isFilterHideMode: filterMode === "hide" && isFilterActive,
7381
- resolvedColumns,
7382
- isTaskSelected: effectiveSelectedTaskIds.has(task.id),
7383
- onTaskSelectionChange: handleToggleTaskSelection,
7384
- taskListMenuCommands,
7385
- taskDateChangeMode,
7386
- onTaskDateChangeModeChange
7387
- }
7388
- ),
7389
- pendingInsertDisplayTaskId === task.id && /* @__PURE__ */ jsx14(
7390
- NewTaskRow,
7391
- {
7392
- rowHeight,
7393
- onConfirm: handleConfirmInsertedTask,
7394
- onCancel: handleCancelInsertedTask,
7395
- nestingDepth: pendingInsert?.nestingDepth ?? 0
7396
- }
7397
- )
7398
- ] }, task.id);
7399
- }) }),
7469
+ /* @__PURE__ */ jsx14(
7470
+ "div",
7471
+ {
7472
+ className: "gantt-tl-body",
7473
+ style: {
7474
+ height: `${totalHeight}px`,
7475
+ minHeight: bodyMinHeight
7476
+ },
7477
+ children: visibleTasks.map((task, index) => {
7478
+ const previousVisibleTask = index > 0 ? visibleTasks[index - 1] : void 0;
7479
+ const canDemoteTask = index === 0 || !task.parentId || previousVisibleTask?.id !== task.parentId;
7480
+ return /* @__PURE__ */ jsxs11(React11.Fragment, { children: [
7481
+ /* @__PURE__ */ jsx14(
7482
+ TaskListRow,
7483
+ {
7484
+ task,
7485
+ rowIndex: index,
7486
+ taskNumber: originalTaskNumberMap[task.id] || "",
7487
+ taskNumberMap: originalTaskNumberMap,
7488
+ rowHeight,
7489
+ onTasksChange,
7490
+ selectedTaskId,
7491
+ onRowClick: handleRowClick,
7492
+ disableTaskNameEditing,
7493
+ disableDependencyEditing,
7494
+ allTasks: tasks,
7495
+ activeLinkType,
7496
+ onSetActiveLinkType: setActiveLinkType,
7497
+ selectingPredecessorFor,
7498
+ dependencyPickMode,
7499
+ onSetDependencyPickMode: setDependencyPickMode,
7500
+ onSetSelectingPredecessorFor: setSelectingPredecessorFor,
7501
+ onAddDependency: handleAddDependency,
7502
+ onRemoveDependency: handleRemoveDependency,
7503
+ selectedChip,
7504
+ onChipSelect: handleChipSelect,
7505
+ onScrollToTask,
7506
+ onDelete,
7507
+ onAdd,
7508
+ onInsertAfter: handleStartInsertAfter,
7509
+ editingTaskId: propEditingTaskId,
7510
+ isDragging: !disableTaskDrag && draggingIndex === index,
7511
+ isDragOver: !disableTaskDrag && dragOverIndex === index,
7512
+ onDragStart: disableTaskDrag ? void 0 : handleDragStart,
7513
+ onDragOver: disableTaskDrag ? void 0 : handleDragOver,
7514
+ onDrop: disableTaskDrag ? void 0 : handleDrop,
7515
+ onDragEnd: disableTaskDrag ? void 0 : handleDragEnd,
7516
+ collapsedParentIds,
7517
+ onToggleCollapse: handleToggleCollapse,
7518
+ onPromoteTask,
7519
+ onDemoteTask: onDemoteTask ? handleDemoteWrapper : void 0,
7520
+ onUngroupTask,
7521
+ onDuplicateTask: onReorder ? handleDuplicateTask : void 0,
7522
+ canDemoteTask,
7523
+ isLastChild: lastChildIds.has(task.id),
7524
+ nestingDepth: nestingDepthMap.get(task.id) ?? 0,
7525
+ hasVisibleChildren: visibleParentIds.has(task.id),
7526
+ ancestorLineModes: ancestorLineModesMap.get(task.id) ?? [],
7527
+ customDays,
7528
+ isWeekend: isWeekend3,
7529
+ businessDays,
7530
+ defaultTaskDurationDays,
7531
+ isFilterMatch: filterMode === "highlight" ? highlightedTaskIds.has(task.id) : false,
7532
+ isFilterHideMode: filterMode === "hide" && isFilterActive,
7533
+ resolvedColumns,
7534
+ isTaskSelected: effectiveSelectedTaskIds.has(task.id),
7535
+ onTaskSelectionChange: handleToggleTaskSelection,
7536
+ activeCustomCell,
7537
+ onActiveCustomCellChange: setActiveCustomCell,
7538
+ taskListMenuCommands,
7539
+ hideTaskListRowActions,
7540
+ taskDateChangeMode,
7541
+ onTaskDateChangeModeChange
7542
+ }
7543
+ ),
7544
+ pendingInsertDisplayTaskId === task.id && /* @__PURE__ */ jsx14(
7545
+ NewTaskRow,
7546
+ {
7547
+ rowHeight,
7548
+ onConfirm: handleConfirmInsertedTask,
7549
+ onCancel: handleCancelInsertedTask,
7550
+ nestingDepth: pendingInsert?.nestingDepth ?? 0
7551
+ }
7552
+ )
7553
+ ] }, task.id);
7554
+ })
7555
+ }
7556
+ ),
7400
7557
  isCreating && !pendingInsert && /* @__PURE__ */ jsx14(
7401
7558
  NewTaskRow,
7402
7559
  {
@@ -7409,25 +7566,25 @@ var TaskList = ({
7409
7566
  enableAddTask && onAdd && !isCreating && !pendingInsert && /* @__PURE__ */ jsx14(
7410
7567
  "button",
7411
7568
  {
7412
- className: `gantt-tl-add-btn${dragOverIndex === visibleTasks.length ? " gantt-tl-add-btn-drag-over" : ""}`,
7569
+ className: `gantt-tl-add-btn${!disableTaskDrag && dragOverIndex === visibleTasks.length ? " gantt-tl-add-btn-drag-over" : ""}`,
7413
7570
  onClick: () => {
7414
7571
  setPendingInsert(null);
7415
7572
  setIsCreating(true);
7416
7573
  },
7417
- onDragEnter: (e) => {
7574
+ onDragEnter: disableTaskDrag ? void 0 : (e) => {
7418
7575
  e.preventDefault();
7419
7576
  setDragOverIndex(visibleTasks.length);
7420
7577
  },
7421
- onDragOver: (e) => {
7578
+ onDragOver: disableTaskDrag ? void 0 : (e) => {
7422
7579
  e.preventDefault();
7423
7580
  e.dataTransfer.dropEffect = "move";
7424
7581
  setDragOverIndex(visibleTasks.length);
7425
7582
  },
7426
- onDragLeave: (e) => {
7583
+ onDragLeave: disableTaskDrag ? void 0 : (e) => {
7427
7584
  e.preventDefault();
7428
7585
  setDragOverIndex(null);
7429
7586
  },
7430
- onDrop: (e) => {
7587
+ onDrop: disableTaskDrag ? void 0 : (e) => {
7431
7588
  e.preventDefault();
7432
7589
  handleDrop(visibleTasks.length, e);
7433
7590
  },
@@ -9120,6 +9277,194 @@ function ResourceTimelineChart({
9120
9277
  ) });
9121
9278
  }
9122
9279
 
9280
+ // src/components/TableMatrix/TableMatrix.tsx
9281
+ import { useMemo as useMemo10 } from "react";
9282
+ import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
9283
+ function joinClasses(...values) {
9284
+ return values.filter(Boolean).join(" ");
9285
+ }
9286
+ function TableMatrix({
9287
+ tasks,
9288
+ allTasks = tasks,
9289
+ columns,
9290
+ columnGroups,
9291
+ rowHeight,
9292
+ headerHeight,
9293
+ bodyMinHeight,
9294
+ selectedTaskId,
9295
+ onTaskSelect,
9296
+ onCellClick,
9297
+ highlightedTaskIds,
9298
+ filterMode = "highlight"
9299
+ }) {
9300
+ const gridTemplateColumns = useMemo10(
9301
+ () => columns.map((column) => `${column.width}px`).join(" "),
9302
+ [columns]
9303
+ );
9304
+ const totalWidth = useMemo10(
9305
+ () => columns.reduce((sum, column) => sum + column.width, 0),
9306
+ [columns]
9307
+ );
9308
+ const hasGroupHeader = useMemo10(
9309
+ () => columns.some((column) => !!column.groupId) || (columnGroups?.length ?? 0) > 0,
9310
+ [columnGroups, columns]
9311
+ );
9312
+ const groupMap = useMemo10(
9313
+ () => new Map((columnGroups ?? []).map((group) => [group.id, group])),
9314
+ [columnGroups]
9315
+ );
9316
+ const headerSpans = useMemo10(() => {
9317
+ if (!hasGroupHeader) return [];
9318
+ if (columnGroups?.some((group) => typeof group.width === "number")) {
9319
+ return columnGroups.map((group) => ({
9320
+ id: group.id,
9321
+ header: group.header,
9322
+ width: group.width ?? 0,
9323
+ className: group.className
9324
+ }));
9325
+ }
9326
+ const spans = [];
9327
+ for (const column of columns) {
9328
+ const groupId = column.groupId ?? column.id;
9329
+ const lastSpan = spans[spans.length - 1];
9330
+ if (lastSpan?.id === groupId) {
9331
+ lastSpan.width += column.width;
9332
+ continue;
9333
+ }
9334
+ const group = groupMap.get(groupId);
9335
+ spans.push({
9336
+ id: groupId,
9337
+ header: group?.header ?? column.header,
9338
+ width: column.width,
9339
+ className: group?.className
9340
+ });
9341
+ }
9342
+ return spans;
9343
+ }, [columns, groupMap, hasGroupHeader]);
9344
+ const headerContentHeight = Math.max(0, headerHeight - 1);
9345
+ const topRowHeight = hasGroupHeader ? Math.ceil(headerContentHeight / 2) : headerContentHeight;
9346
+ const bottomRowHeight = hasGroupHeader ? Math.floor(headerContentHeight / 2) : 0;
9347
+ const parentTaskIds = useMemo10(() => {
9348
+ const ids = /* @__PURE__ */ new Set();
9349
+ for (const task of allTasks) {
9350
+ if (task.parentId) {
9351
+ ids.add(task.parentId);
9352
+ }
9353
+ }
9354
+ return ids;
9355
+ }, [allTasks]);
9356
+ const nestingDepthMap = useMemo10(() => {
9357
+ const depthMap = /* @__PURE__ */ new Map();
9358
+ const taskById = new Map(allTasks.map((task) => [task.id, task]));
9359
+ const getDepth = (taskId, seen = /* @__PURE__ */ new Set()) => {
9360
+ if (depthMap.has(taskId)) return depthMap.get(taskId);
9361
+ if (seen.has(taskId)) return 0;
9362
+ const task = taskById.get(taskId);
9363
+ if (!task?.parentId || !taskById.has(task.parentId)) {
9364
+ depthMap.set(taskId, 0);
9365
+ return 0;
9366
+ }
9367
+ seen.add(taskId);
9368
+ const depth = getDepth(task.parentId, seen) + 1;
9369
+ depthMap.set(taskId, depth);
9370
+ return depth;
9371
+ };
9372
+ for (const task of allTasks) {
9373
+ getDepth(task.id);
9374
+ }
9375
+ return depthMap;
9376
+ }, [allTasks]);
9377
+ return /* @__PURE__ */ jsxs13("div", { className: "gantt-mx-root", style: { width: `${totalWidth}px` }, children: [
9378
+ /* @__PURE__ */ jsxs13("div", { className: "gantt-mx-header", style: { height: `${headerHeight}px` }, children: [
9379
+ hasGroupHeader && /* @__PURE__ */ jsx16(
9380
+ "div",
9381
+ {
9382
+ className: "gantt-mx-headerRow gantt-mx-headerGroupRow",
9383
+ style: { gridTemplateColumns: headerSpans.map((span) => `${span.width}px`).join(" "), height: `${topRowHeight}px` },
9384
+ children: headerSpans.map((span) => /* @__PURE__ */ jsx16("div", { className: joinClasses("gantt-mx-groupCell", span.className), children: span.header }, span.id))
9385
+ }
9386
+ ),
9387
+ /* @__PURE__ */ jsx16(
9388
+ "div",
9389
+ {
9390
+ className: "gantt-mx-headerRow",
9391
+ style: { gridTemplateColumns, height: `${hasGroupHeader ? bottomRowHeight : topRowHeight}px` },
9392
+ children: columns.map((column) => /* @__PURE__ */ jsx16(
9393
+ "div",
9394
+ {
9395
+ className: joinClasses(
9396
+ "gantt-mx-headerCell",
9397
+ column.headerClassName
9398
+ ),
9399
+ children: column.header
9400
+ },
9401
+ column.id
9402
+ ))
9403
+ }
9404
+ )
9405
+ ] }),
9406
+ /* @__PURE__ */ jsx16(
9407
+ "div",
9408
+ {
9409
+ className: "gantt-mx-body",
9410
+ style: {
9411
+ height: `${tasks.length * rowHeight}px`,
9412
+ minHeight: bodyMinHeight
9413
+ },
9414
+ children: tasks.map((task, index) => {
9415
+ const isHighlighted = filterMode === "highlight" && !!highlightedTaskIds?.has(task.id);
9416
+ const isParent = parentTaskIds.has(task.id);
9417
+ const nestingDepth = nestingDepthMap.get(task.id) ?? 0;
9418
+ const rowFillLevel = Math.min(nestingDepth, 2);
9419
+ const isTotal = Boolean(task.isTotal);
9420
+ return /* @__PURE__ */ jsx16(
9421
+ "div",
9422
+ {
9423
+ "data-gantt-task-row-id": task.id,
9424
+ className: joinClasses(
9425
+ "gantt-mx-row",
9426
+ task.parentId && "gantt-mx-row-child",
9427
+ isParent && "gantt-mx-row-parent",
9428
+ `gantt-mx-row-level-${rowFillLevel}`,
9429
+ isTotal && "gantt-mx-row-total",
9430
+ selectedTaskId === task.id && "gantt-mx-row-selected",
9431
+ isHighlighted && "gantt-mx-row-highlighted"
9432
+ ),
9433
+ style: {
9434
+ gridTemplateColumns,
9435
+ top: `${index * rowHeight}px`,
9436
+ height: `${rowHeight}px`
9437
+ },
9438
+ onClick: () => onTaskSelect?.(task.id),
9439
+ children: columns.map((column, columnIndex) => {
9440
+ const resolvedCellClassName = typeof column.cellClassName === "function" ? column.cellClassName(task) : column.cellClassName;
9441
+ return /* @__PURE__ */ jsx16(
9442
+ "div",
9443
+ {
9444
+ className: joinClasses(
9445
+ "gantt-mx-cell",
9446
+ onCellClick && "gantt-mx-cell-clickable",
9447
+ `gantt-mx-cellAlign-${column.align ?? "right"}`,
9448
+ column.className,
9449
+ resolvedCellClassName
9450
+ ),
9451
+ onClick: (event) => {
9452
+ onCellClick?.({ task, column, rowIndex: index, columnIndex, event });
9453
+ },
9454
+ children: column.renderCell(task)
9455
+ },
9456
+ `${task.id}:${column.id}`
9457
+ );
9458
+ })
9459
+ },
9460
+ task.id
9461
+ );
9462
+ })
9463
+ }
9464
+ )
9465
+ ] });
9466
+ }
9467
+
9123
9468
  // src/components/GanttChart/print.ts
9124
9469
  function getPrintDocumentTitle({
9125
9470
  header,
@@ -9458,13 +9803,13 @@ async function printGanttChart({
9458
9803
  }
9459
9804
 
9460
9805
  // src/components/GanttChart/GanttChart.tsx
9461
- import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
9806
+ import { Fragment as Fragment4, jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
9462
9807
  var SCROLL_TO_ROW_CONTEXT_ROWS = 2;
9463
9808
  function GanttChartInner(props, ref) {
9464
9809
  if (props.mode === "resource-planner") {
9465
- return /* @__PURE__ */ jsx16(ResourceTimelineChart, { ...props });
9810
+ return /* @__PURE__ */ jsx17(ResourceTimelineChart, { ...props });
9466
9811
  }
9467
- return /* @__PURE__ */ jsx16(
9812
+ return /* @__PURE__ */ jsx17(
9468
9813
  TaskGanttChart,
9469
9814
  {
9470
9815
  ...props,
@@ -9473,9 +9818,9 @@ function GanttChartInner(props, ref) {
9473
9818
  );
9474
9819
  }
9475
9820
  function TaskGanttChartInner(props, ref) {
9821
+ const isTableMatrixMode = props.mode === "table-matrix";
9476
9822
  const {
9477
9823
  tasks,
9478
- dayWidth = 40,
9479
9824
  rowHeight = 40,
9480
9825
  headerHeight = 40,
9481
9826
  containerHeight,
@@ -9499,10 +9844,6 @@ function TaskGanttChartInner(props, ref) {
9499
9844
  onUngroupTask,
9500
9845
  enableAddTask = true,
9501
9846
  defaultTaskDurationDays,
9502
- viewMode = "day",
9503
- customDays,
9504
- isWeekend: isWeekend3,
9505
- businessDays = true,
9506
9847
  taskFilter,
9507
9848
  filterMode = "highlight",
9508
9849
  collapsedParentIds: externalCollapsedParentIds,
@@ -9516,9 +9857,19 @@ function TaskGanttChartInner(props, ref) {
9516
9857
  additionalColumns,
9517
9858
  hiddenTaskListColumns,
9518
9859
  taskListMenuCommands,
9860
+ hideTaskListRowActions = false,
9861
+ rowContentLines = 1,
9519
9862
  taskDateChangeMode: externalTaskDateChangeMode,
9520
9863
  onTaskDateChangeModeChange: externalOnTaskDateChangeModeChange
9521
9864
  } = props;
9865
+ const dayWidth = !isTableMatrixMode ? props.dayWidth ?? 40 : 40;
9866
+ const viewMode = !isTableMatrixMode ? props.viewMode ?? "day" : "day";
9867
+ const customDays = !isTableMatrixMode ? props.customDays : void 0;
9868
+ const isWeekend3 = !isTableMatrixMode ? props.isWeekend : void 0;
9869
+ const businessDays = !isTableMatrixMode ? props.businessDays ?? true : true;
9870
+ const matrixColumns = isTableMatrixMode ? props.matrixColumns : [];
9871
+ const matrixColumnGroups = isTableMatrixMode ? props.matrixColumnGroups : void 0;
9872
+ const onMatrixCellClick = isTableMatrixMode ? props.onMatrixCellClick : void 0;
9522
9873
  const containerRef = useRef9(null);
9523
9874
  const scrollContainerRef = useRef9(null);
9524
9875
  const scrollContentRef = useRef9(null);
@@ -9532,12 +9883,17 @@ function TaskGanttChartInner(props, ref) {
9532
9883
  const [editingTaskId, setEditingTaskId] = useState9(null);
9533
9884
  const taskDateChangeMode = externalTaskDateChangeMode ?? internalTaskDateChangeMode;
9534
9885
  const handleTaskDateChangeMode = externalOnTaskDateChangeModeChange ?? setInternalTaskDateChangeMode;
9535
- const normalizedTasks = useMemo10(() => normalizeHierarchyTasks(tasks), [tasks]);
9536
- const isCustomWeekend = useMemo10(
9886
+ const resolvedRowContentLines = Math.max(1, Math.floor(rowContentLines));
9887
+ const effectiveRowHeight = useMemo11(
9888
+ () => Math.max(rowHeight, 10 + resolvedRowContentLines * 18),
9889
+ [resolvedRowContentLines, rowHeight]
9890
+ );
9891
+ const normalizedTasks = useMemo11(() => normalizeHierarchyTasks(tasks), [tasks]);
9892
+ const isCustomWeekend = useMemo11(
9537
9893
  () => createCustomDayPredicate({ customDays, isWeekend: isWeekend3 }),
9538
9894
  [customDays, isWeekend3]
9539
9895
  );
9540
- const dateRangeTasks = useMemo10(() => {
9896
+ const dateRangeTasks = useMemo11(() => {
9541
9897
  if (!showBaseline) {
9542
9898
  return normalizedTasks;
9543
9899
  }
@@ -9547,14 +9903,18 @@ function TaskGanttChartInner(props, ref) {
9547
9903
  endDate: task.baselineEndDate && parseUTCDate(task.baselineEndDate).getTime() > parseUTCDate(task.endDate).getTime() ? task.baselineEndDate : task.endDate
9548
9904
  }));
9549
9905
  }, [normalizedTasks, showBaseline]);
9550
- const dateRange = useMemo10(() => getMultiMonthDays(dateRangeTasks), [dateRangeTasks]);
9906
+ const dateRange = useMemo11(() => getMultiMonthDays(dateRangeTasks), [dateRangeTasks]);
9551
9907
  const [validationResult, setValidationResult] = useState9(null);
9552
9908
  const [cascadeOverrides, setCascadeOverrides] = useState9(/* @__PURE__ */ new Map());
9553
- const gridWidth = useMemo10(
9909
+ const gridWidth = useMemo11(
9554
9910
  () => Math.round(dateRange.length * dayWidth),
9555
9911
  [dateRange.length, dayWidth]
9556
9912
  );
9557
- const visibleTasks = useMemo10(() => {
9913
+ const matrixWidth = useMemo11(
9914
+ () => matrixColumns.reduce((sum, column) => sum + column.width, 0),
9915
+ [matrixColumns]
9916
+ );
9917
+ const visibleTasks = useMemo11(() => {
9558
9918
  const parentMap = new Map(normalizedTasks.map((t) => [t.id, t.parentId]));
9559
9919
  function isAnyAncestorCollapsed(parentId) {
9560
9920
  let current = parentId;
@@ -9570,11 +9930,11 @@ function TaskGanttChartInner(props, ref) {
9570
9930
  }
9571
9931
  return tasks2;
9572
9932
  }, [normalizedTasks, collapsedParentIds, filterMode, taskFilter]);
9573
- const matchedTaskIds = useMemo10(() => {
9933
+ const matchedTaskIds = useMemo11(() => {
9574
9934
  if (!taskFilter) return /* @__PURE__ */ new Set();
9575
9935
  return new Set(visibleTasks.filter(taskFilter).map((task) => task.id));
9576
9936
  }, [visibleTasks, taskFilter]);
9577
- const taskListHighlightedTaskIds = useMemo10(() => {
9937
+ const taskListHighlightedTaskIds = useMemo11(() => {
9578
9938
  if (filterMode === "hide") {
9579
9939
  return /* @__PURE__ */ new Set();
9580
9940
  }
@@ -9585,24 +9945,34 @@ function TaskGanttChartInner(props, ref) {
9585
9945
  matchedTaskIds.forEach((taskId) => mergedHighlightedTaskIds.add(taskId));
9586
9946
  return mergedHighlightedTaskIds;
9587
9947
  }, [filterMode, highlightedTaskIds, matchedTaskIds]);
9588
- const totalGridHeight = useMemo10(
9589
- () => visibleTasks.length * rowHeight,
9590
- [visibleTasks.length, rowHeight]
9948
+ const totalGridHeight = useMemo11(
9949
+ () => visibleTasks.length * effectiveRowHeight,
9950
+ [effectiveRowHeight, visibleTasks.length]
9591
9951
  );
9592
9952
  const timelineHeaderHeight = headerHeight + 1;
9593
- const monthStart = useMemo10(() => {
9953
+ const tableBodyMinHeight = useMemo11(() => {
9954
+ if (!isTableMatrixMode || containerHeight === void 0) {
9955
+ return void 0;
9956
+ }
9957
+ if (typeof containerHeight === "number") {
9958
+ return Math.max(0, containerHeight - timelineHeaderHeight);
9959
+ }
9960
+ return `calc(${containerHeight} - ${timelineHeaderHeight}px)`;
9961
+ }, [containerHeight, isTableMatrixMode, timelineHeaderHeight]);
9962
+ const monthStart = useMemo11(() => {
9594
9963
  if (dateRange.length === 0) {
9595
9964
  return new Date(Date.UTC((/* @__PURE__ */ new Date()).getUTCFullYear(), (/* @__PURE__ */ new Date()).getUTCMonth(), 1));
9596
9965
  }
9597
9966
  const firstDay = dateRange[0];
9598
9967
  return new Date(Date.UTC(firstDay.getUTCFullYear(), firstDay.getUTCMonth(), 1));
9599
9968
  }, [dateRange]);
9600
- const todayInRange = useMemo10(() => {
9969
+ const todayInRange = useMemo11(() => {
9601
9970
  const now = /* @__PURE__ */ new Date();
9602
9971
  const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
9603
9972
  return dateRange.some((day) => day.getTime() === today.getTime());
9604
9973
  }, [dateRange]);
9605
9974
  useEffect9(() => {
9975
+ if (isTableMatrixMode) return;
9606
9976
  const container = scrollContainerRef.current;
9607
9977
  if (!container || dateRange.length === 0) return;
9608
9978
  const now = /* @__PURE__ */ new Date();
@@ -9613,7 +9983,7 @@ function TaskGanttChartInner(props, ref) {
9613
9983
  const containerWidth = container.clientWidth;
9614
9984
  const scrollLeft = Math.round(todayOffset + dayWidth / 2 - containerWidth * 0.3);
9615
9985
  container.scrollLeft = Math.max(0, scrollLeft);
9616
- }, []);
9986
+ }, [dateRange, dayWidth, isTableMatrixMode]);
9617
9987
  useEffect9(() => {
9618
9988
  const container = scrollContainerRef.current;
9619
9989
  if (!container) return;
@@ -9627,6 +9997,7 @@ function TaskGanttChartInner(props, ref) {
9627
9997
  };
9628
9998
  }, []);
9629
9999
  const scrollToToday = useCallback8(() => {
10000
+ if (isTableMatrixMode) return;
9630
10001
  const container = scrollContainerRef.current;
9631
10002
  if (!container || dateRange.length === 0) return;
9632
10003
  const now = /* @__PURE__ */ new Date();
@@ -9637,8 +10008,18 @@ function TaskGanttChartInner(props, ref) {
9637
10008
  const containerWidth = container.clientWidth;
9638
10009
  const scrollLeft = Math.round(todayOffset + dayWidth / 2 - containerWidth * 0.3);
9639
10010
  container.scrollTo({ left: Math.max(0, scrollLeft), behavior: "smooth" });
9640
- }, [dateRange, dayWidth]);
10011
+ }, [dateRange, dayWidth, isTableMatrixMode]);
9641
10012
  const scrollToTask = useCallback8((taskId) => {
10013
+ if (isTableMatrixMode) {
10014
+ const container2 = scrollContainerRef.current;
10015
+ if (!container2) return;
10016
+ const rowIndex = visibleTasks.findIndex((visibleTask) => visibleTask.id === taskId);
10017
+ if (rowIndex === -1) return;
10018
+ const paddedRowIndex = Math.max(0, rowIndex - SCROLL_TO_ROW_CONTEXT_ROWS);
10019
+ container2.scrollTo({ top: Math.max(0, effectiveRowHeight * paddedRowIndex), behavior: "smooth" });
10020
+ setSelectedTaskId(taskId);
10021
+ return;
10022
+ }
9642
10023
  const container = scrollContainerRef.current;
9643
10024
  if (!container || dateRange.length === 0) return;
9644
10025
  const task = tasks.find((t) => t.id === taskId);
@@ -9654,7 +10035,7 @@ function TaskGanttChartInner(props, ref) {
9654
10035
  const taskOffset = taskIndex * dayWidth;
9655
10036
  const scrollLeft = Math.round(taskOffset - dayWidth * 2);
9656
10037
  container.scrollTo({ left: Math.max(0, scrollLeft), behavior: "smooth" });
9657
- }, [tasks, dateRange, dayWidth]);
10038
+ }, [dateRange, dayWidth, effectiveRowHeight, isTableMatrixMode, tasks, visibleTasks]);
9658
10039
  const scrollToRow = useCallback8((taskId, options = {}) => {
9659
10040
  const container = scrollContainerRef.current;
9660
10041
  if (!container) return;
@@ -9663,7 +10044,7 @@ function TaskGanttChartInner(props, ref) {
9663
10044
  const rowIndex = visibleTasks.findIndex((visibleTask) => visibleTask.id === task.id);
9664
10045
  if (rowIndex === -1) return;
9665
10046
  const paddedRowIndex = Math.max(0, rowIndex - SCROLL_TO_ROW_CONTEXT_ROWS);
9666
- const scrollTop = Math.max(0, rowHeight * paddedRowIndex);
10047
+ const scrollTop = Math.max(0, effectiveRowHeight * paddedRowIndex);
9667
10048
  const {
9668
10049
  select = true,
9669
10050
  behavior = "smooth",
@@ -9683,7 +10064,7 @@ function TaskGanttChartInner(props, ref) {
9683
10064
  }
9684
10065
  }
9685
10066
  container.scrollTo({ top: scrollTop, behavior });
9686
- }, [tasks, visibleTasks, rowHeight]);
10067
+ }, [effectiveRowHeight, tasks, visibleTasks]);
9687
10068
  const [dragGuideLines, setDragGuideLines] = useState9(null);
9688
10069
  const [draggedTaskOverride, setDraggedTaskOverride] = useState9(null);
9689
10070
  const [previewTasksById, setPreviewTasksById] = useState9(/* @__PURE__ */ new Map());
@@ -9788,7 +10169,7 @@ function TaskGanttChartInner(props, ref) {
9788
10169
  }
9789
10170
  onTasksChange?.(normalized);
9790
10171
  }, [onTasksChange, onReorder]);
9791
- const dependencyOverrides = useMemo10(() => {
10172
+ const dependencyOverrides = useMemo11(() => {
9792
10173
  const map = new Map(cascadeOverrides);
9793
10174
  if (draggedTaskOverride) {
9794
10175
  map.set(draggedTaskOverride.taskId, {
@@ -9802,11 +10183,11 @@ function TaskGanttChartInner(props, ref) {
9802
10183
  setCascadeOverrides(new Map(overrides));
9803
10184
  setPreviewTasksById(new Map(previewTasks.map((task) => [task.id, task])));
9804
10185
  }, []);
9805
- const previewNormalizedTasks = useMemo10(() => {
10186
+ const previewNormalizedTasks = useMemo11(() => {
9806
10187
  if (previewTasksById.size === 0) return normalizedTasks;
9807
10188
  return normalizedTasks.map((task) => previewTasksById.get(task.id) ?? task);
9808
10189
  }, [normalizedTasks, previewTasksById]);
9809
- const previewVisibleTasks = useMemo10(() => {
10190
+ const previewVisibleTasks = useMemo11(() => {
9810
10191
  if (previewTasksById.size === 0) return visibleTasks;
9811
10192
  return visibleTasks.map((task) => previewTasksById.get(task.id) ?? task);
9812
10193
  }, [visibleTasks, previewTasksById]);
@@ -9819,7 +10200,7 @@ function TaskGanttChartInner(props, ref) {
9819
10200
  const hoveredRowElementsRef = useRef9([]);
9820
10201
  const clearHoveredRows = useCallback8(() => {
9821
10202
  for (const element of hoveredRowElementsRef.current) {
9822
- element.classList.remove("gantt-tl-row-hovered", "gantt-tr-row-hovered");
10203
+ element.classList.remove("gantt-tl-row-hovered", "gantt-tr-row-hovered", "gantt-mx-row-hovered");
9823
10204
  }
9824
10205
  hoveredRowElementsRef.current = [];
9825
10206
  }, []);
@@ -9837,6 +10218,9 @@ function TaskGanttChartInner(props, ref) {
9837
10218
  if (element.classList.contains("gantt-tr-row")) {
9838
10219
  element.classList.add("gantt-tr-row-hovered");
9839
10220
  }
10221
+ if (element.classList.contains("gantt-mx-row")) {
10222
+ element.classList.add("gantt-mx-row-hovered");
10223
+ }
9840
10224
  }
9841
10225
  hoveredRowElementsRef.current = nextHoveredRows;
9842
10226
  }, [clearHoveredRows]);
@@ -9861,7 +10245,7 @@ function TaskGanttChartInner(props, ref) {
9861
10245
  return next;
9862
10246
  });
9863
10247
  }, []);
9864
- const allParentIds = useMemo10(() => {
10248
+ const allParentIds = useMemo11(() => {
9865
10249
  return new Set(
9866
10250
  normalizedTasks.filter((t) => isTaskParent(t.id, normalizedTasks)).map((t) => t.id)
9867
10251
  );
@@ -10073,190 +10457,221 @@ function TaskGanttChartInner(props, ref) {
10073
10457
  window.removeEventListener("mouseup", handlePanEnd);
10074
10458
  };
10075
10459
  }, []);
10076
- return /* @__PURE__ */ jsx16("div", { ref: containerRef, className: "gantt-container", children: /* @__PURE__ */ jsx16(
10460
+ return /* @__PURE__ */ jsx17(
10077
10461
  "div",
10078
10462
  {
10079
- ref: scrollContainerRef,
10080
- className: "gantt-scrollContainer",
10081
- style: { height: containerHeight ?? "auto", cursor: "grab" },
10082
- onMouseDown: handlePanStart,
10083
- children: /* @__PURE__ */ jsxs13(
10463
+ ref: containerRef,
10464
+ className: isTableMatrixMode ? "gantt-container gantt-container-tableMatrix" : "gantt-container",
10465
+ children: /* @__PURE__ */ jsx17(
10084
10466
  "div",
10085
10467
  {
10086
- ref: scrollContentRef,
10087
- className: "gantt-scrollContent",
10088
- onMouseOver: handleSharedRowHover,
10089
- onMouseLeave: clearHoveredRows,
10090
- children: [
10091
- /* @__PURE__ */ jsx16(
10092
- TaskList,
10093
- {
10094
- tasks: normalizedTasks,
10095
- rowHeight,
10096
- headerHeight,
10097
- taskListWidth,
10098
- onTasksChange: handleTaskChange,
10099
- selectedTaskId: selectedTaskId ?? void 0,
10100
- onTaskSelect: handleTaskSelect,
10101
- show: showTaskList,
10102
- hasRightShadow: taskListHasRightShadow,
10103
- disableTaskNameEditing,
10104
- disableDependencyEditing,
10105
- onScrollToTask: scrollToTask,
10106
- onSelectedChipChange: setSelectedChip,
10107
- onAdd,
10108
- onDelete: handleDelete,
10109
- onInsertAfter: handleInsertAfter,
10110
- onReorder: handleReorder,
10111
- editingTaskId,
10112
- enableAddTask,
10113
- defaultTaskDurationDays,
10114
- collapsedParentIds,
10115
- onToggleCollapse: handleToggleCollapse,
10116
- onPromoteTask: onPromoteTask ?? handlePromoteTask,
10117
- onDemoteTask: onDemoteTask ?? handleDemoteTask,
10118
- onUngroupTask: onUngroupTask ?? handleUngroupTask,
10119
- highlightedTaskIds: taskListHighlightedTaskIds,
10120
- enableTaskMultiSelect,
10121
- selectedTaskIds,
10122
- onSelectedTaskIdsChange,
10123
- customDays,
10124
- isWeekend: isWeekend3,
10125
- businessDays,
10126
- filterMode,
10127
- filteredTaskIds: matchedTaskIds,
10128
- isFilterActive: !!taskFilter,
10129
- additionalColumns,
10130
- hiddenTaskListColumns,
10131
- taskListMenuCommands,
10132
- taskDateChangeMode,
10133
- onTaskDateChangeModeChange: handleTaskDateChangeMode
10134
- }
10135
- ),
10136
- /* @__PURE__ */ jsxs13(
10137
- "div",
10138
- {
10139
- className: showChart ? "gantt-chartSurface" : "gantt-chartSurface gantt-chart-hidden",
10140
- style: { minWidth: `${gridWidth}px`, flex: 1, display: showChart ? void 0 : "none" },
10141
- children: [
10142
- /* @__PURE__ */ jsx16(
10143
- "div",
10144
- {
10145
- className: "gantt-stickyHeader",
10146
- style: { width: `${gridWidth}px`, height: `${timelineHeaderHeight}px` },
10147
- children: /* @__PURE__ */ jsx16(
10148
- TimeScaleHeader_default,
10468
+ ref: scrollContainerRef,
10469
+ className: "gantt-scrollContainer",
10470
+ style: { height: containerHeight ?? "auto", cursor: "grab" },
10471
+ onMouseDown: handlePanStart,
10472
+ children: /* @__PURE__ */ jsxs14(
10473
+ "div",
10474
+ {
10475
+ ref: scrollContentRef,
10476
+ className: "gantt-scrollContent",
10477
+ onMouseOver: handleSharedRowHover,
10478
+ onMouseLeave: clearHoveredRows,
10479
+ children: [
10480
+ /* @__PURE__ */ jsx17(
10481
+ TaskList,
10482
+ {
10483
+ tasks: normalizedTasks,
10484
+ rowHeight: effectiveRowHeight,
10485
+ headerHeight,
10486
+ taskListWidth,
10487
+ onTasksChange: handleTaskChange,
10488
+ selectedTaskId: selectedTaskId ?? void 0,
10489
+ onTaskSelect: handleTaskSelect,
10490
+ show: showTaskList,
10491
+ hasRightShadow: taskListHasRightShadow,
10492
+ disableTaskNameEditing,
10493
+ disableDependencyEditing,
10494
+ onScrollToTask: scrollToTask,
10495
+ onSelectedChipChange: setSelectedChip,
10496
+ onAdd,
10497
+ onDelete: handleDelete,
10498
+ onInsertAfter: handleInsertAfter,
10499
+ onReorder: handleReorder,
10500
+ disableTaskDrag,
10501
+ editingTaskId,
10502
+ enableAddTask,
10503
+ defaultTaskDurationDays,
10504
+ collapsedParentIds,
10505
+ onToggleCollapse: handleToggleCollapse,
10506
+ onPromoteTask: onPromoteTask ?? handlePromoteTask,
10507
+ onDemoteTask: onDemoteTask ?? handleDemoteTask,
10508
+ onUngroupTask: onUngroupTask ?? handleUngroupTask,
10509
+ highlightedTaskIds: taskListHighlightedTaskIds,
10510
+ enableTaskMultiSelect,
10511
+ selectedTaskIds,
10512
+ onSelectedTaskIdsChange,
10513
+ customDays,
10514
+ isWeekend: isWeekend3,
10515
+ businessDays,
10516
+ filterMode,
10517
+ filteredTaskIds: matchedTaskIds,
10518
+ isFilterActive: !!taskFilter,
10519
+ additionalColumns,
10520
+ hiddenTaskListColumns,
10521
+ taskListMenuCommands,
10522
+ hideTaskListRowActions,
10523
+ rowContentLines: resolvedRowContentLines,
10524
+ bodyMinHeight: tableBodyMinHeight,
10525
+ taskDateChangeMode,
10526
+ onTaskDateChangeModeChange: handleTaskDateChangeMode
10527
+ }
10528
+ ),
10529
+ /* @__PURE__ */ jsx17(
10530
+ "div",
10531
+ {
10532
+ className: isTableMatrixMode || showChart ? "gantt-chartSurface" : "gantt-chartSurface gantt-chart-hidden",
10533
+ style: {
10534
+ minWidth: `${isTableMatrixMode ? matrixWidth : gridWidth}px`,
10535
+ flex: 1,
10536
+ display: isTableMatrixMode || showChart ? void 0 : "none"
10537
+ },
10538
+ children: isTableMatrixMode ? /* @__PURE__ */ jsx17(
10539
+ TableMatrix,
10540
+ {
10541
+ tasks: visibleTasks,
10542
+ allTasks: normalizedTasks,
10543
+ columns: matrixColumns,
10544
+ columnGroups: matrixColumnGroups,
10545
+ rowHeight: effectiveRowHeight,
10546
+ headerHeight: timelineHeaderHeight,
10547
+ bodyMinHeight: tableBodyMinHeight,
10548
+ selectedTaskId,
10549
+ onTaskSelect: handleTaskSelect,
10550
+ onCellClick: onMatrixCellClick,
10551
+ highlightedTaskIds: taskListHighlightedTaskIds,
10552
+ filterMode
10553
+ }
10554
+ ) : /* @__PURE__ */ jsxs14(Fragment4, { children: [
10555
+ /* @__PURE__ */ jsx17(
10556
+ "div",
10149
10557
  {
10150
- days: dateRange,
10151
- dayWidth,
10152
- headerHeight,
10153
- viewMode,
10154
- isCustomWeekend
10558
+ className: "gantt-stickyHeader",
10559
+ style: { width: `${gridWidth}px`, height: `${timelineHeaderHeight}px` },
10560
+ children: /* @__PURE__ */ jsx17(
10561
+ TimeScaleHeader_default,
10562
+ {
10563
+ days: dateRange,
10564
+ dayWidth,
10565
+ headerHeight,
10566
+ viewMode,
10567
+ isCustomWeekend
10568
+ }
10569
+ )
10155
10570
  }
10156
- )
10157
- }
10158
- ),
10159
- /* @__PURE__ */ jsxs13(
10160
- "div",
10161
- {
10162
- className: "gantt-taskArea",
10163
- style: {
10164
- position: "relative",
10165
- width: `${gridWidth}px`
10166
- },
10167
- children: [
10168
- /* @__PURE__ */ jsx16(
10169
- GridBackground_default,
10170
- {
10171
- dateRange,
10172
- dayWidth,
10173
- totalHeight: totalGridHeight,
10174
- viewMode,
10175
- isCustomWeekend
10176
- }
10177
- ),
10178
- todayInRange && /* @__PURE__ */ jsx16(TodayIndicator_default, { monthStart, dayWidth }),
10179
- /* @__PURE__ */ jsx16(
10180
- DependencyLines_default,
10181
- {
10182
- tasks: previewVisibleTasks,
10183
- allTasks: previewNormalizedTasks,
10184
- collapsedParentIds,
10185
- monthStart,
10186
- dayWidth,
10187
- rowHeight,
10188
- gridWidth,
10189
- dragOverrides: dependencyOverrides,
10190
- selectedDep: selectedChip,
10191
- businessDays,
10192
- weekendPredicate: isCustomWeekend
10193
- }
10194
- ),
10195
- dragGuideLines && /* @__PURE__ */ jsx16(
10196
- DragGuideLines_default,
10197
- {
10198
- isDragging: dragGuideLines.isDragging,
10199
- dragMode: dragGuideLines.dragMode,
10200
- left: dragGuideLines.left,
10201
- width: dragGuideLines.width,
10202
- totalHeight: totalGridHeight
10203
- }
10204
- ),
10205
- visibleTasks.map((task, index) => /* @__PURE__ */ jsx16(
10206
- TaskRow_default,
10207
- {
10208
- task,
10209
- monthStart,
10210
- dayWidth,
10211
- rowHeight,
10212
- onTasksChange: handleTaskChange,
10213
- onDragStateChange: (state) => {
10214
- if (state.isDragging) {
10215
- setDragGuideLines(state);
10216
- setDraggedTaskOverride({ taskId: task.id, left: state.left, width: state.width });
10217
- } else {
10218
- setDragGuideLines(null);
10219
- setDraggedTaskOverride(null);
10220
- }
10221
- },
10222
- rowIndex: index,
10223
- allTasks: normalizedTasks,
10224
- enableAutoSchedule: enableAutoSchedule ?? false,
10225
- disableConstraints: disableConstraints ?? false,
10226
- overridePosition: cascadeOverrides.get(task.id),
10227
- onCascadeProgress: handleCascadeProgress,
10228
- onCascade: handleCascade,
10229
- highlightExpiredTasks,
10230
- showBaseline,
10231
- isFilterMatch: filterMode === "highlight" ? matchedTaskIds.has(task.id) : false,
10232
- businessDays,
10233
- customDays,
10234
- isWeekend: isWeekend3,
10235
- disableTaskDrag,
10236
- viewMode
10571
+ ),
10572
+ /* @__PURE__ */ jsxs14(
10573
+ "div",
10574
+ {
10575
+ className: "gantt-taskArea",
10576
+ style: {
10577
+ position: "relative",
10578
+ width: `${gridWidth}px`
10237
10579
  },
10238
- task.id
10239
- ))
10240
- ]
10241
- }
10242
- )
10243
- ]
10244
- }
10245
- )
10246
- ]
10580
+ children: [
10581
+ /* @__PURE__ */ jsx17(
10582
+ GridBackground_default,
10583
+ {
10584
+ dateRange,
10585
+ dayWidth,
10586
+ totalHeight: totalGridHeight,
10587
+ viewMode,
10588
+ isCustomWeekend
10589
+ }
10590
+ ),
10591
+ todayInRange && /* @__PURE__ */ jsx17(TodayIndicator_default, { monthStart, dayWidth }),
10592
+ /* @__PURE__ */ jsx17(
10593
+ DependencyLines_default,
10594
+ {
10595
+ tasks: previewVisibleTasks,
10596
+ allTasks: previewNormalizedTasks,
10597
+ collapsedParentIds,
10598
+ monthStart,
10599
+ dayWidth,
10600
+ rowHeight: effectiveRowHeight,
10601
+ gridWidth,
10602
+ dragOverrides: dependencyOverrides,
10603
+ selectedDep: selectedChip,
10604
+ businessDays,
10605
+ weekendPredicate: isCustomWeekend
10606
+ }
10607
+ ),
10608
+ dragGuideLines && /* @__PURE__ */ jsx17(
10609
+ DragGuideLines_default,
10610
+ {
10611
+ isDragging: dragGuideLines.isDragging,
10612
+ dragMode: dragGuideLines.dragMode,
10613
+ left: dragGuideLines.left,
10614
+ width: dragGuideLines.width,
10615
+ totalHeight: totalGridHeight
10616
+ }
10617
+ ),
10618
+ visibleTasks.map((task, index) => /* @__PURE__ */ jsx17(
10619
+ TaskRow_default,
10620
+ {
10621
+ task,
10622
+ monthStart,
10623
+ dayWidth,
10624
+ rowHeight: effectiveRowHeight,
10625
+ onTasksChange: handleTaskChange,
10626
+ onDragStateChange: (state) => {
10627
+ if (state.isDragging) {
10628
+ setDragGuideLines(state);
10629
+ setDraggedTaskOverride({ taskId: task.id, left: state.left, width: state.width });
10630
+ } else {
10631
+ setDragGuideLines(null);
10632
+ setDraggedTaskOverride(null);
10633
+ }
10634
+ },
10635
+ rowIndex: index,
10636
+ allTasks: normalizedTasks,
10637
+ enableAutoSchedule: enableAutoSchedule ?? false,
10638
+ disableConstraints: disableConstraints ?? false,
10639
+ overridePosition: cascadeOverrides.get(task.id),
10640
+ onCascadeProgress: handleCascadeProgress,
10641
+ onCascade: handleCascade,
10642
+ highlightExpiredTasks,
10643
+ showBaseline,
10644
+ isFilterMatch: filterMode === "highlight" ? matchedTaskIds.has(task.id) : false,
10645
+ businessDays,
10646
+ customDays,
10647
+ isWeekend: isWeekend3,
10648
+ disableTaskDrag,
10649
+ viewMode
10650
+ },
10651
+ task.id
10652
+ ))
10653
+ ]
10654
+ }
10655
+ )
10656
+ ] })
10657
+ }
10658
+ )
10659
+ ]
10660
+ }
10661
+ )
10247
10662
  }
10248
10663
  )
10249
10664
  }
10250
- ) });
10665
+ );
10251
10666
  }
10252
10667
  var TaskGanttChart = forwardRef(TaskGanttChartInner);
10253
10668
  var GanttChart = forwardRef(GanttChartInner);
10254
10669
  GanttChart.displayName = "GanttChart";
10255
10670
 
10256
10671
  // src/components/ui/Button.tsx
10257
- import React14 from "react";
10258
- import { jsx as jsx17 } from "react/jsx-runtime";
10259
- var Button = React14.forwardRef(
10672
+ import React15 from "react";
10673
+ import { jsx as jsx18 } from "react/jsx-runtime";
10674
+ var Button = React15.forwardRef(
10260
10675
  ({ className, variant = "default", size = "default", children, ...props }, ref) => {
10261
10676
  const classes = [
10262
10677
  "gantt-btn",
@@ -10264,7 +10679,7 @@ var Button = React14.forwardRef(
10264
10679
  size !== "default" ? `gantt-btn-${size}` : "",
10265
10680
  className || ""
10266
10681
  ].filter(Boolean).join(" ");
10267
- return /* @__PURE__ */ jsx17("button", { ref, className: classes, ...props, children });
10682
+ return /* @__PURE__ */ jsx18("button", { ref, className: classes, ...props, children });
10268
10683
  }
10269
10684
  );
10270
10685
  Button.displayName = "Button";
@@ -10315,6 +10730,7 @@ export {
10315
10730
  PopoverContent,
10316
10731
  PopoverTrigger,
10317
10732
  ResourceTimelineChart,
10733
+ TableMatrix,
10318
10734
  TaskList,
10319
10735
  TaskRow_default as TaskRow,
10320
10736
  TimeScaleHeader_default as TimeScaleHeader,