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.mjs CHANGED
@@ -7305,12 +7305,86 @@ var compareParsedItems = (a, b) => {
7305
7305
  }
7306
7306
  return a.item.id.localeCompare(b.item.id);
7307
7307
  };
7308
+ var getOverlapRange = (left, right) => {
7309
+ const startDay = Math.max(getUTCDayNumber(left.startDate), getUTCDayNumber(right.startDate));
7310
+ const endDay = Math.min(getUTCDayNumber(left.endDate), getUTCDayNumber(right.endDate));
7311
+ if (startDay > endDay) {
7312
+ return null;
7313
+ }
7314
+ return {
7315
+ startDate: new Date(startDay * 864e5),
7316
+ endDate: new Date(endDay * 864e5),
7317
+ itemIds: [left.item.id, right.item.id]
7318
+ };
7319
+ };
7320
+ var mergeConflictRanges = (ranges) => {
7321
+ const sortedRanges = [...ranges].sort(
7322
+ (left, right) => getUTCDayNumber(left.startDate) - getUTCDayNumber(right.startDate) || getUTCDayNumber(left.endDate) - getUTCDayNumber(right.endDate)
7323
+ );
7324
+ const merged = [];
7325
+ for (const range of sortedRanges) {
7326
+ const previous = merged[merged.length - 1];
7327
+ const rangeStartDay = getUTCDayNumber(range.startDate);
7328
+ const rangeEndDay = getUTCDayNumber(range.endDate);
7329
+ if (!previous || rangeStartDay > getUTCDayNumber(previous.endDate) + 1) {
7330
+ merged.push({
7331
+ startDate: range.startDate,
7332
+ endDate: range.endDate,
7333
+ itemIds: [...range.itemIds]
7334
+ });
7335
+ continue;
7336
+ }
7337
+ if (rangeEndDay > getUTCDayNumber(previous.endDate)) {
7338
+ previous.endDate = range.endDate;
7339
+ }
7340
+ previous.itemIds = Array.from(/* @__PURE__ */ new Set([...previous.itemIds, ...range.itemIds])).sort();
7341
+ }
7342
+ return merged;
7343
+ };
7344
+ var calculateConflictInfo = (parsedItems) => {
7345
+ const conflictRangesByItemId = /* @__PURE__ */ new Map();
7346
+ const conflictsWithByItemId = /* @__PURE__ */ new Map();
7347
+ for (let i = 0; i < parsedItems.length; i++) {
7348
+ for (let j = i + 1; j < parsedItems.length; j++) {
7349
+ const left = parsedItems[i];
7350
+ const right = parsedItems[j];
7351
+ if (getUTCDayNumber(right.startDate) > getUTCDayNumber(left.endDate)) {
7352
+ break;
7353
+ }
7354
+ const overlap = getOverlapRange(left, right);
7355
+ if (!overlap) {
7356
+ continue;
7357
+ }
7358
+ const leftRanges = conflictRangesByItemId.get(left.item.id) ?? [];
7359
+ const rightRanges = conflictRangesByItemId.get(right.item.id) ?? [];
7360
+ leftRanges.push(overlap);
7361
+ rightRanges.push(overlap);
7362
+ conflictRangesByItemId.set(left.item.id, leftRanges);
7363
+ conflictRangesByItemId.set(right.item.id, rightRanges);
7364
+ const leftConflicts = conflictsWithByItemId.get(left.item.id) ?? /* @__PURE__ */ new Set();
7365
+ const rightConflicts = conflictsWithByItemId.get(right.item.id) ?? /* @__PURE__ */ new Set();
7366
+ leftConflicts.add(right.item.id);
7367
+ rightConflicts.add(left.item.id);
7368
+ conflictsWithByItemId.set(left.item.id, leftConflicts);
7369
+ conflictsWithByItemId.set(right.item.id, rightConflicts);
7370
+ }
7371
+ }
7372
+ const result = /* @__PURE__ */ new Map();
7373
+ for (const parsedItem of parsedItems) {
7374
+ result.set(parsedItem.item.id, {
7375
+ conflictRanges: mergeConflictRanges(conflictRangesByItemId.get(parsedItem.item.id) ?? []),
7376
+ conflictsWith: Array.from(conflictsWithByItemId.get(parsedItem.item.id) ?? []).sort()
7377
+ });
7378
+ }
7379
+ return result;
7380
+ };
7308
7381
  var layoutResourceTimelineItems = (resources, options) => {
7309
7382
  const rows = [];
7310
7383
  const items = [];
7311
7384
  const diagnostics = [];
7312
7385
  let currentTop = 0;
7313
- for (const resource of resources) {
7386
+ const rowGap = options.rowGap ?? 0;
7387
+ resources.forEach((resource, resourceIndex) => {
7314
7388
  const parsedItems = [];
7315
7389
  for (const item of resource.items) {
7316
7390
  try {
@@ -7329,6 +7403,7 @@ var layoutResourceTimelineItems = (resources, options) => {
7329
7403
  }
7330
7404
  }
7331
7405
  parsedItems.sort(compareParsedItems);
7406
+ const conflictInfoByItemId = calculateConflictInfo(parsedItems);
7332
7407
  const laneEndDays = [];
7333
7408
  const laidOutItems = [];
7334
7409
  for (const parsed of parsedItems) {
@@ -7342,6 +7417,7 @@ var layoutResourceTimelineItems = (resources, options) => {
7342
7417
  laneEndDays[laneIndex] = endDay;
7343
7418
  }
7344
7419
  const { left, width } = calculateTaskBar(parsed.startDate, parsed.endDate, options.monthStart, options.dayWidth);
7420
+ const conflictInfo = conflictInfoByItemId.get(parsed.item.id);
7345
7421
  laidOutItems.push({
7346
7422
  item: parsed.item,
7347
7423
  itemId: parsed.item.id,
@@ -7354,15 +7430,19 @@ var layoutResourceTimelineItems = (resources, options) => {
7354
7430
  top: currentTop + laneIndex * options.laneHeight,
7355
7431
  height: options.laneHeight,
7356
7432
  startDate: parsed.startDate,
7357
- endDate: parsed.endDate
7433
+ endDate: parsed.endDate,
7434
+ conflictRanges: conflictInfo?.conflictRanges ?? [],
7435
+ conflictsWith: conflictInfo?.conflictsWith ?? []
7358
7436
  });
7359
7437
  }
7360
7438
  const laneCount = Math.max(1, laneEndDays.length);
7361
7439
  const resourceRowHeight = laneCount * options.laneHeight;
7440
+ const conflictCount = laidOutItems.filter((item) => item.conflictsWith.length > 0).length;
7362
7441
  const row = {
7363
7442
  resource,
7364
7443
  resourceId: resource.id,
7365
7444
  laneCount,
7445
+ conflictCount,
7366
7446
  resourceRowTop: currentTop,
7367
7447
  resourceRowHeight
7368
7448
  };
@@ -7371,8 +7451,8 @@ var layoutResourceTimelineItems = (resources, options) => {
7371
7451
  ...item,
7372
7452
  resourceRowHeight
7373
7453
  })));
7374
- currentTop += resourceRowHeight;
7375
- }
7454
+ currentTop += resourceRowHeight + rowGap;
7455
+ });
7376
7456
  return {
7377
7457
  rows,
7378
7458
  items,
@@ -7389,6 +7469,56 @@ var snapToDay = (pixels, dayWidth) => {
7389
7469
  var addUTCDays = (date, days) => {
7390
7470
  return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate() + days));
7391
7471
  };
