gantt-lib 0.102.0 → 0.104.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.js CHANGED
@@ -717,13 +717,13 @@ function computeParentProgress(parentId, tasks) {
717
717
  if (children.length === 0) {
718
718
  return 0;
719
719
  }
720
- const DAY_MS4 = 24 * 60 * 60 * 1e3;
720
+ const DAY_MS5 = 24 * 60 * 60 * 1e3;
721
721
  let totalWeight = 0;
722
722
  let weightedSum = 0;
723
723
  for (const child of children) {
724
724
  const start = new Date(child.startDate).getTime();
725
725
  const end = new Date(child.endDate).getTime();
726
- const duration = (end - start + DAY_MS4) / DAY_MS4;
726
+ const duration = (end - start + DAY_MS5) / DAY_MS5;
727
727
  const progress = child.progress ?? 0;
728
728
  totalWeight += duration;
729
729
  weightedSum += duration * progress;
@@ -817,10 +817,10 @@ function buildTaskRangeFromStart(startDate, duration, businessDays = false, week
817
817
  end: parseDateOnly(addBusinessDays(normalizedStart, duration, weekendPredicate))
818
818
  };
819
819
  }
820
- const DAY_MS4 = 24 * 60 * 60 * 1e3;
820
+ const DAY_MS5 = 24 * 60 * 60 * 1e3;
821
821
  return {
822
822
  start: normalizedStart,
823
- end: new Date(normalizedStart.getTime() + (Math.max(1, duration) - 1) * DAY_MS4)
823
+ end: new Date(normalizedStart.getTime() + (Math.max(1, duration) - 1) * DAY_MS5)
824
824
  };
825
825
  }
826
826
  function buildTaskRangeFromEnd(endDate, duration, businessDays = false, weekendPredicate, snapDirection = -1) {
@@ -831,9 +831,9 @@ function buildTaskRangeFromEnd(endDate, duration, businessDays = false, weekendP
831
831
  end: normalizedEnd
832
832
  };
833
833
  }
834
- const DAY_MS4 = 24 * 60 * 60 * 1e3;
834
+ const DAY_MS5 = 24 * 60 * 60 * 1e3;
835
835
  return {
836
- start: new Date(normalizedEnd.getTime() - (Math.max(1, duration) - 1) * DAY_MS4),
836
+ start: new Date(normalizedEnd.getTime() - (Math.max(1, duration) - 1) * DAY_MS5),
837
837
  end: normalizedEnd
838
838
  };
839
839
  }
