gantt-lib 0.75.1 → 0.77.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
@@ -7402,12 +7402,86 @@ var compareParsedItems = (a, b) => {
7402
7402
  }
7403
7403
  return a.item.id.localeCompare(b.item.id);
7404
7404
  };
7405
+ var getOverlapRange = (left, right) => {
7406
+ const startDay = Math.max(getUTCDayNumber(left.startDate), getUTCDayNumber(right.startDate));
7407
+ const endDay = Math.min(getUTCDayNumber(left.endDate), getUTCDayNumber(right.endDate));
7408
+ if (startDay > endDay) {
7409
+ return null;
7410
+ }
7411
+ return {
7412
+ startDate: new Date(startDay * 864e5),
7413
+ endDate: new Date(endDay * 864e5),
7414
+ itemIds: [left.item.id, right.item.id]
7415
+ };
7416
+ };
7417
+ var mergeConflictRanges = (ranges) => {
7418
+ const sortedRanges = [...ranges].sort(
7419
+ (left, right) => getUTCDayNumber(left.startDate) - getUTCDayNumber(right.startDate) || getUTCDayNumber(left.endDate) - getUTCDayNumber(right.endDate)
7420
+ );
7421
+ const merged = [];
7422
+ for (const range of sortedRanges) {
7423
+ const previous = merged[merged.length - 1];
7424
+ const rangeStartDay = getUTCDayNumber(range.startDate);
7425
+ const rangeEndDay = getUTCDayNumber(range.endDate);
7426
+ if (!previous || rangeStartDay > getUTCDayNumber(previous.endDate) + 1) {
7427
+ merged.push({
7428
+ startDate: range.startDate,
7429
+ endDate: range.endDate,
7430
+ itemIds: [...range.itemIds]
7431
+ });
7432
+ continue;
7433
+ }
7434
+ if (rangeEndDay > getUTCDayNumber(previous.endDate)) {
7435
+ previous.endDate = range.endDate;
7436
+ }
7437
+ previous.itemIds = Array.from(/* @__PURE__ */ new Set([...previous.itemIds, ...range.itemIds])).sort();
7438
+ }
7439
+ return merged;
7440
+ };
7441
+ var calculateConflictInfo = (parsedItems) => {
7442
+ const conflictRangesByItemId = /* @__PURE__ */ new Map();
7443
+ const conflictsWithByItemId = /* @__PURE__ */ new Map();
7444
+ for (let i = 0; i < parsedItems.length; i++) {
7445
+ for (let j = i + 1; j < parsedItems.length; j++) {
7446
+ const left = parsedItems[i];
7447
+ const right = parsedItems[j];
7448
+ if (getUTCDayNumber(right.startDate) > getUTCDayNumber(left.endDate)) {
7449
+ break;
7450
+ }
7451
+ const overlap = getOverlapRange(left, right);
7452
+ if (!overlap) {
7453
+ continue;
7454
+ }
7455
+ const leftRanges = conflictRangesByItemId.get(left.item.id) ?? [];
7456
+ const rightRanges = conflictRangesByItemId.get(right.item.id) ?? [];
7457
+ leftRanges.push(overlap);
7458
+ rightRanges.push(overlap);
7459
+ conflictRangesByItemId.set(left.item.id, leftRanges);
7460
+ conflictRangesByItemId.set(right.item.id, rightRanges);
7461
+ const leftConflicts = conflictsWithByItemId.get(left.item.id) ?? /* @__PURE__ */ new Set();
7462
+ const rightConflicts = conflictsWithByItemId.get(right.item.id) ?? /* @__PURE__ */ new Set();
7463
+ leftConflicts.add(right.item.id);
7464
+ rightConflicts.add(left.item.id);
7465
+ conflictsWithByItemId.set(left.item.id, leftConflicts);
7466
+ conflictsWithByItemId.set(right.item.id, rightConflicts);
7467
+ }
7468
+ }
7469
+ const result = /* @__PURE__ */ new Map();
7470
+ for (const parsedItem of parsedItems) {
7471
+ result.set(parsedItem.item.id, {
7472
+ conflictRanges: mergeConflictRanges(conflictRangesByItemId.get(parsedItem.item.id) ?? []),
7473
+ conflictsWith: Array.from(conflictsWithByItemId.get(parsedItem.item.id) ?? []).sort()
7474
+ });
7475
+ }
7476
+ return result;
7477
+ };
7405
7478
  var layoutResourceTimelineItems = (resources, options) => {
7406
7479
  const rows = [];
7407
7480
  const items = [];
7408
7481
  const diagnostics = [];
7409
7482
  let currentTop = 0;
7410
- for (const resource of resources) {
7483
+ const rowGap = options.rowGap ?? 0;
7484
+ resources.forEach((resource, resourceIndex) => {
7411
7485
  const parsedItems = [];
7412
7486
  for (const item of resource.items) {
7413
7487
  try {
@@ -7426,6 +7500,7 @@ var layoutResourceTimelineItems = (resources, options) => {
7426
7500
  }
7427
7501
  }
7428
7502
  parsedItems.sort(compareParsedItems);
7503
+ const conflictInfoByItemId = calculateConflictInfo(parsedItems);
7429
7504
  const laneEndDays = [];
7430
7505
  const laidOutItems = [];
7431
7506
  for (const parsed of parsedItems) {
@@ -7439,6 +7514,7 @@ var layoutResourceTimelineItems = (resources, options) => {
7439
7514
  laneEndDays[laneIndex] = endDay;
7440
7515
  }
7441
7516
  const { left, width } = calculateTaskBar(parsed.startDate, parsed.endDate, options.monthStart, options.dayWidth);
7517
+ const conflictInfo = conflictInfoByItemId.get(parsed.item.id);
7442
7518
  laidOutItems.push({
7443
7519
  item: parsed.item,
7444
7520
  itemId: parsed.item.id,
@@ -7451,15 +7527,19 @@ var layoutResourceTimelineItems = (resources, options) => {
7451
7527
  top: currentTop + laneIndex * options.laneHeight,
7452
7528
  height: options.laneHeight,
7453
7529
  startDate: parsed.startDate,
7454
- endDate: parsed.endDate
7530
+ endDate: parsed.endDate,
7531
+ conflictRanges: conflictInfo?.conflictRanges ?? [],
7532
+ conflictsWith: conflictInfo?.conflictsWith ?? []
7455
7533
  });
7456
7534
  }
7457
7535
  const laneCount = Math.max(1, laneEndDays.length);
7458
7536
  const resourceRowHeight = laneCount * options.laneHeight;
7537
+ const conflictCount = laidOutItems.filter((item) => item.conflictsWith.length > 0).length;
7459
7538
  const row = {
7460
7539
  resource,
7461
7540
  resourceId: resource.id,
7462
7541
  laneCount,
7542
+ conflictCount,
7463
7543
  resourceRowTop: currentTop,
7464
7544
  resourceRowHeight
7465
7545
  };
@@ -7468,8 +7548,8 @@ var layoutResourceTimelineItems = (resources, options) => {
7468
7548
  ...item,
7469
7549
  resourceRowHeight
7470
7550
  })));
7471
- currentTop += resourceRowHeight;
7472
- }
7551
+ currentTop += resourceRowHeight + rowGap;
7552
+ });
7473
7553
  return {
7474
7554
  rows,
7475
7555
  items,
@@ -7486,6 +7566,56 @@ var snapToDay = (pixels, dayWidth) => {
7486
7566
  var addUTCDays = (date, days) => {
7487
7567
  return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate() + days));
7488
7568
  };