7472
+ var getDayOffset2 = (date, monthStart) => {
7473
+ return Math.round(
7474
+ (Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()) - Date.UTC(monthStart.getUTCFullYear(), monthStart.getUTCMonth(), monthStart.getUTCDate())) / (24 * 60 * 60 * 1e3)
7475
+ );
7476
+ };
7477
+ var resolveResourceMoveRange = (activeDrag, nextLeft, nextWidth) => {
7478
+ const dayOffset = Math.round(nextLeft / activeDrag.dayWidth);
7479
+ const durationDays = Math.round(nextWidth / activeDrag.dayWidth);
7480
+ const rawStartDate = addUTCDays(activeDrag.monthStart, dayOffset);
7481
+ const rawEndDate = addUTCDays(rawStartDate, durationDays - 1);
7482
+ if (!activeDrag.businessDays || !activeDrag.weekendPredicate) {
7483
+ return {
7484
+ startDate: rawStartDate,
7485
+ endDate: rawEndDate,
7486
+ left: nextLeft,
7487
+ width: nextWidth
7488
+ };
7489
+ }
7490
+ const range = (() => {
7491
+ if (activeDrag.mode === "resize-start") {
7492
+ const snapDirection2 = rawStartDate.getTime() >= activeDrag.startDate.getTime() ? 1 : -1;
7493
+ const duration = getBusinessDaysCount(rawStartDate, activeDrag.endDate, activeDrag.weekendPredicate);
7494
+ return buildTaskRangeFromEnd(activeDrag.endDate, duration, true, activeDrag.weekendPredicate, snapDirection2);
7495
+ }
7496
+ if (activeDrag.mode === "resize-end") {
7497
+ const snapDirection2 = rawEndDate.getTime() >= activeDrag.endDate.getTime() ? 1 : -1;
7498
+ const duration = getBusinessDaysCount(activeDrag.startDate, rawEndDate, activeDrag.weekendPredicate);
7499
+ return buildTaskRangeFromStart(activeDrag.startDate, duration, true, activeDrag.weekendPredicate, snapDirection2);
7500
+ }
7501
+ const dayDelta = Math.round((nextLeft - activeDrag.initialLeft) / activeDrag.dayWidth);
7502
+ const proposedStartDate = addUTCDays(activeDrag.startDate, dayDelta);
7503
+ const snapDirection = proposedStartDate.getTime() >= activeDrag.startDate.getTime() ? 1 : -1;
7504
+ return moveTaskRange(
7505
+ activeDrag.startDate,
7506
+ activeDrag.endDate,
7507
+ proposedStartDate,
7508
+ true,
7509
+ activeDrag.weekendPredicate,
7510
+ snapDirection
7511
+ );
7512
+ })();
7513
+ const startOffset = getDayOffset2(range.start, activeDrag.monthStart);
7514
+ const endOffset = getDayOffset2(range.end, activeDrag.monthStart);
7515
+ return {
7516
+ startDate: range.start,
7517
+ endDate: range.end,
7518
+ left: Math.round(startOffset * activeDrag.dayWidth),
7519
+ width: Math.round((endOffset - startOffset + 1) * activeDrag.dayWidth)
7520
+ };
7521
+ };
7392
7522
  var resolveTargetResource = (rows, clientY, gridTop) => {
7393
7523
  const localY = clientY - gridTop;
7394
7524
  return rows.find(
@@ -7397,10 +7527,13 @@ var resolveTargetResource = (rows, clientY, gridTop) => {
7397
7527
  };
7398
7528
  var useResourceItemDrag = ({
7399
7529
  dayWidth,
7530
+ monthStart,
7400
7531
  rows,
7401
7532
  gridElementRef,
7402
7533
  readonly,
7403
7534
  disableResourceReassignment,
7535
+ businessDays = false,
7536
+ weekendPredicate,
7404
7537
  onResourceItemMove
7405
7538
  }) => {
7406
7539
  const activeDragRef = useRef7(null);
@@ -7437,14 +7570,30 @@ var useResourceItemDrag = ({
7437
7570
  if (!latestDrag) {
7438
7571
  return;
7439
7572
  }
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;
7573
+ const snappedDelta = snapToDay(event.clientX - latestDrag.startX, latestDrag.dayWidth);
7574
+ const rightEdge = latestDrag.initialLeft + latestDrag.initialWidth;
7575
+ const nextGeometry = (() => {
7576
+ if (latestDrag.mode === "resize-start") {
7577
+ const left = Math.min(latestDrag.initialLeft + snappedDelta, rightEdge - latestDrag.dayWidth);
7578
+ return { left, width: rightEdge - left };
7579
+ }
7580
+ if (latestDrag.mode === "resize-end") {
7581
+ return { left: latestDrag.initialLeft, width: Math.max(latestDrag.dayWidth, latestDrag.initialWidth + snappedDelta) };
7582
+ }
7583
+ return { left: latestDrag.initialLeft + snappedDelta, width: latestDrag.initialWidth };
7584
+ })();
7585
+ const nextRange = resolveResourceMoveRange(latestDrag, nextGeometry.left, nextGeometry.width);
7586
+ const nextTop = disableResourceReassignment || latestDrag.mode !== "move" ? latestDrag.initialTop : latestDrag.initialTop + (event.clientY - latestDrag.startY);
7587
+ latestDrag.currentLeft = nextRange.left;
7588
+ latestDrag.currentWidth = nextRange.width;
7443
7589
  latestDrag.currentTop = nextTop;
7444
7590
  setPreview({
7445
7591
  itemId: latestDrag.itemId,
7446
- left: nextLeft,
7447
- top: nextTop
7592
+ left: nextRange.left,
7593
+ top: nextTop,
7594
+ width: nextRange.width,
7595
+ startDate: nextRange.startDate,
7596
+ endDate: nextRange.endDate
7448
7597
  });
7449
7598
  });
7450
7599
  };
@@ -7457,18 +7606,20 @@ var useResourceItemDrag = ({
7457
7606
  activeDragRef.current = null;
7458
7607
  setPreview(null);
7459
7608
  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);
7609
+ const targetResource = disableResourceReassignment || activeDrag.mode !== "move" ? rowsRef.current.find((row) => row.resourceId === activeDrag.fromResourceId)?.resource ?? null : resolveTargetResource(rowsRef.current, event.clientY, gridTop);
7461
7610
  if (!targetResource) {
7462
7611
  return;
7463
7612
  }
7464
- const dayDelta = Math.round((activeDrag.currentLeft - activeDrag.initialLeft) / activeDrag.dayWidth);
7613
+ const nextRange = resolveResourceMoveRange(activeDrag, activeDrag.currentLeft, activeDrag.currentWidth);
7465
7614
  onResourceItemMoveRef.current?.({
7466
7615
  item: activeDrag.item,
7467
7616
  itemId: activeDrag.itemId,
7617
+ taskId: activeDrag.item.taskId,
7468
7618
  fromResourceId: activeDrag.fromResourceId,
7469
7619
  toResourceId: targetResource.id,
7470
- startDate: addUTCDays(activeDrag.startDate, dayDelta),
7471
- endDate: addUTCDays(activeDrag.endDate, dayDelta)
7620
+ startDate: nextRange.startDate,
7621
+ endDate: nextRange.endDate,
7622
+ changeType: activeDrag.mode
7472
7623
  });
7473
7624
  };
7474
7625
  window.addEventListener("mousemove", handleMouseMove);
@@ -7483,27 +7634,38 @@ var useResourceItemDrag = ({
7483
7634
  if (readonly || layoutItem.item.locked || event.button !== 0) {
7484
7635
  return;
7485
7636
  }
7637
+ const target = event.target;
7638
+ const mode = target.closest(".gantt-resourceTimeline-resizeHandleStart") ? "resize-start" : target.closest(".gantt-resourceTimeline-resizeHandleEnd") ? "resize-end" : "move";
7486
7639
  event.preventDefault();
7487
7640
  activeDragRef.current = {
7488
7641
  item: layoutItem.item,
7489
7642
  itemId: layoutItem.itemId,
7643
+ mode,
7490
7644
  fromResourceId: layoutItem.resourceId,
7491
7645
  startX: event.clientX,
7492
7646
  startY: event.clientY,
7493
7647
  initialLeft: layoutItem.left,
7494
7648
  initialTop: layoutItem.top,
7649
+ initialWidth: layoutItem.width,
7495
7650
  currentLeft: layoutItem.left,
7496
7651
  currentTop: layoutItem.top,
7652
+ currentWidth: layoutItem.width,
7497
7653
  dayWidth,
7498
7654
  startDate: layoutItem.startDate,
7499
- endDate: layoutItem.endDate
7655
+ endDate: layoutItem.endDate,
7656
+ monthStart,
7657
+ businessDays,
7658
+ weekendPredicate
7500
7659
  };
7501
7660
  setPreview({
7502
7661
  itemId: layoutItem.itemId,
7503
7662
  left: layoutItem.left,
7504
- top: layoutItem.top
7663
+ top: layoutItem.top,
7664
+ width: layoutItem.width,
7665
+ startDate: layoutItem.startDate,
7666
+ endDate: layoutItem.endDate
7505
7667
  });
7506
- }, [dayWidth, readonly]);
7668
+ }, [businessDays, dayWidth, monthStart, readonly, weekendPredicate]);
7507
7669
  return {
7508
7670
  preview,
7509
7671
  startDrag,
@@ -7517,6 +7679,7 @@ var DEFAULT_DAY_WIDTH = 40;
7517
7679
  var DEFAULT_HEADER_HEIGHT = 40;
7518
7680
  var DEFAULT_LANE_HEIGHT = 40;
7519
7681
  var DEFAULT_ROW_HEADER_WIDTH = 240;
7682
+ var DEFAULT_RESOURCE_ROW_GAP = 8;
7520
7683
  var ITEM_OUTER_VERTICAL_INSET = 2;
7521
7684
  var ITEM_INNER_VERTICAL_INSET = 1;
7522
7685
  var ITEM_HORIZONTAL_INSET = 1;
@@ -7576,16 +7739,64 @@ var getVisualItemGeometry = (geometry, laneIndex, laneCount) => {
7576
7739
  height: Math.max(0, geometry.height - topInset - bottomInset)
7577
7740
  };
7578
7741
  };
