gantt-lib 0.72.1 → 0.73.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
@@ -4246,6 +4246,26 @@ var CopyIcon = () => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
4246
4246
  ]
4247
4247
  }
4248
4248
  );
4249
+ var UngroupIcon = () => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
4250
+ "svg",
4251
+ {
4252
+ xmlns: "http://www.w3.org/2000/svg",
4253
+ width: "16",
4254
+ height: "16",
4255
+ viewBox: "0 0 24 24",
4256
+ fill: "none",
4257
+ stroke: "currentColor",
4258
+ strokeWidth: "2",
4259
+ strokeLinecap: "round",
4260
+ strokeLinejoin: "round",
4261
+ children: [
4262
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M3 12h10" }),
4263
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "m6 9-3 3 3 3" }),
4264
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M13 6h8" }),
4265
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M13 18h8" })
4266
+ ]
4267
+ }
4268
+ );
4249
4269
  var TASK_COLOR_PALETTE = [
4250
4270
  // { label: "Палисандр", value: "#A61E4D" },
4251
4271
  // { label: "Киноварь", value: "#E8590C" },
@@ -4678,6 +4698,7 @@ var TaskListRow = import_react10.default.memo(
4678
4698
  onToggleCollapse,
4679
4699
  onPromoteTask,
4680
4700
  onDemoteTask,
4701
+ onUngroupTask,
4681
4702
  onDuplicateTask,
4682
4703
  canDemoteTask = true,
4683
4704
  isLastChild = true,
@@ -4689,7 +4710,8 @@ var TaskListRow = import_react10.default.memo(
4689
4710
  businessDays,
4690
4711
  isFilterMatch = false,
4691
4712
  isFilterHideMode = false,
4692
- resolvedColumns
4713
+ resolvedColumns,
4714
+ taskListMenuCommands = []
4693
4715
  }) => {
4694
4716
  const [editingColumnId, setEditingColumnId] = (0, import_react10.useState)(null);
4695
4717
  const editingName = editingColumnId === "name";
@@ -4723,6 +4745,7 @@ var TaskListRow = import_react10.default.memo(
4723
4745
  [task.id, allTasks]
4724
4746
  );
4725
4747
  const isChild = task.parentId !== void 0;
4748
+ const isMilestoneRow = normalizedTask.type === "milestone";
4726
4749
  const weekendPredicate = (0, import_react10.useMemo)(
4727
4750
  () => createCustomDayPredicate({ customDays, isWeekend: isWeekend3 }),
4728
4751
  [customDays, isWeekend3]
@@ -5245,6 +5268,38 @@ var TaskListRow = import_react10.default.memo(
5245
5268
  },
5246
5269
  [allTasks, isParent, onTasksChange, task]
5247
5270
  );
5271
+ const handleUngroup = (0, import_react10.useCallback)(
5272
+ (e) => {
5273
+ e.stopPropagation();
5274
+ setContextMenuOpen(false);
5275
+ onUngroupTask?.(task.id);
5276
+ },
5277
+ [onUngroupTask, task.id]
5278
+ );
5279
+ const visibleCustomMenuCommands = (0, import_react10.useMemo)(
5280
+ () => taskListMenuCommands.filter(
5281
+ (command) => {
5282
+ const scope = command.scope ?? "all";
5283
+ if (scope === "group" && !isParent) return false;
5284
+ if (scope === "linear" && (isParent || isMilestoneRow)) return false;
5285
+ if (scope === "milestone" && !isMilestoneRow) return false;
5286
+ return command.isVisible?.(task) ?? true;
5287
+ }
5288
+ ),
5289
+ [taskListMenuCommands, task, isParent, isMilestoneRow]
5290
+ );
5291
+ const hasContextMenu = visibleCustomMenuCommands.length > 0 || !!onDuplicateTask || !!onDelete || !!onTasksChange || isParent && !!onUngroupTask;
5292
+ const handleCustomMenuCommandClick = (0, import_react10.useCallback)(
5293
+ (command) => (e) => {
5294
+ e.stopPropagation();
5295
+ if (command.closeOnSelect !== false) {
5296
+ setContextMenuOpen(false);
5297
+ setColorMenuOpen(false);
5298
+ }
5299
+ command.onSelect(task);
5300
+ },
5301
+ [task]
5302
+ );
5248
5303
  const handleAddClick = (0, import_react10.useCallback)(
5249
5304
  (e) => {
5250
5305
  e.stopPropagation();
@@ -5671,7 +5726,7 @@ var TaskListRow = import_react10.default.memo(
5671
5726
  "aria-hidden": "true"
5672
5727
  }
5673
5728
  ),
5674
- !editingName && (onInsertAfter || onDelete || onPromoteTask || onDemoteTask || onDuplicateTask || onTasksChange) && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-name-actions", children: [
5729
+ !editingName && (onInsertAfter || onDelete || onPromoteTask || onDemoteTask || onUngroupTask || onDuplicateTask || onTasksChange || hasContextMenu) && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-name-actions", children: [
5675
5730
  onInsertAfter && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
5676
5731
  "button",
5677
5732
  {
@@ -5717,7 +5772,7 @@ var TaskListRow = import_react10.default.memo(
5717
5772
  onDemote: onDemoteTask ? handleDemote : void 0
5718
5773
  }
5719
5774
  ),
5720
- (onDuplicateTask || onDelete || onTasksChange) && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Popover, { open: contextMenuOpen, onOpenChange: (open) => {
5775
+ hasContextMenu && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Popover, { open: contextMenuOpen, onOpenChange: (open) => {
5721
5776
  setContextMenuOpen(open);
5722
5777
  if (!open) setColorMenuOpen(false);
5723
5778
  }, children: [
@@ -5810,6 +5865,32 @@ var TaskListRow = import_react10.default.memo(
5810
5865
  ]
5811
5866
  }
5812
5867
  ),
5868
+ visibleCustomMenuCommands.map((command) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
5869
+ "button",
5870
+ {
5871
+ type: "button",
5872
+ className: `gantt-tl-context-menu-item${command.danger ? " gantt-tl-context-menu-item-danger" : ""}`,
5873
+ onClick: handleCustomMenuCommandClick(command),
5874
+ disabled: command.isDisabled?.(task) ?? false,
5875
+ children: [
5876
+ command.icon,
5877
+ command.label
5878
+ ]
5879
+ },
5880
+ command.id
5881
+ )),
5882
+ isParent && onUngroupTask && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
5883
+ "button",
5884
+ {
5885
+ type: "button",
5886
+ className: "gantt-tl-context-menu-item",
5887
+ onClick: handleUngroup,
5888
+ children: [
5889
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(UngroupIcon, {}),
5890
+ "\u0420\u0430\u0437\u0433\u0440\u0443\u043F\u043F\u0438\u0440\u043E\u0432\u0430\u0442\u044C"
5891
+ ]
5892
+ }
5893
+ ),
5813
5894
  onDelete && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
5814
5895
  "button",
5815
5896
  {
@@ -6505,6 +6586,7 @@ var TaskList = ({
6505
6586
  onToggleCollapse: externalOnToggleCollapse,
6506
6587
  onPromoteTask,
6507
6588
  onDemoteTask,
6589
+ onUngroupTask,
6508
6590
  customDays,
6509
6591
  isWeekend: isWeekend3,
6510
6592
  businessDays,
@@ -6512,7 +6594,8 @@ var TaskList = ({
6512
6594
  filterMode = "highlight",
6513
6595
  filteredTaskIds = /* @__PURE__ */ new Set(),
6514
6596
  isFilterActive = false,
6515
- additionalColumns
6597
+ additionalColumns,
6598
+ taskListMenuCommands
6516
6599
  }) => {
6517
6600
  const [internalCollapsedParentIds, setInternalCollapsedParentIds] = (0, import_react12.useState)(/* @__PURE__ */ new Set());
6518
6601
  const collapsedParentIds = externalCollapsedParentIds ?? internalCollapsedParentIds;
@@ -7176,6 +7259,7 @@ var TaskList = ({
7176
7259
  onToggleCollapse: handleToggleCollapse,
7177
7260
  onPromoteTask,
7178
7261
  onDemoteTask: onDemoteTask ? handleDemoteWrapper : void 0,
7262
+ onUngroupTask,
7179
7263
  onDuplicateTask: onReorder ? handleDuplicateTask : void 0,
7180
7264
  canDemoteTask,
7181
7265
  isLastChild: lastChildIds.has(task.id),
@@ -7187,7 +7271,8 @@ var TaskList = ({
7187
7271
  businessDays,
7188
7272
  isFilterMatch: filterMode === "highlight" ? highlightedTaskIds.has(task.id) : false,
7189
7273
  isFilterHideMode: filterMode === "hide" && isFilterActive,
7190
- resolvedColumns
7274
+ resolvedColumns,
7275
+ taskListMenuCommands
7191
7276
  }
7192
7277
  ),
7193
7278
  pendingInsertDisplayTaskId === task.id && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
@@ -7245,8 +7330,13 @@ var TaskList = ({
7245
7330
  };
7246
7331
 
7247
7332
  // src/components/GanttChart/print.ts
7248
- function getPrintDocumentTitle({ header, title, fileName }) {
7249
- return header?.projectName || title || header?.serviceName || fileName || "Gantt chart";
7333
+ function getPrintDocumentTitle({
7334
+ header,
7335
+ documentTitle,
7336
+ title,
7337
+ fileName
7338
+ }) {
7339
+ return documentTitle || fileName || title || header?.projectName || header?.serviceName || "Gantt chart";
7250
7340
  }
7251
7341
  function formatHeaderExportDate(exportDate) {
7252
7342
  if (!exportDate) return null;
@@ -7541,6 +7631,7 @@ async function printGanttChart({
7541
7631
  sourceContainer,
7542
7632
  printContent,
7543
7633
  header,
7634
+ documentTitle,
7544
7635
  title,
7545
7636
  fileName,
7546
7637
  orientation
@@ -7552,7 +7643,7 @@ async function printGanttChart({
7552
7643
  if (!printWindow || !printDocument) {
7553
7644
  throw new Error("Unable to create print frame");
7554
7645
  }
7555
- const printTitle = getPrintDocumentTitle({ header, title, fileName });
7646
+ const printTitle = getPrintDocumentTitle({ header, documentTitle, title, fileName });
7556
7647
  printDocument.open();
7557
7648
  printDocument.write('<!doctype html><html><head><meta charset="utf-8" /></head><body></body></html>');
7558
7649
  printDocument.close();
@@ -7601,6 +7692,7 @@ function GanttChartInner(props, ref) {
7601
7692
  onReorder,
7602
7693
  onPromoteTask,
7603
7694
  onDemoteTask,
7695
+ onUngroupTask,
7604
7696
  enableAddTask = true,
7605
7697
  viewMode = "day",
7606
7698
  customDays,
@@ -7613,7 +7705,8 @@ function GanttChartInner(props, ref) {
7613
7705
  highlightedTaskIds,
7614
7706
  disableTaskDrag = false,
7615
7707
  showChart = true,
7616
- additionalColumns
7708
+ additionalColumns,
7709
+ taskListMenuCommands
7617
7710
  } = props;
7618
7711
  const containerRef = (0, import_react13.useRef)(null);
7619
7712
  const scrollContainerRef = (0, import_react13.useRef)(null);
@@ -7920,6 +8013,7 @@ function GanttChartInner(props, ref) {
7920
8013
  }
7921
8014
  if (includeChart) {
7922
8015
  chartClone?.classList.remove("gantt-chart-hidden");
8016
+ if (chartClone) chartClone.style.display = "";
7923
8017
  } else {
7924
8018
  chartClone?.remove();
7925
8019
  }
@@ -7928,6 +8022,7 @@ function GanttChartInner(props, ref) {
7928
8022
  sourceContainer,
7929
8023
  printContent,
7930
8024
  header: options?.header,
8025
+ documentTitle: options?.documentTitle,
7931
8026
  title: options?.title,
7932
8027
  fileName: options?.fileName,
7933
8028
  orientation: options?.orientation
@@ -8027,6 +8122,33 @@ function GanttChartInner(props, ref) {
8027
8122
  };
8028
8123
  onTasksChange?.([updatedDemotedTask]);
8029
8124
  }, [tasks, onTasksChange, onDemoteTask]);
8125
+ const handleUngroupTask = (0, import_react13.useCallback)((taskId) => {
8126
+ if (onUngroupTask) {
8127
+ onUngroupTask(taskId);
8128
+ return;
8129
+ }
8130
+ const parentTask = tasks.find((task) => task.id === taskId);
8131
+ if (!parentTask) return;
8132
+ const hasDirectChildren = tasks.some((task) => task.parentId === taskId);
8133
+ if (!hasDirectChildren) return;
8134
+ const changedTasks = [];
8135
+ for (const task of tasks) {
8136
+ if (task.id === taskId) continue;
8137
+ const nextParentId = task.parentId === taskId ? parentTask.parentId : task.parentId;
8138
+ const nextDependencies = task.dependencies?.filter((dep) => dep.taskId !== taskId);
8139
+ if (nextParentId !== task.parentId || nextDependencies?.length !== task.dependencies?.length) {
8140
+ changedTasks.push({
8141
+ ...task,
8142
+ parentId: nextParentId,
8143
+ dependencies: nextDependencies
8144
+ });
8145
+ }
8146
+ }
8147
+ if (changedTasks.length > 0) {
8148
+ onTasksChange?.(changedTasks);
8149
+ }
8150
+ onDelete?.(taskId);
8151
+ }, [tasks, onTasksChange, onDelete, onUngroupTask]);
8030
8152
  const panStateRef = (0, import_react13.useRef)(null);
8031
8153
  const handlePanStart = (0, import_react13.useCallback)((e) => {
8032
8154
  if (e.button !== 0) return;
@@ -8105,6 +8227,7 @@ function GanttChartInner(props, ref) {
8105
8227
  onToggleCollapse: handleToggleCollapse,
8106
8228
  onPromoteTask: onPromoteTask ?? handlePromoteTask,
8107
8229
  onDemoteTask: onDemoteTask ?? handleDemoteTask,
8230
+ onUngroupTask: onUngroupTask ?? handleUngroupTask,
8108
8231
  highlightedTaskIds: taskListHighlightedTaskIds,
8109
8232
  customDays,
8110
8233
  isWeekend: isWeekend3,
@@ -8112,103 +8235,111 @@ function GanttChartInner(props, ref) {
8112
8235
  filterMode,
8113
8236
  filteredTaskIds: matchedTaskIds,
8114
8237
  isFilterActive: !!taskFilter,
8115
- additionalColumns
8238
+ additionalColumns,
8239
+ taskListMenuCommands
8116
8240
  }
8117
8241
  ),
8118
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: showChart ? "gantt-chartSurface" : "gantt-chartSurface gantt-chart-hidden", style: { minWidth: `${gridWidth}px`, flex: 1 }, children: [
8119
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "gantt-stickyHeader", style: { width: `${gridWidth}px` }, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8120
- TimeScaleHeader_default,
8121
- {
8122
- days: dateRange,
8123
- dayWidth,
8124
- headerHeight,
8125
- viewMode,
8126
- isCustomWeekend
8127
- }
8128
- ) }),
8129
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
8130
- "div",
8131
- {
8132
- className: "gantt-taskArea",
8133
- style: {
8134
- position: "relative",
8135
- width: `${gridWidth}px`
8136
- },
8137
- children: [
8138
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8139
- GridBackground_default,
8140
- {
8141
- dateRange,
8142
- dayWidth,
8143
- totalHeight: totalGridHeight,
8144
- viewMode,
8145
- isCustomWeekend
8146
- }
8147
- ),
8148
- todayInRange && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TodayIndicator_default, { monthStart, dayWidth }),
8149
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8150
- DependencyLines_default,
8151
- {
8152
- tasks: previewVisibleTasks,
8153
- allTasks: previewNormalizedTasks,
8154
- collapsedParentIds,
8155
- monthStart,
8156
- dayWidth,
8157
- rowHeight,
8158
- gridWidth,
8159
- dragOverrides: dependencyOverrides,
8160
- selectedDep: selectedChip,
8161
- businessDays,
8162
- weekendPredicate: isCustomWeekend
8163
- }
8164
- ),
8165
- dragGuideLines && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8166
- DragGuideLines_default,
8167
- {
8168
- isDragging: dragGuideLines.isDragging,
8169
- dragMode: dragGuideLines.dragMode,
8170
- left: dragGuideLines.left,
8171
- width: dragGuideLines.width,
8172
- totalHeight: totalGridHeight
8173
- }
8174
- ),
8175
- visibleTasks.map((task, index) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8176
- TaskRow_default,
8177
- {
8178
- task,
8179
- monthStart,
8180
- dayWidth,
8181
- rowHeight,
8182
- onTasksChange: handleTaskChange,
8183
- onDragStateChange: (state) => {
8184
- if (state.isDragging) {
8185
- setDragGuideLines(state);
8186
- setDraggedTaskOverride({ taskId: task.id, left: state.left, width: state.width });
8187
- } else {
8188
- setDragGuideLines(null);
8189
- setDraggedTaskOverride(null);
8190
- }
8191
- },
8192
- rowIndex: index,
8193
- allTasks: normalizedTasks,
8194
- enableAutoSchedule: enableAutoSchedule ?? false,
8195
- disableConstraints: disableConstraints ?? false,
8196
- overridePosition: cascadeOverrides.get(task.id),
8197
- onCascadeProgress: handleCascadeProgress,
8198
- onCascade: handleCascade,
8199
- highlightExpiredTasks,
8200
- isFilterMatch: filterMode === "highlight" ? matchedTaskIds.has(task.id) : false,
8201
- businessDays,
8202
- customDays,
8203
- isWeekend: isWeekend3,
8204
- disableTaskDrag
8242
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
8243
+ "div",
8244
+ {
8245
+ className: showChart ? "gantt-chartSurface" : "gantt-chartSurface gantt-chart-hidden",
8246
+ style: { minWidth: `${gridWidth}px`, flex: 1, display: showChart ? void 0 : "none" },
8247
+ children: [
8248
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "gantt-stickyHeader", style: { width: `${gridWidth}px` }, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8249
+ TimeScaleHeader_default,
8250
+ {
8251
+ days: dateRange,
8252
+ dayWidth,
8253
+ headerHeight,
8254
+ viewMode,
8255
+ isCustomWeekend
8256
+ }
8257
+ ) }),
8258
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
8259
+ "div",
8260
+ {
8261
+ className: "gantt-taskArea",
8262
+ style: {
8263
+ position: "relative",
8264
+ width: `${gridWidth}px`
8205
8265
  },
8206
- task.id
8207
- ))
8208
- ]
8209
- }
8210
- )
8211
- ] })
8266
+ children: [
8267
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8268
+ GridBackground_default,
8269
+ {
8270
+ dateRange,
8271
+ dayWidth,
8272
+ totalHeight: totalGridHeight,
8273
+ viewMode,
8274
+ isCustomWeekend
8275
+ }
8276
+ ),
8277
+ todayInRange && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TodayIndicator_default, { monthStart, dayWidth }),
8278
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8279
+ DependencyLines_default,
8280
+ {
8281
+ tasks: previewVisibleTasks,
8282
+ allTasks: previewNormalizedTasks,
8283
+ collapsedParentIds,
8284
+ monthStart,
8285
+ dayWidth,
8286
+ rowHeight,
8287
+ gridWidth,
8288
+ dragOverrides: dependencyOverrides,
8289
+ selectedDep: selectedChip,
8290
+ businessDays,
8291
+ weekendPredicate: isCustomWeekend
8292
+ }
8293
+ ),
8294
+ dragGuideLines && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8295
+ DragGuideLines_default,
8296
+ {
8297
+ isDragging: dragGuideLines.isDragging,
8298
+ dragMode: dragGuideLines.dragMode,
8299
+ left: dragGuideLines.left,
8300
+ width: dragGuideLines.width,
8301
+ totalHeight: totalGridHeight
8302
+ }
8303
+ ),
8304
+ visibleTasks.map((task, index) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8305
+ TaskRow_default,
8306
+ {
8307
+ task,
8308
+ monthStart,
8309
+ dayWidth,
8310
+ rowHeight,
8311
+ onTasksChange: handleTaskChange,
8312
+ onDragStateChange: (state) => {
8313
+ if (state.isDragging) {
8314
+ setDragGuideLines(state);
8315
+ setDraggedTaskOverride({ taskId: task.id, left: state.left, width: state.width });
8316
+ } else {
8317
+ setDragGuideLines(null);
8318
+ setDraggedTaskOverride(null);
8319
+ }
8320
+ },
8321
+ rowIndex: index,
8322
+ allTasks: normalizedTasks,
8323
+ enableAutoSchedule: enableAutoSchedule ?? false,
8324
+ disableConstraints: disableConstraints ?? false,
8325
+ overridePosition: cascadeOverrides.get(task.id),
8326
+ onCascadeProgress: handleCascadeProgress,
8327
+ onCascade: handleCascade,
8328
+ highlightExpiredTasks,
8329
+ isFilterMatch: filterMode === "highlight" ? matchedTaskIds.has(task.id) : false,
8330
+ businessDays,
8331
+ customDays,
8332
+ isWeekend: isWeekend3,
8333
+ disableTaskDrag
8334
+ },
8335
+ task.id
8336
+ ))
8337
+ ]
8338
+ }
8339
+ )
8340
+ ]
8341
+ }
8342
+ )
8212
8343
  ] })
8213
8344
  }
8214
8345
  ) });