apexgantt 3.3.0 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -357,14 +357,18 @@ ganttInstance.zoomOut();
357
357
 
358
358
  ## Events
359
359
 
360
- ApexGantt emits CustomEvents on the container element when tasks are updated through the dialog form.
361
-
362
- | Event | When | Detail |
363
- | --------------------- | ----------------------------- | --------------------------------------------- |
364
- | `taskUpdate` | Task is being updated | `{ taskId, updates, updatedTask, timestamp }` |
365
- | `taskUpdateSuccess` | Update completed successfully | `{ taskId, updatedTask, timestamp }` |
366
- | `taskValidationError` | Form validation failed | `{ taskId, errors, timestamp }` |
367
- | `taskUpdateError` | Update failed | `{ taskId, error, timestamp }` |
360
+ ApexGantt emits CustomEvents on the container element for various user interactions, allowing you to track and respond to changes in real-time.
361
+
362
+ ### Available Events
363
+
364
+ | Event | When | Detail |
365
+ | --- | --- | --- |
366
+ | `taskUpdate` | Task is being updated | `{ taskId, updates, updatedTask, timestamp }` |
367
+ | `taskUpdateSuccess` | Update completed successfully | `{ taskId, updatedTask, timestamp }` |
368
+ | `taskValidationError` | Form validation failed | `{ taskId, errors, timestamp }` |
369
+ | `taskUpdateError` | Update failed | `{ taskId, error, timestamp }` |
370
+ | `taskDragged` | Task bar is dragged | `{ taskId, oldStartTime, oldEndTime, newStartTime, newEndTime, daysMoved, affectedChildTasks, timestamp }` |
371
+ | `taskResized` | Task bar is resized | `{ taskId, resizeHandle, oldStartTime, oldEndTime, newStartTime, newEndTime, durationChange, timestamp }` |
368
372
 
369
373
  ### Events Usage
370
374
 
@@ -12929,6 +12929,32 @@ function getDefaultOptions(theme) {
12929
12929
  };
12930
12930
  }
12931
12931
  const DefaultOptions$1 = getDefaultOptions("light");