7742
+ var getWeekendOverlaySegments = (startDate, endDate, dayWidth, weekendPredicate) => {
7743
+ const segments2 = [];
7744
+ const current = new Date(Date.UTC(startDate.getUTCFullYear(), startDate.getUTCMonth(), startDate.getUTCDate()));
7745
+ let activeStartOffset = null;
7746
+ let offset = 0;
7747
+ while (current.getTime() <= endDate.getTime()) {
7748
+ const isWeekendDay = weekendPredicate(current);
7749
+ if (isWeekendDay && activeStartOffset === null) {
7750
+ activeStartOffset = offset;
7751
+ }
7752
+ if (!isWeekendDay && activeStartOffset !== null) {
7753
+ segments2.push({
7754
+ left: Math.round(activeStartOffset * dayWidth),
7755
+ width: Math.round((offset - activeStartOffset) * dayWidth)
7756
+ });
7757
+ activeStartOffset = null;
7758
+ }
7759
+ current.setUTCDate(current.getUTCDate() + 1);
7760
+ offset += 1;
7761
+ }
7762
+ if (activeStartOffset !== null) {
7763
+ segments2.push({
7764
+ left: Math.round(activeStartOffset * dayWidth),
7765
+ width: Math.round((offset - activeStartOffset) * dayWidth)
7766
+ });
7767
+ }
7768
+ return segments2;
7769
+ };
7770
+ var getRangeOverlaySegments = (itemStartDate, ranges, dayWidth) => {
7771
+ return ranges.map((range) => {
7772
+ const startOffset = Math.max(0, Math.round(
7773
+ (Date.UTC(range.startDate.getUTCFullYear(), range.startDate.getUTCMonth(), range.startDate.getUTCDate()) - Date.UTC(itemStartDate.getUTCFullYear(), itemStartDate.getUTCMonth(), itemStartDate.getUTCDate())) / (24 * 60 * 60 * 1e3)
7774
+ ));
7775
+ const endOffset = Math.max(startOffset, Math.round(
7776
+ (Date.UTC(range.endDate.getUTCFullYear(), range.endDate.getUTCMonth(), range.endDate.getUTCDate()) - Date.UTC(itemStartDate.getUTCFullYear(), itemStartDate.getUTCMonth(), itemStartDate.getUTCDate())) / (24 * 60 * 60 * 1e3)
7777
+ ));
7778
+ return {
7779
+ left: Math.round(startOffset * dayWidth),
7780
+ width: Math.round((endOffset - startOffset + 1) * dayWidth)
7781
+ };
7782
+ });
7783
+ };
7784
+ 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);
7579
7785
  function ResourceTimelineChart({
7580
7786
  resources,
7581
7787
  dayWidth = DEFAULT_DAY_WIDTH,
7582
7788
  rowHeaderWidth = DEFAULT_ROW_HEADER_WIDTH,
7583
7789
  laneHeight = DEFAULT_LANE_HEIGHT,
7584
7790
  headerHeight = DEFAULT_HEADER_HEIGHT,
7791
+ allowVerticalPan = false,
7792
+ customDays,
7793
+ isWeekend: isWeekend3,
7794
+ businessDays = true,
7585
7795
  readonly,
7586
7796
  disableResourceReassignment,
7587
7797
  renderItem,
7588
7798
  getItemClassName,
7799
+ onResourceItemClick,
7589
7800
  onResourceItemMove
7590
7801
  }) {
7591
7802
  const scrollContainerRef = useRef8(null);
@@ -7599,9 +7810,18 @@ function ResourceTimelineChart({
7599
7810
  const firstDay = dateRange[0] ?? /* @__PURE__ */ new Date();
7600
7811
  return new Date(Date.UTC(firstDay.getUTCFullYear(), firstDay.getUTCMonth(), 1));
7601
7812
  }, [dateRange]);
7813
+ const weekendPredicate = useMemo9(
7814
+ () => createCustomDayPredicate({ customDays, isWeekend: isWeekend3 }),
7815
+ [customDays, isWeekend3]
7816
+ );
7602
7817
  const gridWidth = useMemo9(() => Math.round(dateRange.length * dayWidth), [dateRange.length, dayWidth]);
7603
7818
  const layout = useMemo9(
7604
- () => layoutResourceTimelineItems(resources, { monthStart, dayWidth, laneHeight }),
7819
+ () => layoutResourceTimelineItems(resources, {
7820
+ monthStart,
7821
+ dayWidth,
7822
+ laneHeight,
7823
+ rowGap: DEFAULT_RESOURCE_ROW_GAP
7824
+ }),
7605
7825
  [resources, monthStart, dayWidth, laneHeight]
7606
7826
  );
7607
7827
  const todayInRange = useMemo9(() => {
@@ -7620,10 +7840,13 @@ function ResourceTimelineChart({
7620
7840
  }, [layout.items]);
7621
7841
  const { preview, startDrag } = useResourceItemDrag({
7622
7842
  dayWidth,
7843
+ monthStart,
7623
7844
  rows: layout.rows,
7624
7845
  gridElementRef: gridRef,
7625
7846
  readonly,
7626
7847
  disableResourceReassignment,
7848
+ businessDays,
7849
+ weekendPredicate,
7627
7850
  onResourceItemMove
7628
7851
  });
7629
7852
  const handlePanStart = useCallback7((event) => {
@@ -7662,7 +7885,9 @@ function ResourceTimelineChart({
7662
7885
  return;
7663
7886
  }
7664
7887
  container.scrollLeft = pan.scrollX - (event.clientX - pan.startX);
7665
- container.scrollTop = pan.scrollY - (event.clientY - pan.startY);
7888
+ if (allowVerticalPan) {
7889
+ container.scrollTop = pan.scrollY - (event.clientY - pan.startY);
7890
+ }
7666
7891
  };
7667
7892
  const handlePanEnd = () => {
7668
7893
  if (!panStateRef.current?.active) {
@@ -7680,13 +7905,14 @@ function ResourceTimelineChart({
7680
7905
  window.removeEventListener("mousemove", handlePanMove);
7681
7906
  window.removeEventListener("mouseup", handlePanEnd);
7682
7907
  };
7683
- }, []);
7908
+ }, [allowVerticalPan]);
7684
7909
  return /* @__PURE__ */ jsx15("div", { className: "gantt-container gantt-resourceTimeline", children: /* @__PURE__ */ jsx15(
7685
7910
  "div",
7686
7911
  {
7687
7912
  ref: scrollContainerRef,
7688
7913
  className: "gantt-resourceTimeline-scrollContainer",
7689
7914
  style: { cursor: "grab" },
7915
+ "data-allow-vertical-pan": allowVerticalPan ? "true" : "false",
7690
7916
  onMouseDown: handlePanStart,
7691
7917
  children: /* @__PURE__ */ jsxs12("div", { className: "gantt-resourceTimeline-scrollContent", children: [
7692
7918
  /* @__PURE__ */ jsxs12(
@@ -7702,13 +7928,26 @@ function ResourceTimelineChart({
7702
7928
  style: { height: `${headerHeight}px` }
7703
7929
  }
7704
7930
  ),
7705
- layout.rows.map((row) => /* @__PURE__ */ jsx15(
7931
+ layout.rows.map((row) => /* @__PURE__ */ jsxs12(
7706
7932
  "div",
7707
7933
  {
7708
7934
  className: "gantt-resourceTimeline-resourceHeader",
7709
7935
  "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 })
7936
+ style: {
7937
+ height: `${row.resourceRowHeight + DEFAULT_RESOURCE_ROW_GAP}px`,
7938
+ paddingBottom: `${DEFAULT_RESOURCE_ROW_GAP}px`
7939
+ },
7940
+ children: [
7941
+ /* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-resourceName", children: row.resource.name }),
7942
+ row.conflictCount > 0 && /* @__PURE__ */ jsx15(
7943
+ "span",
7944
+ {
7945
+ className: "gantt-resourceTimeline-conflictBadge",
7946
+ "aria-label": `${row.conflictCount} \u043A\u043E\u043D\u0444\u043B\u0438\u043A\u0442\u043E\u0432`,
7947
+ children: row.conflictCount
7948
+ }
7949
+ )
7950
+ ]
7712
7951
  },
7713
7952
  row.resourceId
7714
7953
  ))
@@ -7721,7 +7960,15 @@ function ResourceTimelineChart({
7721
7960
  className: "gantt-resourceTimeline-chartSurface",
7722
7961
  style: { minWidth: `${gridWidth}px` },
7723
7962
  children: [
7724
- /* @__PURE__ */ jsx15("div", { className: "gantt-resourceTimeline-stickyHeader", style: { width: `${gridWidth}px` }, children: /* @__PURE__ */ jsx15(TimeScaleHeader_default, { days: dateRange, dayWidth, headerHeight }) }),
7963
+ /* @__PURE__ */ jsx15("div", { className: "gantt-resourceTimeline-stickyHeader", style: { width: `${gridWidth}px` }, children: /* @__PURE__ */ jsx15(
7964
+ TimeScaleHeader_default,
7965
+ {
7966
+ days: dateRange,
7967
+ dayWidth,
7968
+ headerHeight,
7969
+ isCustomWeekend: weekendPredicate
7970
+ }
7971
+ ) }),
7725
7972
  /* @__PURE__ */ jsxs12(
7726
7973
  "div",
7727
7974
  {
@@ -7729,7 +7976,15 @@ function ResourceTimelineChart({
7729
7976
  className: "gantt-resourceTimeline-grid",
7730
7977
  style: { width: `${gridWidth}px`, height: `${layout.totalHeight}px` },
7731
7978
  children: [
7732
- /* @__PURE__ */ jsx15(GridBackground_default, { dateRange, dayWidth, totalHeight: layout.totalHeight }),
7979
+ /* @__PURE__ */ jsx15(
7980
+ GridBackground_default,
7981
+ {
7982
+ dateRange,
7983
+ dayWidth,
7984
+ totalHeight: layout.totalHeight,
7985
+ isCustomWeekend: weekendPredicate
7986
+ }
7987
+ ),
7733
7988
  todayInRange && /* @__PURE__ */ jsx15(TodayIndicator_default, { monthStart, dayWidth }),
7734
7989
  layout.rows.map((row) => /* @__PURE__ */ jsx15(
7735
7990
  "div",
@@ -7738,7 +7993,7 @@ function ResourceTimelineChart({
7738
7993
  "data-resource-row-id": row.resourceId,
7739
7994
  style: {
7740
7995
  top: `${row.resourceRowTop}px`,
7741
- height: `${row.resourceRowHeight}px`
7996
+ height: `${row.resourceRowHeight + DEFAULT_RESOURCE_ROW_GAP}px`
7742
7997
  }
7743
7998
  },
7744
7999
  row.resourceId
@@ -7746,17 +8001,18 @@ function ResourceTimelineChart({
7746
8001
  Array.from(itemsByResourceId.values()).flatMap(
7747
8002
  (resourceItems) => resourceItems.map((layoutItem) => {
7748
8003
  const customClassName = getItemClassName?.(layoutItem.item);
8004
+ const isDraggingItem = preview?.itemId === layoutItem.itemId;
7749
8005
  const className = [
7750
8006
  "gantt-resourceTimeline-item",
7751
- preview?.itemId === layoutItem.itemId && "gantt-resourceTimeline-itemDragging",
8007
+ isDraggingItem && "gantt-resourceTimeline-itemDragging",
7752
8008
  (readonly || layoutItem.item.locked) && "gantt-resourceTimeline-itemDisabled",
7753
8009
  customClassName
7754
8010
  ].filter(Boolean).join(" ");
7755
8011
  const laneCount = Math.max(1, Math.round(layoutItem.resourceRowHeight / layoutItem.height));
7756
- const previewStyle = preview?.itemId === layoutItem.itemId ? getVisualItemGeometry({
8012
+ const previewStyle = isDraggingItem ? getVisualItemGeometry({
7757
8013
  left: preview.left,
7758
8014
  top: preview.top,
7759
- width: layoutItem.width,
8015
+ width: preview.width,
7760
8016
  height: layoutItem.height
7761
8017
  }, layoutItem.laneIndex, laneCount) : void 0;
7762
8018
  const itemGeometry = getVisualItemGeometry({
@@ -7765,25 +8021,96 @@ function ResourceTimelineChart({
7765
8021
  width: layoutItem.width,
7766
8022
  height: layoutItem.height
7767
8023
  }, layoutItem.laneIndex, laneCount);
7768
- return /* @__PURE__ */ jsx15(
8024
+ const overlayStartDate = isDraggingItem ? preview.startDate : layoutItem.startDate;
8025
+ const overlayEndDate = isDraggingItem ? preview.endDate : layoutItem.endDate;
8026
+ const weekendOverlaySegments = businessDays ? getWeekendOverlaySegments(overlayStartDate, overlayEndDate, dayWidth, weekendPredicate) : [];
8027
+ const conflictOverlaySegments = getRangeOverlaySegments(
8028
+ overlayStartDate,
8029
+ isDraggingItem ? [] : layoutItem.conflictRanges,
8030
+ dayWidth
8031
+ );
8032
+ const durationValue = getDurationValue(
8033
+ overlayStartDate,
8034
+ overlayEndDate,
8035
+ businessDays,
8036
+ weekendPredicate
8037
+ );
8038
+ const renderContext = {
8039
+ startDate: overlayStartDate,
8040
+ endDate: overlayEndDate,
8041
+ durationDays: durationValue,
8042
+ isDragging: isDraggingItem
8043
+ };
8044
+ return /* @__PURE__ */ jsxs12(
7769
8045
  "div",
7770
8046
  {
7771
8047
  className,
7772
8048
  "data-resource-item-id": layoutItem.itemId,
7773
8049
  onMouseDown: (event) => startDrag(event, layoutItem),
8050
+ onClick: () => onResourceItemClick?.(layoutItem.item),
8051
+ onKeyDown: (event) => {
8052
+ if (!onResourceItemClick) {
8053
+ return;
8054
+ }
8055
+ if (event.key === "Enter" || event.key === " ") {
8056
+ event.preventDefault();
8057
+ onResourceItemClick(layoutItem.item);
8058
+ }
8059
+ },
8060
+ role: onResourceItemClick ? "button" : void 0,
8061
+ tabIndex: onResourceItemClick ? 0 : void 0,
7774
8062
  style: {
7775
8063
  left: `${itemGeometry.left}px`,
7776
8064
  top: `${itemGeometry.top}px`,
7777
- ...previewStyle,
7778
8065
  width: `${itemGeometry.width}px`,
7779
8066
  height: `${itemGeometry.height}px`,
8067
+ ...previewStyle,
7780
8068
  backgroundColor: layoutItem.item.color ?? "var(--gantt-task-bar-default-color, #3b82f6)"
7781
8069
  },
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
- ] }) })
8070
+ children: [
8071
+ !readonly && !layoutItem.item.locked && /* @__PURE__ */ jsxs12(Fragment3, { children: [
8072
+ /* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-resizeHandle gantt-resourceTimeline-resizeHandleStart" }),
8073
+ /* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-resizeHandle gantt-resourceTimeline-resizeHandleEnd" })
8074
+ ] }),
8075
+ weekendOverlaySegments.map((segment, index) => /* @__PURE__ */ jsx15(
8076
+ "span",
8077
+ {
8078
+ className: "gantt-resourceTimeline-weekendOverlay",
8079
+ "data-resource-weekend-overlay": "true",
8080
+ style: {
8081
+ left: `${segment.left}px`,
8082
+ width: `${segment.width}px`
8083
+ }
8084
+ },
8085
+ `weekend-overlay-${index}`
8086
+ )),
8087
+ conflictOverlaySegments.map((segment, index) => /* @__PURE__ */ jsx15(
8088
+ "span",
8089
+ {
8090
+ className: "gantt-resourceTimeline-conflictOverlay",
8091
+ "data-resource-conflict-overlay": "true",
8092
+ style: {
8093
+ left: `${segment.left}px`,
8094
+ width: `${segment.width}px`
8095
+ }
8096
+ },
8097
+ `conflict-overlay-${index}`
8098
+ )),
8099
+ /* @__PURE__ */ jsx15("div", { className: "gantt-resourceTimeline-itemInner", children: renderItem ? renderItem(layoutItem.item, renderContext) : /* @__PURE__ */ jsxs12("div", { className: "gantt-resourceTimeline-defaultItemContent", children: [
8100
+ /* @__PURE__ */ jsxs12("div", { className: "gantt-resourceTimeline-defaultItemMain", children: [
8101
+ /* @__PURE__ */ jsx15(
8102
+ "span",
8103
+ {
8104
+ className: "gantt-resourceTimeline-itemDurationChip",
8105
+ "aria-label": `${durationValue} \u0434`,
8106
+ children: durationValue
8107
+ }
8108
+ ),
8109
+ /* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-itemTitle", children: layoutItem.item.title })
8110
+ ] }),
8111
+ layoutItem.item.subtitle && /* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-itemSubtitle", children: layoutItem.item.subtitle })
8112
+ ] }) })
8113
+ ]
7787
8114
  },
7788
8115
  layoutItem.itemId
7789
8116
  );