7569
+ var getDayOffset2 = (date, monthStart) => {
7570
+ return Math.round(
7571
+ (Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()) - Date.UTC(monthStart.getUTCFullYear(), monthStart.getUTCMonth(), monthStart.getUTCDate())) / (24 * 60 * 60 * 1e3)
7572
+ );
7573
+ };
7574
+ var resolveResourceMoveRange = (activeDrag, nextLeft, nextWidth) => {
7575
+ const dayOffset = Math.round(nextLeft / activeDrag.dayWidth);
7576
+ const durationDays = Math.round(nextWidth / activeDrag.dayWidth);
7577
+ const rawStartDate = addUTCDays(activeDrag.monthStart, dayOffset);
7578
+ const rawEndDate = addUTCDays(rawStartDate, durationDays - 1);
7579
+ if (!activeDrag.businessDays || !activeDrag.weekendPredicate) {
7580
+ return {
7581
+ startDate: rawStartDate,
7582
+ endDate: rawEndDate,
7583
+ left: nextLeft,
7584
+ width: nextWidth
7585
+ };
7586
+ }
7587
+ const range = (() => {
7588
+ if (activeDrag.mode === "resize-start") {
7589
+ const snapDirection2 = rawStartDate.getTime() >= activeDrag.startDate.getTime() ? 1 : -1;
7590
+ const duration = getBusinessDaysCount(rawStartDate, activeDrag.endDate, activeDrag.weekendPredicate);
7591
+ return buildTaskRangeFromEnd(activeDrag.endDate, duration, true, activeDrag.weekendPredicate, snapDirection2);
7592
+ }
7593
+ if (activeDrag.mode === "resize-end") {
7594
+ const snapDirection2 = rawEndDate.getTime() >= activeDrag.endDate.getTime() ? 1 : -1;
7595
+ const duration = getBusinessDaysCount(activeDrag.startDate, rawEndDate, activeDrag.weekendPredicate);
7596
+ return buildTaskRangeFromStart(activeDrag.startDate, duration, true, activeDrag.weekendPredicate, snapDirection2);
7597
+ }
7598
+ const dayDelta = Math.round((nextLeft - activeDrag.initialLeft) / activeDrag.dayWidth);
7599
+ const proposedStartDate = addUTCDays(activeDrag.startDate, dayDelta);
7600
+ const snapDirection = proposedStartDate.getTime() >= activeDrag.startDate.getTime() ? 1 : -1;
7601
+ return moveTaskRange(
7602
+ activeDrag.startDate,
7603
+ activeDrag.endDate,
7604
+ proposedStartDate,
7605
+ true,
7606
+ activeDrag.weekendPredicate,
7607
+ snapDirection
7608
+ );
7609
+ })();
7610
+ const startOffset = getDayOffset2(range.start, activeDrag.monthStart);
7611
+ const endOffset = getDayOffset2(range.end, activeDrag.monthStart);
7612
+ return {
7613
+ startDate: range.start,
7614
+ endDate: range.end,
7615
+ left: Math.round(startOffset * activeDrag.dayWidth),
7616
+ width: Math.round((endOffset - startOffset + 1) * activeDrag.dayWidth)
7617
+ };
7618
+ };
7489
7619
  var resolveTargetResource = (rows, clientY, gridTop) => {
7490
7620
  const localY = clientY - gridTop;
7491
7621
  return rows.find(
@@ -7494,10 +7624,13 @@ var resolveTargetResource = (rows, clientY, gridTop) => {
7494
7624
  };
7495
7625
  var useResourceItemDrag = ({
7496
7626
  dayWidth,
7627
+ monthStart,
7497
7628
  rows,
7498
7629
  gridElementRef,
7499
7630
  readonly,
7500
7631
  disableResourceReassignment,
7632
+ businessDays = false,
7633
+ weekendPredicate,
7501
7634
  onResourceItemMove
7502
7635
  }) => {
7503
7636
  const activeDragRef = (0, import_react13.useRef)(null);
@@ -7534,14 +7667,30 @@ var useResourceItemDrag = ({
7534
7667
  if (!latestDrag) {
7535
7668
  return;
7536
7669
  }
7537
- const nextLeft = latestDrag.initialLeft + snapToDay(event.clientX - latestDrag.startX, latestDrag.dayWidth);
7538
- const nextTop = disableResourceReassignment ? latestDrag.initialTop : latestDrag.initialTop + (event.clientY - latestDrag.startY);
7539
- latestDrag.currentLeft = nextLeft;
7670
+ const snappedDelta = snapToDay(event.clientX - latestDrag.startX, latestDrag.dayWidth);
7671
+ const rightEdge = latestDrag.initialLeft + latestDrag.initialWidth;
7672
+ const nextGeometry = (() => {
7673
+ if (latestDrag.mode === "resize-start") {
7674
+ const left = Math.min(latestDrag.initialLeft + snappedDelta, rightEdge - latestDrag.dayWidth);
7675
+ return { left, width: rightEdge - left };
7676
+ }
7677
+ if (latestDrag.mode === "resize-end") {
7678
+ return { left: latestDrag.initialLeft, width: Math.max(latestDrag.dayWidth, latestDrag.initialWidth + snappedDelta) };
7679
+ }
7680
+ return { left: latestDrag.initialLeft + snappedDelta, width: latestDrag.initialWidth };
7681
+ })();
7682
+ const nextRange = resolveResourceMoveRange(latestDrag, nextGeometry.left, nextGeometry.width);
7683
+ const nextTop = disableResourceReassignment || latestDrag.mode !== "move" ? latestDrag.initialTop : latestDrag.initialTop + (event.clientY - latestDrag.startY);
7684
+ latestDrag.currentLeft = nextRange.left;
7685
+ latestDrag.currentWidth = nextRange.width;
7540
7686
  latestDrag.currentTop = nextTop;
7541
7687
  setPreview({
7542
7688
  itemId: latestDrag.itemId,
7543
- left: nextLeft,
7544
- top: nextTop
7689
+ left: nextRange.left,
7690
+ top: nextTop,
7691
+ width: nextRange.width,
7692
+ startDate: nextRange.startDate,
7693
+ endDate: nextRange.endDate
7545
7694
  });
7546
7695
  });
7547
7696
  };
@@ -7554,18 +7703,20 @@ var useResourceItemDrag = ({
7554
7703
  activeDragRef.current = null;
7555
7704
  setPreview(null);
7556
7705
  const gridTop = gridElementRef?.current?.getBoundingClientRect().top ?? 0;
7557
- const targetResource = disableResourceReassignment ? rowsRef.current.find((row) => row.resourceId === activeDrag.fromResourceId)?.resource ?? null : resolveTargetResource(rowsRef.current, event.clientY, gridTop);
7706
+ const targetResource = disableResourceReassignment || activeDrag.mode !== "move" ? rowsRef.current.find((row) => row.resourceId === activeDrag.fromResourceId)?.resource ?? null : resolveTargetResource(rowsRef.current, event.clientY, gridTop);
7558
7707
  if (!targetResource) {
7559
7708
  return;
7560
7709
  }
7561
- const dayDelta = Math.round((activeDrag.currentLeft - activeDrag.initialLeft) / activeDrag.dayWidth);
7710
+ const nextRange = resolveResourceMoveRange(activeDrag, activeDrag.currentLeft, activeDrag.currentWidth);
7562
7711
  onResourceItemMoveRef.current?.({
7563
7712
  item: activeDrag.item,
7564
7713
  itemId: activeDrag.itemId,
7714
+ taskId: activeDrag.item.taskId,
7565
7715
  fromResourceId: activeDrag.fromResourceId,
7566
7716
  toResourceId: targetResource.id,
7567
- startDate: addUTCDays(activeDrag.startDate, dayDelta),
7568
- endDate: addUTCDays(activeDrag.endDate, dayDelta)
7717
+ startDate: nextRange.startDate,
7718
+ endDate: nextRange.endDate,
7719
+ changeType: activeDrag.mode
7569
7720
  });
7570
7721
  };
7571
7722
  window.addEventListener("mousemove", handleMouseMove);
@@ -7580,27 +7731,38 @@ var useResourceItemDrag = ({
7580
7731
  if (readonly || layoutItem.item.locked || event.button !== 0) {
7581
7732
  return;
7582
7733
  }
7734
+ const target = event.target;
7735
+ const mode = target.closest(".gantt-resourceTimeline-resizeHandleStart") ? "resize-start" : target.closest(".gantt-resourceTimeline-resizeHandleEnd") ? "resize-end" : "move";
7583
7736
  event.preventDefault();
7584
7737
  activeDragRef.current = {
7585
7738
  item: layoutItem.item,
7586
7739
  itemId: layoutItem.itemId,
7740
+ mode,
7587
7741
  fromResourceId: layoutItem.resourceId,
7588
7742
  startX: event.clientX,
7589
7743
  startY: event.clientY,
7590
7744
  initialLeft: layoutItem.left,
7591
7745
  initialTop: layoutItem.top,
7746
+ initialWidth: layoutItem.width,
7592
7747
  currentLeft: layoutItem.left,
7593
7748
  currentTop: layoutItem.top,
7749
+ currentWidth: layoutItem.width,
7594
7750
  dayWidth,
7595
7751
  startDate: layoutItem.startDate,
7596
- endDate: layoutItem.endDate
7752
+ endDate: layoutItem.endDate,
7753
+ monthStart,
7754
+ businessDays,
7755
+ weekendPredicate
7597
7756
  };
7598
7757
  setPreview({
7599
7758
  itemId: layoutItem.itemId,
7600
7759
  left: layoutItem.left,
7601
- top: layoutItem.top
7760
+ top: layoutItem.top,
7761
+ width: layoutItem.width,
7762
+ startDate: layoutItem.startDate,
7763
+ endDate: layoutItem.endDate
7602
7764
  });
7603
- }, [dayWidth, readonly]);
7765
+ }, [businessDays, dayWidth, monthStart, readonly, weekendPredicate]);
7604
7766
  return {
7605
7767
  preview,
7606
7768
  startDrag,
@@ -7614,6 +7776,7 @@ var DEFAULT_DAY_WIDTH = 40;
7614
7776
  var DEFAULT_HEADER_HEIGHT = 40;
7615
7777
  var DEFAULT_LANE_HEIGHT = 40;
7616
7778
  var DEFAULT_ROW_HEADER_WIDTH = 240;
7779
+ var DEFAULT_RESOURCE_ROW_GAP = 8;
7617
7780
  var ITEM_OUTER_VERTICAL_INSET = 2;
7618
7781
  var ITEM_INNER_VERTICAL_INSET = 1;
7619
7782
  var ITEM_HORIZONTAL_INSET = 1;
@@ -7673,16 +7836,64 @@ var getVisualItemGeometry = (geometry, laneIndex, laneCount) => {
7673
7836
  height: Math.max(0, geometry.height - topInset - bottomInset)
7674
7837
  };
7675
7838
  };
7839
+ var getWeekendOverlaySegments = (startDate, endDate, dayWidth, weekendPredicate) => {
7840
+ const segments2 = [];
7841
+ const current = new Date(Date.UTC(startDate.getUTCFullYear(), startDate.getUTCMonth(), startDate.getUTCDate()));
7842
+ let activeStartOffset = null;
7843
+ let offset = 0;
7844
+ while (current.getTime() <= endDate.getTime()) {
7845
+ const isWeekendDay = weekendPredicate(current);
7846
+ if (isWeekendDay && activeStartOffset === null) {
7847
+ activeStartOffset = offset;
7848
+ }
7849
+ if (!isWeekendDay && activeStartOffset !== null) {
7850
+ segments2.push({
7851
+ left: Math.round(activeStartOffset * dayWidth),
7852
+ width: Math.round((offset - activeStartOffset) * dayWidth)
7853
+ });
7854
+ activeStartOffset = null;
7855
+ }
7856
+ current.setUTCDate(current.getUTCDate() + 1);
7857
+ offset += 1;
7858
+ }
7859
+ if (activeStartOffset !== null) {
7860
+ segments2.push({
7861
+ left: Math.round(activeStartOffset * dayWidth),
7862
+ width: Math.round((offset - activeStartOffset) * dayWidth)
7863
+ });
7864
+ }
7865
+ return segments2;
7866
+ };
7867
+ var getRangeOverlaySegments = (itemStartDate, ranges, dayWidth) => {
7868
+ return ranges.map((range) => {
7869
+ const startOffset = Math.max(0, Math.round(
7870
+ (Date.UTC(range.startDate.getUTCFullYear(), range.startDate.getUTCMonth(), range.startDate.getUTCDate()) - Date.UTC(itemStartDate.getUTCFullYear(), itemStartDate.getUTCMonth(), itemStartDate.getUTCDate())) / (24 * 60 * 60 * 1e3)
7871
+ ));
7872
+ const endOffset = Math.max(startOffset, Math.round(
7873
+ (Date.UTC(range.endDate.getUTCFullYear(), range.endDate.getUTCMonth(), range.endDate.getUTCDate()) - Date.UTC(itemStartDate.getUTCFullYear(), itemStartDate.getUTCMonth(), itemStartDate.getUTCDate())) / (24 * 60 * 60 * 1e3)
7874
+ ));
7875
+ return {
7876
+ left: Math.round(startOffset * dayWidth),
7877
+ width: Math.round((endOffset - startOffset + 1) * dayWidth)
7878
+ };
7879
+ });
7880
+ };
7881
+ var getDurationValue = (startDate, endDate, businessDays, weekendPredicate) => businessDays ? getBusinessDaysCount(startDate, endDate, weekendPredicate) : Math.max(1, Math.round((endDate.getTime() - startDate.getTime()) / (24 * 60 * 60 * 1e3)) + 1);
7676
7882
  function ResourceTimelineChart({
7677
7883
  resources,
7678
7884
  dayWidth = DEFAULT_DAY_WIDTH,
7679
7885
  rowHeaderWidth = DEFAULT_ROW_HEADER_WIDTH,
7680
7886
  laneHeight = DEFAULT_LANE_HEIGHT,
7681
7887
  headerHeight = DEFAULT_HEADER_HEIGHT,
7888
+ allowVerticalPan = false,
7889
+ customDays,
7890
+ isWeekend: isWeekend3,
7891
+ businessDays = true,
7682
7892
  readonly,
7683
7893
  disableResourceReassignment,
7684
7894
  renderItem,
7685
7895
  getItemClassName,
7896
+ onResourceItemClick,
7686
7897
  onResourceItemMove
7687
7898
  }) {
7688
7899
  const scrollContainerRef = (0, import_react14.useRef)(null);
@@ -7696,9 +7907,18 @@ function ResourceTimelineChart({
7696
7907
  const firstDay = dateRange[0] ?? /* @__PURE__ */ new Date();
7697
7908
  return new Date(Date.UTC(firstDay.getUTCFullYear(), firstDay.getUTCMonth(), 1));
7698
7909
  }, [dateRange]);
7910
+ const weekendPredicate = (0, import_react14.useMemo)(
7911
+ () => createCustomDayPredicate({ customDays, isWeekend: isWeekend3 }),
7912
+ [customDays, isWeekend3]
7913
+ );
7699
7914
  const gridWidth = (0, import_react14.useMemo)(() => Math.round(dateRange.length * dayWidth), [dateRange.length, dayWidth]);
7700
7915
  const layout = (0, import_react14.useMemo)(
7701
- () => layoutResourceTimelineItems(resources, { monthStart, dayWidth, laneHeight }),
7916
+ () => layoutResourceTimelineItems(resources, {
7917
+ monthStart,
7918
+ dayWidth,
7919
+ laneHeight,
7920
+ rowGap: DEFAULT_RESOURCE_ROW_GAP
7921
+ }),
7702
7922
  [resources, monthStart, dayWidth, laneHeight]
7703
7923
  );
7704
7924
  const todayInRange = (0, import_react14.useMemo)(() => {
@@ -7717,10 +7937,13 @@ function ResourceTimelineChart({
7717
7937
  }, [layout.items]);
7718
7938
  const { preview, startDrag } = useResourceItemDrag({
7719
7939
  dayWidth,
7940
+ monthStart,
7720
7941
  rows: layout.rows,
7721
7942
  gridElementRef: gridRef,
7722
7943
  readonly,
7723
7944
  disableResourceReassignment,
7945
+ businessDays,
7946
+ weekendPredicate,
7724
7947
  onResourceItemMove
7725
7948
  });
7726
7949
  const handlePanStart = (0, import_react14.useCallback)((event) => {
@@ -7759,7 +7982,9 @@ function ResourceTimelineChart({
7759
7982
  return;
7760
7983
  }
7761
7984
  container.scrollLeft = pan.scrollX - (event.clientX - pan.startX);
7762
- container.scrollTop = pan.scrollY - (event.clientY - pan.startY);
7985
+ if (allowVerticalPan) {
7986
+ container.scrollTop = pan.scrollY - (event.clientY - pan.startY);
7987
+ }
7763
7988
  };
7764
7989
  const handlePanEnd = () => {
7765
7990
  if (!panStateRef.current?.active) {
@@ -7777,13 +8002,14 @@ function ResourceTimelineChart({
7777
8002
  window.removeEventListener("mousemove", handlePanMove);
7778
8003
  window.removeEventListener("mouseup", handlePanEnd);
7779
8004
  };
7780
- }, []);
8005
+ }, [allowVerticalPan]);
7781
8006
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "gantt-container gantt-resourceTimeline", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
7782
8007
  "div",
7783
8008
  {
7784
8009
  ref: scrollContainerRef,
7785
8010
  className: "gantt-resourceTimeline-scrollContainer",
7786
8011
  style: { cursor: "grab" },
8012
+ "data-allow-vertical-pan": allowVerticalPan ? "true" : "false",
7787
8013
  onMouseDown: handlePanStart,
7788
8014
  children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "gantt-resourceTimeline-scrollContent", children: [
7789
8015
  /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
@@ -7799,13 +8025,26 @@ function ResourceTimelineChart({
7799
8025
  style: { height: `${headerHeight}px` }
7800
8026
  }
7801
8027
  ),
7802
- layout.rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8028
+ layout.rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
7803
8029
  "div",
7804
8030
  {
7805
8031
  className: "gantt-resourceTimeline-resourceHeader",
7806
8032
  "data-resource-row-id": row.resourceId,
7807
- style: { height: `${row.resourceRowHeight}px` },
7808
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "gantt-resourceTimeline-resourceName", children: row.resource.name })
8033
+ style: {
8034
+ height: `${row.resourceRowHeight + DEFAULT_RESOURCE_ROW_GAP}px`,
8035
+ paddingBottom: `${DEFAULT_RESOURCE_ROW_GAP}px`
8036
+ },
8037
+ children: [
8038
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "gantt-resourceTimeline-resourceName", children: row.resource.name }),
8039
+ row.conflictCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8040
+ "span",
8041
+ {
8042
+ className: "gantt-resourceTimeline-conflictBadge",
8043
+ "aria-label": `${row.conflictCount} \u043A\u043E\u043D\u0444\u043B\u0438\u043A\u0442\u043E\u0432`,
8044
+ children: row.conflictCount
8045
+ }
8046
+ )
8047
+ ]
7809
8048
  },
7810
8049
  row.resourceId
7811
8050
  ))
