@underverse-ui/underverse 0.2.98 → 0.2.100

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.cjs CHANGED
@@ -8121,6 +8121,22 @@ function startOfZonedDay(date, timeZone) {
8121
8121
  const p = getZonedParts(date, timeZone);
8122
8122
  return new Date(zonedTimeToUtcMs({ ...p, hour: 0, minute: 0, second: 0 }, timeZone));
8123
8123
  }
8124
+ function zonedDateAtTime(date, timeZone, time) {
8125
+ const p = getZonedParts(date, timeZone);
8126
+ return new Date(
8127
+ zonedTimeToUtcMs(
8128
+ {
8129
+ year: p.year,
8130
+ month: p.month,
8131
+ day: p.day,
8132
+ hour: time.hour,
8133
+ minute: time.minute ?? 0,
8134
+ second: time.second ?? 0
8135
+ },
8136
+ timeZone
8137
+ )
8138
+ );
8139
+ }
8124
8140
  function startOfZonedMonth(date, timeZone) {
8125
8141
  const p = getZonedParts(date, timeZone);
8126
8142
  return new Date(zonedTimeToUtcMs({ year: p.year, month: p.month, day: 1, hour: 0, minute: 0, second: 0 }, timeZone));
@@ -8429,17 +8445,24 @@ function getGroupResourceCounts(resources) {
8429
8445
  return counts;
8430
8446
  }
8431
8447
  function computeSlotStarts(args) {
8432
- const { view, date, timeZone, weekStartsOn, dayTimeStepMinutes } = args;
8433
- const start = view === "month" ? startOfZonedMonth(date, timeZone) : view === "week" ? startOfZonedWeek(date, weekStartsOn, timeZone) : startOfZonedDay(date, timeZone);
8448
+ const { view, date, timeZone, weekStartsOn, dayTimeStepMinutes, dayRangeMode, workHours } = args;
8449
+ const baseDayStart = startOfZonedDay(date, timeZone);
8450
+ const start = view === "month" ? startOfZonedMonth(date, timeZone) : view === "week" ? startOfZonedWeek(date, weekStartsOn, timeZone) : baseDayStart;
8434
8451
  if (view === "day") {
8435
8452
  const step = Math.max(5, Math.min(240, Math.trunc(dayTimeStepMinutes)));
8436
8453
  const stepMs = step * 6e4;
8437
- const end2 = addZonedDays(start, 1, timeZone);
8454
+ const hours = workHours ?? { startHour: 8, endHour: 17 };
8455
+ const boundedStartHour = clamp3(Math.trunc(hours.startHour), 0, 23);
8456
+ const boundedEndHour = clamp3(Math.trunc(hours.endHour), 1, 24);
8457
+ const isWork = dayRangeMode === "work";
8458
+ const start2 = isWork ? zonedDateAtTime(baseDayStart, timeZone, { hour: boundedStartHour }) : start;
8459
+ const end2 = isWork ? boundedEndHour === 24 ? addZonedDays(baseDayStart, 1, timeZone) : zonedDateAtTime(baseDayStart, timeZone, { hour: clamp3(boundedEndHour, 0, 23) }) : addZonedDays(start, 1, timeZone);
8460
+ const end3 = end2.getTime() > start2.getTime() ? end2 : addZonedDays(start2, 1, timeZone);
8438
8461
  const slotStarts2 = [];
8439
- for (let cur2 = start.getTime(), guard2 = 0; cur2 < end2.getTime() && guard2++ < 2e3; cur2 += stepMs) {
8462
+ for (let cur2 = start2.getTime(), guard2 = 0; cur2 < end3.getTime() && guard2++ < 2e3; cur2 += stepMs) {
8440
8463
  slotStarts2.push(new Date(cur2));
8441
8464
  }
8442
- return { start, end: end2, slotStarts: slotStarts2 };
8465
+ return { start: start2, end: end3, slotStarts: slotStarts2 };
8443
8466
  }
8444
8467
  const end = view === "month" ? startOfZonedMonth(addZonedMonths(start, 1, timeZone), timeZone) : addZonedDays(start, 7, timeZone);
8445
8468
  const slotStarts = [];
@@ -8736,9 +8759,12 @@ function CalendarTimeline({
8736
8759
  rowHeights,
8737
8760
  defaultRowHeights,
8738
8761
  onRowHeightsChange,
8762
+ autoRowHeight,
8739
8763
  enableLayoutResize,
8740
8764
  slotMinWidth,
8741
8765
  dayTimeStepMinutes = 60,
8766
+ dayRangeMode,
8767
+ workHours,
8742
8768
  maxLanesPerRow = 3,
8743
8769
  now,
8744
8770
  renderResource,
@@ -8786,6 +8812,10 @@ function CalendarTimeline({
8786
8812
  [isControlledEventSheetOpen, onEventSheetOpenChange, setSelectedEventId]
8787
8813
  );
8788
8814
  const sizeConfig = React28.useMemo(() => getSizeConfig(size), [size]);
8815
+ const densityClass = sizeConfig.densityClass;
8816
+ const eventHeight = sizeConfig.eventHeight;
8817
+ const laneGap = sizeConfig.laneGap;
8818
+ const lanePaddingY = sizeConfig.lanePaddingY;
8789
8819
  const canResizeColumn = React28.useMemo(() => {
8790
8820
  const cfg = enableLayoutResize;
8791
8821
  if (!cfg) return false;
@@ -8900,7 +8930,9 @@ function CalendarTimeline({
8900
8930
  date: activeDate,
8901
8931
  timeZone: resolvedTimeZone,
8902
8932
  weekStartsOn,
8903
- dayTimeStepMinutes
8933
+ dayTimeStepMinutes,
8934
+ dayRangeMode,
8935
+ workHours
8904
8936
  });
8905
8937
  const todayStart = startOfZonedDay(resolvedNow, resolvedTimeZone).getTime();
8906
8938
  const slotItems = slotStarts2.map((s) => ({
@@ -8909,7 +8941,7 @@ function CalendarTimeline({
8909
8941
  isToday: startOfZonedDay(s, resolvedTimeZone).getTime() === todayStart
8910
8942
  }));
8911
8943
  return { slots: slotItems, range: { start, end } };
8912
- }, [activeView, activeDate, resolvedTimeZone, resolvedLocale, weekStartsOn, dayTimeStepMinutes, resolvedNow, formatters]);
8944
+ }, [activeView, activeDate, resolvedTimeZone, resolvedLocale, weekStartsOn, dayTimeStepMinutes, dayRangeMode, workHours, resolvedNow, formatters]);
8913
8945
  React28.useEffect(() => {
8914
8946
  onRangeChange?.(range);
8915
8947
  }, [range.start, range.end, onRangeChange]);
@@ -8919,7 +8951,7 @@ function CalendarTimeline({
8919
8951
  const bodyClientWidth = useClientWidth(bodyRef);
8920
8952
  const slotStarts = React28.useMemo(() => slots.map((s) => s.start), [slots]);
8921
8953
  const slotWidth = React28.useMemo(() => {
8922
- const baseSlotWidth = activeView === "month" ? effectiveSlotMinWidth * 3 : effectiveSlotMinWidth;
8954
+ const baseSlotWidth = activeView === "month" ? effectiveSlotMinWidth * 3 : activeView === "day" ? effectiveSlotMinWidth * 3 : effectiveSlotMinWidth;
8923
8955
  if (activeView !== "week") return baseSlotWidth;
8924
8956
  if (bodyClientWidth <= 0) return baseSlotWidth;
8925
8957
  if (slots.length <= 0) return baseSlotWidth;
@@ -8971,13 +9003,43 @@ function CalendarTimeline({
8971
9003
  setInternalRowHeights(defaultRowHeights);
8972
9004
  }, [defaultRowHeights, isControlledRowHeights]);
8973
9005
  const activeRowHeights = isControlledRowHeights ? rowHeights : internalRowHeights;
9006
+ const autoRowHeightCfg = React28.useMemo(() => {
9007
+ if (!autoRowHeight) return null;
9008
+ return autoRowHeight === true ? {} : autoRowHeight;
9009
+ }, [autoRowHeight]);
9010
+ const effectiveMaxLanesPerRow = React28.useMemo(() => {
9011
+ if (!autoRowHeightCfg) return maxLanesPerRow;
9012
+ const maxLanes = autoRowHeightCfg.maxLanesPerRow;
9013
+ if (typeof maxLanes === "number" && Number.isFinite(maxLanes) && maxLanes > 0) return Math.floor(maxLanes);
9014
+ return Number.POSITIVE_INFINITY;
9015
+ }, [autoRowHeightCfg, maxLanesPerRow]);
9016
+ const autoRowHeightsByResource = React28.useMemo(() => {
9017
+ if (!autoRowHeightCfg) return null;
9018
+ const maxRowHeight2 = autoRowHeightCfg.maxRowHeight;
9019
+ const out = /* @__PURE__ */ new Map();
9020
+ for (const [resourceId, list] of eventsByResource.entries()) {
9021
+ const mapped = list.map((ev) => {
9022
+ const startIdx = binarySearchLastLE(slotStarts, ev._start);
9023
+ const endIdx = clamp3(binarySearchFirstGE(slotStarts, ev._end), startIdx + 1, slots.length);
9024
+ return { startIdx, endIdx };
9025
+ });
9026
+ const { laneCount } = intervalPack(mapped);
9027
+ const lanesToFit = Number.isFinite(effectiveMaxLanesPerRow) ? Math.max(1, Math.min(laneCount, effectiveMaxLanesPerRow)) : Math.max(1, laneCount);
9028
+ const needed = lanePaddingY * 2 + lanesToFit * eventHeight + laneGap * Math.max(0, lanesToFit - 1);
9029
+ const next = typeof maxRowHeight2 === "number" && Number.isFinite(maxRowHeight2) && maxRowHeight2 > 0 ? Math.min(needed, maxRowHeight2) : needed;
9030
+ out.set(resourceId, next);
9031
+ }
9032
+ return out;
9033
+ }, [autoRowHeightCfg, eventHeight, eventsByResource, laneGap, lanePaddingY, slotStarts, slots.length, effectiveMaxLanesPerRow]);
8974
9034
  const getResourceRowHeight = React28.useCallback(
8975
9035
  (resourceId) => {
8976
9036
  const h = activeRowHeights[resourceId];
8977
- if (typeof h === "number" && Number.isFinite(h) && h > 0) return h;
8978
- return effectiveRowHeight;
9037
+ const base = typeof h === "number" && Number.isFinite(h) && h > 0 ? h : effectiveRowHeight;
9038
+ const auto = autoRowHeightsByResource?.get(resourceId);
9039
+ if (typeof auto === "number" && Number.isFinite(auto) && auto > 0) return Math.max(base, auto);
9040
+ return base;
8979
9041
  },
8980
- [activeRowHeights, effectiveRowHeight]
9042
+ [activeRowHeights, autoRowHeightsByResource, effectiveRowHeight]
8981
9043
  );
8982
9044
  const setRowHeightForResource = React28.useCallback(
8983
9045
  (resourceId, height) => {
@@ -9110,10 +9172,6 @@ function CalendarTimeline({
9110
9172
  const fmt = getDtf(resolvedLocale, resolvedTimeZone, { weekday: "long", year: "numeric", month: "long", day: "numeric" });
9111
9173
  return fmt.format(range.start);
9112
9174
  }, [activeDate, activeView, formatters, l.week, range.end, range.start, resolvedLocale, resolvedTimeZone]);
9113
- const densityClass = sizeConfig.densityClass;
9114
- const eventHeight = sizeConfig.eventHeight;
9115
- const laneGap = sizeConfig.laneGap;
9116
- const lanePaddingY = sizeConfig.lanePaddingY;
9117
9175
  const createMode = interactions?.createMode ?? "drag";
9118
9176
  const canCreate = !isViewOnly && (interactions?.creatable ?? false) && !!onCreateEvent;
9119
9177
  const [createOpen, setCreateOpen] = React28.useState(false);
@@ -9180,18 +9238,33 @@ function CalendarTimeline({
9180
9238
  const dragRef = React28.useRef(null);
9181
9239
  const [preview, setPreview] = React28.useState(null);
9182
9240
  const suppressNextEventClickRef = React28.useRef(false);
9241
+ const autoScrollStateRef = React28.useRef({
9242
+ dir: 0,
9243
+ speed: 0,
9244
+ lastClientX: 0,
9245
+ lastClientY: 0
9246
+ });
9247
+ const autoScrollRafRef = React28.useRef(null);
9248
+ const stopAutoScroll = React28.useCallback(() => {
9249
+ if (autoScrollRafRef.current != null) cancelAnimationFrame(autoScrollRafRef.current);
9250
+ autoScrollRafRef.current = null;
9251
+ autoScrollStateRef.current.dir = 0;
9252
+ autoScrollStateRef.current.speed = 0;
9253
+ }, []);
9183
9254
  const getPointerContext = React28.useCallback(
9184
9255
  (clientX, clientY, opts) => {
9185
9256
  const body = bodyRef.current;
9186
9257
  if (!body) return null;
9187
- const el = document.elementFromPoint(clientX, clientY);
9188
- if (!el || !body.contains(el)) return null;
9189
9258
  const bodyRect = body.getBoundingClientRect();
9190
- const x = clientX - bodyRect.left + body.scrollLeft;
9259
+ const probeX = clamp3(clientX, bodyRect.left + 1, bodyRect.right - 1);
9260
+ const probeY = clamp3(clientY, bodyRect.top + 1, bodyRect.bottom - 1);
9261
+ const el = document.elementFromPoint(probeX, probeY);
9262
+ const x = probeX - bodyRect.left + body.scrollLeft;
9191
9263
  const epsilon = opts?.biasLeft ? 0.01 : 0;
9192
9264
  const slotIdx = clamp3(Math.floor((x - epsilon) / slotWidth), 0, Math.max(0, slots.length - 1));
9193
- const rowEl = el?.closest?.("[data-uv-ct-row]");
9194
- const rid = rowEl?.dataset?.uvCtRow ?? null;
9265
+ const rowEl = el && body.contains(el) ? el.closest?.("[data-uv-ct-row]") ?? null : null;
9266
+ const rid = rowEl?.dataset?.uvCtRow ?? opts?.fallbackResourceId ?? null;
9267
+ if (!rid) return null;
9195
9268
  return { slotIdx, resourceId: rid, x };
9196
9269
  },
9197
9270
  [slotWidth, slots.length]
@@ -9207,6 +9280,97 @@ function CalendarTimeline({
9207
9280
  },
9208
9281
  [activeView, dayTimeStepMinutes, resolvedTimeZone, slotStarts]
9209
9282
  );
9283
+ const updateDragPreview = React28.useCallback(
9284
+ (clientX, clientY) => {
9285
+ const drag = dragRef.current;
9286
+ if (!drag) return;
9287
+ const ctx = getPointerContext(clientX, clientY, drag.mode === "create" ? { biasLeft: true, fallbackResourceId: drag.resourceId } : { fallbackResourceId: drag.resourceId });
9288
+ if (!ctx) return;
9289
+ const { slotIdx } = ctx;
9290
+ const movedEnough = Math.abs(clientX - drag.startClientX) > 3 || Math.abs(clientY - drag.startClientY) > 3 || slotIdx !== drag.startSlotIdx || ctx.resourceId !== drag.startRowResourceId;
9291
+ if (movedEnough) suppressNextEventClickRef.current = true;
9292
+ if (drag.mode === "create") {
9293
+ const a = Math.min(drag.startSlotIdx, slotIdx);
9294
+ const b = Math.max(drag.startSlotIdx, slotIdx) + 1;
9295
+ const s = slotToDate(a).start;
9296
+ const e2 = b >= slots.length ? range.end : slotToDate(b).start;
9297
+ setPreview({ resourceId: drag.resourceId, start: s, end: e2 });
9298
+ return;
9299
+ }
9300
+ const targetSlotStart = slotToDate(slotIdx).start;
9301
+ const originSlotStart = slotToDate(drag.startSlotIdx).start;
9302
+ const deltaMs = targetSlotStart.getTime() - originSlotStart.getTime();
9303
+ if (drag.mode === "move") {
9304
+ const nextStart = new Date(drag.originStart.getTime() + deltaMs);
9305
+ const nextEnd = new Date(drag.originEnd.getTime() + deltaMs);
9306
+ setPreview({ eventId: drag.eventId, resourceId: ctx.resourceId, start: nextStart, end: nextEnd });
9307
+ drag.resourceId = ctx.resourceId;
9308
+ return;
9309
+ }
9310
+ if (drag.mode === "resize-start") {
9311
+ const nextStart = new Date(clamp3(targetSlotStart.getTime(), range.start.getTime(), drag.originEnd.getTime() - 6e4));
9312
+ setPreview({ eventId: drag.eventId, resourceId: drag.resourceId, start: nextStart, end: drag.originEnd });
9313
+ return;
9314
+ }
9315
+ if (drag.mode === "resize-end") {
9316
+ const nextEnd = new Date(clamp3(targetSlotStart.getTime(), drag.originStart.getTime() + 6e4, range.end.getTime()));
9317
+ setPreview({ eventId: drag.eventId, resourceId: drag.resourceId, start: drag.originStart, end: nextEnd });
9318
+ return;
9319
+ }
9320
+ },
9321
+ [getPointerContext, range.end, range.start, slotToDate, slots.length]
9322
+ );
9323
+ const autoScrollTick = React28.useCallback(() => {
9324
+ const drag = dragRef.current;
9325
+ const body = bodyRef.current;
9326
+ const st = autoScrollStateRef.current;
9327
+ if (!drag || !body || st.dir === 0) {
9328
+ stopAutoScroll();
9329
+ return;
9330
+ }
9331
+ const maxScrollLeft = Math.max(0, body.scrollWidth - body.clientWidth);
9332
+ const prevLeft = body.scrollLeft;
9333
+ const nextLeft = clamp3(prevLeft + st.dir * st.speed, 0, maxScrollLeft);
9334
+ if (nextLeft === prevLeft) {
9335
+ stopAutoScroll();
9336
+ return;
9337
+ }
9338
+ body.scrollLeft = nextLeft;
9339
+ updateDragPreview(st.lastClientX, st.lastClientY);
9340
+ autoScrollRafRef.current = requestAnimationFrame(autoScrollTick);
9341
+ }, [stopAutoScroll, updateDragPreview]);
9342
+ const updateAutoScrollFromPointer = React28.useCallback(
9343
+ (clientX, clientY) => {
9344
+ const body = bodyRef.current;
9345
+ if (!body) return;
9346
+ const rect = body.getBoundingClientRect();
9347
+ const edge = 56;
9348
+ let dir = 0;
9349
+ let speed = 0;
9350
+ if (clientX < rect.left + edge) {
9351
+ dir = -1;
9352
+ const dist = clientX - rect.left;
9353
+ const t2 = clamp3(1 - dist / edge, 0, 1);
9354
+ speed = 8 + t2 * 28;
9355
+ } else if (clientX > rect.right - edge) {
9356
+ dir = 1;
9357
+ const dist = rect.right - clientX;
9358
+ const t2 = clamp3(1 - dist / edge, 0, 1);
9359
+ speed = 8 + t2 * 28;
9360
+ }
9361
+ autoScrollStateRef.current.lastClientX = clientX;
9362
+ autoScrollStateRef.current.lastClientY = clientY;
9363
+ autoScrollStateRef.current.dir = dir;
9364
+ autoScrollStateRef.current.speed = speed;
9365
+ if (dir === 0) {
9366
+ stopAutoScroll();
9367
+ return;
9368
+ }
9369
+ if (autoScrollRafRef.current == null) autoScrollRafRef.current = requestAnimationFrame(autoScrollTick);
9370
+ },
9371
+ [autoScrollTick, stopAutoScroll]
9372
+ );
9373
+ React28.useEffect(() => stopAutoScroll, [stopAutoScroll]);
9210
9374
  const onPointerDownEvent = (e, ev, mode) => {
9211
9375
  if (e.button !== 0 || e.ctrlKey) return;
9212
9376
  if (isViewOnly) return;
@@ -9218,6 +9382,8 @@ function CalendarTimeline({
9218
9382
  suppressNextEventClickRef.current = false;
9219
9383
  const startIdx = binarySearchLastLE(slotStarts, ev._start);
9220
9384
  const endIdx = binarySearchFirstGE(slotStarts, ev._end);
9385
+ const pointerCtx = getPointerContext(e.clientX, e.clientY, { fallbackResourceId: ev.resourceId });
9386
+ const grabSlotIdx = pointerCtx?.slotIdx ?? startIdx;
9221
9387
  dragRef.current = {
9222
9388
  mode,
9223
9389
  eventId: ev.id,
@@ -9226,7 +9392,7 @@ function CalendarTimeline({
9226
9392
  originEnd: ev._end,
9227
9393
  durationMs: ev._end.getTime() - ev._start.getTime(),
9228
9394
  pointerId: e.pointerId,
9229
- startSlotIdx: startIdx,
9395
+ startSlotIdx: grabSlotIdx,
9230
9396
  startRowResourceId: ev.resourceId,
9231
9397
  startClientX: e.clientX,
9232
9398
  startClientY: e.clientY
@@ -9282,44 +9448,14 @@ function CalendarTimeline({
9282
9448
  const onPointerMove = (e) => {
9283
9449
  const drag = dragRef.current;
9284
9450
  if (!drag || drag.pointerId !== e.pointerId) return;
9285
- const ctx = getPointerContext(e.clientX, e.clientY, drag.mode === "create" ? { biasLeft: true } : void 0);
9286
- if (!ctx || !ctx.resourceId) return;
9287
- const { slotIdx } = ctx;
9288
- const movedEnough = Math.abs(e.clientX - drag.startClientX) > 3 || Math.abs(e.clientY - drag.startClientY) > 3 || slotIdx !== drag.startSlotIdx || ctx.resourceId !== drag.startRowResourceId;
9289
- if (movedEnough) suppressNextEventClickRef.current = true;
9290
- if (drag.mode === "create") {
9291
- const a = Math.min(drag.startSlotIdx, slotIdx);
9292
- const b = Math.max(drag.startSlotIdx, slotIdx) + 1;
9293
- const s = slotToDate(a).start;
9294
- const e2 = b >= slots.length ? range.end : slotToDate(b).start;
9295
- setPreview({ resourceId: drag.resourceId, start: s, end: e2 });
9296
- return;
9297
- }
9298
- const targetSlotStart = slotToDate(slotIdx).start;
9299
- const originSlotStart = slotToDate(drag.startSlotIdx).start;
9300
- const deltaMs = targetSlotStart.getTime() - originSlotStart.getTime();
9301
- if (drag.mode === "move") {
9302
- const nextStart = new Date(drag.originStart.getTime() + deltaMs);
9303
- const nextEnd = new Date(drag.originEnd.getTime() + deltaMs);
9304
- setPreview({ eventId: drag.eventId, resourceId: ctx.resourceId, start: nextStart, end: nextEnd });
9305
- drag.resourceId = ctx.resourceId;
9306
- return;
9307
- }
9308
- if (drag.mode === "resize-start") {
9309
- const nextStart = new Date(clamp3(targetSlotStart.getTime(), range.start.getTime(), drag.originEnd.getTime() - 6e4));
9310
- setPreview({ eventId: drag.eventId, resourceId: drag.resourceId, start: nextStart, end: drag.originEnd });
9311
- return;
9312
- }
9313
- if (drag.mode === "resize-end") {
9314
- const nextEnd = new Date(clamp3(targetSlotStart.getTime(), drag.originStart.getTime() + 6e4, range.end.getTime()));
9315
- setPreview({ eventId: drag.eventId, resourceId: drag.resourceId, start: drag.originStart, end: nextEnd });
9316
- return;
9317
- }
9451
+ updateAutoScrollFromPointer(e.clientX, e.clientY);
9452
+ updateDragPreview(e.clientX, e.clientY);
9318
9453
  };
9319
9454
  const onPointerUp = (e) => {
9320
9455
  const drag = dragRef.current;
9321
9456
  if (!drag || drag.pointerId !== e.pointerId) return;
9322
9457
  dragRef.current = null;
9458
+ stopAutoScroll();
9323
9459
  if (!preview) {
9324
9460
  setPreview(null);
9325
9461
  return;
@@ -9420,10 +9556,10 @@ function CalendarTimeline({
9420
9556
  return { ev: { ...ev, _start: s, _end: e }, startIdx, endIdx };
9421
9557
  });
9422
9558
  const { packed, laneCount } = intervalPack(mapped);
9423
- const visible = packed.filter((p) => p.lane < maxLanesPerRow);
9424
- const hidden = packed.filter((p) => p.lane >= maxLanesPerRow);
9559
+ const visible = packed.filter((p) => p.lane < effectiveMaxLanesPerRow);
9560
+ const hidden = packed.filter((p) => p.lane >= effectiveMaxLanesPerRow);
9425
9561
  const rowHeightPx = getResourceRowHeight(resourceId);
9426
- const visibleLaneCount = Math.max(1, Math.min(laneCount, maxLanesPerRow));
9562
+ const visibleLaneCount = Math.max(1, Math.min(laneCount, effectiveMaxLanesPerRow));
9427
9563
  const available = Math.max(0, rowHeightPx - lanePaddingY * 2 - laneGap * Math.max(0, visibleLaneCount - 1));
9428
9564
  const fitPerLane = visibleLaneCount > 0 ? Math.floor(available / visibleLaneCount) : eventHeight;
9429
9565
  const perLaneHeight = Math.max(9, Math.min(eventHeight, fitPerLane || eventHeight));
@@ -9441,7 +9577,7 @@ function CalendarTimeline({
9441
9577
  });
9442
9578
  }
9443
9579
  return map;
9444
- }, [eventsByResource, getResourceRowHeight, laneGap, lanePaddingY, slotStarts, slots.length, slotWidth, maxLanesPerRow, preview, eventHeight]);
9580
+ }, [eventsByResource, getResourceRowHeight, laneGap, lanePaddingY, slotStarts, slots.length, slotWidth, effectiveMaxLanesPerRow, preview, eventHeight]);
9445
9581
  return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
9446
9582
  "div",
9447
9583
  {