gantt-renderer 0.4.0 → 0.6.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
@@ -39,17 +39,20 @@ const taskBase = {
39
39
  const TaskLeafSchema = z.object({
40
40
  ...taskBase,
41
41
  kind: z.literal("task"),
42
- /** Duration in hours. Must be positive; use `kind: 'milestone'` for zero-duration points. */
43
- durationHours: z.number().int().positive(),
42
+ /** ISO date: YYYY-MM-DD */
43
+ endDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/u, "Expected YYYY-MM-DD"),
44
44
  /** 0–100 completion percentage (integer). */
45
45
  percentComplete: z.number().int().min(0).max(100).default(0)
46
+ }).refine((t) => t.endDate >= t.startDate, {
47
+ message: "endDate must be on or after startDate",
48
+ path: ["endDate"]
46
49
  });
47
50
  /** @internal */
48
51
  const TaskProjectSchema = z.object({
49
52
  ...taskBase,
50
53
  kind: z.literal("project"),
51
- /** Duration in hours. Must be positive; use `kind: 'milestone'` for zero-duration points. */
52
- durationHours: z.number().int().positive(),
54
+ /** ISO date: YYYY-MM-DD */
55
+ endDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/u, "Expected YYYY-MM-DD"),
53
56
  /** 0–100 completion percentage (integer). */
54
57
  percentComplete: z.number().int().min(0).max(100).default(0),
55
58
  /**
@@ -59,6 +62,9 @@ const TaskProjectSchema = z.object({
59
62
  * @default true
60
63
  */
61
64
  open: z.boolean().default(true)
65
+ }).refine((t) => t.endDate >= t.startDate, {
66
+ message: "endDate must be on or after startDate",
67
+ path: ["endDate"]
62
68
  });
63
69
  /** @internal */
