gantt-lib 0.74.0 → 0.75.1

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
@@ -492,7 +492,7 @@ var init_dateUtils = __esm({
492
492
 
493
493
  // src/components/GanttChart/GanttChart.tsx
494
494
  init_dateUtils();
495
- import { useMemo as useMemo9, useCallback as useCallback6, useRef as useRef7, useState as useState7, useEffect as useEffect7, useImperativeHandle, forwardRef } from "react";
495
+ import { useMemo as useMemo10, useCallback as useCallback8, useRef as useRef9, useState as useState8, useEffect as useEffect9, useImperativeHandle, forwardRef } from "react";
496
496
 
497
497
  // src/core/scheduling/index.ts
498
498
  init_dateMath();
@@ -637,13 +637,13 @@ function computeParentProgress(parentId, tasks) {
637
637
  if (children.length === 0) {
638
638
  return 0;
639
639
  }
640
- const DAY_MS3 = 24 * 60 * 60 * 1e3;
640
+ const DAY_MS4 = 24 * 60 * 60 * 1e3;
641
641
  let totalWeight = 0;
642
642
  let weightedSum = 0;
643
643
  for (const child of children) {
644
644
  const start = new Date(child.startDate).getTime();
645
645
  const end = new Date(child.endDate).getTime();
646
- const duration = (end - start + DAY_MS3) / DAY_MS3;
646
+ const duration = (end - start + DAY_MS4) / DAY_MS4;
647
647
  const progress = child.progress ?? 0;
648
648
  totalWeight += duration;
649
649
  weightedSum += duration * progress;
@@ -738,10 +738,10 @@ function buildTaskRangeFromStart(startDate, duration, businessDays = false, week
738
738
  end: parseDateOnly(addBusinessDays(normalizedStart, duration, weekendPredicate))
739
739
  };
740
740
  }
741
- const DAY_MS3 = 24 * 60 * 60 * 1e3;
741
+ const DAY_MS4 = 24 * 60 * 60 * 1e3;
742
742
  return {
743
743
  start: normalizedStart,
744
- end: new Date(normalizedStart.getTime() + (Math.max(1, duration) - 1) * DAY_MS3)
744
+ end: new Date(normalizedStart.getTime() + (Math.max(1, duration) - 1) * DAY_MS4)
745
745
  };
746
746
  }
747
747
  function buildTaskRangeFromEnd(endDate, duration, businessDays = false, weekendPredicate, snapDirection = -1) {
@@ -752,9 +752,9 @@ function buildTaskRangeFromEnd(endDate, duration, businessDays = false, weekendP
752
752
  end: normalizedEnd
753
753
  };
754
754
  }
755
- const DAY_MS3 = 24 * 60 * 60 * 1e3;
755
+ const DAY_MS4 = 24 * 60 * 60 * 1e3;
756
756
  return {
757
- start: new Date(normalizedEnd.getTime() - (Math.max(1, duration) - 1) * DAY_MS3),
757
+ start: new Date(normalizedEnd.getTime() - (Math.max(1, duration) - 1) * DAY_MS4),
758
758
  end: normalizedEnd
759
759
  };
760
760
  }
@@ -4088,21 +4088,56 @@ var LINK_TYPE_LABELS = {
4088
4088
  SF: "\u041D\u0430\u0447\u0430\u043B\u043E-\u043E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u0435"
4089
4089
  };
4090
4090
 
4091
+ // src/components/TaskList/defaultTaskDates.ts
4092
+ init_dateUtils();
4093
+ var DAY_MS2 = 24 * 60 * 60 * 1e3;
4094
+ var DEFAULT_TASK_DURATION_DAYS = 5;
4095
+ function toISODate(date) {
4096
+ return date.toISOString().split("T")[0];
4097
+ }
4098
+ function getTodayISODate() {
4099
+ const now = /* @__PURE__ */ new Date();
4100
+ return toISODate(new Date(Date.UTC(
4101
+ now.getUTCFullYear(),
4102
+ now.getUTCMonth(),
4103
+ now.getUTCDate()
4104
+ )));
4105
+ }
4106
+ function buildDefaultTaskDateRange(startDate, {
4107
+ businessDays,
4108
+ defaultTaskDurationDays = DEFAULT_TASK_DURATION_DAYS,
4109
+ weekendPredicate
4110
+ } = {}) {
4111
+ const durationDays = Math.max(1, Math.round(defaultTaskDurationDays));
4112
+ const start = parseUTCDate(startDate);
4113
+ if (businessDays && weekendPredicate) {
4114
+ const range = buildTaskRangeFromStart(start, durationDays, true, weekendPredicate);
4115
+ return {
4116
+ startDate: toISODate(range.start),
4117
+ endDate: toISODate(range.end)
4118
+ };
4119
+ }
4120
+ return {
4121
+ startDate: toISODate(start),
4122
+ endDate: toISODate(new Date(start.getTime() + (durationDays - 1) * DAY_MS2))
4123
+ };
4124
+ }
4125
+
4091
4126
  // src/components/TaskList/TaskListRow.tsx
4092
4127
  import { Fragment as Fragment2, jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
4093
- var DAY_MS2 = 24 * 60 * 60 * 1e3;
4128
+ var DAY_MS3 = 24 * 60 * 60 * 1e3;
4094
4129
  var LINK_TYPE_ORDER = ["FS", "SS", "FF", "SF"];
4095
4130
  var getInclusiveDurationDays = (startDate, endDate) => {
4096
4131
  const start = parseUTCDate(startDate);
4097
4132
  const end = parseUTCDate(endDate);
4098
4133
  return Math.max(
4099
4134
  1,
4100
- Math.round((end.getTime() - start.getTime()) / DAY_MS2) + 1
4135
+ Math.round((end.getTime() - start.getTime()) / DAY_MS3) + 1
4101
4136
  );
4102
4137
  };
4103
4138
  var getEndDateFromDuration = (startDate, durationDays) => {
4104
4139
  const start = parseUTCDate(startDate);
4105
- return new Date(start.getTime() + (durationDays - 1) * DAY_MS2).toISOString().split("T")[0];
4140
+ return new Date(start.getTime() + (durationDays - 1) * DAY_MS3).toISOString().split("T")[0];
4106
4141
  };
4107
4142
  var TrashIcon = () => /* @__PURE__ */ jsxs9(
4108
4143
  "svg",
@@ -4587,7 +4622,7 @@ var DepChip = ({
4587
4622
  )
4588
4623
  ] });
4589
4624
  };