@@ -7818,7 +8057,15 @@ function ResourceTimelineChart({
7818
8057
  className: "gantt-resourceTimeline-chartSurface",
7819
8058
  style: { minWidth: `${gridWidth}px` },
7820
8059
  children: [
7821
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "gantt-resourceTimeline-stickyHeader", style: { width: `${gridWidth}px` }, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TimeScaleHeader_default, { days: dateRange, dayWidth, headerHeight }) }),
8060
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "gantt-resourceTimeline-stickyHeader", style: { width: `${gridWidth}px` }, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8061
+ TimeScaleHeader_default,
8062
+ {
8063
+ days: dateRange,
8064
+ dayWidth,
8065
+ headerHeight,
8066
+ isCustomWeekend: weekendPredicate
8067
+ }
8068
+ ) }),
7822
8069
  /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
7823
8070
  "div",
7824
8071
  {
@@ -7826,7 +8073,15 @@ function ResourceTimelineChart({
7826
8073
  className: "gantt-resourceTimeline-grid",
7827
8074
  style: { width: `${gridWidth}px`, height: `${layout.totalHeight}px` },
7828
8075
  children: [
7829
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(GridBackground_default, { dateRange, dayWidth, totalHeight: layout.totalHeight }),
8076
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8077
+ GridBackground_default,
8078
+ {
8079
+ dateRange,
8080
+ dayWidth,
8081
+ totalHeight: layout.totalHeight,
8082
+ isCustomWeekend: weekendPredicate
8083
+ }
8084
+ ),
7830
8085
  todayInRange && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TodayIndicator_default, { monthStart, dayWidth }),
7831
8086
  layout.rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
7832
8087
  "div",
@@ -7835,7 +8090,7 @@ function ResourceTimelineChart({
7835
8090
  "data-resource-row-id": row.resourceId,
7836
8091
  style: {
7837
8092
  top: `${row.resourceRowTop}px`,
7838
- height: `${row.resourceRowHeight}px`
8093
+ height: `${row.resourceRowHeight + DEFAULT_RESOURCE_ROW_GAP}px`
7839
8094
  }
7840
8095
  },
7841
8096
  row.resourceId
@@ -7843,17 +8098,18 @@ function ResourceTimelineChart({
7843
8098
  Array.from(itemsByResourceId.values()).flatMap(
7844
8099
  (resourceItems) => resourceItems.map((layoutItem) => {
7845
8100
  const customClassName = getItemClassName?.(layoutItem.item);
8101
+ const isDraggingItem = preview?.itemId === layoutItem.itemId;
7846
8102
  const className = [
7847
8103
  "gantt-resourceTimeline-item",
7848
- preview?.itemId === layoutItem.itemId && "gantt-resourceTimeline-itemDragging",
8104
+ isDraggingItem && "gantt-resourceTimeline-itemDragging",
7849
8105
  (readonly || layoutItem.item.locked) && "gantt-resourceTimeline-itemDisabled",
7850
8106
  customClassName
7851
8107
  ].filter(Boolean).join(" ");
7852
8108
  const laneCount = Math.max(1, Math.round(layoutItem.resourceRowHeight / layoutItem.height));
7853
- const previewStyle = preview?.itemId === layoutItem.itemId ? getVisualItemGeometry({
8109
+ const previewStyle = isDraggingItem ? getVisualItemGeometry({
7854
8110
  left: preview.left,
7855
8111
  top: preview.top,
7856
- width: layoutItem.width,
8112
+ width: preview.width,
7857
8113
  height: layoutItem.height
7858
8114
  }, layoutItem.laneIndex, laneCount) : void 0;
7859
8115
  const itemGeometry = getVisualItemGeometry({
@@ -7862,25 +8118,96 @@ function ResourceTimelineChart({
7862
8118
  width: layoutItem.width,
7863
8119
  height: layoutItem.height
7864
8120
  }, layoutItem.laneIndex, laneCount);
7865
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8121
+ const overlayStartDate = isDraggingItem ? preview.startDate : layoutItem.startDate;
8122
+ const overlayEndDate = isDraggingItem ? preview.endDate : layoutItem.endDate;
8123
+ const weekendOverlaySegments = businessDays ? getWeekendOverlaySegments(overlayStartDate, overlayEndDate, dayWidth, weekendPredicate) : [];
8124
+ const conflictOverlaySegments = getRangeOverlaySegments(
8125
+ overlayStartDate,
8126
+ isDraggingItem ? [] : layoutItem.conflictRanges,
8127
+ dayWidth
8128
+ );
8129
+ const durationValue = getDurationValue(
8130
+ overlayStartDate,
8131
+ overlayEndDate,
8132
+ businessDays,
8133
+ weekendPredicate
8134
+ );
8135
+ const renderContext = {
8136
+ startDate: overlayStartDate,
8137
+ endDate: overlayEndDate,
8138
+ durationDays: durationValue,
8139
+ isDragging: isDraggingItem
8140
+ };
8141
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
7866
8142
  "div",
7867
8143
  {
7868
8144
  className,
7869
8145
  "data-resource-item-id": layoutItem.itemId,
7870
8146
  onMouseDown: (event) => startDrag(event, layoutItem),
8147
+ onClick: () => onResourceItemClick?.(layoutItem.item),
8148
+ onKeyDown: (event) => {
8149
+ if (!onResourceItemClick) {
8150
+ return;
8151
+ }
8152
+ if (event.key === "Enter" || event.key === " ") {
8153
+ event.preventDefault();
8154
+ onResourceItemClick(layoutItem.item);
8155
+ }
8156
+ },
8157
+ role: onResourceItemClick ? "button" : void 0,
8158
+ tabIndex: onResourceItemClick ? 0 : void 0,
7871
8159
  style: {
7872
8160
  left: `${itemGeometry.left}px`,
7873
8161
  top: `${itemGeometry.top}px`,
7874
- ...previewStyle,
7875
8162
  width: `${itemGeometry.width}px`,
7876
8163
  height: `${itemGeometry.height}px`,
8164
+ ...previewStyle,
7877
8165
  backgroundColor: layoutItem.item.color ?? "var(--gantt-task-bar-default-color, #3b82f6)"
7878
8166
  },
7879
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "gantt-resourceTimeline-itemInner", children: renderItem ? renderItem(layoutItem.item) : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
7880
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "gantt-resourceTimeline-itemTitle", children: layoutItem.item.title }),
7881
- layoutItem.item.subtitle && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "gantt-resourceTimeline-itemSubtitle", children: layoutItem.item.subtitle }),
7882
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "gantt-resourceTimeline-itemDates", children: formatDateRangeLabel(layoutItem.startDate, layoutItem.endDate) })
7883
- ] }) })
8167
+ children: [
8168
+ !readonly && !layoutItem.item.locked && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
8169
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "gantt-resourceTimeline-resizeHandle gantt-resourceTimeline-resizeHandleStart" }),
8170
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "gantt-resourceTimeline-resizeHandle gantt-resourceTimeline-resizeHandleEnd" })
8171
+ ] }),
8172
+ weekendOverlaySegments.map((segment, index) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8173
+ "span",
8174
+ {
8175
+ className: "gantt-resourceTimeline-weekendOverlay",
8176
+ "data-resource-weekend-overlay": "true",
8177
+ style: {
8178
+ left: `${segment.left}px`,
8179
+ width: `${segment.width}px`
8180
+ }
8181
+ },
8182
+ `weekend-overlay-${index}`
8183
+ )),
8184
+ conflictOverlaySegments.map((segment, index) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8185
+ "span",
8186
+ {
8187
+ className: "gantt-resourceTimeline-conflictOverlay",
8188
+ "data-resource-conflict-overlay": "true",
8189
+ style: {
8190
+ left: `${segment.left}px`,
8191
+ width: `${segment.width}px`
8192
+ }
8193
+ },
8194
+ `conflict-overlay-${index}`
8195
+ )),
8196
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "gantt-resourceTimeline-itemInner", children: renderItem ? renderItem(layoutItem.item, renderContext) : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "gantt-resourceTimeline-defaultItemContent", children: [
8197
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "gantt-resourceTimeline-defaultItemMain", children: [
8198
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8199
+ "span",
8200
+ {
8201
+ className: "gantt-resourceTimeline-itemDurationChip",
8202
+ "aria-label": `${durationValue} \u0434`,
8203
+ children: durationValue
8204
+ }
8205
+ ),
8206
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "gantt-resourceTimeline-itemTitle", children: layoutItem.item.title })
8207
+ ] }),
8208
+ layoutItem.item.subtitle && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "gantt-resourceTimeline-itemSubtitle", children: layoutItem.item.subtitle })
8209
+ ] }) })
8210
+ ]
7884
8211
  },
7885
8212
  layoutItem.itemId
7886
8213
  );