12932
+ const GanttEvents = {
12933
+ /**
12934
+ * emits when a task is being updated (before completion)
12935
+ */
12936
+ TASK_UPDATE: "taskUpdate",
12937
+ /**
12938
+ * emits when form validation fails
12939
+ */
12940
+ TASK_VALIDATION_ERROR: "taskValidationError",
12941
+ /**
12942
+ * emits after a task update completes successfully
12943
+ */
12944
+ TASK_UPDATE_SUCCESS: "taskUpdateSuccess",
12945
+ /**
12946
+ * emits when a task update fails
12947
+ */
12948
+ TASK_UPDATE_ERROR: "taskUpdateError",
12949
+ /**
12950
+ * emits when a task bar is dragged to a new position
12951
+ */
12952
+ TASK_DRAGGED: "taskDragged",
12953
+ /**
12954
+ * emits when a task bar is resized via handles
12955
+ */
12956
+ TASK_RESIZED: "taskResized"
12957
+ };
12932
12958
  class BarDragManager {
12933
12959
  constructor(taskId, options, viewMode, chartContext, dataManager) {
12934
12960
  this.taskId = taskId;
@@ -12940,6 +12966,8 @@ class BarDragManager {
12940
12966
  daysPerPixel: 0,
12941
12967
  initialLeft: 0,
12942
12968
  initialPosition: 0,
12969
+ initialStartTime: "",
12970
+ initialEndTime: "",
12943
12971
  isDragging: false,
12944
12972
  parentWidth: 0,
12945
12973
  parentX1: 0,
@@ -12970,6 +12998,8 @@ class BarDragManager {
12970
12998
  ...this.dragState,
12971
12999
  initialLeft: parseInt(barElement.style.left) || 0,
12972
13000
  initialPosition: e.clientX,
13001
+ initialStartTime: this.task.startTime,
13002
+ initialEndTime: this.task.endTime,
12973
13003
  isDragging: true,
12974
13004
  startX: e.clientX
12975
13005
  };
@@ -13016,10 +13046,47 @@ class BarDragManager {
13016
13046
  barElement.classList.remove("dragging");
13017
13047
  const currentWidth = parseInt(barElement.style.width) || 0;
13018
13048
  const { calculatedLeft, daysMoved } = this.calculateFinalPosition(e, currentWidth);
13049
+ if (daysMoved === 0) {
13050
+ this.dragState = {
13051
+ ...this.dragState,
13052
+ isDragging: false
13053
+ };
13054
+ return;
13055
+ }
13056
+ const newStart = dayjs(this.task.startTime).add(daysMoved, "day").format(this.options.inputDateFormat);
13057
+ const newEnd = dayjs(this.task.endTime).add(daysMoved, "day").format(this.options.inputDateFormat);
13058
+ const affectedChildTasks = this.dragState.childTasks.map((childTask) => ({
13059
+ taskId: childTask.id,
13060
+ newStartTime: dayjs(childTask.startTime).add(daysMoved, "day").format(this.options.inputDateFormat),
13061
+ newEndTime: childTask.endTime ? dayjs(childTask.endTime).add(daysMoved, "day").format(this.options.inputDateFormat) : null
13062
+ })).filter((child) => child.newEndTime !== null);
13063
+ this.emitTaskDraggedEvent(daysMoved, newStart, newEnd, affectedChildTasks);
13019
13064
  this.updateTaskPosition(barElement, calculatedLeft, daysMoved, onUpdate);
13020
13065
  this.updateChildrenPositions(calculatedLeft, daysMoved, onUpdate);
13021
13066
  };
13022
13067
  }
13068
+ emitTaskDraggedEvent(daysMoved, newStartTime, newEndTime, affectedChildTasks) {
13069
+ const eventDetail = {
13070
+ taskId: this.task.id,
13071
+ oldStartTime: this.dragState.initialStartTime,
13072
+ oldEndTime: this.dragState.initialEndTime,
13073
+ newStartTime,
13074
+ newEndTime,
13075
+ daysMoved,
13076
+ affectedChildTasks,
13077
+ timestamp: Date.now()
13078
+ };
13079
+ const event = new CustomEvent(GanttEvents.TASK_DRAGGED, {
13080
+ detail: eventDetail,
13081
+ bubbles: true,
13082
+ composed: true,
13083
+ cancelable: false
13084
+ });
13085
+ const chartContainer = this.chartContext.getChartContainer();
13086
+ if (chartContainer) {
13087
+ chartContainer.dispatchEvent(event);
13088
+ }
13089
+ }
13023
13090
  isOutOfBounds(currentLeft, currentWidth, dx2) {
13024
13091
  const { parentX1, parentX2 } = this.dragState;
13025
13092
  return dx2 < 0 && currentLeft <= parentX1 || dx2 > 0 && currentLeft + currentWidth >= parentX2;
@@ -13084,6 +13151,8 @@ class BarResizeManager {
13084
13151
  initialLeft: 0,
13085
13152
  initialPosition: 0,
13086
13153
  initialWidth: 0,
13154
+ initialStartTime: "",
13155
+ initialEndTime: "",
13087
13156
  isResizing: false,
13088
13157
  parentWidth: 0,
13089
13158
  parentX1: 0,
@@ -13130,6 +13199,11 @@ class BarResizeManager {
13130
13199
  barElement.classList.remove("resizing");
13131
13200
  const { daysPerPixel, initialLeft, initialPosition, initialWidth, parentX1, parentX2, resizeHandle } = this.interactionState;
13132
13201
  const dx2 = e.clientX - initialPosition;
13202
+ const oldStartTime = this.interactionState.initialStartTime;
13203
+ const oldEndTime = this.interactionState.initialEndTime;
13204
+ let newStartTime = oldStartTime;
13205
+ let newEndTime = oldEndTime;
13206
+ let durationChange = 0;
13133
13207
  if (resizeHandle === "left") {
13134
13208
  let daysChange = Math.round(dx2 / daysPerPixel);
13135
13209
  let calculatedLeft = initialLeft + daysChange * daysPerPixel;
@@ -13143,10 +13217,19 @@ class BarResizeManager {
13143
13217
  calculatedLeft = initialLeft + initialWidth - daysPerPixel;
13144
13218
  daysChange = Math.round((calculatedLeft - initialLeft) / daysPerPixel);
13145
13219
  }
13220
+ if (daysChange === 0) {
13221
+ this.interactionState = {
13222
+ ...this.interactionState,
13223
+ isResizing: false,
13224
+ resizeHandle: null
13225
+ };
13226
+ return;
13227
+ }
13146
13228
  barElement.style.left = `${calculatedLeft}px`;
13147
13229
  barElement.style.width = `${calculatedWidth}px`;
13148
- const newStart = dayjs(this.task.startTime).add(daysChange, "day").format(this.options.inputDateFormat);
13149
- onUpdate == null ? void 0 : onUpdate(this.task.id, { startTime: newStart });
13230
+ newStartTime = dayjs(this.task.startTime).add(daysChange, "day").format(this.options.inputDateFormat);
13231
+ durationChange = -daysChange;
13232
+ onUpdate == null ? void 0 : onUpdate(this.task.id, { startTime: newStartTime });
13150
13233
  } else {
13151
13234
  let daysWidth = Math.round(dx2 / daysPerPixel);
13152
13235
  let calculatedWidth = initialWidth + daysWidth * daysPerPixel;
@@ -13157,10 +13240,20 @@ class BarResizeManager {
13157
13240
  calculatedWidth = parentX2 - initialLeft;
13158
13241
  daysWidth = Math.round((calculatedWidth - initialWidth) / daysPerPixel);
13159
13242
  }
13243
+ if (daysWidth === 0) {
13244
+ this.interactionState = {
13245
+ ...this.interactionState,
13246
+ isResizing: false,
13247
+ resizeHandle: null
13248
+ };
13249
+ return;
13250
+ }
13160
13251
  barElement.style.width = `${calculatedWidth}px`;
13161
- const newEnd = dayjs(this.task.endTime).add(daysWidth, "day").format(this.options.inputDateFormat);
13162
- onUpdate == null ? void 0 : onUpdate(this.task.id, { endTime: newEnd });
13252
+ newEndTime = dayjs(this.task.endTime).add(daysWidth, "day").format(this.options.inputDateFormat);
13253
+ durationChange = daysWidth;
13254
+ onUpdate == null ? void 0 : onUpdate(this.task.id, { endTime: newEndTime });
13163
13255
  }
13256
+ this.emitTaskResizedEvent(resizeHandle, oldStartTime, oldEndTime, newStartTime, newEndTime, durationChange);
13164
13257
  this.dataManager.updateDependencyArrows(this.task.id, this.chartContext);
13165
13258
  this.interactionState = {
13166
13259
  ...this.interactionState,
@@ -13169,6 +13262,28 @@ class BarResizeManager {
13169
13262
  };
13170
13263
  };
13171
13264
  }
13265
+ emitTaskResizedEvent(resizeHandle, oldStartTime, oldEndTime, newStartTime, newEndTime, durationChange) {
13266
+ const eventDetail = {
13267
+ taskId: this.task.id,
13268
+ resizeHandle,
13269
+ oldStartTime,
13270
+ oldEndTime,
13271
+ newStartTime,
13272
+ newEndTime,
13273
+ durationChange,
13274
+ timestamp: Date.now()
13275
+ };
13276
+ const event = new CustomEvent(GanttEvents.TASK_RESIZED, {
13277
+ detail: eventDetail,
13278
+ bubbles: true,
13279
+ composed: true,
13280
+ cancelable: false
13281
+ });
13282
+ const chartContainer = this.chartContext.getChartContainer();
13283
+ if (chartContainer) {
13284
+ chartContainer.dispatchEvent(event);
13285
+ }
13286
+ }
13172
13287
  createResizeMouseDownHandler(barElement) {
13173
13288
  return (e, handle) => {
13174
13289
  var _a;
@@ -13179,6 +13294,8 @@ class BarResizeManager {
13179
13294
  initialLeft: parseInt(barElement.style.left) || 0,
13180
13295
  initialPosition: e.clientX,
13181
13296
  initialWidth: parseInt(barElement.style.width) || 0,
13297
+ initialStartTime: this.task.startTime,
13298
+ initialEndTime: this.task.endTime,
13182
13299
  isResizing: true,
13183
13300
  resizeHandle: handle,
13184
13301
  startX: e.clientX
@@ -13389,24 +13506,6 @@ class Dialog {
13389
13506
  firstFocusable == null ? void 0 : firstFocusable.focus();
13390
13507
  }
13391
13508
  }
13392
- const GanttEvents = {
13393
- /**
13394
- * emits when a task is being updated (before completion)
13395
- */
13396
- TASK_UPDATE: "taskUpdate",
13397
- /**
13398
- * emits when form validation fails
13399
- */
13400
- TASK_VALIDATION_ERROR: "taskValidationError",
13401
- /**
13402
- * emits after a task update completes successfully
13403
- */
13404
- TASK_UPDATE_SUCCESS: "taskUpdateSuccess",
13405
- /**
13406
- * emits when a task update fails
13407
- */
13408
- TASK_UPDATE_ERROR: "taskUpdateError"
13409
- };
13410
13509
  class TaskForm {
13411
13510
  constructor(chartContext, dataManager, task, containerElement, onSubmit, dateFormat = "MM-DD-YYYY") {
13412
13511
  this.chartContext = chartContext;