4590
- var toISODate = (value) => {
4625
+ var toISODate2 = (value) => {
4591
4626
  if (value instanceof Date) return value.toISOString().split("T")[0];
4592
4627
  if (typeof value === "string" && value.includes("T"))
4593
4628
  return value.split("T")[0];
@@ -4641,6 +4676,7 @@ var TaskListRow = React9.memo(
4641
4676
  customDays,
4642
4677
  isWeekend: isWeekend3,
4643
4678
  businessDays,
4679
+ defaultTaskDurationDays = DEFAULT_TASK_DURATION_DAYS,
4644
4680
  isFilterMatch = false,
4645
4681
  isFilterHideMode = false,
4646
4682
  resolvedColumns,
@@ -5448,8 +5484,8 @@ var TaskListRow = React9.memo(
5448
5484
  },
5449
5485
  [selectedChip?.successorId, selectedChip?.predecessorId, selectedChip?.linkType, onRemoveDependency, onChipSelect]
5450
5486
  );
5451
- const startDateISO = toISODate(normalizedTask.startDate);
5452
- const endDateISO = editingDuration ? getEndDate(normalizedTask.startDate, durationValue) : toISODate(normalizedTask.endDate);
5487
+ const startDateISO = toISODate2(normalizedTask.startDate);
5488
+ const endDateISO = editingDuration ? getEndDate(normalizedTask.startDate, durationValue) : toISODate2(normalizedTask.endDate);
5453
5489
  const numberCell = /* @__PURE__ */ jsxs9(
5454
5490
  "div",
5455
5491
  {
@@ -5667,26 +5703,16 @@ var TaskListRow = React9.memo(
5667
5703
  className: "gantt-tl-name-action-btn gantt-tl-action-insert",
5668
5704
  onClick: (e) => {
5669
5705
  e.stopPropagation();
5670
- const now = /* @__PURE__ */ new Date();
5671
- const todayISO = new Date(
5672
- Date.UTC(
5673
- now.getUTCFullYear(),
5674
- now.getUTCMonth(),
5675
- now.getUTCDate()
5676
- )
5677
- ).toISOString().split("T")[0];
5678
- const endISO = new Date(
5679
- Date.UTC(
5680
- now.getUTCFullYear(),
5681
- now.getUTCMonth(),
5682
- now.getUTCDate() + 7
5683
- )
5684
- ).toISOString().split("T")[0];
5706
+ const range = buildDefaultTaskDateRange(getTodayISODate(), {
5707
+ businessDays,
5708
+ defaultTaskDurationDays,
5709
+ weekendPredicate
5710
+ });
5685
5711
  const newTask = {
5686
5712
  id: crypto.randomUUID(),
5687
5713
  name: "\u041D\u043E\u0432\u0430\u044F \u0437\u0430\u0434\u0430\u0447\u0430",
5688
- startDate: todayISO,
5689
- endDate: endISO,
5714
+ startDate: range.startDate,
5715
+ endDate: range.endDate,
5690
5716
  parentId: task.parentId
5691
5717
  };
5692
5718
  onInsertAfter(task.id, newTask);
@@ -6515,6 +6541,7 @@ var TaskList = ({
6515
6541
  onReorder,
6516
6542
  editingTaskId: propEditingTaskId,
6517
6543
  enableAddTask = true,
6544
+ defaultTaskDurationDays = DEFAULT_TASK_DURATION_DAYS,
6518
6545
  collapsedParentIds: externalCollapsedParentIds,
6519
6546
  onToggleCollapse: externalOnToggleCollapse,
6520
6547
  onPromoteTask,
@@ -6917,26 +6944,20 @@ var TaskList = ({
6917
6944
  dragTaskIdRef.current = null;
6918
6945
  }, []);
6919
6946
  const handleConfirmNewTask = useCallback5((name) => {
6920
- const now = /* @__PURE__ */ new Date();
6921
- const todayISO = new Date(Date.UTC(
6922
- now.getUTCFullYear(),
6923
- now.getUTCMonth(),
6924
- now.getUTCDate()
6925
- )).toISOString().split("T")[0];
6926
- const endISO = new Date(Date.UTC(
6927
- now.getUTCFullYear(),
6928
- now.getUTCMonth(),
6929
- now.getUTCDate() + 7
6930
- )).toISOString().split("T")[0];
6947
+ const range = buildDefaultTaskDateRange(getTodayISODate(), {
6948
+ businessDays,
6949
+ defaultTaskDurationDays,
6950
+ weekendPredicate
6951
+ });
6931
6952
  const newTask = {
6932
6953
  id: crypto.randomUUID(),
6933
6954
  name,
6934
- startDate: todayISO,
6935
- endDate: endISO
6955
+ startDate: range.startDate,
6956
+ endDate: range.endDate
6936
6957
  };
6937
6958
  onAdd?.(newTask);
6938
6959
  setIsCreating(false);
6939
- }, [onAdd]);
6960
+ }, [businessDays, defaultTaskDurationDays, onAdd, weekendPredicate]);
6940
6961
  const handleCancelNewTask = useCallback5(() => setIsCreating(false), []);
6941
6962
  const findInsertAfterTaskId = useCallback5((anchorTaskId) => {
6942
6963
  const anchorIndex = orderedTasks.findIndex((task) => task.id === anchorTaskId);
@@ -7202,6 +7223,7 @@ var TaskList = ({
7202
7223
  customDays,
7203
7224
  isWeekend: isWeekend3,
7204
7225
  businessDays,
7226
+ defaultTaskDurationDays,
7205
7227
  isFilterMatch: filterMode === "highlight" ? highlightedTaskIds.has(task.id) : false,
7206
7228
  isFilterHideMode: filterMode === "hide" && isFilterActive,
7207
7229
  resolvedColumns,
@@ -7262,6 +7284,522 @@ var TaskList = ({
7262
7284
  );
7263
7285
  };
7264
7286
 
7287
+ // src/components/ResourceTimelineChart/ResourceTimelineChart.tsx
7288
+ init_dateUtils();
7289
+ import { useCallback as useCallback7, useEffect as useEffect8, useMemo as useMemo9, useRef as useRef8 } from "react";
7290
+
7291
+ // src/utils/resourceTimelineLayout.ts
7292
+ init_dateUtils();
7293
+ var isInvalidDate = (date) => Number.isNaN(date.getTime());
7294
+ var getUTCDayNumber = (date) => {
7295
+ return Math.floor(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()) / 864e5);
7296
+ };
7297
+ var compareParsedItems = (a, b) => {
7298
+ const startDiff = getUTCDayNumber(a.startDate) - getUTCDayNumber(b.startDate);
7299
+ if (startDiff !== 0) {
7300
+ return startDiff;
7301
+ }
7302
+ const endDiff = getUTCDayNumber(a.endDate) - getUTCDayNumber(b.endDate);
7303
+ if (endDiff !== 0) {
7304
+ return endDiff;
7305
+ }
7306
+ return a.item.id.localeCompare(b.item.id);
7307
+ };
7308
+ var layoutResourceTimelineItems = (resources, options) => {
7309
+ const rows = [];
7310
+ const items = [];
7311
+ const diagnostics = [];
7312
+ let currentTop = 0;
7313
+ for (const resource of resources) {
7314
+ const parsedItems = [];
7315
+ for (const item of resource.items) {
7316
+ try {
7317
+ const startDate = parseUTCDate(item.startDate);
7318
+ const endDate = parseUTCDate(item.endDate);
7319
+ if (isInvalidDate(startDate) || isInvalidDate(endDate)) {
7320
+ throw new Error("Invalid date");
7321
+ }
7322
+ parsedItems.push({ item, startDate, endDate });
7323
+ } catch {
7324
+ diagnostics.push({
7325
+ itemId: item.id,
7326
+ resourceId: resource.id,
7327
+ reason: "invalid-date"
7328
+ });
7329
+ }
7330
+ }
7331
+ parsedItems.sort(compareParsedItems);
7332
+ const laneEndDays = [];
7333
+ const laidOutItems = [];
7334
+ for (const parsed of parsedItems) {
7335
+ const startDay = getUTCDayNumber(parsed.startDate);
7336
+ const endDay = getUTCDayNumber(parsed.endDate);
7337
+ let laneIndex = laneEndDays.findIndex((laneEndDay) => laneEndDay < startDay);
7338
+ if (laneIndex === -1) {
7339
+ laneIndex = laneEndDays.length;
7340
+ laneEndDays.push(endDay);
7341
+ } else {
7342
+ laneEndDays[laneIndex] = endDay;
7343
+ }
7344
+ const { left, width } = calculateTaskBar(parsed.startDate, parsed.endDate, options.monthStart, options.dayWidth);
7345
+ laidOutItems.push({
7346
+ item: parsed.item,
7347
+ itemId: parsed.item.id,
7348
+ resourceId: resource.id,
7349
+ laneIndex,
7350
+ left,
7351
+ width,
7352
+ resourceRowTop: currentTop,
7353
+ resourceRowHeight: 0,
7354
+ top: currentTop + laneIndex * options.laneHeight,
7355
+ height: options.laneHeight,
7356
+ startDate: parsed.startDate,
7357
+ endDate: parsed.endDate
7358
+ });
7359
+ }
7360
+ const laneCount = Math.max(1, laneEndDays.length);
7361
+ const resourceRowHeight = laneCount * options.laneHeight;
7362
+ const row = {
7363
+ resource,
7364
+ resourceId: resource.id,
7365
+ laneCount,
7366
+ resourceRowTop: currentTop,
7367
+ resourceRowHeight
7368
+ };
7369
+ rows.push(row);
7370
+ items.push(...laidOutItems.map((item) => ({
7371
+ ...item,
7372
+ resourceRowHeight
7373
+ })));
7374
+ currentTop += resourceRowHeight;
7375
+ }
7376
+ return {
7377
+ rows,
7378
+ items,
7379
+ diagnostics,
7380
+ totalHeight: currentTop
7381
+ };
7382
+ };
7383
+
7384
+ // src/hooks/useResourceItemDrag.ts
7385
+ import { useCallback as useCallback6, useEffect as useEffect7, useRef as useRef7, useState as useState7 } from "react";
7386
+ var snapToDay = (pixels, dayWidth) => {
7387
+ return Math.round(pixels / dayWidth) * dayWidth;
7388
+ };
7389
+ var addUTCDays = (date, days) => {
7390
+ return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate() + days));
7391
+ };
7392
+ var resolveTargetResource = (rows, clientY, gridTop) => {
7393
+ const localY = clientY - gridTop;
7394
+ return rows.find(
7395
+ (row) => localY >= row.resourceRowTop && localY < row.resourceRowTop + row.resourceRowHeight
7396
+ )?.resource ?? null;
7397
+ };
7398
+ var useResourceItemDrag = ({
7399
+ dayWidth,
7400
+ rows,
7401
+ gridElementRef,
7402
+ readonly,
7403
+ disableResourceReassignment,
7404
+ onResourceItemMove
7405
+ }) => {
7406
+ const activeDragRef = useRef7(null);
7407
+ const rowsRef = useRef7(rows);
7408
+ const onResourceItemMoveRef = useRef7(onResourceItemMove);
7409
+ const rafRef = useRef7(null);
7410
+ const [preview, setPreview] = useState7(null);
7411
+ useEffect7(() => {
7412
+ rowsRef.current = rows;
7413
+ }, [rows]);
7414
+ useEffect7(() => {
7415
+ onResourceItemMoveRef.current = onResourceItemMove;
7416
+ }, [onResourceItemMove]);
7417
+ const clearRaf = useCallback6(() => {
7418
+ if (rafRef.current !== null) {
7419
+ cancelAnimationFrame(rafRef.current);
7420
+ rafRef.current = null;
7421
+ }
7422
+ }, []);
7423
+ const cancelDrag2 = useCallback6(() => {
7424
+ clearRaf();
7425
+ activeDragRef.current = null;
7426
+ setPreview(null);
7427
+ }, [clearRaf]);
7428
+ useEffect7(() => {
7429
+ const handleMouseMove = (event) => {
7430
+ const activeDrag = activeDragRef.current;
7431
+ if (!activeDrag || rafRef.current !== null) {
7432
+ return;
7433
+ }
7434
+ rafRef.current = requestAnimationFrame(() => {
7435
+ rafRef.current = null;
7436
+ const latestDrag = activeDragRef.current;
7437
+ if (!latestDrag) {
7438
+ return;
7439
+ }
7440
+ const nextLeft = latestDrag.initialLeft + snapToDay(event.clientX - latestDrag.startX, latestDrag.dayWidth);
7441
+ const nextTop = disableResourceReassignment ? latestDrag.initialTop : latestDrag.initialTop + (event.clientY - latestDrag.startY);
7442
+ latestDrag.currentLeft = nextLeft;
7443
+ latestDrag.currentTop = nextTop;
7444
+ setPreview({
7445
+ itemId: latestDrag.itemId,
7446
+ left: nextLeft,
7447
+ top: nextTop
7448
+ });
7449
+ });
7450
+ };
7451
+ const handleMouseUp = (event) => {
7452
+ const activeDrag = activeDragRef.current;
7453
+ if (!activeDrag) {
7454
+ return;
7455
+ }
7456
+ clearRaf();
7457
+ activeDragRef.current = null;
7458
+ setPreview(null);
7459
+ const gridTop = gridElementRef?.current?.getBoundingClientRect().top ?? 0;
7460
+ const targetResource = disableResourceReassignment ? rowsRef.current.find((row) => row.resourceId === activeDrag.fromResourceId)?.resource ?? null : resolveTargetResource(rowsRef.current, event.clientY, gridTop);
7461
+ if (!targetResource) {
7462
+ return;
7463
+ }
7464
+ const dayDelta = Math.round((activeDrag.currentLeft - activeDrag.initialLeft) / activeDrag.dayWidth);
7465
+ onResourceItemMoveRef.current?.({
7466
+ item: activeDrag.item,
7467
+ itemId: activeDrag.itemId,
7468
+ fromResourceId: activeDrag.fromResourceId,
7469
+ toResourceId: targetResource.id,
7470
+ startDate: addUTCDays(activeDrag.startDate, dayDelta),
7471
+ endDate: addUTCDays(activeDrag.endDate, dayDelta)
7472
+ });
7473
+ };
7474
+ window.addEventListener("mousemove", handleMouseMove);
7475
+ window.addEventListener("mouseup", handleMouseUp);
7476
+ return () => {
7477
+ window.removeEventListener("mousemove", handleMouseMove);
7478
+ window.removeEventListener("mouseup", handleMouseUp);
7479
+ cancelDrag2();
7480
+ };
7481
+ }, [cancelDrag2, clearRaf, disableResourceReassignment, gridElementRef]);
7482
+ const startDrag = useCallback6((event, layoutItem) => {
7483
+ if (readonly || layoutItem.item.locked || event.button !== 0) {
7484
+ return;
7485
+ }
7486
+ event.preventDefault();
7487
+ activeDragRef.current = {
7488
+ item: layoutItem.item,
7489
+ itemId: layoutItem.itemId,
7490
+ fromResourceId: layoutItem.resourceId,
7491
+ startX: event.clientX,
7492
+ startY: event.clientY,
7493
+ initialLeft: layoutItem.left,
7494
+ initialTop: layoutItem.top,
7495
+ currentLeft: layoutItem.left,
7496
+ currentTop: layoutItem.top,
7497
+ dayWidth,
7498
+ startDate: layoutItem.startDate,
7499
+ endDate: layoutItem.endDate
7500
+ };
7501
+ setPreview({
7502
+ itemId: layoutItem.itemId,
7503
+ left: layoutItem.left,
7504
+ top: layoutItem.top
7505
+ });
7506
+ }, [dayWidth, readonly]);
7507
+ return {
7508
+ preview,
7509
+ startDrag,
7510
+ cancelDrag: cancelDrag2
7511
+ };
7512
+ };
7513
+
7514
+ // src/components/ResourceTimelineChart/ResourceTimelineChart.tsx
7515
+ import { Fragment as Fragment3, jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
7516
+ var DEFAULT_DAY_WIDTH = 40;
7517
+ var DEFAULT_HEADER_HEIGHT = 40;
7518
+ var DEFAULT_LANE_HEIGHT = 40;
7519
+ var DEFAULT_ROW_HEADER_WIDTH = 240;
7520
+ var ITEM_OUTER_VERTICAL_INSET = 2;
7521
+ var ITEM_INNER_VERTICAL_INSET = 1;
7522
+ var ITEM_HORIZONTAL_INSET = 1;
7523
+ var isValidDate = (date) => !Number.isNaN(date.getTime());
7524
+ var getResourceTimelineDays = (items) => {
7525
+ if (items.length === 0) {
7526
+ return getMonthDays(/* @__PURE__ */ new Date());
7527
+ }
7528
+ let minDate = null;
7529
+ let maxDate = null;
7530
+ for (const item of items) {
7531
+ const startDate = parseUTCDate(item.startDate);
7532
+ const endDate = parseUTCDate(item.endDate);
7533
+ if (!minDate || startDate.getTime() < minDate.getTime()) {
7534
+ minDate = startDate;
7535
+ }
7536
+ if (!maxDate || endDate.getTime() > maxDate.getTime()) {
7537
+ maxDate = endDate;
7538
+ }
7539
+ }
7540
+ if (!minDate || !maxDate) {
7541
+ return getMonthDays(/* @__PURE__ */ new Date());
7542
+ }
7543
+ const startOfMonth2 = new Date(Date.UTC(minDate.getUTCFullYear(), minDate.getUTCMonth(), 1));
7544
+ const endOfMonth = new Date(Date.UTC(maxDate.getUTCFullYear(), maxDate.getUTCMonth() + 1, 0));
7545
+ const days = [];
7546
+ const current = new Date(startOfMonth2);
7547
+ while (current.getTime() <= endOfMonth.getTime()) {
7548
+ days.push(new Date(Date.UTC(current.getUTCFullYear(), current.getUTCMonth(), current.getUTCDate())));
7549
+ current.setUTCDate(current.getUTCDate() + 1);
7550
+ }
7551
+ return days;
7552
+ };
7553
+ var collectValidItems = (resources) => {
7554
+ return resources.flatMap(
7555
+ (resource) => resource.items.flatMap((item) => {
7556
+ try {
7557
+ const startDate = parseUTCDate(item.startDate);
7558
+ const endDate = parseUTCDate(item.endDate);
7559
+ if (!isValidDate(startDate) || !isValidDate(endDate)) {
7560
+ return [];
7561
+ }
7562
+ return [{ startDate, endDate }];
7563
+ } catch {
7564
+ return [];
7565
+ }
7566
+ })
7567
+ );
7568
+ };
7569
+ var getVisualItemGeometry = (geometry, laneIndex, laneCount) => {
7570
+ const topInset = laneIndex === 0 ? ITEM_OUTER_VERTICAL_INSET : ITEM_INNER_VERTICAL_INSET;
7571
+ const bottomInset = laneIndex === laneCount - 1 ? ITEM_OUTER_VERTICAL_INSET : ITEM_INNER_VERTICAL_INSET;
7572
+ return {
7573
+ left: geometry.left + ITEM_HORIZONTAL_INSET,
7574
+ top: geometry.top + topInset,
7575
+ width: Math.max(0, geometry.width - ITEM_HORIZONTAL_INSET * 2),
7576
+ height: Math.max(0, geometry.height - topInset - bottomInset)
7577
+ };
7578
+ };
7579
+ function ResourceTimelineChart({
7580
+ resources,
7581
+ dayWidth = DEFAULT_DAY_WIDTH,
7582
+ rowHeaderWidth = DEFAULT_ROW_HEADER_WIDTH,
7583
+ laneHeight = DEFAULT_LANE_HEIGHT,
7584
+ headerHeight = DEFAULT_HEADER_HEIGHT,
7585
+ readonly,
7586
+ disableResourceReassignment,
7587
+ renderItem,
7588
+ getItemClassName,
7589
+ onResourceItemMove
7590
+ }) {
7591
+ const scrollContainerRef = useRef8(null);
7592
+ const gridRef = useRef8(null);
7593
+ const panStateRef = useRef8(null);
7594
+ const validItems = useMemo9(() => collectValidItems(resources), [resources]);
7595
+ const dateRange = useMemo9(() => {
7596
+ return getResourceTimelineDays(validItems);
7597
+ }, [validItems]);
7598
+ const monthStart = useMemo9(() => {
7599
+ const firstDay = dateRange[0] ?? /* @__PURE__ */ new Date();
7600
+ return new Date(Date.UTC(firstDay.getUTCFullYear(), firstDay.getUTCMonth(), 1));
7601
+ }, [dateRange]);
7602
+ const gridWidth = useMemo9(() => Math.round(dateRange.length * dayWidth), [dateRange.length, dayWidth]);
7603
+ const layout = useMemo9(
7604
+ () => layoutResourceTimelineItems(resources, { monthStart, dayWidth, laneHeight }),
7605
+ [resources, monthStart, dayWidth, laneHeight]
7606
+ );
7607
+ const todayInRange = useMemo9(() => {
7608
+ const now = /* @__PURE__ */ new Date();
7609
+ const today = new Date(Date.UTC(now.getFullYear(), now.getMonth(), now.getDate()));
7610
+ return dateRange.some((day) => day.getTime() === today.getTime());
7611
+ }, [dateRange]);
7612
+ const itemsByResourceId = useMemo9(() => {
7613
+ const map = /* @__PURE__ */ new Map();
7614
+ for (const item of layout.items) {
7615
+ const next = map.get(item.resourceId) ?? [];
7616
+ next.push(item);
7617
+ map.set(item.resourceId, next);
7618
+ }
7619
+ return map;
7620
+ }, [layout.items]);
7621
+ const { preview, startDrag } = useResourceItemDrag({
7622
+ dayWidth,
7623
+ rows: layout.rows,
7624
+ gridElementRef: gridRef,
7625
+ readonly,
7626
+ disableResourceReassignment,
7627
+ onResourceItemMove
7628
+ });
7629
+ const handlePanStart = useCallback7((event) => {
7630
+ if (event.button !== 0) {
7631
+ return;
7632
+ }
7633
+ const target = event.target;
7634
+ if (target.closest("[data-resource-item-id]")) {
7635
+ return;
7636
+ }
7637
+ if (target.closest("input, button, textarea, [contenteditable]")) {
7638
+ return;
7639
+ }
7640
+ const container = scrollContainerRef.current;
7641
+ if (!container) {
7642
+ return;
7643
+ }
7644
+ panStateRef.current = {
7645
+ active: true,
7646
+ startX: event.clientX,
7647
+ startY: event.clientY,
7648
+ scrollX: container.scrollLeft,
7649
+ scrollY: container.scrollTop
7650
+ };
7651
+ if (document.activeElement instanceof HTMLElement) {
7652
+ document.activeElement.blur();
7653
+ }
7654
+ container.style.cursor = "grabbing";
7655
+ event.preventDefault();
7656
+ }, []);
7657
+ useEffect8(() => {
7658
+ const handlePanMove = (event) => {
7659
+ const pan = panStateRef.current;
7660
+ const container = scrollContainerRef.current;
7661
+ if (!pan?.active || !container) {
7662
+ return;
7663
+ }
7664
+ container.scrollLeft = pan.scrollX - (event.clientX - pan.startX);
7665
+ container.scrollTop = pan.scrollY - (event.clientY - pan.startY);
7666
+ };
7667
+ const handlePanEnd = () => {
7668
+ if (!panStateRef.current?.active) {
7669
+ return;
7670
+ }
7671
+ panStateRef.current = null;
7672
+ const container = scrollContainerRef.current;
7673
+ if (container) {
7674
+ container.style.cursor = "";
7675
+ }
7676
+ };
7677
+ window.addEventListener("mousemove", handlePanMove);
7678
+ window.addEventListener("mouseup", handlePanEnd);
7679
+ return () => {
7680
+ window.removeEventListener("mousemove", handlePanMove);
7681
+ window.removeEventListener("mouseup", handlePanEnd);
7682
+ };
7683
+ }, []);
7684
+ return /* @__PURE__ */ jsx15("div", { className: "gantt-container gantt-resourceTimeline", children: /* @__PURE__ */ jsx15(
7685
+ "div",
7686
+ {
7687
+ ref: scrollContainerRef,
7688
+ className: "gantt-resourceTimeline-scrollContainer",
7689
+ style: { cursor: "grab" },
7690
+ onMouseDown: handlePanStart,
7691
+ children: /* @__PURE__ */ jsxs12("div", { className: "gantt-resourceTimeline-scrollContent", children: [
7692
+ /* @__PURE__ */ jsxs12(
7693
+ "div",
7694
+ {
7695
+ className: "gantt-resourceTimeline-resourceColumn",
7696
+ style: { width: `${rowHeaderWidth}px`, minWidth: `${rowHeaderWidth}px` },
7697
+ children: [
7698
+ /* @__PURE__ */ jsx15(
7699
+ "div",
7700
+ {
7701
+ className: "gantt-resourceTimeline-corner",
7702
+ style: { height: `${headerHeight}px` }
7703
+ }
7704
+ ),
7705
+ layout.rows.map((row) => /* @__PURE__ */ jsx15(
7706
+ "div",
7707
+ {
7708
+ className: "gantt-resourceTimeline-resourceHeader",
7709
+ "data-resource-row-id": row.resourceId,
7710
+ style: { height: `${row.resourceRowHeight}px` },
7711
+ children: /* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-resourceName", children: row.resource.name })
7712
+ },
7713
+ row.resourceId
7714
+ ))
7715
+ ]
7716
+ }
7717
+ ),
7718
+ /* @__PURE__ */ jsxs12(
7719
+ "div",
7720
+ {
7721
+ className: "gantt-resourceTimeline-chartSurface",
7722
+ style: { minWidth: `${gridWidth}px` },
7723
+ children: [
7724
+ /* @__PURE__ */ jsx15("div", { className: "gantt-resourceTimeline-stickyHeader", style: { width: `${gridWidth}px` }, children: /* @__PURE__ */ jsx15(TimeScaleHeader_default, { days: dateRange, dayWidth, headerHeight }) }),
7725
+ /* @__PURE__ */ jsxs12(
7726
+ "div",
7727
+ {
7728
+ ref: gridRef,
7729
+ className: "gantt-resourceTimeline-grid",
7730
+ style: { width: `${gridWidth}px`, height: `${layout.totalHeight}px` },
7731
+ children: [
7732
+ /* @__PURE__ */ jsx15(GridBackground_default, { dateRange, dayWidth, totalHeight: layout.totalHeight }),
7733
+ todayInRange && /* @__PURE__ */ jsx15(TodayIndicator_default, { monthStart, dayWidth }),
7734
+ layout.rows.map((row) => /* @__PURE__ */ jsx15(
7735
+ "div",
7736
+ {
7737
+ className: "gantt-resourceTimeline-row",
7738
+ "data-resource-row-id": row.resourceId,
7739
+ style: {
7740
+ top: `${row.resourceRowTop}px`,
7741
+ height: `${row.resourceRowHeight}px`
7742
+ }
7743
+ },
7744
+ row.resourceId
7745
+ )),
7746
+ Array.from(itemsByResourceId.values()).flatMap(
7747
+ (resourceItems) => resourceItems.map((layoutItem) => {
7748
+ const customClassName = getItemClassName?.(layoutItem.item);
7749
+ const className = [
7750
+ "gantt-resourceTimeline-item",
7751
+ preview?.itemId === layoutItem.itemId && "gantt-resourceTimeline-itemDragging",
7752
+ (readonly || layoutItem.item.locked) && "gantt-resourceTimeline-itemDisabled",
7753
+ customClassName
7754
+ ].filter(Boolean).join(" ");
7755
+ const laneCount = Math.max(1, Math.round(layoutItem.resourceRowHeight / layoutItem.height));
7756
+ const previewStyle = preview?.itemId === layoutItem.itemId ? getVisualItemGeometry({
7757
+ left: preview.left,
7758
+ top: preview.top,
7759
+ width: layoutItem.width,
7760
+ height: layoutItem.height
7761
+ }, layoutItem.laneIndex, laneCount) : void 0;
7762
+ const itemGeometry = getVisualItemGeometry({
7763
+ left: layoutItem.left,
7764
+ top: layoutItem.top,
7765
+ width: layoutItem.width,
7766
+ height: layoutItem.height
7767
+ }, layoutItem.laneIndex, laneCount);
7768
+ return /* @__PURE__ */ jsx15(
7769
+ "div",
7770
+ {
7771
+ className,
7772
+ "data-resource-item-id": layoutItem.itemId,
7773
+ onMouseDown: (event) => startDrag(event, layoutItem),
7774
+ style: {
7775
+ left: `${itemGeometry.left}px`,
7776
+ top: `${itemGeometry.top}px`,
7777
+ ...previewStyle,
7778
+ width: `${itemGeometry.width}px`,
7779
+ height: `${itemGeometry.height}px`,
7780
+ backgroundColor: layoutItem.item.color ?? "var(--gantt-task-bar-default-color, #3b82f6)"
7781
+ },
7782
+ children: /* @__PURE__ */ jsx15("div", { className: "gantt-resourceTimeline-itemInner", children: renderItem ? renderItem(layoutItem.item) : /* @__PURE__ */ jsxs12(Fragment3, { children: [
7783
+ /* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-itemTitle", children: layoutItem.item.title }),
7784
+ layoutItem.item.subtitle && /* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-itemSubtitle", children: layoutItem.item.subtitle }),
7785
+ /* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-itemDates", children: formatDateRangeLabel(layoutItem.startDate, layoutItem.endDate) })
7786
+ ] }) })
7787
+ },
7788
+ layoutItem.itemId
7789
+ );
7790
+ })
7791
+ )
7792
+ ]
7793
+ }
7794
+ )
7795
+ ]
7796
+ }
7797
+ )
7798
+ ] })
7799
+ }
7800
+ ) });
7801
+ }
7802
+
7265
7803
  // src/components/GanttChart/print.ts
7266
7804
  function getPrintDocumentTitle({
7267
7805
  header,
@@ -7600,9 +8138,21 @@ async function printGanttChart({
7600
8138
  }
7601
8139
 
7602
8140
  // src/components/GanttChart/GanttChart.tsx
7603
- import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
8141
+ import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
7604
8142
  var SCROLL_TO_ROW_CONTEXT_ROWS = 2;
7605
8143
  function GanttChartInner(props, ref) {
8144
+ if (props.mode === "resource-planner") {
8145
+ return /* @__PURE__ */ jsx16(ResourceTimelineChart, { ...props });
8146
+ }
8147
+ return /* @__PURE__ */ jsx16(
8148
+ TaskGanttChart,
8149
+ {
8150
+ ...props,
8151
+ ref
8152
+ }
8153
+ );
8154
+ }
8155
+ function TaskGanttChartInner(props, ref) {
7606
8156
  const {
7607
8157
  tasks,
7608
8158
  dayWidth = 40,
@@ -7628,6 +8178,7 @@ function GanttChartInner(props, ref) {
7628
8178
  onDemoteTask,
7629
8179
  onUngroupTask,
7630
8180
  enableAddTask = true,
8181
+ defaultTaskDurationDays,
7631
8182
  viewMode = "day",
7632
8183
  customDays,
7633
8184
  isWeekend: isWeekend3,
@@ -7642,28 +8193,28 @@ function GanttChartInner(props, ref) {
7642
8193
  additionalColumns,
7643
8194
  taskListMenuCommands
7644
8195
  } = props;
7645
- const containerRef = useRef7(null);
7646
- const scrollContainerRef = useRef7(null);
7647
- const scrollContentRef = useRef7(null);
7648
- const [selectedTaskId, setSelectedTaskId] = useState7(null);
7649
- const [taskListHasRightShadow, setTaskListHasRightShadow] = useState7(false);
7650
- const [selectedChip, setSelectedChip] = useState7(null);
7651
- const [internalCollapsedParentIds, setInternalCollapsedParentIds] = useState7(/* @__PURE__ */ new Set());
8196
+ const containerRef = useRef9(null);
8197
+ const scrollContainerRef = useRef9(null);
8198
+ const scrollContentRef = useRef9(null);
8199
+ const [selectedTaskId, setSelectedTaskId] = useState8(null);
8200
+ const [taskListHasRightShadow, setTaskListHasRightShadow] = useState8(false);
8201
+ const [selectedChip, setSelectedChip] = useState8(null);
8202
+ const [internalCollapsedParentIds, setInternalCollapsedParentIds] = useState8(/* @__PURE__ */ new Set());
7652
8203
  const collapsedParentIds = externalCollapsedParentIds ?? internalCollapsedParentIds;
7653
- const [editingTaskId, setEditingTaskId] = useState7(null);
7654
- const normalizedTasks = useMemo9(() => normalizeHierarchyTasks(tasks), [tasks]);
7655
- const isCustomWeekend = useMemo9(
8204
+ const [editingTaskId, setEditingTaskId] = useState8(null);
8205
+ const normalizedTasks = useMemo10(() => normalizeHierarchyTasks(tasks), [tasks]);
8206
+ const isCustomWeekend = useMemo10(
7656
8207
  () => createCustomDayPredicate({ customDays, isWeekend: isWeekend3 }),
7657
8208
  [customDays, isWeekend3]
7658
8209
  );
7659
- const dateRange = useMemo9(() => getMultiMonthDays(normalizedTasks), [normalizedTasks]);
7660
- const [validationResult, setValidationResult] = useState7(null);
7661
- const [cascadeOverrides, setCascadeOverrides] = useState7(/* @__PURE__ */ new Map());
7662
- const gridWidth = useMemo9(
8210
+ const dateRange = useMemo10(() => getMultiMonthDays(normalizedTasks), [normalizedTasks]);
8211
+ const [validationResult, setValidationResult] = useState8(null);
8212
+ const [cascadeOverrides, setCascadeOverrides] = useState8(/* @__PURE__ */ new Map());
8213
+ const gridWidth = useMemo10(
7663
8214
  () => Math.round(dateRange.length * dayWidth),
7664
8215
  [dateRange.length, dayWidth]
7665
8216
  );
7666
- const visibleTasks = useMemo9(() => {
8217
+ const visibleTasks = useMemo10(() => {
7667
8218
  const parentMap = new Map(normalizedTasks.map((t) => [t.id, t.parentId]));
7668
8219
  function isAnyAncestorCollapsed(parentId) {
7669
8220
  let current = parentId;
@@ -7679,11 +8230,11 @@ function GanttChartInner(props, ref) {
7679
8230
  }
7680
8231
  return tasks2;
7681
8232
  }, [normalizedTasks, collapsedParentIds, filterMode, taskFilter]);
7682
- const matchedTaskIds = useMemo9(() => {
8233
+ const matchedTaskIds = useMemo10(() => {
7683
8234
  if (!taskFilter) return /* @__PURE__ */ new Set();
7684
8235
  return new Set(visibleTasks.filter(taskFilter).map((task) => task.id));
7685
8236
  }, [visibleTasks, taskFilter]);
7686
- const taskListHighlightedTaskIds = useMemo9(() => {
8237
+ const taskListHighlightedTaskIds = useMemo10(() => {
7687
8238
  if (filterMode === "hide") {
7688
8239
  return /* @__PURE__ */ new Set();
7689
8240
  }
@@ -7694,23 +8245,23 @@ function GanttChartInner(props, ref) {
7694
8245
  matchedTaskIds.forEach((taskId) => mergedHighlightedTaskIds.add(taskId));
7695
8246
  return mergedHighlightedTaskIds;
7696
8247
  }, [filterMode, highlightedTaskIds, matchedTaskIds]);
7697
- const totalGridHeight = useMemo9(
8248
+ const totalGridHeight = useMemo10(
7698
8249
  () => visibleTasks.length * rowHeight,
7699
8250
  [visibleTasks.length, rowHeight]
7700
8251
  );
7701
- const monthStart = useMemo9(() => {
8252
+ const monthStart = useMemo10(() => {
7702
8253
  if (dateRange.length === 0) {
7703
8254
  return new Date(Date.UTC((/* @__PURE__ */ new Date()).getUTCFullYear(), (/* @__PURE__ */ new Date()).getUTCMonth(), 1));
7704
8255
  }
7705
8256
  const firstDay = dateRange[0];
7706
8257
  return new Date(Date.UTC(firstDay.getUTCFullYear(), firstDay.getUTCMonth(), 1));
7707
8258
  }, [dateRange]);
7708
- const todayInRange = useMemo9(() => {
8259
+ const todayInRange = useMemo10(() => {
7709
8260
  const now = /* @__PURE__ */ new Date();
7710
8261
  const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
7711
8262
  return dateRange.some((day) => day.getTime() === today.getTime());
7712
8263
  }, [dateRange]);
7713
- useEffect7(() => {
8264
+ useEffect9(() => {
7714
8265
  const container = scrollContainerRef.current;
7715
8266
  if (!container || dateRange.length === 0) return;
7716
8267
  const now = /* @__PURE__ */ new Date();
@@ -7722,7 +8273,7 @@ function GanttChartInner(props, ref) {
7722
8273
  const scrollLeft = Math.round(todayOffset + dayWidth / 2 - containerWidth * 0.3);
7723
8274
  container.scrollLeft = Math.max(0, scrollLeft);
7724
8275
  }, []);
7725
- useEffect7(() => {
8276
+ useEffect9(() => {
7726
8277
  const container = scrollContainerRef.current;
7727
8278
  if (!container) return;
7728
8279
  const updateShadow = () => {
@@ -7734,7 +8285,7 @@ function GanttChartInner(props, ref) {
7734
8285
  container.removeEventListener("scroll", updateShadow);
7735
8286
  };
7736
8287
  }, []);
7737
- const scrollToToday = useCallback6(() => {
8288
+ const scrollToToday = useCallback8(() => {
7738
8289
  const container = scrollContainerRef.current;
7739
8290
  if (!container || dateRange.length === 0) return;
7740
8291
  const now = /* @__PURE__ */ new Date();
@@ -7746,7 +8297,7 @@ function GanttChartInner(props, ref) {
7746
8297
  const scrollLeft = Math.round(todayOffset + dayWidth / 2 - containerWidth * 0.3);
7747
8298
  container.scrollTo({ left: Math.max(0, scrollLeft), behavior: "smooth" });
7748
8299
  }, [dateRange, dayWidth]);
7749
- const scrollToTask = useCallback6((taskId) => {
8300
+ const scrollToTask = useCallback8((taskId) => {
7750
8301
  const container = scrollContainerRef.current;
7751
8302
  if (!container || dateRange.length === 0) return;
7752
8303
  const task = tasks.find((t) => t.id === taskId);
@@ -7763,7 +8314,7 @@ function GanttChartInner(props, ref) {
7763
8314
  const scrollLeft = Math.round(taskOffset - dayWidth * 2);
7764
8315
  container.scrollTo({ left: Math.max(0, scrollLeft), behavior: "smooth" });
7765
8316
  }, [tasks, dateRange, dayWidth]);
7766
- const scrollToRow = useCallback6((taskId) => {
8317
+ const scrollToRow = useCallback8((taskId) => {
7767
8318
  const container = scrollContainerRef.current;
7768
8319
  if (!container) return;
7769
8320
  const task = tasks.find((t) => t.id === taskId);
@@ -7775,15 +8326,15 @@ function GanttChartInner(props, ref) {
7775
8326
  setSelectedTaskId(taskId);
7776
8327
  container.scrollTo({ top: scrollTop, behavior: "smooth" });
7777
8328
  }, [tasks, visibleTasks, rowHeight]);
7778
- const [dragGuideLines, setDragGuideLines] = useState7(null);
7779
- const [draggedTaskOverride, setDraggedTaskOverride] = useState7(null);
7780
- const [previewTasksById, setPreviewTasksById] = useState7(/* @__PURE__ */ new Map());
7781
- useEffect7(() => {
8329
+ const [dragGuideLines, setDragGuideLines] = useState8(null);
8330
+ const [draggedTaskOverride, setDraggedTaskOverride] = useState8(null);
8331
+ const [previewTasksById, setPreviewTasksById] = useState8(/* @__PURE__ */ new Map());
8332
+ useEffect9(() => {
7782
8333
  const result = validateDependencies(tasks);
7783
8334
  setValidationResult(result);
7784
8335
  onValidateDependencies?.(result);
7785
8336
  }, [tasks, onValidateDependencies]);
7786
- const handleTaskChange = useCallback6((updatedTasks) => {
8337
+ const handleTaskChange = useCallback8((updatedTasks) => {
7787
8338
  const updatedTask = updatedTasks[0];
7788
8339
  if (!updatedTask) return;
7789
8340
  const originalTask = tasks.find((t) => t.id === updatedTask.id);
@@ -7829,7 +8380,7 @@ function GanttChartInner(props, ref) {
7829
8380
  const cascadedTasks = disableConstraints ? [updatedTask] : universalCascade(updatedTask, newStart, newEnd, sourceTasks, businessDays, isCustomWeekend);
7830
8381
  onTasksChange?.(cascadedTasks);
7831
8382
  }, [tasks, onTasksChange, disableConstraints, editingTaskId, businessDays, isCustomWeekend]);
7832
- const handleDelete = useCallback6((taskId) => {
8383
+ const handleDelete = useCallback8((taskId) => {
7833
8384
  const toDelete = /* @__PURE__ */ new Set([taskId]);
7834
8385
  function collectDescendants(parentId) {
7835
8386
  const children = getChildren(parentId, tasks);
@@ -7854,10 +8405,10 @@ function GanttChartInner(props, ref) {
7854
8405
  }
7855
8406
  toDelete.forEach((id) => onDelete?.(id));
7856
8407
  }, [tasks, onTasksChange, onDelete]);
7857
- const handleInsertAfter = useCallback6((taskId, newTask) => {
8408
+ const handleInsertAfter = useCallback8((taskId, newTask) => {
7858
8409
  onInsertAfter?.(taskId, newTask);
7859
8410
  }, [onInsertAfter]);
7860
- const handleReorder = useCallback6((reorderedTasks, movedTaskId, inferredParentId) => {
8411
+ const handleReorder = useCallback8((reorderedTasks, movedTaskId, inferredParentId) => {
7861
8412
  let updated = reorderedTasks;
7862
8413
  if (movedTaskId) {
7863
8414
  updated = updated.map((t) => {
@@ -7874,7 +8425,7 @@ function GanttChartInner(props, ref) {
7874
8425
  }
7875
8426
  onTasksChange?.(normalized);
7876
8427
  }, [onTasksChange, onReorder]);
7877
- const dependencyOverrides = useMemo9(() => {
8428
+ const dependencyOverrides = useMemo10(() => {
7878
8429
  const map = new Map(cascadeOverrides);
7879
8430
  if (draggedTaskOverride) {
7880
8431
  map.set(draggedTaskOverride.taskId, {
@@ -7884,25 +8435,25 @@ function GanttChartInner(props, ref) {
7884
8435
  }
7885
8436
  return map;
7886
8437
  }, [cascadeOverrides, draggedTaskOverride]);
7887
- const handleCascadeProgress = useCallback6((overrides, previewTasks = []) => {
8438
+ const handleCascadeProgress = useCallback8((overrides, previewTasks = []) => {
7888
8439
  setCascadeOverrides(new Map(overrides));
7889
8440
  setPreviewTasksById(new Map(previewTasks.map((task) => [task.id, task])));
7890
8441
  }, []);
7891
- const previewNormalizedTasks = useMemo9(() => {
8442
+ const previewNormalizedTasks = useMemo10(() => {
7892
8443
  if (previewTasksById.size === 0) return normalizedTasks;
7893
8444
  return normalizedTasks.map((task) => previewTasksById.get(task.id) ?? task);
7894
8445
  }, [normalizedTasks, previewTasksById]);
7895
- const previewVisibleTasks = useMemo9(() => {
8446
+ const previewVisibleTasks = useMemo10(() => {
7896
8447
  if (previewTasksById.size === 0) return visibleTasks;
7897
8448
  return visibleTasks.map((task) => previewTasksById.get(task.id) ?? task);
7898
8449
  }, [visibleTasks, previewTasksById]);
7899
- const handleCascade = useCallback6((cascadedTasks) => {
8450
+ const handleCascade = useCallback8((cascadedTasks) => {
7900
8451
  onTasksChange?.(cascadedTasks);
7901
8452
  }, [tasks, onTasksChange]);
7902
- const handleTaskSelect = useCallback6((taskId) => {
8453
+ const handleTaskSelect = useCallback8((taskId) => {
7903
8454
  setSelectedTaskId(taskId);
7904
8455
  }, []);
7905
- const handleToggleCollapse = externalOnToggleCollapse ?? useCallback6((parentId) => {
8456
+ const handleToggleCollapse = externalOnToggleCollapse ?? useCallback8((parentId) => {
7906
8457
  setInternalCollapsedParentIds((prev) => {
7907
8458
  const next = new Set(prev);
7908
8459
  if (next.has(parentId)) {
@@ -7913,20 +8464,20 @@ function GanttChartInner(props, ref) {
7913
8464
  return next;
7914
8465
  });
7915
8466
  }, []);
7916
- const allParentIds = useMemo9(() => {
8467
+ const allParentIds = useMemo10(() => {
7917
8468
  return new Set(
7918
8469
  normalizedTasks.filter((t) => isTaskParent(t.id, normalizedTasks)).map((t) => t.id)
7919
8470
  );
7920
8471
  }, [normalizedTasks]);
7921
- const handleCollapseAll = useCallback6(() => {
8472
+ const handleCollapseAll = useCallback8(() => {
7922
8473
  if (externalCollapsedParentIds) return;
7923
8474
  setInternalCollapsedParentIds(allParentIds);
7924
8475
  }, [allParentIds, externalCollapsedParentIds]);
7925
- const handleExpandAll = useCallback6(() => {
8476
+ const handleExpandAll = useCallback8(() => {
7926
8477
  if (externalCollapsedParentIds) return;
7927
8478
  setInternalCollapsedParentIds(/* @__PURE__ */ new Set());
7928
8479
  }, [externalCollapsedParentIds]);
7929
- const exportToPdf = useCallback6(async (options) => {
8480
+ const exportToPdf = useCallback8(async (options) => {
7930
8481
  const sourceContainer = containerRef.current;
7931
8482
  const sourceContent = scrollContentRef.current;
7932
8483
  if (!sourceContainer || !sourceContent || typeof window === "undefined" || typeof document === "undefined") {
@@ -7985,7 +8536,7 @@ function GanttChartInner(props, ref) {
7985
8536
  }
7986
8537
  return depth;
7987
8538
  }
7988
- const handlePromoteTask = useCallback6((taskId) => {
8539
+ const handlePromoteTask = useCallback8((taskId) => {
7989
8540
  if (onPromoteTask) {
7990
8541
  onPromoteTask(taskId);
7991
8542
  return;
@@ -8015,7 +8566,7 @@ function GanttChartInner(props, ref) {
8015
8566
  ]);
8016
8567
  onTasksChange?.(reorderedTasks);
8017
8568
  }, [tasks, onTasksChange, onPromoteTask]);
8018
- const handleDemoteTask = useCallback6((taskId, newParentId) => {
8569
+ const handleDemoteTask = useCallback8((taskId, newParentId) => {
8019
8570
  if (onDemoteTask) {
8020
8571
  onDemoteTask(taskId, newParentId);
8021
8572
  return;
@@ -8056,7 +8607,7 @@ function GanttChartInner(props, ref) {
8056
8607
  };
8057
8608
  onTasksChange?.([updatedDemotedTask]);
8058
8609
  }, [tasks, onTasksChange, onDemoteTask]);
8059
- const handleUngroupTask = useCallback6((taskId) => {
8610
+ const handleUngroupTask = useCallback8((taskId) => {
8060
8611
  if (onUngroupTask) {
8061
8612
  onUngroupTask(taskId);
8062
8613
  return;
@@ -8083,8 +8634,8 @@ function GanttChartInner(props, ref) {
8083
8634
  }
8084
8635
  onDelete?.(taskId);
8085
8636
  }, [tasks, onTasksChange, onDelete, onUngroupTask]);
8086
- const panStateRef = useRef7(null);
8087
- const handlePanStart = useCallback6((e) => {
8637
+ const panStateRef = useRef9(null);
8638
+ const handlePanStart = useCallback8((e) => {
8088
8639
  if (e.button !== 0) return;
8089
8640
  const target = e.target;
8090
8641
  if (target.closest("[data-taskbar]")) return;
@@ -8105,7 +8656,7 @@ function GanttChartInner(props, ref) {
8105
8656
  container.style.cursor = "grabbing";
8106
8657
  e.preventDefault();
8107
8658
  }, []);
8108
- useEffect7(() => {
8659
+ useEffect9(() => {
8109
8660
  const handlePanMove = (e) => {
8110
8661
  const pan = panStateRef.current;
8111
8662
  if (!pan?.active) return;
@@ -8127,15 +8678,15 @@ function GanttChartInner(props, ref) {
8127
8678
  window.removeEventListener("mouseup", handlePanEnd);
8128
8679
  };
8129
8680
  }, []);
8130
- return /* @__PURE__ */ jsx15("div", { ref: containerRef, className: "gantt-container", children: /* @__PURE__ */ jsx15(
8681
+ return /* @__PURE__ */ jsx16("div", { ref: containerRef, className: "gantt-container", children: /* @__PURE__ */ jsx16(
8131
8682
  "div",
8132
8683
  {
8133
8684
  ref: scrollContainerRef,
8134
8685
  className: "gantt-scrollContainer",
8135
8686
  style: { height: containerHeight ?? "auto", cursor: "grab" },
8136
8687
  onMouseDown: handlePanStart,
8137
- children: /* @__PURE__ */ jsxs12("div", { ref: scrollContentRef, className: "gantt-scrollContent", children: [
8138
- /* @__PURE__ */ jsx15(
8688
+ children: /* @__PURE__ */ jsxs13("div", { ref: scrollContentRef, className: "gantt-scrollContent", children: [
8689
+ /* @__PURE__ */ jsx16(
8139
8690
  TaskList,
8140
8691
  {
8141
8692
  tasks: normalizedTasks,
@@ -8157,6 +8708,7 @@ function GanttChartInner(props, ref) {
8157
8708
  onReorder: handleReorder,
8158
8709
  editingTaskId,
8159
8710
  enableAddTask,
8711
+ defaultTaskDurationDays,
8160
8712
  collapsedParentIds,
8161
8713
  onToggleCollapse: handleToggleCollapse,
8162
8714
  onPromoteTask: onPromoteTask ?? handlePromoteTask,
@@ -8173,13 +8725,13 @@ function GanttChartInner(props, ref) {
8173
8725
  taskListMenuCommands
8174
8726
  }
8175
8727
  ),
8176
- /* @__PURE__ */ jsxs12(
8728
+ /* @__PURE__ */ jsxs13(
8177
8729
  "div",
8178
8730
  {
8179
8731
  className: showChart ? "gantt-chartSurface" : "gantt-chartSurface gantt-chart-hidden",
8180
8732
  style: { minWidth: `${gridWidth}px`, flex: 1, display: showChart ? void 0 : "none" },
8181
8733
  children: [
8182
- /* @__PURE__ */ jsx15("div", { className: "gantt-stickyHeader", style: { width: `${gridWidth}px` }, children: /* @__PURE__ */ jsx15(
8734
+ /* @__PURE__ */ jsx16("div", { className: "gantt-stickyHeader", style: { width: `${gridWidth}px` }, children: /* @__PURE__ */ jsx16(
8183
8735
  TimeScaleHeader_default,
8184
8736
  {
8185
8737
  days: dateRange,
@@ -8189,7 +8741,7 @@ function GanttChartInner(props, ref) {
8189
8741
  isCustomWeekend
8190
8742
  }
8191
8743
  ) }),
8192
- /* @__PURE__ */ jsxs12(
8744
+ /* @__PURE__ */ jsxs13(
8193
8745
  "div",
8194
8746
  {
8195
8747
  className: "gantt-taskArea",
@@ -8198,7 +8750,7 @@ function GanttChartInner(props, ref) {
8198
8750
  width: `${gridWidth}px`
8199
8751
  },
8200
8752
  children: [
8201
- /* @__PURE__ */ jsx15(
8753
+ /* @__PURE__ */ jsx16(
8202
8754
  GridBackground_default,
8203
8755
  {
8204
8756
  dateRange,
@@ -8208,8 +8760,8 @@ function GanttChartInner(props, ref) {
8208
8760
  isCustomWeekend
8209
8761
  }
8210
8762
  ),
8211
- todayInRange && /* @__PURE__ */ jsx15(TodayIndicator_default, { monthStart, dayWidth }),
8212
- /* @__PURE__ */ jsx15(
8763
+ todayInRange && /* @__PURE__ */ jsx16(TodayIndicator_default, { monthStart, dayWidth }),
8764
+ /* @__PURE__ */ jsx16(
8213
8765
  DependencyLines_default,
8214
8766
  {
8215
8767
  tasks: previewVisibleTasks,
@@ -8225,7 +8777,7 @@ function GanttChartInner(props, ref) {
8225
8777
  weekendPredicate: isCustomWeekend
8226
8778
  }
8227
8779
  ),
8228
- dragGuideLines && /* @__PURE__ */ jsx15(
8780
+ dragGuideLines && /* @__PURE__ */ jsx16(
8229
8781
  DragGuideLines_default,
8230
8782
  {
8231
8783
  isDragging: dragGuideLines.isDragging,
@@ -8235,7 +8787,7 @@ function GanttChartInner(props, ref) {
8235
8787
  totalHeight: totalGridHeight
8236
8788
  }
8237
8789
  ),
8238
- visibleTasks.map((task, index) => /* @__PURE__ */ jsx15(
8790
+ visibleTasks.map((task, index) => /* @__PURE__ */ jsx16(
8239
8791
  TaskRow_default,
8240
8792
  {
8241
8793
  task,
@@ -8279,13 +8831,14 @@ function GanttChartInner(props, ref) {
8279
8831
  }
8280
8832
  ) });
8281
8833
  }
8834
+ var TaskGanttChart = forwardRef(TaskGanttChartInner);
8282
8835
  var GanttChart = forwardRef(GanttChartInner);
8283
8836
  GanttChart.displayName = "GanttChart";
8284
8837
 
8285
8838
  // src/components/ui/Button.tsx
8286
- import React13 from "react";
8287
- import { jsx as jsx16 } from "react/jsx-runtime";
8288
- var Button = React13.forwardRef(
8839
+ import React14 from "react";
8840
+ import { jsx as jsx17 } from "react/jsx-runtime";
8841
+ var Button = React14.forwardRef(
8289
8842
  ({ className, variant = "default", size = "default", children, ...props }, ref) => {
8290
8843
  const classes = [
8291
8844
  "gantt-btn",
@@ -8293,7 +8846,7 @@ var Button = React13.forwardRef(
8293
8846
  size !== "default" ? `gantt-btn-${size}` : "",
8294
8847
  className || ""
8295
8848
  ].filter(Boolean).join(" ");
8296
- return /* @__PURE__ */ jsx16("button", { ref, className: classes, ...props, children });
8849
+ return /* @__PURE__ */ jsx17("button", { ref, className: classes, ...props, children });
8297
8850
  }
8298
8851
  );
8299
8852
  Button.displayName = "Button";
@@ -8338,6 +8891,7 @@ export {
8338
8891
  Popover,
8339
8892
  PopoverContent,
8340
8893
  PopoverTrigger,
8894
+ ResourceTimelineChart,
8341
8895
  TaskList,
8342
8896
  TaskRow_default as TaskRow,
8343
8897
  TimeScaleHeader_default as TimeScaleHeader,
@@ -8401,6 +8955,7 @@ export {
8401
8955
  isTaskParent,
8402
8956
  isToday,
8403
8957
  isWeekend,
8958
+ layoutResourceTimelineItems,
8404
8959
  moveTaskRange,
8405
8960
  moveTaskWithCascade,
8406
8961
  nameContains,