@@ -4857,6 +4857,30 @@ var TaskListRow = import_react10.default.memo(
4857
4857
  const editingName = editingColumnId === "name";
4858
4858
  const editingDuration = editingColumnId === "duration";
4859
4859
  const editingProgress = editingColumnId === "progress";
4860
+ const columnWidthStyleMap = (0, import_react10.useMemo)(() => {
4861
+ return new Map(
4862
+ (resolvedColumns ?? []).map((column) => {
4863
+ const width = column.width ?? 120;
4864
+ return [
4865
+ column.id,
4866
+ {
4867
+ width,
4868
+ minWidth: width,
4869
+ maxWidth: width,
4870
+ flex: `0 0 ${width}px`
4871
+ }
4872
+ ];
4873
+ })
4874
+ );
4875
+ }, [resolvedColumns]);
4876
+ const getColumnStyle = (0, import_react10.useCallback)((columnId, fallbackWidth) => {
4877
+ return columnWidthStyleMap.get(columnId) ?? {
4878
+ width: fallbackWidth,
4879
+ minWidth: fallbackWidth,
4880
+ maxWidth: fallbackWidth,
4881
+ flex: `0 0 ${fallbackWidth}px`
4882
+ };
4883
+ }, [columnWidthStyleMap]);
4860
4884
  const normalizedTask = (0, import_react10.useMemo)(() => normalizeTaskDatesForType(task), [task]);
4861
4885
  const isMilestone = (0, import_react10.useMemo)(() => isMilestoneTask(normalizedTask), [normalizedTask]);
4862
4886
  const [nameValue, setNameValue] = (0, import_react10.useState)("");
@@ -5654,6 +5678,7 @@ var TaskListRow = import_react10.default.memo(
5654
5678
  "div",
5655
5679
  {
5656
5680
  className: "gantt-tl-cell gantt-tl-cell-selection",
5681
+ style: getColumnStyle("selection", 36),
5657
5682
  onClick: (e) => e.stopPropagation(),
5658
5683
  children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
5659
5684
  "input",
@@ -5671,6 +5696,7 @@ var TaskListRow = import_react10.default.memo(
5671
5696
  "div",
5672
5697
  {
5673
5698
  className: "gantt-tl-cell gantt-tl-cell-number",
5699
+ style: getColumnStyle("number", 40),
5674
5700
  onClick: handleNumberClick,
5675
5701
  children: [
5676
5702
  onDragStart && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
@@ -5693,7 +5719,7 @@ var TaskListRow = import_react10.default.memo(
5693
5719
  );
5694
5720
  const nameTriggerPaddingLeft = isParent ? `${nestingDepth * 20 + 28}px` : nestingDepth > 0 ? `${nestingDepth * 20 + 8}px` : void 0;
5695
5721
  const nameInputPaddingLeft = nestingDepth > 0 ? `${nestingDepth * 20 + 8}px` : void 0;
5696
- const nameCell = /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-cell gantt-tl-cell-name", children: [
5722
+ const nameCell = /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-cell gantt-tl-cell-name", style: getColumnStyle("name", 200), children: [
5697
5723
  isChild && !editingName && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
5698
5724
  !isFilterHideMode && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
5699
5725
  ancestorLineModes.map(
@@ -6055,6 +6081,7 @@ var TaskListRow = import_react10.default.memo(
6055
6081
  "div",
6056
6082
  {
6057
6083
  className: "gantt-tl-cell gantt-tl-cell-date",
6084
+ style: getColumnStyle("startDate", 90),
6058
6085
  onClick: (e) => e.stopPropagation(),
6059
6086
  children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
6060
6087
  DatePicker,
@@ -6075,6 +6102,7 @@ var TaskListRow = import_react10.default.memo(
6075
6102
  "div",
6076
6103
  {
6077
6104
  className: "gantt-tl-cell gantt-tl-cell-date",
6105
+ style: getColumnStyle("endDate", 90),
6078
6106
  onClick: (e) => e.stopPropagation(),
6079
6107
  children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
6080
6108
  DatePicker,
@@ -6095,6 +6123,7 @@ var TaskListRow = import_react10.default.memo(
6095
6123
  "div",
6096
6124
  {
6097
6125
  className: "gantt-tl-cell gantt-tl-cell-duration",
6126
+ style: getColumnStyle("duration", 60),
6098
6127
  onClick: handleDurationClick,
6099
6128
  children: [
6100
6129
  editingDuration && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
@@ -6186,6 +6215,7 @@ var TaskListRow = import_react10.default.memo(
6186
6215
  "div",
6187
6216
  {
6188
6217
  className: "gantt-tl-cell gantt-tl-cell-progress",
6218
+ style: getColumnStyle("progress", 50),
6189
6219
  onClick: handleProgressClick,
6190
6220
  children: [
6191
6221
  editingProgress && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
@@ -6283,6 +6313,7 @@ var TaskListRow = import_react10.default.memo(
6283
6313
  "div",
6284
6314
  {
6285
6315
  className: "gantt-tl-cell gantt-tl-cell-deps",
6316
+ style: getColumnStyle("dependencies", 128),
6286
6317
  onClick: isSourceRow ? handleSourceCellClick : isPicking ? handlePredecessorPick : void 0,
6287
6318
  children: isSourceRow ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
6288
6319
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
@@ -6749,6 +6780,18 @@ function resolveTaskListColumns(builtIn, custom, hiddenColumnIds = []) {
6749
6780
  var import_jsx_runtime14 = require("react/jsx-runtime");
6750
6781
  var LINK_TYPE_ORDER2 = ["FS", "SS", "FF", "SF"];
6751
6782
  var MIN_TASK_LIST_WIDTH = 530;
6783
+ var DEFAULT_COLUMN_MIN_WIDTH = 40;
6784
+ var BUILT_IN_COLUMN_MIN_WIDTHS = {
6785
+ selection: 36,
6786
+ number: 40,
6787
+ name: 160,
6788
+ startDate: 68,
6789
+ endDate: 68,
6790
+ duration: 60,
6791
+ progress: 50,
6792
+ dependencies: 128,
6793
+ actions: 56
6794
+ };
6752
6795
  var BUILT_IN_CSS_CLASSES = {
6753
6796
  selection: "gantt-tl-cell-selection",
6754
6797
  number: "gantt-tl-cell-number",
@@ -6826,6 +6869,24 @@ function getTaskNumber(tasks, taskIndex) {
6826
6869
  }
6827
6870
  return `${parentNumber}.${siblingIndex + 1}`;
6828
6871
  }
6872
+ function normalizeColumnWidthMap(widths) {
6873
+ if (!widths) {
6874
+ return {};
6875
+ }
6876
+ return Object.entries(widths).reduce((acc, [columnId, width]) => {
6877
+ if (typeof width !== "number" || !Number.isFinite(width) || width <= 0) {
6878
+ return acc;
6879
+ }
6880
+ acc[columnId] = Math.round(width);
6881
+ return acc;
6882
+ }, {});
6883
+ }
6884
+ function getColumnMinWidth(column) {
6885
+ return Math.max(
6886
+ typeof column.minWidth === "number" && Number.isFinite(column.minWidth) ? column.minWidth : 0,
6887
+ BUILT_IN_COLUMN_MIN_WIDTHS[column.id] ?? DEFAULT_COLUMN_MIN_WIDTH
6888
+ );
6889
+ }
6829
6890
  var SelectAllCheckbox = ({
6830
6891
  checked,
6831
6892
  indeterminate,
@@ -6889,6 +6950,8 @@ var TaskList = ({
6889
6950
  isFilterActive = false,
6890
6951
  additionalColumns,
6891
6952
  hiddenTaskListColumns,
6953
+ taskListColumnWidths,
6954
+ onTaskListColumnWidthsChange,
6892
6955
  taskListMenuCommands,
6893
6956
  hideTaskListRowActions = false,
6894
6957
  rowContentLines = 1,
@@ -6898,6 +6961,8 @@ var TaskList = ({
6898
6961
  }) => {
6899
6962
  const [internalSelectedTaskIds, setInternalSelectedTaskIds] = (0, import_react12.useState)(/* @__PURE__ */ new Set());
6900
6963
  const [activeCustomCell, setActiveCustomCell] = (0, import_react12.useState)(null);
6964
+ const [columnWidthOverrides, setColumnWidthOverrides] = (0, import_react12.useState)(() => normalizeColumnWidthMap(taskListColumnWidths));
6965
+ const resizeStateRef = (0, import_react12.useRef)(null);
6901
6966
  const effectiveSelectedTaskIds = selectedTaskIds ?? internalSelectedTaskIds;
6902
6967
  const emitSelectedTaskIdsChange = (0, import_react12.useCallback)((nextSelectedTaskIds) => {
6903
6968
  if (!selectedTaskIds) {
@@ -7470,13 +7535,24 @@ var TaskList = ({
7470
7535
  () => createBuiltInColumns({ businessDays, enableTaskMultiSelect }),
7471
7536
  [businessDays, enableTaskMultiSelect]
7472
7537
  );
7538
+ (0, import_react12.useEffect)(() => {
7539
+ setColumnWidthOverrides(normalizeColumnWidthMap(taskListColumnWidths));
7540
+ }, [taskListColumnWidths]);
7473
7541
  const resolvedColumns = (0, import_react12.useMemo)(
7474
7542
  () => resolveTaskListColumns(
7475
7543
  builtInColumns,
7476
7544
  additionalColumns ?? [],
7477
7545
  hiddenTaskListColumns
7478
- ),
7479
- [builtInColumns, additionalColumns, hiddenTaskListColumns]
7546
+ ).map((column) => {
7547
+ const configuredWidth = columnWidthOverrides[column.id];
7548
+ const baseWidth = configuredWidth ?? column.width ?? 120;
7549
+ const width = Math.max(getColumnMinWidth(column), baseWidth);
7550
+ return {
7551
+ ...column,
7552
+ width
7553
+ };
7554
+ }),
7555
+ [builtInColumns, additionalColumns, hiddenTaskListColumns, columnWidthOverrides]
7480
7556
  );
7481
7557
  const resolvedColumnWidthTotal = (0, import_react12.useMemo)(
7482
7558
  () => resolvedColumns.reduce((sum, col) => sum + (col.width ?? 120), 0),
@@ -7485,6 +7561,78 @@ var TaskList = ({
7485
7561
  const requestedTaskListWidth = taskListWidth ?? Math.min(MIN_TASK_LIST_WIDTH, resolvedColumnWidthTotal);
7486
7562
  const effectiveTaskListWidth = Math.max(requestedTaskListWidth, resolvedColumnWidthTotal);
7487
7563
  const tableHeaderHeight = headerHeight + 1;
7564
+ const updateColumnWidth = (0, import_react12.useCallback)((columnId, width) => {
7565
+ setColumnWidthOverrides((prev) => {
7566
+ if (prev[columnId] === width) {
7567
+ return prev;
7568
+ }
7569
+ const next = { ...prev, [columnId]: width };
7570
+ onTaskListColumnWidthsChange?.(next);
7571
+ return next;
7572
+ });
7573
+ }, [onTaskListColumnWidthsChange]);
7574
+ (0, import_react12.useEffect)(() => {
7575
+ const handleMouseMove = (event) => {
7576
+ const resizeState = resizeStateRef.current;
7577
+ if (!resizeState) {
7578
+ return;
7579
+ }
7580
+ const column = resolvedColumns.find((item) => item.id === resizeState.columnId);
7581
+ if (!column) {
7582
+ return;
7583
+ }
7584
+ const nextWidth = Math.max(
7585
+ getColumnMinWidth(column),
7586
+ Math.round(resizeState.startWidth + event.clientX - resizeState.startX)
7587
+ );
7588
+ updateColumnWidth(column.id, nextWidth);
7589
+ };
7590
+ const handleMouseUp = () => {
7591
+ if (!resizeStateRef.current) {
7592
+ return;
7593
+ }
7594
+ resizeStateRef.current = null;
7595
+ document.body.style.removeProperty("cursor");
7596
+ document.body.style.removeProperty("user-select");
7597
+ };
7598
+ window.addEventListener("mousemove", handleMouseMove);
7599
+ window.addEventListener("mouseup", handleMouseUp);
7600
+ return () => {
7601
+ window.removeEventListener("mousemove", handleMouseMove);
7602
+ window.removeEventListener("mouseup", handleMouseUp);
7603
+ document.body.style.removeProperty("cursor");
7604
+ document.body.style.removeProperty("user-select");
7605
+ };
7606
+ }, [resolvedColumns, updateColumnWidth]);
7607
+ const startColumnResize = (0, import_react12.useCallback)((columnId, event) => {
7608
+ const column = resolvedColumns.find((item) => item.id === columnId);
7609
+ if (!column) {
7610
+ return;
7611
+ }
7612
+ event.preventDefault();
7613
+ event.stopPropagation();
7614
+ resizeStateRef.current = {
7615
+ columnId,
7616
+ startX: event.clientX,
7617
+ startWidth: column.width ?? 120
7618
+ };
7619
+ document.body.style.cursor = "col-resize";
7620
+ document.body.style.userSelect = "none";
7621
+ }, [resolvedColumns]);
7622
+ const renderResizeHandle = (0, import_react12.useCallback)((columnId) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
7623
+ "button",
7624
+ {
7625
+ type: "button",
7626
+ className: "gantt-tl-column-resize-handle",
7627
+ "data-testid": `tasklist-resize-handle-${columnId}`,
7628
+ "aria-label": `Resize ${columnId} column`,
7629
+ onMouseDown: (event) => startColumnResize(columnId, event),
7630
+ onClick: (event) => {
7631
+ event.preventDefault();
7632
+ event.stopPropagation();
7633
+ }
7634
+ }
7635
+ ), [startColumnResize]);
7488
7636
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
7489
7637
  "div",
7490
7638
  {
@@ -7497,19 +7645,23 @@ var TaskList = ({
7497
7645
  children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "gantt-tl-table", children: [
7498
7646
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "gantt-tl-header", style: { height: `${tableHeaderHeight}px` }, children: resolvedColumns.map((col) => {
7499
7647
  if (col.id === "selection") {
7500
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
7648
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
7501
7649
  "div",
7502
7650
  {
7503
7651
  className: "gantt-tl-headerCell gantt-tl-cell-selection",
7504
7652
  "data-column-id": "selection",
7505
- children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
7506
- SelectAllCheckbox,
7507
- {
7508
- checked: areAllVisibleTasksSelected,
7509
- indeterminate: areSomeVisibleTasksSelected,
7510
- onChange: handleToggleAllVisibleTaskSelection
7511
- }
7512
- )
7653
+ style: { width: col.width, minWidth: col.width, maxWidth: col.width, flex: `0 0 ${col.width}px`, position: "relative" },
7654
+ children: [
7655
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
7656
+ SelectAllCheckbox,
7657
+ {
7658
+ checked: areAllVisibleTasksSelected,
7659
+ indeterminate: areSomeVisibleTasksSelected,
7660
+ onChange: handleToggleAllVisibleTaskSelection
7661
+ }
7662
+ ),
7663
+ renderResizeHandle(col.id)
7664
+ ]
7513
7665
  },
7514
7666
  col.id
7515
7667
  );
@@ -7520,7 +7672,7 @@ var TaskList = ({
7520
7672
  {
7521
7673
  className: "gantt-tl-headerCell gantt-tl-cell-deps",
7522
7674
  "data-column-id": "dependencies",
7523
- style: { position: "relative" },
7675
+ style: { width: col.width, minWidth: col.width, maxWidth: col.width, flex: `0 0 ${col.width}px`, position: "relative" },
7524
7676
  children: [
7525
7677
  /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(Popover, { open: typeMenuOpen, onOpenChange: setTypeMenuOpen, children: [
7526
7678
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
@@ -7552,7 +7704,8 @@ var TaskList = ({
7552
7704
  lt
7553
7705
  )) }) })
7554
7706
  ] }),
7555
- dependencyError && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "gantt-tl-dep-error", children: dependencyError })
7707
+ dependencyError && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "gantt-tl-dep-error", children: dependencyError }),
7708
+ renderResizeHandle(col.id)
7556
7709
  ]
7557
7710
  },
7558
7711
  col.id
@@ -7560,24 +7713,31 @@ var TaskList = ({
7560
7713
  }
7561
7714
  const builtInClass = BUILT_IN_CSS_CLASSES[col.id];
7562
7715
  if (builtInClass !== void 0) {
7563
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
7716
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
7564
7717
  "div",
7565
7718
  {
7566
7719
  className: `gantt-tl-headerCell ${builtInClass}`,
7567
7720
  "data-column-id": col.id,
7568
- children: col.header
7721
+ style: { width: col.width, minWidth: col.width, maxWidth: col.width, flex: `0 0 ${col.width}px`, position: "relative" },
7722
+ children: [
7723
+ col.header,
7724
+ renderResizeHandle(col.id)
7725
+ ]
7569
7726
  },
7570
7727
  col.id
7571
7728
  );
7572
7729
  }
7573
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
7730
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
7574
7731
  "div",
7575
7732
  {
7576
7733
  className: `gantt-tl-headerCell gantt-tl-headerCell-custom gantt-tl-cell-align-${col.align ?? "left"}`,
7577
7734
  "data-column-id": `custom:${col.id}`,
7578
7735
  "data-custom-column-id": col.id,
7579
- style: { width: col.width, minWidth: col.width, flexShrink: 0 },
7580
- children: col.header
7736
+ style: { width: col.width, minWidth: col.width, maxWidth: col.width, flex: `0 0 ${col.width}px`, position: "relative" },
7737
+ children: [
7738
+ col.header,
7739
+ renderResizeHandle(col.id)
7740
+ ]
7581
7741
  },
7582
7742
  col.id
7583
7743
  );
@@ -9398,6 +9558,7 @@ var import_react15 = require("react");
9398
9558
  var import_jsx_runtime16 = require("react/jsx-runtime");
9399
9559
  var AUTO_COLUMN_MIN_WIDTH = 72;
9400
9560
  var AUTO_COLUMN_MAX_WIDTH = 180;
9561
+ var DAY_MS4 = 24 * 60 * 60 * 1e3;
9401
9562
  function joinClasses(...values) {
9402
9563
  return values.filter(Boolean).join(" ");
9403
9564
  }
@@ -9410,6 +9571,40 @@ function getAutoMinWidth(column) {
9410
9571
  function getAutoMaxWidth(column) {
9411
9572
  return column.maxWidth ?? AUTO_COLUMN_MAX_WIDTH;
9412
9573
  }
9574
+ function parseDateOnlyMs(value) {
9575
+ if (value instanceof Date) {
9576
+ return Date.UTC(value.getFullYear(), value.getMonth(), value.getDate());
9577
+ }
9578
+ const [year, month, day] = value.split("T")[0].split("-").map(Number);
9579
+ if (!year || !month || !day) {
9580
+ return Number.NaN;
9581
+ }
9582
+ return Date.UTC(year, month - 1, day);
9583
+ }
9584
+ function getOverlayWidthPercent(column, overlayDateMs) {
9585
+ if (overlayDateMs === null || column.periodStartDate === void 0 || column.periodEndDate === void 0) {
9586
+ return 0;
9587
+ }
9588
+ const startMs = parseDateOnlyMs(column.periodStartDate);
9589
+ const endMs = parseDateOnlyMs(column.periodEndDate);
9590
+ if (!Number.isFinite(startMs) || !Number.isFinite(endMs) || endMs < startMs || overlayDateMs < startMs) {
9591
+ return 0;
9592
+ }
9593
+ if (overlayDateMs >= endMs) {
9594
+ return 100;
9595
+ }
9596
+ const totalDays = Math.max(1, Math.round((endMs - startMs) / DAY_MS4) + 1);
9597
+ const elapsedDays = Math.min(totalDays, Math.max(0, Math.round((overlayDateMs - startMs) / DAY_MS4) + 1));
9598
+ return elapsedDays / totalDays * 100;
9599
+ }
9600
+ function isOverlayDateInColumn(column, overlayDateMs) {
9601
+ if (overlayDateMs === null || column.periodStartDate === void 0 || column.periodEndDate === void 0) {
9602
+ return false;
9603
+ }
9604
+ const startMs = parseDateOnlyMs(column.periodStartDate);
9605
+ const endMs = parseDateOnlyMs(column.periodEndDate);
9606
+ return Number.isFinite(startMs) && Number.isFinite(endMs) && startMs <= overlayDateMs && overlayDateMs <= endMs;
9607
+ }
9413
9608
  function TableMatrix({
9414
9609
  tasks,
9415
9610
  allTasks = tasks,
@@ -9421,6 +9616,7 @@ function TableMatrix({
9421
9616
  selectedTaskId,
9422
9617
  onTaskSelect,
9423
9618
  onCellClick,
9619
+ dateOverlay,
9424
9620
  highlightedTaskIds,
9425
9621
  filterMode = "highlight"
9426
9622
  }) {
@@ -9474,6 +9670,10 @@ function TableMatrix({
9474
9670
  () => resolvedColumnWidths.reduce((sum, width) => sum + width, 0),
9475
9671
  [resolvedColumnWidths]
9476
9672
  );
9673
+ const overlayDateMs = (0, import_react15.useMemo)(
9674
+ () => dateOverlay ? parseDateOnlyMs(dateOverlay.date) : null,
9675
+ [dateOverlay]
9676
+ );
9477
9677
  const hasGroupHeader = (0, import_react15.useMemo)(
9478
9678
  () => columns.some((column) => !!column.groupId) || (columnGroups?.length ?? 0) > 0,
9479
9679
  [columnGroups, columns]
@@ -9484,7 +9684,7 @@ function TableMatrix({
9484
9684
  );
9485
9685
  const headerSpans = (0, import_react15.useMemo)(() => {
9486
9686
  if (!hasGroupHeader) return [];
9487
- if (!hasAutoWidthColumns && columnGroups?.some((group) => typeof group.width === "number")) {
9687
+ if (columnGroups?.some((group) => typeof group.width === "number")) {
9488
9688
  return columnGroups.map((group) => ({
9489
9689
  id: group.id,
9490
9690
  header: group.header,
@@ -9572,14 +9772,14 @@ function TableMatrix({
9572
9772
  {
9573
9773
  className: "gantt-mx-headerRow gantt-mx-headerGroupRow",
9574
9774
  style: {
9575
- gridTemplateColumns: hasAutoWidthColumns ? gridTemplateColumns : headerSpans.map((span) => `${span.width ?? 0}px`).join(" "),
9775
+ gridTemplateColumns: headerSpans.map((span) => `${span.width ?? 0}px`).join(" "),
9576
9776
  height: `${topRowHeight}px`
9577
9777
  },
9578
9778
  children: headerSpans.map((span) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
9579
9779
  "div",
9580
9780
  {
9581
9781
  className: joinClasses("gantt-mx-groupCell", span.className),
9582
- style: hasAutoWidthColumns ? { gridColumn: `span ${span.columnSpan ?? 1}` } : void 0,
9782
+ style: span.columnSpan !== void 0 ? { gridColumn: `span ${span.columnSpan}` } : void 0,
9583
9783
  children: span.header
9584
9784
  },
9585
9785
  span.id
@@ -9591,18 +9791,34 @@ function TableMatrix({
9591
9791
  {
9592
9792
  className: "gantt-mx-headerRow",
9593
9793
  style: { gridTemplateColumns, height: `${hasGroupHeader ? bottomRowHeight : topRowHeight}px` },
9594
- children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
9595
- "div",
9596
- {
9597
- className: joinClasses(
9598
- "gantt-mx-headerCell",
9599
- column.headerClassName
9600
- ),
9601
- style: column.minWidth !== void 0 ? { minWidth: `${column.minWidth}px` } : void 0,
9602
- children: column.header
9603
- },
9604
- column.id
9605
- ))
9794
+ children: columns.map((column) => {
9795
+ const overlayWidthPercent = getOverlayWidthPercent(column, overlayDateMs);
9796
+ const shouldRenderOverlayEdge = isOverlayDateInColumn(column, overlayDateMs);
9797
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
9798
+ "div",
9799
+ {
9800
+ className: joinClasses(
9801
+ "gantt-mx-headerCell",
9802
+ column.headerClassName
9803
+ ),
9804
+ style: column.minWidth !== void 0 ? { minWidth: `${column.minWidth}px` } : void 0,
9805
+ children: [
9806
+ shouldRenderOverlayEdge && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
9807
+ "span",
9808
+ {
9809
+ className: "gantt-mx-dateOverlayEdge",
9810
+ style: {
9811
+ left: `${overlayWidthPercent}%`,
9812
+ background: dateOverlay && dateOverlay.edgeColor ? dateOverlay.edgeColor : void 0
9813
+ }
9814
+ }
9815
+ ),
9816
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "gantt-mx-headerContent", children: column.header })
9817
+ ]
9818
+ },
9819
+ column.id
9820
+ );
9821
+ })
9606
9822
  }
9607
9823
  )
9608
9824
  ] }),
@@ -9642,7 +9858,10 @@ function TableMatrix({
9642
9858
  onClick: () => onTaskSelect?.(task.id),
9643
9859
  children: columns.map((column, columnIndex) => {
9644
9860
  const resolvedCellClassName = typeof column.cellClassName === "function" ? column.cellClassName(task) : column.cellClassName;
9645
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
9861
+ const overlayWidthPercent = getOverlayWidthPercent(column, overlayDateMs);
9862
+ const shouldRenderOverlay = overlayWidthPercent > 0 && (!dateOverlay || !dateOverlay.shouldRender || dateOverlay.shouldRender({ task, column, rowIndex: index, columnIndex }));
9863
+ const shouldRenderOverlayEdge = isOverlayDateInColumn(column, overlayDateMs);
9864
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
9646
9865
  "div",
9647
9866
  {
9648
9867
  className: joinClasses(
@@ -9656,7 +9875,29 @@ function TableMatrix({
9656
9875
  onClick: (event) => {
9657
9876
  onCellClick?.({ task, column, rowIndex: index, columnIndex, event });
9658
9877
  },
9659
- children: column.renderCell(task)
9878
+ children: [
9879
+ shouldRenderOverlay && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
9880
+ "span",
9881
+ {
9882
+ className: joinClasses("gantt-mx-dateOverlay", dateOverlay && dateOverlay.className),
9883
+ style: {
9884
+ width: `${overlayWidthPercent}%`,
9885
+ background: dateOverlay && dateOverlay.color ? dateOverlay.color : void 0
9886
+ }
9887
+ }
9888
+ ),
9889
+ shouldRenderOverlayEdge && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
9890
+ "span",
9891
+ {
9892
+ className: "gantt-mx-dateOverlayEdge",
9893
+ style: {
9894
+ left: `${overlayWidthPercent}%`,
9895
+ background: dateOverlay && dateOverlay.edgeColor ? dateOverlay.edgeColor : void 0
9896
+ }
9897
+ }
9898
+ ),
9899
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "gantt-mx-cellContent", children: column.renderCell(task) })
9900
+ ]
9660
9901
  },
9661
9902
  `${task.id}:${column.id}`
9662
9903
  );
@@ -10061,6 +10302,8 @@ function TaskGanttChartInner(props, ref) {
10061
10302
  showChart = true,
10062
10303
  additionalColumns,
10063
10304
  hiddenTaskListColumns,
10305
+ taskListColumnWidths,
10306
+ onTaskListColumnWidthsChange,
10064
10307
  taskListMenuCommands,
10065
10308
  hideTaskListRowActions = false,
10066
10309
  rowContentLines = 1,
@@ -10075,6 +10318,7 @@ function TaskGanttChartInner(props, ref) {
10075
10318
  const matrixColumns = isTableMatrixMode ? props.matrixColumns : [];
10076
10319
  const matrixColumnGroups = isTableMatrixMode ? props.matrixColumnGroups : void 0;
10077
10320
  const onMatrixCellClick = isTableMatrixMode ? props.onMatrixCellClick : void 0;
10321
+ const matrixDateOverlay = isTableMatrixMode ? props.matrixDateOverlay : void 0;
10078
10322
  const containerRef = (0, import_react16.useRef)(null);
10079
10323
  const scrollContainerRef = (0, import_react16.useRef)(null);
10080
10324
  const scrollContentRef = (0, import_react16.useRef)(null);
@@ -10726,6 +10970,8 @@ function TaskGanttChartInner(props, ref) {
10726
10970
  isFilterActive: !!taskFilter,
10727
10971
  additionalColumns,
10728
10972
  hiddenTaskListColumns,
10973
+ taskListColumnWidths,
10974
+ onTaskListColumnWidthsChange,
10729
10975
  taskListMenuCommands,
10730
10976
  hideTaskListRowActions,
10731
10977
  rowContentLines: resolvedRowContentLines,
@@ -10757,6 +11003,7 @@ function TaskGanttChartInner(props, ref) {
10757
11003
  selectedTaskId,
10758
11004
  onTaskSelect: handleTaskSelect,
10759
11005
  onCellClick: onMatrixCellClick,
11006
+ dateOverlay: matrixDateOverlay,
10760
11007
  highlightedTaskIds: taskListHighlightedTaskIds,
10761
11008
  filterMode
10762
11009
  }