64
70
  const TaskMilestoneSchema = z.object({
@@ -152,7 +158,7 @@ const GanttInputSchema = z.object({
152
158
  * Parses raw external data.
153
159
  *
154
160
  * @param raw - The unvalidated input from the consumer.
155
- * @returns The parsed and validated {@link GanttInput}.
161
+ * @returns The parsed and validated input with `data` typed as `Record<string, unknown>`.
156
162
  * @throws {import('zod').ZodError} On schema validation failure.
157
163
  */
158
164
  function parseGanttInput(raw) {
@@ -466,7 +472,8 @@ const EN_US_LABELS = {
466
472
  ariaMilestone: "Milestone {0}",
467
473
  addSubtaskTitle: "Add subtask",
468
474
  columnTaskName: "Task name",
469
- columnStartDate: "Start time",
475
+ columnStartDate: "Start",
476
+ columnEndDate: "End",
470
477
  columnDuration: "Duration",
471
478
  columnQuarter: "Q"
472
479
  };
@@ -477,6 +484,134 @@ const CHART_LOCALE_EN_US = {
477
484
  weekNumbering: "iso",
478
485
  weekendDays: [0, 6]
479
486
  };
487
+ const CHART_LOCALE_EN_GB = {
488
+ code: "en-GB",
489
+ labels: {
490
+ ariaTask: "Task {0}",
491
+ ariaMilestone: "Milestone {0}",
492
+ addSubtaskTitle: "Add subtask",
493
+ columnTaskName: "Task name",
494
+ columnStartDate: "Start",
495
+ columnEndDate: "End",
496
+ columnDuration: "Duration",
497
+ columnQuarter: "Q"
498
+ },
499
+ weekStartsOn: 1,
500
+ weekNumbering: "iso",
501
+ weekendDays: [0, 6]
502
+ };
503
+ const CHART_LOCALE_DE_DE = {
504
+ code: "de-DE",
505
+ labels: {
506
+ ariaTask: "Aufgabe {0}",
507
+ ariaMilestone: "Meilenstein {0}",
508
+ addSubtaskTitle: "Teilaufgabe hinzufügen",
509
+ columnTaskName: "Aufgabenname",
510
+ columnStartDate: "Start",
511
+ columnEndDate: "Ende",
512
+ columnDuration: "Dauer",
513
+ columnQuarter: "Q"
514
+ },
515
+ weekStartsOn: 1,
516
+ weekNumbering: "iso",
517
+ weekendDays: [0, 6]
518
+ };
519
+ const CHART_LOCALE_FR_FR = {
520
+ code: "fr-FR",
521
+ labels: {
522
+ ariaTask: "Tâche {0}",
523
+ ariaMilestone: "Jalon {0}",
524
+ addSubtaskTitle: "Ajouter une sous-tâche",
525
+ columnTaskName: "Nom de la tâche",
526
+ columnStartDate: "Début",
527
+ columnEndDate: "Fin",
528
+ columnDuration: "Durée",
529
+ columnQuarter: "T"
530
+ },
531
+ weekStartsOn: 1,
532
+ weekNumbering: "iso",
533
+ weekendDays: [0, 6]
534
+ };
535
+ const CHART_LOCALE_ES_ES = {
536
+ code: "es-ES",
537
+ labels: {
538
+ ariaTask: "Tarea {0}",
539
+ ariaMilestone: "Hito {0}",
540
+ addSubtaskTitle: "Añadir subtarea",
541
+ columnTaskName: "Nombre de tarea",
542
+ columnStartDate: "Inicio",
543
+ columnEndDate: "Fin",
544
+ columnDuration: "Duración",
545
+ columnQuarter: "T"
546
+ },
547
+ weekStartsOn: 1,
548
+ weekNumbering: "iso",
549
+ weekendDays: [0, 6]
550
+ };
551
+ const CHART_LOCALE_IT_IT = {
552
+ code: "it-IT",
553
+ labels: {
554
+ ariaTask: "Attività {0}",
555
+ ariaMilestone: "Pietra miliare {0}",
556
+ addSubtaskTitle: "Aggiungi sottoattività",
557
+ columnTaskName: "Nome attività",
558
+ columnStartDate: "Inizio",
559
+ columnEndDate: "Fine",
560
+ columnDuration: "Durata",
561
+ columnQuarter: "T"
562
+ },
563
+ weekStartsOn: 1,
564
+ weekNumbering: "iso",
565
+ weekendDays: [0, 6]
566
+ };
567
+ const CHART_LOCALE_PT_PT = {
568
+ code: "pt-PT",
569
+ labels: {
570
+ ariaTask: "Tarefa {0}",
571
+ ariaMilestone: "Marco {0}",
572
+ addSubtaskTitle: "Adicionar subtarefa",
573
+ columnTaskName: "Nome da tarefa",
574
+ columnStartDate: "Início",
575
+ columnEndDate: "Fim",
576
+ columnDuration: "Duração",
577
+ columnQuarter: "T"
578
+ },
579
+ weekStartsOn: 1,
580
+ weekNumbering: "iso",
581
+ weekendDays: [0, 6]
582
+ };
583
+ const CHART_LOCALE_ZH_CN = {
584
+ code: "zh-CN",
585
+ labels: {
586
+ ariaTask: "任务 {0}",
587
+ ariaMilestone: "里程碑 {0}",
588
+ addSubtaskTitle: "添加子任务",
589
+ columnTaskName: "任务名称",
590
+ columnStartDate: "开始",
591
+ columnEndDate: "结束",
592
+ columnDuration: "工期",
593
+ columnQuarter: "季"
594
+ },
595
+ weekStartsOn: 1,
596
+ weekNumbering: "us",
597
+ weekendDays: [0, 6]
598
+ };
599
+ const CHART_LOCALE_JA_JP = {
600
+ code: "ja-JP",
601
+ labels: {
602
+ ariaTask: "タスク {0}",
603
+ ariaMilestone: "マイルストーン {0}",
604
+ addSubtaskTitle: "サブタスクを追加",
605
+ columnTaskName: "タスク名",
606
+ columnStartDate: "開始",
607
+ columnEndDate: "終了",
608
+ columnDuration: "期間",
609
+ columnQuarter: "Q"
610
+ },
611
+ weekStartsOn: 0,
612
+ weekNumbering: "us",
613
+ weekendDays: [0, 6]
614
+ };
480
615
  function tryGetWeekInfo(code) {
481
616
  try {
482
617
  if (typeof Intl !== "undefined" && typeof Intl.Locale === "function") {
@@ -759,6 +894,16 @@ function formatUpperLabel(date, scale, locale) {
759
894
  }
760
895
  }
761
896
  /**
897
+ * Returns the number of days in an inclusive range from `start` to `end`.
898
+ *
899
+ * @param start - The start date.
900
+ * @param end - The end date.
901
+ * @returns The number of days, inclusive.
902
+ */
903
+ function getRangeDays(start, end) {
904
+ return Math.round(diffDays(start, end)) + 1;
905
+ }
906
+ /**
762
907
  * Formats a `YYYY-MM-DD` string for display in the grid.
763
908
  *
764
909
  * @param dateStr - An ISO-8601 date string in `YYYY-MM-DD` format.
@@ -871,7 +1016,7 @@ function createPixelMapper(scale, viewportStart) {
871
1016
  const originMs = viewportStart.getTime();
872
1017
  const pxPerMs = columnWidth / msPerColumn;
873
1018
  const msPerPx = msPerColumn / columnWidth;
874
- const msPerHour = 36e5;
1019
+ const msPerDay = 864e5;
875
1020
  return {
876
1021
  originMs,
877
1022
  columnWidth,
@@ -881,11 +1026,11 @@ function createPixelMapper(scale, viewportStart) {
881
1026
  toDate(x) {
882
1027
  return new Date(originMs + x * msPerPx);
883
1028
  },
884
- durationToWidth(hours) {
885
- return hours * msPerHour * pxPerMs;
1029
+ durationDaysToWidth(days) {
1030
+ return days * msPerDay * pxPerMs;
886
1031
  },
887
- widthToDuration(px) {
888
- return px * msPerPx / msPerHour;
1032
+ widthToDurationDays(px) {
1033
+ return px * msPerPx / msPerDay;
889
1034
  }
890
1035
  };
891
1036
  }
@@ -934,7 +1079,8 @@ function computeLayout(rows, mapper) {
934
1079
  });
935
1080
  continue;
936
1081
  }
937
- const width = Math.max(mapper.durationToWidth(task.durationHours), 4);
1082
+ const days = getRangeDays(start, parseDate(task.endDate));
1083
+ const width = Math.max(mapper.durationDaysToWidth(days), 4);
938
1084
  const progressWidth = width * Math.min(1, Math.max(0, (task.percentComplete ?? 0) / 100));
939
1085
  result.set(task.id, {
940
1086
  taskId: task.id,
@@ -978,7 +1124,7 @@ function deriveViewport(tasks, paddingHours = 48) {
978
1124
  const start = parseDate(task.startDate);
979
1125
  if (start.getTime() < minMs) minMs = start.getTime();
980
1126
  if (task.kind !== "milestone") {
981
- const end = addHours(start, task.durationHours);
1127
+ const end = parseDate(task.endDate);
982
1128
  if (end.getTime() > maxMs) maxMs = end.getTime();
983
1129
  } else if (start.getTime() > maxMs) maxMs = start.getTime();
984
1130
  }
@@ -1490,17 +1636,10 @@ const DEFAULT_GRID_COLUMNS = [
1490
1636
  },
1491
1637
  {
1492
1638
  id: "startDate",
1493
- header: "Start time",
1639
+ header: "Start",
1494
1640
  width: "90px",
1495
1641
  field: "startDate",
1496
- format: (value, _task, _row, locale) => formatDisplayDate(String(value), locale)
1497
- },
1498
- {
1499
- id: "durationHours",
1500
- header: "Duration",
1501
- width: "68px",
1502
- field: "durationHours",
1503
- format: (value) => value > 0 ? String(value) : "—"
1642
+ format: (value, _task, _row, locale) => formatDisplayDate(value, locale)
1504
1643
  },
1505
1644
  {
1506
1645
  id: "actions",
@@ -1529,13 +1668,6 @@ function gridColumnDefaults(locale) {
1529
1668
  field: "startDate",
1530
1669
  format: (value, _task, _row, loc) => formatDisplayDate(String(value), loc)
1531
1670
  },
1532
- {
1533
- id: "durationHours",
1534
- header: locale.labels?.columnDuration ?? EN_US_LABELS.columnDuration,
1535
- width: "68px",
1536
- field: "durationHours",
1537
- format: (value) => value > 0 ? String(value) : "—"
1538
- },
1539
1671
  {
1540
1672
  id: "actions",
1541
1673
  header: "",
@@ -1601,13 +1733,13 @@ function toTask$1(node) {
1601
1733
  case "task": return {
1602
1734
  ...base,
1603
1735
  kind: "task",
1604
- durationHours: node.durationHours,
1736
+ endDate: node.endDate,
1605
1737
  percentComplete: node.percentComplete
1606
1738
  };
1607
1739
  case "project": return {
1608
1740
  ...base,
1609
1741
  kind: "project",
1610
- durationHours: node.durationHours,
1742
+ endDate: node.endDate,
1611
1743
  percentComplete: node.percentComplete,
1612
1744
  open: node.open
1613
1745
  };
@@ -1619,7 +1751,7 @@ function toTask$1(node) {
1619
1751
  }
1620
1752
  function getTaskField(task, field) {
1621
1753
  switch (field) {
1622
- case "durationHours": return task.kind !== "milestone" ? task.durationHours : void 0;
1754
+ case "endDate": return task.kind !== "milestone" ? task.endDate : void 0;
1623
1755
  case "percentComplete": return task.kind !== "milestone" ? task.percentComplete : void 0;
1624
1756
  case "open": return task.kind === "project" ? task.open : void 0;
1625
1757
  default: return task[field];
@@ -1716,14 +1848,17 @@ function buildAddButton(row, cbs, locale) {
1716
1848
  });
1717
1849
  return btn;
1718
1850
  }
1719
- function buildCell(column, row, expandedIds, cbs, locale) {
1851
+ function buildActionsPlaceholder() {
1852
+ return el("div");
1853
+ }
1854
+ function buildCell(column, row, expandedIds, cbs, locale, showAddTaskButton) {
1720
1855
  switch (column.id) {
1721
1856
  case "name": return buildTreeNameCell(row, expandedIds, cbs);
1722
- case "actions": return buildAddButton(row, cbs, locale);
1857
+ case "actions": return showAddTaskButton ? buildAddButton(row, cbs, locale) : buildActionsPlaceholder();
1723
1858
  default: return buildDataCell(row, column, locale);
1724
1859
  }
1725
1860
  }
1726
- function buildRow(row, selectedId, expandedIds, cbs, columns, locale) {
1861
+ function buildRow(row, selectedId, expandedIds, cbs, columns, locale, showAddTaskButton) {
1727
1862
  const selected = row.id === selectedId;
1728
1863
  const wrapper = el("div");
1729
1864
  wrapper.className = "gantt-row";
@@ -1755,7 +1890,7 @@ function buildRow(row, selectedId, expandedIds, cbs, columns, locale) {
1755
1890
  cbs.onTaskClick(row.id);
1756
1891
  }
1757
1892
  });
1758
- for (const column of visibleColumns(columns)) wrapper.append(buildCell(column, row, expandedIds, cbs, locale));
1893
+ for (const column of visibleColumns(columns)) wrapper.append(buildCell(column, row, expandedIds, cbs, locale, showAddTaskButton));
1759
1894
  return wrapper;
1760
1895
  }
1761
1896
  /**
@@ -1765,8 +1900,9 @@ function buildRow(row, selectedId, expandedIds, cbs, columns, locale) {
1765
1900
  * @param state - The current chart state.
1766
1901
  * @param cbs - The left pane callbacks.
1767
1902
  * @param columns - The grid column schema.
1903
+ * @param showAddTaskButton - Whether to render the add-subtask button in the actions column.
1768
1904
  */
1769
- function renderLeftPane(container, state, cbs, columns) {
1905
+ function renderLeftPane(container, state, cbs, columns, showAddTaskButton = true) {
1770
1906
  const { allRows, selectedId, expandedIds, startIndex, endIndex, paddingTop, paddingBottom, locale } = state;
1771
1907
  const frag = document.createDocumentFragment();
1772
1908
  if (paddingTop > 0) {
@@ -1774,7 +1910,7 @@ function renderLeftPane(container, state, cbs, columns) {
1774
1910
  spacer.style.height = `${paddingTop}px`;
1775
1911
  frag.append(spacer);
1776
1912
  }
1777
- for (const row of allRows.slice(startIndex, endIndex + 1)) frag.append(buildRow(row, selectedId, expandedIds, cbs, columns, locale));
1913
+ for (const row of allRows.slice(startIndex, endIndex + 1)) frag.append(buildRow(row, selectedId, expandedIds, cbs, columns, locale, showAddTaskButton));
1778
1914
  if (paddingBottom > 0) {
1779
1915
  const spacer = el("div");
1780
1916
  spacer.style.height = `${paddingBottom}px`;
@@ -2067,13 +2203,13 @@ function toTask(node) {
2067
2203
  case "task": return {
2068
2204
  ...base,
2069
2205
  kind: "task",
2070
- durationHours: node.durationHours,
2206
+ endDate: node.endDate,
2071
2207
  percentComplete: node.percentComplete
2072
2208
  };
2073
2209
  case "project": return {
2074
2210
  ...base,
2075
2211
  kind: "project",
2076
- durationHours: node.durationHours,
2212
+ endDate: node.endDate,
2077
2213
  percentComplete: node.percentComplete,
2078
2214
  open: node.open
2079
2215
  };
@@ -2107,22 +2243,22 @@ function attachDrag(barEl, resizeHandleEl, task, getMapper, cbs) {
2107
2243
  const startX = e.clientX;
2108
2244
  const originDate = parseDate(task.startDate);
2109
2245
  const mapper = getMapper();
2110
- let lastHours = 0;
2246
+ let lastDays = 0;
2111
2247
  function onMove(me) {
2112
2248
  const dx = me.clientX - startX;
2113
- lastHours = Math.round(mapper.widthToDuration(dx));
2249
+ lastDays = Math.round(mapper.widthToDurationDays(dx));
2114
2250
  cbs.onTaskMove?.({
2115
2251
  id: task.id,
2116
- startDate: addHours(originDate, lastHours)
2252
+ startDate: addDays(originDate, lastDays)
2117
2253
  });
2118
2254
  }
2119
2255
  function onUp() {
2120
2256
  window.removeEventListener("pointermove", onMove);
2121
2257
  window.removeEventListener("pointerup", onUp);
2122
2258
  barEl.style.cursor = "grab";
2123
- if (lastHours !== 0) cbs._onTaskMoveFinal?.({
2259
+ if (lastDays !== 0) cbs._onTaskMoveFinal?.({
2124
2260
  id: task.id,
2125
- startDate: addHours(originDate, lastHours)
2261
+ startDate: addDays(originDate, lastDays)
2126
2262
  });
2127
2263
  }
2128
2264
  barEl.style.cursor = "grabbing";
@@ -2137,16 +2273,16 @@ function attachDrag(barEl, resizeHandleEl, task, getMapper, cbs) {
2137
2273
  resizeHandleEl.setPointerCapture(e.pointerId);
2138
2274
  } catch {}
2139
2275
  const startX = e.clientX;
2140
- const origDur = task.kind !== "milestone" ? task.durationHours : 0;
2276
+ if (task.kind === "milestone") return;
2277
+ const origEnd = parseDate(task.endDate);
2141
2278
  const mapper = getMapper();
2142
- let lastDuration = origDur;
2279
+ let lastEnd = origEnd;
2143
2280
  function onMove(me) {
2144
2281
  const dx = me.clientX - startX;
2145
- const hoursDelta = Math.round(mapper.widthToDuration(dx));
2146
- lastDuration = Math.max(1, origDur + hoursDelta);
2282
+ lastEnd = addDays(origEnd, Math.round(mapper.widthToDurationDays(dx)));
2147
2283
  cbs.onTaskResize?.({
2148
2284
  id: task.id,
2149
- durationHours: lastDuration
2285
+ endDate: lastEnd.toISOString().slice(0, 10)
2150
2286
  });
2151
2287
  }
2152
2288
  function onUp() {
@@ -2154,7 +2290,7 @@ function attachDrag(barEl, resizeHandleEl, task, getMapper, cbs) {
2154
2290
  window.removeEventListener("pointerup", onUp);
2155
2291
  cbs._onTaskResizeFinal?.({
2156
2292
  id: task.id,
2157
- durationHours: lastDuration
2293
+ endDate: lastEnd.toISOString().slice(0, 10)
2158
2294
  });
2159
2295
  }
2160
2296
  window.addEventListener("pointermove", onMove);
@@ -2920,9 +3056,12 @@ const OVERSCAN = 4;
2920
3056
  * Validates input, builds a DOM tree, and renders a full interactive chart
2921
3057
  * inside the given container element.
2922
3058
  *
3059
+ * @param TTaskData - The type of the optional `data` property on tasks. Defaults to `never`.
3060
+ * @param TLinkData - The type of the optional `data` property on links. Defaults to `never`.
3061
+ *
2923
3062
  * @example
2924
3063
  * ```ts
2925
- * const chart = new GanttChart(document.getElementById('chart')!, input, {
3064
+ * const chart = new GanttChart(document.getElementById('chart')!, {
2926
3065
  * locale: 'de-DE',
2927
3066
  * theme: 'dark',
2928
3067
  * });
@@ -2948,6 +3087,7 @@ var GanttChart = class {
2948
3087
  #timelineMinWidth;
2949
3088
  #columns;
2950
3089
  #leftPaneDefaultWidth;
3090
+ #showAddTaskButton;
2951
3091
  #weekendDays;
2952
3092
  #specialDaysByDate;
2953
3093
  #expandedIds;
@@ -2979,6 +3119,7 @@ var GanttChart = class {
2979
3119
  this.#locale = resolveChartLocale(opts.locale);
2980
3120
  this.#columns = opts.gridColumns ?? gridColumnDefaults(this.#locale);
2981
3121
  this.#leftPaneDefaultWidth = opts.leftPaneWidth ?? gridNaturalWidth(this.#columns);
3122
+ this.#showAddTaskButton = opts.showAddTaskButton ?? true;
2982
3123
  this.#height = opts.height ?? 500;
2983
3124
  this.#timelineMinWidth = opts.timelineMinWidth ?? 220;
2984
3125
  this.#weekendDays = normalizeWeekendDays(opts.weekendDays ?? this.#locale.weekendDays);
@@ -3030,9 +3171,11 @@ var GanttChart = class {
3030
3171
  _onTaskMoveFinal: async (payload) => {
3031
3172
  const task = this.#findTask(payload.id);
3032
3173
  if (task !== void 0) {
3174
+ const newEndDate = task.kind !== "milestone" ? parseDate(task.endDate) : payload.startDate;
3033
3175
  const result = this.#callbacks.onTaskMove?.({
3034
3176
  task,
3035
3177
  newStartDate: payload.startDate,
3178
+ newEndDate,
3036
3179
  instance: this
3037
3180
  });
3038
3181
  if (result instanceof Promise) {
@@ -3054,25 +3197,30 @@ var GanttChart = class {
3054
3197
  const task = this.#input?.tasks.find((t) => t.id === payload.id);
3055
3198
  if (task !== void 0) this.#dragOriginals.set(payload.id, task);
3056
3199
  }
3057
- this.#patchTask(payload.id, { durationHours: payload.durationHours });
3200
+ this.#patchTask(payload.id, { endDate: payload.endDate });
3058
3201
  this.#scheduleRender();
3059
3202
  },
3060
3203
  _onTaskResizeFinal: async (payload) => {
3061
3204
  const task = this.#findTask(payload.id);
3062
- if (task !== void 0) {
3205
+ if (task !== void 0 && task.kind !== "milestone") {
3206
+ const newStartDate = parseDate(task.startDate);
3207
+ const newEndDate = parseDate(task.endDate);
3208
+ const newDurationHours = diffHours(newEndDate, newStartDate);
3063
3209
  const result = this.#callbacks.onTaskResize?.({
3064
3210
  task,
3065
- newDurationHours: payload.durationHours,
3211
+ newDurationHours,
3212
+ newStartDate,
3213
+ newEndDate,
3066
3214
  instance: this
3067
3215
  });
3068
3216
  if (result instanceof Promise) {
3069
3217
  if (!await result) {
3070
3218
  const original = this.#dragOriginals.get(payload.id);
3071
- if (original !== void 0 && original.kind !== "milestone") this.#patchTask(payload.id, { durationHours: original.durationHours });
3219
+ if (original !== void 0 && original.kind !== "milestone") this.#patchTask(payload.id, { endDate: original.endDate });
3072
3220
  }
3073
3221
  } else if (!result) {
3074
3222
  const original = this.#dragOriginals.get(payload.id);
3075
- if (original !== void 0 && original.kind !== "milestone") this.#patchTask(payload.id, { durationHours: original.durationHours });
3223
+ if (original !== void 0 && original.kind !== "milestone") this.#patchTask(payload.id, { endDate: original.endDate });
3076
3224
  }
3077
3225
  }
3078
3226
  this.#dragOriginals.clear();
@@ -3229,9 +3377,10 @@ var GanttChart = class {
3229
3377
  if (opts.weekendDays !== void 0) this.#weekendDays = normalizeWeekendDays(opts.weekendDays);
3230
3378
  if (opts.specialDays !== void 0) this.#specialDaysByDate = buildSpecialDayIndex(opts.specialDays);
3231
3379
  if (opts.theme !== void 0) this.#applyTheme();
3380
+ if (opts.showAddTaskButton !== void 0) this.#showAddTaskButton = opts.showAddTaskButton;
3232
3381
  const hasLayoutChange = opts.leftPaneWidth !== void 0 || opts.responsiveSplitPane !== void 0 || opts.mobileBreakpoint !== void 0 || opts.mobileLeftPaneMinWidth !== void 0 || opts.mobileLeftPaneMaxRatio !== void 0 || opts.timelineMinWidth !== void 0;
3233
3382
  if (hasLayoutChange) this.#applyResponsivePaneStyles();
3234
- const hasLeftPaneChange = columnsChanged || opts.locale !== void 0;
3383
+ const hasLeftPaneChange = columnsChanged || opts.locale !== void 0 || opts.showAddTaskButton !== void 0;
3235
3384
  const hasRightPaneChange = opts.scale !== void 0 || opts.showWeekends !== void 0 || opts.weekendDays !== void 0 || opts.specialDays !== void 0 || opts.highlightLinkedDependenciesOnSelect !== void 0 || opts.linkCreationEnabled !== void 0 || opts.progressDragEnabled !== void 0 || opts.viewportStart !== void 0 || opts.viewportEnd !== void 0 || opts.locale !== void 0 || opts.timelineMinWidth !== void 0;
3236
3385
  if (!(hasLeftPaneChange || hasRightPaneChange || hasLayoutChange)) return;
3237
3386
  if (this.#rafPending && this.#rafId !== null) {
@@ -3438,7 +3587,7 @@ var GanttChart = class {
3438
3587
  },
3439
3588
  onTaskDoubleClick: (payload) => this.#cbs.onTaskDoubleClick?.(payload),
3440
3589
  onTaskAdd: (id) => this.#cbs.onTaskAdd?.(id)
3441
- }, this.#columns);
3590
+ }, this.#columns, this.#showAddTaskButton);
3442
3591
  }
3443
3592
  #renderTimeline = () => {
3444
3593
  this.#rafPending = false;
@@ -3582,6 +3731,6 @@ var GanttChart = class {
3582
3731
  }
3583
3732
  };
3584
3733
  //#endregion
3585
- export { BAR_HEIGHT, BAR_Y_OFFSET, CHART_LOCALE_EN_US, DEFAULT_GRID_COLUMNS, DENSITY, EN_US_LABELS, GRID_COLUMN_FR_MIN_WIDTH, GanttChart, GanttError, GanttInputSchema, LinkSchema, LinkTypeSchema, MILESTONE_HALF, MILESTONE_SIZE, ROW_HEIGHT, SCALE_CONFIGS, SpecialDayKindSchema, SpecialDaySchema, TaskKindSchema, TaskSchema, addDays, addHours, buildTaskTree, computeLayout, createPixelMapper, deriveViewport, deriveWeekNumbering, deriveWeekStartsOn, deriveWeekendDays, detectCycles, diffDays, diffHours, flattenTree, formatLabel, formatWeekNumber, gridColumnDefaults, gridNaturalWidth, gridTemplateColumns, isParent, parseDate, parseGanttInput, resolveChartLocale, routeLinks, validateLinkRefs, visibleColumns };
3734
+ export { BAR_HEIGHT, BAR_Y_OFFSET, CHART_LOCALE_DE_DE, CHART_LOCALE_EN_GB, CHART_LOCALE_EN_US, CHART_LOCALE_ES_ES, CHART_LOCALE_FR_FR, CHART_LOCALE_IT_IT, CHART_LOCALE_JA_JP, CHART_LOCALE_PT_PT, CHART_LOCALE_ZH_CN, DEFAULT_GRID_COLUMNS, DENSITY, EN_US_LABELS, GRID_COLUMN_FR_MIN_WIDTH, GanttChart, GanttError, GanttInputSchema, LinkSchema, LinkTypeSchema, MILESTONE_HALF, MILESTONE_SIZE, ROW_HEIGHT, SCALE_CONFIGS, SpecialDayKindSchema, SpecialDaySchema, TaskKindSchema, TaskSchema, addDays, addHours, buildTaskTree, computeLayout, createPixelMapper, deriveViewport, deriveWeekNumbering, deriveWeekStartsOn, deriveWeekendDays, detectCycles, diffDays, diffHours, flattenTree, formatLabel, formatWeekNumber, gridColumnDefaults, gridNaturalWidth, gridTemplateColumns, isParent, parseDate, parseGanttInput, resolveChartLocale, routeLinks, validateLinkRefs, visibleColumns };
3586
3735
 
3587
3736
  //# sourceMappingURL=index.mjs.map