gantt-lib 0.91.0 → 0.100.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) => {
6328
6405
  e.stopPropagation();
6329
- setEditingColumnId(col.id);
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) => {
6413
+ e.stopPropagation();
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,13 @@ var TaskList = ({
6644
6774
  additionalColumns,
6645
6775
  hiddenTaskListColumns,
6646
6776
  taskListMenuCommands,
6777
+ hideTaskListRowActions = false,
6778
+ rowContentLines = 1,
6647
6779
  taskDateChangeMode = "preserve-duration",
6648
6780
  onTaskDateChangeModeChange
6649
6781
  }) => {
6650
6782
  const [internalSelectedTaskIds, setInternalSelectedTaskIds] = useState6(/* @__PURE__ */ new Set());
6783
+ const [activeCustomCell, setActiveCustomCell] = useState6(null);
6651
6784
  const effectiveSelectedTaskIds = selectedTaskIds ?? internalSelectedTaskIds;
6652
6785
  const emitSelectedTaskIdsChange = useCallback5((nextSelectedTaskIds) => {
6653
6786
  if (!selectedTaskIds) {
@@ -6819,21 +6952,28 @@ var TaskList = ({
6819
6952
  onSelectedChipChange?.(chip);
6820
6953
  }, [onSelectedChipChange]);
6821
6954
  useEffect6(() => {
6822
- if (!selectingPredecessorFor && !selectedChip && !selectedTaskId) return;
6955
+ if (!selectingPredecessorFor && !selectedChip && !selectedTaskId && !activeCustomCell) return;
6823
6956
  const handleKeyDown = (e) => {
6824
6957
  if (e.key === "Escape") {
6825
6958
  setSelectingPredecessorFor(null);
6826
6959
  setSelectedChip(null);
6960
+ setActiveCustomCell(null);
6827
6961
  onSelectedChipChange?.(null);
6828
6962
  onTaskSelect?.(null);
6829
6963
  }
6830
6964
  };
6831
6965
  const handleMouseDown = (e) => {
6832
6966
  const target = e.target;
6833
- if (overlayRef.current?.contains(target)) return;
6967
+ if (overlayRef.current?.contains(target)) {
6968
+ if (activeCustomCell && !target.closest?.("[data-custom-column-id]")) {
6969
+ setActiveCustomCell(null);
6970
+ }
6971
+ return;
6972
+ }
6834
6973
  if (target.closest?.(".gantt-popover")) return;
6835
6974
  setSelectingPredecessorFor(null);
6836
6975
  setSelectedChip(null);
6976
+ setActiveCustomCell(null);
6837
6977
  onSelectedChipChange?.(null);
6838
6978
  onTaskSelect?.(null);
6839
6979
  };
@@ -6843,7 +6983,7 @@ var TaskList = ({
6843
6983
  document.removeEventListener("keydown", handleKeyDown);
6844
6984
  document.removeEventListener("mousedown", handleMouseDown, true);
6845
6985
  };
6846
- }, [selectingPredecessorFor, selectedChip, selectedTaskId, onTaskSelect, onSelectedChipChange]);
6986
+ }, [selectingPredecessorFor, selectedChip, selectedTaskId, activeCustomCell, onTaskSelect, onSelectedChipChange]);
6847
6987
  const handleAddDependency = useCallback5((successorTaskId, predecessorTaskId, linkType) => {
6848
6988
  if (successorTaskId === predecessorTaskId) return;
6849
6989
  if (areTasksHierarchicallyRelated(successorTaskId, predecessorTaskId, tasks)) {
@@ -7233,7 +7373,10 @@ var TaskList = ({
7233
7373
  {
7234
7374
  ref: overlayRef,
7235
7375
  className: `gantt-tl-overlay${show ? "" : " gantt-tl-hidden"}${hasRightShadow ? " gantt-tl-overlay-shadowed" : ""}`,
7236
- style: { "--tasklist-width": `${effectiveTaskListWidth}px` },
7376
+ style: {
7377
+ "--tasklist-width": `${effectiveTaskListWidth}px`,
7378
+ "--gantt-row-content-lines": String(Math.max(2, Math.floor(rowContentLines)))
7379
+ },
7237
7380
  children: /* @__PURE__ */ jsxs11("div", { className: "gantt-tl-table", children: [
7238
7381
  /* @__PURE__ */ jsx14("div", { className: "gantt-tl-header", style: { height: `${tableHeaderHeight}px` }, children: resolvedColumns.map((col) => {
7239
7382
  if (col.id === "selection") {
@@ -7313,7 +7456,7 @@ var TaskList = ({
7313
7456
  return /* @__PURE__ */ jsx14(
7314
7457
  "div",
7315
7458
  {
7316
- className: "gantt-tl-headerCell gantt-tl-headerCell-custom",
7459
+ className: `gantt-tl-headerCell gantt-tl-headerCell-custom gantt-tl-cell-align-${col.align ?? "left"}`,
7317
7460
  "data-column-id": `custom:${col.id}`,
7318
7461
  "data-custom-column-id": col.id,
7319
7462
  style: { width: col.width, minWidth: col.width, flexShrink: 0 },
@@ -7355,12 +7498,12 @@ var TaskList = ({
7355
7498
  onAdd,
7356
7499
  onInsertAfter: handleStartInsertAfter,
7357
7500
  editingTaskId: propEditingTaskId,
7358
- isDragging: draggingIndex === index,
7359
- isDragOver: dragOverIndex === index,
7360
- onDragStart: handleDragStart,
7361
- onDragOver: handleDragOver,
7362
- onDrop: handleDrop,
7363
- onDragEnd: handleDragEnd,
7501
+ isDragging: !disableTaskDrag && draggingIndex === index,
7502
+ isDragOver: !disableTaskDrag && dragOverIndex === index,
7503
+ onDragStart: disableTaskDrag ? void 0 : handleDragStart,
7504
+ onDragOver: disableTaskDrag ? void 0 : handleDragOver,
7505
+ onDrop: disableTaskDrag ? void 0 : handleDrop,
7506
+ onDragEnd: disableTaskDrag ? void 0 : handleDragEnd,
7364
7507
  collapsedParentIds,
7365
7508
  onToggleCollapse: handleToggleCollapse,
7366
7509
  onPromoteTask,
@@ -7381,7 +7524,10 @@ var TaskList = ({
7381
7524
  resolvedColumns,
7382
7525
  isTaskSelected: effectiveSelectedTaskIds.has(task.id),
7383
7526
  onTaskSelectionChange: handleToggleTaskSelection,
7527
+ activeCustomCell,
7528
+ onActiveCustomCellChange: setActiveCustomCell,
7384
7529
  taskListMenuCommands,
7530
+ hideTaskListRowActions,
7385
7531
  taskDateChangeMode,
7386
7532
  onTaskDateChangeModeChange
7387
7533
  }
@@ -7409,25 +7555,25 @@ var TaskList = ({
7409
7555
  enableAddTask && onAdd && !isCreating && !pendingInsert && /* @__PURE__ */ jsx14(
7410
7556
  "button",
7411
7557
  {
7412
- className: `gantt-tl-add-btn${dragOverIndex === visibleTasks.length ? " gantt-tl-add-btn-drag-over" : ""}`,
7558
+ className: `gantt-tl-add-btn${!disableTaskDrag && dragOverIndex === visibleTasks.length ? " gantt-tl-add-btn-drag-over" : ""}`,
7413
7559
  onClick: () => {
7414
7560
  setPendingInsert(null);
7415
7561
  setIsCreating(true);
7416
7562
  },
7417
- onDragEnter: (e) => {
7563
+ onDragEnter: disableTaskDrag ? void 0 : (e) => {
7418
7564
  e.preventDefault();
7419
7565
  setDragOverIndex(visibleTasks.length);
7420
7566
  },
7421
- onDragOver: (e) => {
7567
+ onDragOver: disableTaskDrag ? void 0 : (e) => {
7422
7568
  e.preventDefault();
7423
7569
  e.dataTransfer.dropEffect = "move";
7424
7570
  setDragOverIndex(visibleTasks.length);
7425
7571
  },
7426
- onDragLeave: (e) => {
7572
+ onDragLeave: disableTaskDrag ? void 0 : (e) => {
7427
7573
  e.preventDefault();
7428
7574
  setDragOverIndex(null);
7429
7575
  },
7430
- onDrop: (e) => {
7576
+ onDrop: disableTaskDrag ? void 0 : (e) => {
7431
7577
  e.preventDefault();
7432
7578
  handleDrop(visibleTasks.length, e);
7433
7579
  },
@@ -9120,6 +9266,190 @@ function ResourceTimelineChart({
9120
9266
  ) });
9121
9267
  }
9122
9268
 
9269
+ // src/components/TableMatrix/TableMatrix.tsx
9270
+ import { useMemo as useMemo10 } from "react";
9271
+ import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
9272
+ function joinClasses(...values) {
9273
+ return values.filter(Boolean).join(" ");
9274
+ }
9275
+ function TableMatrix({
9276
+ tasks,
9277
+ allTasks = tasks,
9278
+ columns,
9279
+ columnGroups,
9280
+ rowHeight,
9281
+ headerHeight,
9282
+ selectedTaskId,
9283
+ onTaskSelect,
9284
+ onCellClick,
9285
+ highlightedTaskIds,
9286
+ filterMode = "highlight"
9287
+ }) {
9288
+ const gridTemplateColumns = useMemo10(
9289
+ () => columns.map((column) => `${column.width}px`).join(" "),
9290
+ [columns]
9291
+ );
9292
+ const totalWidth = useMemo10(
9293
+ () => columns.reduce((sum, column) => sum + column.width, 0),
9294
+ [columns]
9295
+ );
9296
+ const hasGroupHeader = useMemo10(
9297
+ () => columns.some((column) => !!column.groupId) || (columnGroups?.length ?? 0) > 0,
9298
+ [columnGroups, columns]
9299
+ );
9300
+ const groupMap = useMemo10(
9301
+ () => new Map((columnGroups ?? []).map((group) => [group.id, group])),
9302
+ [columnGroups]
9303
+ );
9304
+ const headerSpans = useMemo10(() => {
9305
+ if (!hasGroupHeader) return [];
9306
+ if (columnGroups?.some((group) => typeof group.width === "number")) {
9307
+ return columnGroups.map((group) => ({
9308
+ id: group.id,
9309
+ header: group.header,
9310
+ width: group.width ?? 0,
9311
+ className: group.className
9312
+ }));
9313
+ }
9314
+ const spans = [];
9315
+ for (const column of columns) {
9316
+ const groupId = column.groupId ?? column.id;
9317
+ const lastSpan = spans[spans.length - 1];
9318
+ if (lastSpan?.id === groupId) {
9319
+ lastSpan.width += column.width;
9320
+ continue;
9321
+ }
9322
+ const group = groupMap.get(groupId);
9323
+ spans.push({
9324
+ id: groupId,
9325
+ header: group?.header ?? column.header,
9326
+ width: column.width,
9327
+ className: group?.className
9328
+ });
9329
+ }
9330
+ return spans;
9331
+ }, [columns, groupMap, hasGroupHeader]);
9332
+ const headerContentHeight = Math.max(0, headerHeight - 1);
9333
+ const topRowHeight = hasGroupHeader ? Math.ceil(headerContentHeight / 2) : headerContentHeight;
9334
+ const bottomRowHeight = hasGroupHeader ? Math.floor(headerContentHeight / 2) : 0;
9335
+ const parentTaskIds = useMemo10(() => {
9336
+ const ids = /* @__PURE__ */ new Set();
9337
+ for (const task of allTasks) {
9338
+ if (task.parentId) {
9339
+ ids.add(task.parentId);
9340
+ }
9341
+ }
9342
+ return ids;
9343
+ }, [allTasks]);
9344
+ const nestingDepthMap = useMemo10(() => {
9345
+ const depthMap = /* @__PURE__ */ new Map();
9346
+ const taskById = new Map(allTasks.map((task) => [task.id, task]));
9347
+ const getDepth = (taskId, seen = /* @__PURE__ */ new Set()) => {
9348
+ if (depthMap.has(taskId)) return depthMap.get(taskId);
9349
+ if (seen.has(taskId)) return 0;
9350
+ const task = taskById.get(taskId);
9351
+ if (!task?.parentId || !taskById.has(task.parentId)) {
9352
+ depthMap.set(taskId, 0);
9353
+ return 0;
9354
+ }
9355
+ seen.add(taskId);
9356
+ const depth = getDepth(task.parentId, seen) + 1;
9357
+ depthMap.set(taskId, depth);
9358
+ return depth;
9359
+ };
9360
+ for (const task of allTasks) {
9361
+ getDepth(task.id);
9362
+ }
9363
+ return depthMap;
9364
+ }, [allTasks]);
9365
+ return /* @__PURE__ */ jsxs13("div", { className: "gantt-mx-root", style: { width: `${totalWidth}px` }, children: [
9366
+ /* @__PURE__ */ jsxs13("div", { className: "gantt-mx-header", style: { height: `${headerHeight}px` }, children: [
9367
+ hasGroupHeader && /* @__PURE__ */ jsx16(
9368
+ "div",
9369
+ {
9370
+ className: "gantt-mx-headerRow gantt-mx-headerGroupRow",
9371
+ style: { gridTemplateColumns: headerSpans.map((span) => `${span.width}px`).join(" "), height: `${topRowHeight}px` },
9372
+ children: headerSpans.map((span) => /* @__PURE__ */ jsx16("div", { className: joinClasses("gantt-mx-groupCell", span.className), children: span.header }, span.id))
9373
+ }
9374
+ ),
9375
+ /* @__PURE__ */ jsx16(
9376
+ "div",
9377
+ {
9378
+ className: "gantt-mx-headerRow",
9379
+ style: { gridTemplateColumns, height: `${hasGroupHeader ? bottomRowHeight : topRowHeight}px` },
9380
+ children: columns.map((column) => /* @__PURE__ */ jsx16(
9381
+ "div",
9382
+ {
9383
+ className: joinClasses(
9384
+ "gantt-mx-headerCell",
9385
+ column.headerClassName
9386
+ ),
9387
+ children: column.header
9388
+ },
9389
+ column.id
9390
+ ))
9391
+ }
9392
+ )
9393
+ ] }),
9394
+ /* @__PURE__ */ jsx16(
9395
+ "div",
9396
+ {
9397
+ className: "gantt-mx-body",
9398
+ style: { height: `${tasks.length * rowHeight}px` },
9399
+ children: tasks.map((task, index) => {
9400
+ const isHighlighted = filterMode === "highlight" && !!highlightedTaskIds?.has(task.id);
9401
+ const isParent = parentTaskIds.has(task.id);
9402
+ const nestingDepth = nestingDepthMap.get(task.id) ?? 0;
9403
+ const rowFillLevel = Math.min(nestingDepth, 2);
9404
+ const isTotal = Boolean(task.isTotal);
9405
+ return /* @__PURE__ */ jsx16(
9406
+ "div",
9407
+ {
9408
+ "data-gantt-task-row-id": task.id,
9409
+ className: joinClasses(
9410
+ "gantt-mx-row",
9411
+ task.parentId && "gantt-mx-row-child",
9412
+ isParent && "gantt-mx-row-parent",
9413
+ `gantt-mx-row-level-${rowFillLevel}`,
9414
+ isTotal && "gantt-mx-row-total",
9415
+ selectedTaskId === task.id && "gantt-mx-row-selected",
9416
+ isHighlighted && "gantt-mx-row-highlighted"
9417
+ ),
9418
+ style: {
9419
+ gridTemplateColumns,
9420
+ top: `${index * rowHeight}px`,
9421
+ height: `${rowHeight}px`
9422
+ },
9423
+ onClick: () => onTaskSelect?.(task.id),
9424
+ children: columns.map((column, columnIndex) => {
9425
+ const resolvedCellClassName = typeof column.cellClassName === "function" ? column.cellClassName(task) : column.cellClassName;
9426
+ return /* @__PURE__ */ jsx16(
9427
+ "div",
9428
+ {
9429
+ className: joinClasses(
9430
+ "gantt-mx-cell",
9431
+ onCellClick && "gantt-mx-cell-clickable",
9432
+ `gantt-mx-cellAlign-${column.align ?? "right"}`,
9433
+ column.className,
9434
+ resolvedCellClassName
9435
+ ),
9436
+ onClick: (event) => {
9437
+ onCellClick?.({ task, column, rowIndex: index, columnIndex, event });
9438
+ },
9439
+ children: column.renderCell(task)
9440
+ },
9441
+ `${task.id}:${column.id}`
9442
+ );
9443
+ })
9444
+ },
9445
+ task.id
9446
+ );
9447
+ })
9448
+ }
9449
+ )
9450
+ ] });
9451
+ }
9452
+
9123
9453
  // src/components/GanttChart/print.ts
9124
9454
  function getPrintDocumentTitle({
9125
9455
  header,
@@ -9458,13 +9788,13 @@ async function printGanttChart({
9458
9788
  }
9459
9789
 
9460
9790
  // src/components/GanttChart/GanttChart.tsx
9461
- import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
9791
+ import { Fragment as Fragment4, jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
9462
9792
  var SCROLL_TO_ROW_CONTEXT_ROWS = 2;
9463
9793
  function GanttChartInner(props, ref) {
9464
9794
  if (props.mode === "resource-planner") {
9465
- return /* @__PURE__ */ jsx16(ResourceTimelineChart, { ...props });
9795
+ return /* @__PURE__ */ jsx17(ResourceTimelineChart, { ...props });
9466
9796
  }
9467
- return /* @__PURE__ */ jsx16(
9797
+ return /* @__PURE__ */ jsx17(
9468
9798
  TaskGanttChart,
9469
9799
  {
9470
9800
  ...props,
@@ -9473,9 +9803,9 @@ function GanttChartInner(props, ref) {
9473
9803
  );
9474
9804
  }
9475
9805
  function TaskGanttChartInner(props, ref) {
9806
+ const isTableMatrixMode = props.mode === "table-matrix";
9476
9807
  const {
9477
9808
  tasks,
9478
- dayWidth = 40,
9479
9809
  rowHeight = 40,
9480
9810
  headerHeight = 40,
9481
9811
  containerHeight,
@@ -9499,10 +9829,6 @@ function TaskGanttChartInner(props, ref) {
9499
9829
  onUngroupTask,
9500
9830
  enableAddTask = true,
9501
9831
  defaultTaskDurationDays,
9502
- viewMode = "day",
9503
- customDays,
9504
- isWeekend: isWeekend3,
9505
- businessDays = true,
9506
9832
  taskFilter,
9507
9833
  filterMode = "highlight",
9508
9834
  collapsedParentIds: externalCollapsedParentIds,
@@ -9516,9 +9842,19 @@ function TaskGanttChartInner(props, ref) {
9516
9842
  additionalColumns,
9517
9843
  hiddenTaskListColumns,
9518
9844
  taskListMenuCommands,
9845
+ hideTaskListRowActions = false,
9846
+ rowContentLines = 1,
9519
9847
  taskDateChangeMode: externalTaskDateChangeMode,
9520
9848
  onTaskDateChangeModeChange: externalOnTaskDateChangeModeChange
9521
9849
  } = props;
9850
+ const dayWidth = !isTableMatrixMode ? props.dayWidth ?? 40 : 40;
9851
+ const viewMode = !isTableMatrixMode ? props.viewMode ?? "day" : "day";
9852
+ const customDays = !isTableMatrixMode ? props.customDays : void 0;
9853
+ const isWeekend3 = !isTableMatrixMode ? props.isWeekend : void 0;
9854
+ const businessDays = !isTableMatrixMode ? props.businessDays ?? true : true;
9855
+ const matrixColumns = isTableMatrixMode ? props.matrixColumns : [];
9856
+ const matrixColumnGroups = isTableMatrixMode ? props.matrixColumnGroups : void 0;
9857
+ const onMatrixCellClick = isTableMatrixMode ? props.onMatrixCellClick : void 0;
9522
9858
  const containerRef = useRef9(null);
9523
9859
  const scrollContainerRef = useRef9(null);
9524
9860
  const scrollContentRef = useRef9(null);
@@ -9532,12 +9868,17 @@ function TaskGanttChartInner(props, ref) {
9532
9868
  const [editingTaskId, setEditingTaskId] = useState9(null);
9533
9869
  const taskDateChangeMode = externalTaskDateChangeMode ?? internalTaskDateChangeMode;
9534
9870
  const handleTaskDateChangeMode = externalOnTaskDateChangeModeChange ?? setInternalTaskDateChangeMode;
9535
- const normalizedTasks = useMemo10(() => normalizeHierarchyTasks(tasks), [tasks]);
9536
- const isCustomWeekend = useMemo10(
9871
+ const resolvedRowContentLines = Math.max(1, Math.floor(rowContentLines));
9872
+ const effectiveRowHeight = useMemo11(
9873
+ () => Math.max(rowHeight, 10 + resolvedRowContentLines * 18),
9874
+ [resolvedRowContentLines, rowHeight]
9875
+ );
9876
+ const normalizedTasks = useMemo11(() => normalizeHierarchyTasks(tasks), [tasks]);
9877
+ const isCustomWeekend = useMemo11(
9537
9878
  () => createCustomDayPredicate({ customDays, isWeekend: isWeekend3 }),
9538
9879
  [customDays, isWeekend3]
9539
9880
  );
9540
- const dateRangeTasks = useMemo10(() => {
9881
+ const dateRangeTasks = useMemo11(() => {
9541
9882
  if (!showBaseline) {
9542
9883
  return normalizedTasks;
9543
9884
  }
@@ -9547,14 +9888,18 @@ function TaskGanttChartInner(props, ref) {
9547
9888
  endDate: task.baselineEndDate && parseUTCDate(task.baselineEndDate).getTime() > parseUTCDate(task.endDate).getTime() ? task.baselineEndDate : task.endDate
9548
9889
  }));
9549
9890
  }, [normalizedTasks, showBaseline]);
9550
- const dateRange = useMemo10(() => getMultiMonthDays(dateRangeTasks), [dateRangeTasks]);
9891
+ const dateRange = useMemo11(() => getMultiMonthDays(dateRangeTasks), [dateRangeTasks]);
9551
9892
  const [validationResult, setValidationResult] = useState9(null);
9552
9893
  const [cascadeOverrides, setCascadeOverrides] = useState9(/* @__PURE__ */ new Map());
9553
- const gridWidth = useMemo10(
9894
+ const gridWidth = useMemo11(
9554
9895
  () => Math.round(dateRange.length * dayWidth),
9555
9896
  [dateRange.length, dayWidth]
9556
9897
  );
9557
- const visibleTasks = useMemo10(() => {
9898
+ const matrixWidth = useMemo11(
9899
+ () => matrixColumns.reduce((sum, column) => sum + column.width, 0),
9900
+ [matrixColumns]
9901
+ );
9902
+ const visibleTasks = useMemo11(() => {
9558
9903
  const parentMap = new Map(normalizedTasks.map((t) => [t.id, t.parentId]));
9559
9904
  function isAnyAncestorCollapsed(parentId) {
9560
9905
  let current = parentId;
@@ -9570,11 +9915,11 @@ function TaskGanttChartInner(props, ref) {
9570
9915
  }
9571
9916
  return tasks2;
9572
9917
  }, [normalizedTasks, collapsedParentIds, filterMode, taskFilter]);
9573
- const matchedTaskIds = useMemo10(() => {
9918
+ const matchedTaskIds = useMemo11(() => {
9574
9919
  if (!taskFilter) return /* @__PURE__ */ new Set();
9575
9920
  return new Set(visibleTasks.filter(taskFilter).map((task) => task.id));
9576
9921
  }, [visibleTasks, taskFilter]);
9577
- const taskListHighlightedTaskIds = useMemo10(() => {
9922
+ const taskListHighlightedTaskIds = useMemo11(() => {
9578
9923
  if (filterMode === "hide") {
9579
9924
  return /* @__PURE__ */ new Set();
9580
9925
  }
@@ -9585,24 +9930,25 @@ function TaskGanttChartInner(props, ref) {
9585
9930
  matchedTaskIds.forEach((taskId) => mergedHighlightedTaskIds.add(taskId));
9586
9931
  return mergedHighlightedTaskIds;
9587
9932
  }, [filterMode, highlightedTaskIds, matchedTaskIds]);
9588
- const totalGridHeight = useMemo10(
9589
- () => visibleTasks.length * rowHeight,
9590
- [visibleTasks.length, rowHeight]
9933
+ const totalGridHeight = useMemo11(
9934
+ () => visibleTasks.length * effectiveRowHeight,
9935
+ [effectiveRowHeight, visibleTasks.length]
9591
9936
  );
9592
9937
  const timelineHeaderHeight = headerHeight + 1;
9593
- const monthStart = useMemo10(() => {
9938
+ const monthStart = useMemo11(() => {
9594
9939
  if (dateRange.length === 0) {
9595
9940
  return new Date(Date.UTC((/* @__PURE__ */ new Date()).getUTCFullYear(), (/* @__PURE__ */ new Date()).getUTCMonth(), 1));
9596
9941
  }
9597
9942
  const firstDay = dateRange[0];
9598
9943
  return new Date(Date.UTC(firstDay.getUTCFullYear(), firstDay.getUTCMonth(), 1));
9599
9944
  }, [dateRange]);
9600
- const todayInRange = useMemo10(() => {
9945
+ const todayInRange = useMemo11(() => {
9601
9946
  const now = /* @__PURE__ */ new Date();
9602
9947
  const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
9603
9948
  return dateRange.some((day) => day.getTime() === today.getTime());
9604
9949
  }, [dateRange]);
9605
9950
  useEffect9(() => {
9951
+ if (isTableMatrixMode) return;
9606
9952
  const container = scrollContainerRef.current;
9607
9953
  if (!container || dateRange.length === 0) return;
9608
9954
  const now = /* @__PURE__ */ new Date();
@@ -9613,7 +9959,7 @@ function TaskGanttChartInner(props, ref) {
9613
9959
  const containerWidth = container.clientWidth;
9614
9960
  const scrollLeft = Math.round(todayOffset + dayWidth / 2 - containerWidth * 0.3);
9615
9961
  container.scrollLeft = Math.max(0, scrollLeft);
9616
- }, []);
9962
+ }, [dateRange, dayWidth, isTableMatrixMode]);
9617
9963
  useEffect9(() => {
9618
9964
  const container = scrollContainerRef.current;
9619
9965
  if (!container) return;
@@ -9627,6 +9973,7 @@ function TaskGanttChartInner(props, ref) {
9627
9973
  };
9628
9974
  }, []);
9629
9975
  const scrollToToday = useCallback8(() => {
9976
+ if (isTableMatrixMode) return;
9630
9977
  const container = scrollContainerRef.current;
9631
9978
  if (!container || dateRange.length === 0) return;
9632
9979
  const now = /* @__PURE__ */ new Date();
@@ -9637,8 +9984,18 @@ function TaskGanttChartInner(props, ref) {
9637
9984
  const containerWidth = container.clientWidth;
9638
9985
  const scrollLeft = Math.round(todayOffset + dayWidth / 2 - containerWidth * 0.3);
9639
9986
  container.scrollTo({ left: Math.max(0, scrollLeft), behavior: "smooth" });
9640
- }, [dateRange, dayWidth]);
9987
+ }, [dateRange, dayWidth, isTableMatrixMode]);
9641
9988
  const scrollToTask = useCallback8((taskId) => {
9989
+ if (isTableMatrixMode) {
9990
+ const container2 = scrollContainerRef.current;
9991
+ if (!container2) return;
9992
+ const rowIndex = visibleTasks.findIndex((visibleTask) => visibleTask.id === taskId);
9993
+ if (rowIndex === -1) return;
9994
+ const paddedRowIndex = Math.max(0, rowIndex - SCROLL_TO_ROW_CONTEXT_ROWS);
9995
+ container2.scrollTo({ top: Math.max(0, effectiveRowHeight * paddedRowIndex), behavior: "smooth" });
9996
+ setSelectedTaskId(taskId);
9997
+ return;
9998
+ }
9642
9999
  const container = scrollContainerRef.current;
9643
10000
  if (!container || dateRange.length === 0) return;
9644
10001
  const task = tasks.find((t) => t.id === taskId);
@@ -9654,7 +10011,7 @@ function TaskGanttChartInner(props, ref) {
9654
10011
  const taskOffset = taskIndex * dayWidth;
9655
10012
  const scrollLeft = Math.round(taskOffset - dayWidth * 2);
9656
10013
  container.scrollTo({ left: Math.max(0, scrollLeft), behavior: "smooth" });
9657
- }, [tasks, dateRange, dayWidth]);
10014
+ }, [dateRange, dayWidth, effectiveRowHeight, isTableMatrixMode, tasks, visibleTasks]);
9658
10015
  const scrollToRow = useCallback8((taskId, options = {}) => {
9659
10016
  const container = scrollContainerRef.current;
9660
10017
  if (!container) return;
@@ -9663,7 +10020,7 @@ function TaskGanttChartInner(props, ref) {
9663
10020
  const rowIndex = visibleTasks.findIndex((visibleTask) => visibleTask.id === task.id);
9664
10021
  if (rowIndex === -1) return;
9665
10022
  const paddedRowIndex = Math.max(0, rowIndex - SCROLL_TO_ROW_CONTEXT_ROWS);
9666
- const scrollTop = Math.max(0, rowHeight * paddedRowIndex);
10023
+ const scrollTop = Math.max(0, effectiveRowHeight * paddedRowIndex);
9667
10024
  const {
9668
10025
  select = true,
9669
10026
  behavior = "smooth",
@@ -9683,7 +10040,7 @@ function TaskGanttChartInner(props, ref) {
9683
10040
  }
9684
10041
  }
9685
10042
  container.scrollTo({ top: scrollTop, behavior });
9686
- }, [tasks, visibleTasks, rowHeight]);
10043
+ }, [effectiveRowHeight, tasks, visibleTasks]);
9687
10044
  const [dragGuideLines, setDragGuideLines] = useState9(null);
9688
10045
  const [draggedTaskOverride, setDraggedTaskOverride] = useState9(null);
9689
10046
  const [previewTasksById, setPreviewTasksById] = useState9(/* @__PURE__ */ new Map());
@@ -9788,7 +10145,7 @@ function TaskGanttChartInner(props, ref) {
9788
10145
  }
9789
10146
  onTasksChange?.(normalized);
9790
10147
  }, [onTasksChange, onReorder]);
9791
- const dependencyOverrides = useMemo10(() => {
10148
+ const dependencyOverrides = useMemo11(() => {
9792
10149
  const map = new Map(cascadeOverrides);
9793
10150
  if (draggedTaskOverride) {
9794
10151
  map.set(draggedTaskOverride.taskId, {
@@ -9802,11 +10159,11 @@ function TaskGanttChartInner(props, ref) {
9802
10159
  setCascadeOverrides(new Map(overrides));
9803
10160
  setPreviewTasksById(new Map(previewTasks.map((task) => [task.id, task])));
9804
10161
  }, []);
9805
- const previewNormalizedTasks = useMemo10(() => {
10162
+ const previewNormalizedTasks = useMemo11(() => {
9806
10163
  if (previewTasksById.size === 0) return normalizedTasks;
9807
10164
  return normalizedTasks.map((task) => previewTasksById.get(task.id) ?? task);
9808
10165
  }, [normalizedTasks, previewTasksById]);
9809
- const previewVisibleTasks = useMemo10(() => {
10166
+ const previewVisibleTasks = useMemo11(() => {
9810
10167
  if (previewTasksById.size === 0) return visibleTasks;
9811
10168
  return visibleTasks.map((task) => previewTasksById.get(task.id) ?? task);
9812
10169
  }, [visibleTasks, previewTasksById]);
@@ -9819,7 +10176,7 @@ function TaskGanttChartInner(props, ref) {
9819
10176
  const hoveredRowElementsRef = useRef9([]);
9820
10177
  const clearHoveredRows = useCallback8(() => {
9821
10178
  for (const element of hoveredRowElementsRef.current) {
9822
- element.classList.remove("gantt-tl-row-hovered", "gantt-tr-row-hovered");
10179
+ element.classList.remove("gantt-tl-row-hovered", "gantt-tr-row-hovered", "gantt-mx-row-hovered");
9823
10180
  }
9824
10181
  hoveredRowElementsRef.current = [];
9825
10182
  }, []);
@@ -9837,6 +10194,9 @@ function TaskGanttChartInner(props, ref) {
9837
10194
  if (element.classList.contains("gantt-tr-row")) {
9838
10195
  element.classList.add("gantt-tr-row-hovered");
9839
10196
  }
10197
+ if (element.classList.contains("gantt-mx-row")) {
10198
+ element.classList.add("gantt-mx-row-hovered");
10199
+ }
9840
10200
  }
9841
10201
  hoveredRowElementsRef.current = nextHoveredRows;
9842
10202
  }, [clearHoveredRows]);
@@ -9861,7 +10221,7 @@ function TaskGanttChartInner(props, ref) {
9861
10221
  return next;
9862
10222
  });
9863
10223
  }, []);
9864
- const allParentIds = useMemo10(() => {
10224
+ const allParentIds = useMemo11(() => {
9865
10225
  return new Set(
9866
10226
  normalizedTasks.filter((t) => isTaskParent(t.id, normalizedTasks)).map((t) => t.id)
9867
10227
  );
@@ -10073,190 +10433,219 @@ function TaskGanttChartInner(props, ref) {
10073
10433
  window.removeEventListener("mouseup", handlePanEnd);
10074
10434
  };
10075
10435
  }, []);
10076
- return /* @__PURE__ */ jsx16("div", { ref: containerRef, className: "gantt-container", children: /* @__PURE__ */ jsx16(
10436
+ return /* @__PURE__ */ jsx17(
10077
10437
  "div",
10078
10438
  {
10079
- ref: scrollContainerRef,
10080
- className: "gantt-scrollContainer",
10081
- style: { height: containerHeight ?? "auto", cursor: "grab" },
10082
- onMouseDown: handlePanStart,
10083
- children: /* @__PURE__ */ jsxs13(
10439
+ ref: containerRef,
10440
+ className: isTableMatrixMode ? "gantt-container gantt-container-tableMatrix" : "gantt-container",
10441
+ children: /* @__PURE__ */ jsx17(
10084
10442
  "div",
10085
10443
  {
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,
10444
+ ref: scrollContainerRef,
10445
+ className: "gantt-scrollContainer",
10446
+ style: { height: containerHeight ?? "auto", cursor: "grab" },
10447
+ onMouseDown: handlePanStart,
10448
+ children: /* @__PURE__ */ jsxs14(
10449
+ "div",
10450
+ {
10451
+ ref: scrollContentRef,
10452
+ className: "gantt-scrollContent",
10453
+ onMouseOver: handleSharedRowHover,
10454
+ onMouseLeave: clearHoveredRows,
10455
+ children: [
10456
+ /* @__PURE__ */ jsx17(
10457
+ TaskList,
10458
+ {
10459
+ tasks: normalizedTasks,
10460
+ rowHeight: effectiveRowHeight,
10461
+ headerHeight,
10462
+ taskListWidth,
10463
+ onTasksChange: handleTaskChange,
10464
+ selectedTaskId: selectedTaskId ?? void 0,
10465
+ onTaskSelect: handleTaskSelect,
10466
+ show: showTaskList,
10467
+ hasRightShadow: taskListHasRightShadow,
10468
+ disableTaskNameEditing,
10469
+ disableDependencyEditing,
10470
+ onScrollToTask: scrollToTask,
10471
+ onSelectedChipChange: setSelectedChip,
10472
+ onAdd,
10473
+ onDelete: handleDelete,
10474
+ onInsertAfter: handleInsertAfter,
10475
+ onReorder: handleReorder,
10476
+ disableTaskDrag,
10477
+ editingTaskId,
10478
+ enableAddTask,
10479
+ defaultTaskDurationDays,
10480
+ collapsedParentIds,
10481
+ onToggleCollapse: handleToggleCollapse,
10482
+ onPromoteTask: onPromoteTask ?? handlePromoteTask,
10483
+ onDemoteTask: onDemoteTask ?? handleDemoteTask,
10484
+ onUngroupTask: onUngroupTask ?? handleUngroupTask,
10485
+ highlightedTaskIds: taskListHighlightedTaskIds,
10486
+ enableTaskMultiSelect,
10487
+ selectedTaskIds,
10488
+ onSelectedTaskIdsChange,
10489
+ customDays,
10490
+ isWeekend: isWeekend3,
10491
+ businessDays,
10492
+ filterMode,
10493
+ filteredTaskIds: matchedTaskIds,
10494
+ isFilterActive: !!taskFilter,
10495
+ additionalColumns,
10496
+ hiddenTaskListColumns,
10497
+ taskListMenuCommands,
10498
+ hideTaskListRowActions,
10499
+ rowContentLines: resolvedRowContentLines,
10500
+ taskDateChangeMode,
10501
+ onTaskDateChangeModeChange: handleTaskDateChangeMode
10502
+ }
10503
+ ),
10504
+ /* @__PURE__ */ jsx17(
10505
+ "div",
10506
+ {
10507
+ className: isTableMatrixMode || showChart ? "gantt-chartSurface" : "gantt-chartSurface gantt-chart-hidden",
10508
+ style: {
10509
+ minWidth: `${isTableMatrixMode ? matrixWidth : gridWidth}px`,
10510
+ flex: 1,
10511
+ display: isTableMatrixMode || showChart ? void 0 : "none"
10512
+ },
10513
+ children: isTableMatrixMode ? /* @__PURE__ */ jsx17(
10514
+ TableMatrix,
10515
+ {
10516
+ tasks: visibleTasks,
10517
+ allTasks: normalizedTasks,
10518
+ columns: matrixColumns,
10519
+ columnGroups: matrixColumnGroups,
10520
+ rowHeight: effectiveRowHeight,
10521
+ headerHeight: timelineHeaderHeight,
10522
+ selectedTaskId,
10523
+ onTaskSelect: handleTaskSelect,
10524
+ onCellClick: onMatrixCellClick,
10525
+ highlightedTaskIds: taskListHighlightedTaskIds,
10526
+ filterMode
10527
+ }
10528
+ ) : /* @__PURE__ */ jsxs14(Fragment4, { children: [
10529
+ /* @__PURE__ */ jsx17(
10530
+ "div",
10149
10531
  {
10150
- days: dateRange,
10151
- dayWidth,
10152
- headerHeight,
10153
- viewMode,
10154
- isCustomWeekend
10532
+ className: "gantt-stickyHeader",
10533
+ style: { width: `${gridWidth}px`, height: `${timelineHeaderHeight}px` },
10534
+ children: /* @__PURE__ */ jsx17(
10535
+ TimeScaleHeader_default,
10536
+ {
10537
+ days: dateRange,
10538
+ dayWidth,
10539
+ headerHeight,
10540
+ viewMode,
10541
+ isCustomWeekend
10542
+ }
10543
+ )
10155
10544
  }
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
10545
+ ),
10546
+ /* @__PURE__ */ jsxs14(
10547
+ "div",
10548
+ {
10549
+ className: "gantt-taskArea",
10550
+ style: {
10551
+ position: "relative",
10552
+ width: `${gridWidth}px`
10237
10553
  },
10238
- task.id
10239
- ))
10240
- ]
10241
- }
10242
- )
10243
- ]
10244
- }
10245
- )
10246
- ]
10554
+ children: [
10555
+ /* @__PURE__ */ jsx17(
10556
+ GridBackground_default,
10557
+ {
10558
+ dateRange,
10559
+ dayWidth,
10560
+ totalHeight: totalGridHeight,
10561
+ viewMode,
10562
+ isCustomWeekend
10563
+ }
10564
+ ),
10565
+ todayInRange && /* @__PURE__ */ jsx17(TodayIndicator_default, { monthStart, dayWidth }),
10566
+ /* @__PURE__ */ jsx17(
10567
+ DependencyLines_default,
10568
+ {
10569
+ tasks: previewVisibleTasks,
10570
+ allTasks: previewNormalizedTasks,
10571
+ collapsedParentIds,
10572
+ monthStart,
10573
+ dayWidth,
10574
+ rowHeight: effectiveRowHeight,
10575
+ gridWidth,
10576
+ dragOverrides: dependencyOverrides,
10577
+ selectedDep: selectedChip,
10578
+ businessDays,
10579
+ weekendPredicate: isCustomWeekend
10580
+ }
10581
+ ),
10582
+ dragGuideLines && /* @__PURE__ */ jsx17(
10583
+ DragGuideLines_default,
10584
+ {
10585
+ isDragging: dragGuideLines.isDragging,
10586
+ dragMode: dragGuideLines.dragMode,
10587
+ left: dragGuideLines.left,
10588
+ width: dragGuideLines.width,
10589
+ totalHeight: totalGridHeight
10590
+ }
10591
+ ),
10592
+ visibleTasks.map((task, index) => /* @__PURE__ */ jsx17(
10593
+ TaskRow_default,
10594
+ {
10595
+ task,
10596
+ monthStart,
10597
+ dayWidth,
10598
+ rowHeight: effectiveRowHeight,
10599
+ onTasksChange: handleTaskChange,
10600
+ onDragStateChange: (state) => {
10601
+ if (state.isDragging) {
10602
+ setDragGuideLines(state);
10603
+ setDraggedTaskOverride({ taskId: task.id, left: state.left, width: state.width });
10604
+ } else {
10605
+ setDragGuideLines(null);
10606
+ setDraggedTaskOverride(null);
10607
+ }
10608
+ },
10609
+ rowIndex: index,
10610
+ allTasks: normalizedTasks,
10611
+ enableAutoSchedule: enableAutoSchedule ?? false,
10612
+ disableConstraints: disableConstraints ?? false,
10613
+ overridePosition: cascadeOverrides.get(task.id),
10614
+ onCascadeProgress: handleCascadeProgress,
10615
+ onCascade: handleCascade,
10616
+ highlightExpiredTasks,
10617
+ showBaseline,
10618
+ isFilterMatch: filterMode === "highlight" ? matchedTaskIds.has(task.id) : false,
10619
+ businessDays,
10620
+ customDays,
10621
+ isWeekend: isWeekend3,
10622
+ disableTaskDrag,
10623
+ viewMode
10624
+ },
10625
+ task.id
10626
+ ))
10627
+ ]
10628
+ }
10629
+ )
10630
+ ] })
10631
+ }
10632
+ )
10633
+ ]
10634
+ }
10635
+ )
10247
10636
  }
10248
10637
  )
10249
10638
  }
10250
- ) });
10639
+ );
10251
10640
  }
10252
10641
  var TaskGanttChart = forwardRef(TaskGanttChartInner);
10253
10642
  var GanttChart = forwardRef(GanttChartInner);
10254
10643
  GanttChart.displayName = "GanttChart";
10255
10644
 
10256
10645
  // src/components/ui/Button.tsx
10257
- import React14 from "react";
10258
- import { jsx as jsx17 } from "react/jsx-runtime";
10259
- var Button = React14.forwardRef(
10646
+ import React15 from "react";
10647
+ import { jsx as jsx18 } from "react/jsx-runtime";
10648
+ var Button = React15.forwardRef(
10260
10649
  ({ className, variant = "default", size = "default", children, ...props }, ref) => {
10261
10650
  const classes = [
10262
10651
  "gantt-btn",
@@ -10264,7 +10653,7 @@ var Button = React14.forwardRef(
10264
10653
  size !== "default" ? `gantt-btn-${size}` : "",
10265
10654
  className || ""
10266
10655
  ].filter(Boolean).join(" ");
10267
- return /* @__PURE__ */ jsx17("button", { ref, className: classes, ...props, children });
10656
+ return /* @__PURE__ */ jsx18("button", { ref, className: classes, ...props, children });
10268
10657
  }
10269
10658
  );
10270
10659
  Button.displayName = "Button";
@@ -10315,6 +10704,7 @@ export {
10315
10704
  PopoverContent,
10316
10705
  PopoverTrigger,
10317
10706
  ResourceTimelineChart,
10707
+ TableMatrix,
10318
10708
  TaskList,
10319
10709
  TaskRow_default as TaskRow,
10320
10710
  TimeScaleHeader_default as TimeScaleHeader,