@underverse-ui/underverse 0.2.101 → 0.2.103

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.d.cts CHANGED
@@ -1030,6 +1030,17 @@ interface CalendarTimelineVirtualization {
1030
1030
  enabled?: boolean;
1031
1031
  overscan?: number;
1032
1032
  }
1033
+ type CalendarTimelineAdaptiveSlotWidths = boolean | {
1034
+ /**
1035
+ * "shrink": empty slots get `emptySlotWidth`, event slots keep the fixed base width (default).
1036
+ * "redistribute": keep the total grid width as in fixed mode, redistribute freed width to event slots (capped).
1037
+ */
1038
+ mode?: "shrink" | "redistribute";
1039
+ /** Width (px) for empty slots (month/day only). Default: `slotMinWidth * 0.6` (bounded). */
1040
+ emptySlotWidth?: number;
1041
+ /** Cap (px) for event slot width when `mode="redistribute"`. Default: `baseSlotWidth * 2.5`. */
1042
+ maxEventSlotWidth?: number;
1043
+ };
1033
1044
  interface CalendarTimelineProps<TResourceMeta = unknown, TEventMeta = unknown> extends Omit<React$1.HTMLAttributes<HTMLDivElement>, "onChange"> {
1034
1045
  resources: CalendarTimelineResource<TResourceMeta>[];
1035
1046
  events: CalendarTimelineEvent<TEventMeta>[];
@@ -1113,6 +1124,19 @@ interface CalendarTimelineProps<TResourceMeta = unknown, TEventMeta = unknown> e
1113
1124
  row?: boolean;
1114
1125
  };
1115
1126
  slotMinWidth?: number;
1127
+ /**
1128
+ * Month/day only: make slots (columns) without any events smaller to free space for slots that have events.
1129
+ * Week view is unaffected.
1130
+ */
1131
+ adaptiveSlotWidths?: CalendarTimelineAdaptiveSlotWidths;
1132
+ /**
1133
+ * Day view: visual style for events that span many time slots.
1134
+ * - "span": event blocks span the full duration on the timeline (default)
1135
+ * - "compact": event blocks keep a capped visual width (still positioned at correct start)
1136
+ */
1137
+ dayEventStyle?: "span" | "compact";
1138
+ /** Day view only (when `dayEventStyle="compact"`): max visual width (px). */
1139
+ dayEventMaxWidth?: number;
1116
1140
  dayTimeStepMinutes?: number;
1117
1141
  /**
1118
1142
  * Day view horizontal range:
@@ -1185,7 +1209,7 @@ interface CalendarTimelineProps<TResourceMeta = unknown, TEventMeta = unknown> e
1185
1209
  virtualization?: CalendarTimelineVirtualization;
1186
1210
  }
1187
1211
 
1188
- declare function CalendarTimeline<TResourceMeta = unknown, TEventMeta = unknown>({ resources, events, size, enableEventSheet, eventSheetSize, renderEventSheet, selectedEventId, defaultSelectedEventId, onSelectedEventIdChange, eventSheetOpen, defaultEventSheetOpen, onEventSheetOpenChange, view, defaultView, onViewChange, date, defaultDate, onDateChange, weekStartsOn, locale, timeZone, labels, formatters, groups, groupCollapsed, defaultGroupCollapsed, onGroupCollapsedChange, resourceColumnWidth, defaultResourceColumnWidth, onResourceColumnWidthChange, minResourceColumnWidth, maxResourceColumnWidth, rowHeight, defaultRowHeight, onRowHeightChange, minRowHeight, maxRowHeight, rowHeights, defaultRowHeights, onRowHeightsChange, autoRowHeight, enableLayoutResize, slotMinWidth, dayTimeStepMinutes, dayRangeMode, workHours, maxLanesPerRow, now, renderResource, renderGroup, renderEvent, interactions, onRangeChange, onEventClick, onEventDoubleClick, onCreateEventClick, onCreateEvent, onEventMove, onEventResize, onEventDelete, onMoreClick, virtualization, className, ...rest }: CalendarTimelineProps<TResourceMeta, TEventMeta>): react_jsx_runtime.JSX.Element;
1212
+ declare function CalendarTimeline<TResourceMeta = unknown, TEventMeta = unknown>({ resources, events, size, enableEventSheet, eventSheetSize, renderEventSheet, selectedEventId, defaultSelectedEventId, onSelectedEventIdChange, eventSheetOpen, defaultEventSheetOpen, onEventSheetOpenChange, view, defaultView, onViewChange, date, defaultDate, onDateChange, weekStartsOn, locale, timeZone, labels, formatters, groups, groupCollapsed, defaultGroupCollapsed, onGroupCollapsedChange, resourceColumnWidth, defaultResourceColumnWidth, onResourceColumnWidthChange, minResourceColumnWidth, maxResourceColumnWidth, rowHeight, defaultRowHeight, onRowHeightChange, minRowHeight, maxRowHeight, rowHeights, defaultRowHeights, onRowHeightsChange, autoRowHeight, enableLayoutResize, slotMinWidth, adaptiveSlotWidths, dayEventStyle, dayEventMaxWidth, dayTimeStepMinutes, dayRangeMode, workHours, maxLanesPerRow, now, renderResource, renderGroup, renderEvent, interactions, onRangeChange, onEventClick, onEventDoubleClick, onCreateEventClick, onCreateEvent, onEventMove, onEventResize, onEventDelete, onMoreClick, virtualization, className, ...rest }: CalendarTimelineProps<TResourceMeta, TEventMeta>): react_jsx_runtime.JSX.Element;
1189
1213
 
1190
1214
  type ComboboxOption = string | {
1191
1215
  label: string;
package/dist/index.d.ts CHANGED
@@ -1030,6 +1030,17 @@ interface CalendarTimelineVirtualization {
1030
1030
  enabled?: boolean;
1031
1031
  overscan?: number;
1032
1032
  }
1033
+ type CalendarTimelineAdaptiveSlotWidths = boolean | {
1034
+ /**
1035
+ * "shrink": empty slots get `emptySlotWidth`, event slots keep the fixed base width (default).
1036
+ * "redistribute": keep the total grid width as in fixed mode, redistribute freed width to event slots (capped).
1037
+ */
1038
+ mode?: "shrink" | "redistribute";
1039
+ /** Width (px) for empty slots (month/day only). Default: `slotMinWidth * 0.6` (bounded). */
1040
+ emptySlotWidth?: number;
1041
+ /** Cap (px) for event slot width when `mode="redistribute"`. Default: `baseSlotWidth * 2.5`. */
1042
+ maxEventSlotWidth?: number;
1043
+ };
1033
1044
  interface CalendarTimelineProps<TResourceMeta = unknown, TEventMeta = unknown> extends Omit<React$1.HTMLAttributes<HTMLDivElement>, "onChange"> {
1034
1045
  resources: CalendarTimelineResource<TResourceMeta>[];
1035
1046
  events: CalendarTimelineEvent<TEventMeta>[];
@@ -1113,6 +1124,19 @@ interface CalendarTimelineProps<TResourceMeta = unknown, TEventMeta = unknown> e
1113
1124
  row?: boolean;
1114
1125
  };
1115
1126
  slotMinWidth?: number;
1127
+ /**
1128
+ * Month/day only: make slots (columns) without any events smaller to free space for slots that have events.
1129
+ * Week view is unaffected.
1130
+ */
1131
+ adaptiveSlotWidths?: CalendarTimelineAdaptiveSlotWidths;
1132
+ /**
1133
+ * Day view: visual style for events that span many time slots.
1134
+ * - "span": event blocks span the full duration on the timeline (default)
1135
+ * - "compact": event blocks keep a capped visual width (still positioned at correct start)
1136
+ */
1137
+ dayEventStyle?: "span" | "compact";
1138
+ /** Day view only (when `dayEventStyle="compact"`): max visual width (px). */
1139
+ dayEventMaxWidth?: number;
1116
1140
  dayTimeStepMinutes?: number;
1117
1141
  /**
1118
1142
  * Day view horizontal range:
@@ -1185,7 +1209,7 @@ interface CalendarTimelineProps<TResourceMeta = unknown, TEventMeta = unknown> e
1185
1209
  virtualization?: CalendarTimelineVirtualization;
1186
1210
  }
1187
1211
 
1188
- declare function CalendarTimeline<TResourceMeta = unknown, TEventMeta = unknown>({ resources, events, size, enableEventSheet, eventSheetSize, renderEventSheet, selectedEventId, defaultSelectedEventId, onSelectedEventIdChange, eventSheetOpen, defaultEventSheetOpen, onEventSheetOpenChange, view, defaultView, onViewChange, date, defaultDate, onDateChange, weekStartsOn, locale, timeZone, labels, formatters, groups, groupCollapsed, defaultGroupCollapsed, onGroupCollapsedChange, resourceColumnWidth, defaultResourceColumnWidth, onResourceColumnWidthChange, minResourceColumnWidth, maxResourceColumnWidth, rowHeight, defaultRowHeight, onRowHeightChange, minRowHeight, maxRowHeight, rowHeights, defaultRowHeights, onRowHeightsChange, autoRowHeight, enableLayoutResize, slotMinWidth, dayTimeStepMinutes, dayRangeMode, workHours, maxLanesPerRow, now, renderResource, renderGroup, renderEvent, interactions, onRangeChange, onEventClick, onEventDoubleClick, onCreateEventClick, onCreateEvent, onEventMove, onEventResize, onEventDelete, onMoreClick, virtualization, className, ...rest }: CalendarTimelineProps<TResourceMeta, TEventMeta>): react_jsx_runtime.JSX.Element;
1212
+ declare function CalendarTimeline<TResourceMeta = unknown, TEventMeta = unknown>({ resources, events, size, enableEventSheet, eventSheetSize, renderEventSheet, selectedEventId, defaultSelectedEventId, onSelectedEventIdChange, eventSheetOpen, defaultEventSheetOpen, onEventSheetOpenChange, view, defaultView, onViewChange, date, defaultDate, onDateChange, weekStartsOn, locale, timeZone, labels, formatters, groups, groupCollapsed, defaultGroupCollapsed, onGroupCollapsedChange, resourceColumnWidth, defaultResourceColumnWidth, onResourceColumnWidthChange, minResourceColumnWidth, maxResourceColumnWidth, rowHeight, defaultRowHeight, onRowHeightChange, minRowHeight, maxRowHeight, rowHeights, defaultRowHeights, onRowHeightsChange, autoRowHeight, enableLayoutResize, slotMinWidth, adaptiveSlotWidths, dayEventStyle, dayEventMaxWidth, dayTimeStepMinutes, dayRangeMode, workHours, maxLanesPerRow, now, renderResource, renderGroup, renderEvent, interactions, onRangeChange, onEventClick, onEventDoubleClick, onCreateEventClick, onCreateEvent, onEventMove, onEventResize, onEventDelete, onMoreClick, virtualization, className, ...rest }: CalendarTimelineProps<TResourceMeta, TEventMeta>): react_jsx_runtime.JSX.Element;
1189
1213
 
1190
1214
  type ComboboxOption = string | {
1191
1215
  label: string;
package/dist/index.js CHANGED
@@ -8587,6 +8587,9 @@ function CalendarTimeline({
8587
8587
  autoRowHeight,
8588
8588
  enableLayoutResize,
8589
8589
  slotMinWidth,
8590
+ adaptiveSlotWidths,
8591
+ dayEventStyle = "span",
8592
+ dayEventMaxWidth,
8590
8593
  dayTimeStepMinutes = 60,
8591
8594
  dayRangeMode,
8592
8595
  workHours,
@@ -8775,17 +8778,135 @@ function CalendarTimeline({
8775
8778
  const headerRef = React28.useRef(null);
8776
8779
  const bodyClientWidth = useClientWidth(bodyRef);
8777
8780
  const slotStarts = React28.useMemo(() => slots.map((s) => s.start), [slots]);
8778
- const slotWidth = React28.useMemo(() => {
8779
- const baseSlotWidth = activeView === "month" ? effectiveSlotMinWidth * 3 : activeView === "day" ? effectiveSlotMinWidth * 3 : effectiveSlotMinWidth;
8781
+ const fixedSlotWidth = React28.useMemo(() => {
8782
+ const baseSlotWidth = activeView === "month" || activeView === "day" ? effectiveSlotMinWidth * 3 : effectiveSlotMinWidth;
8780
8783
  if (activeView !== "week") return baseSlotWidth;
8781
8784
  if (bodyClientWidth <= 0) return baseSlotWidth;
8782
8785
  if (slots.length <= 0) return baseSlotWidth;
8783
8786
  return Math.max(baseSlotWidth, bodyClientWidth / slots.length);
8784
8787
  }, [activeView, bodyClientWidth, effectiveSlotMinWidth, slots.length]);
8785
- const gridWidth = slots.length * slotWidth;
8786
8788
  const normalizedEvents = React28.useMemo(() => {
8787
8789
  return normalizeEvents({ events, range, view: activeView, timeZone: resolvedTimeZone });
8788
8790
  }, [events, range, activeView, resolvedTimeZone]);
8791
+ const dayHeaderMarks = React28.useMemo(() => {
8792
+ if (activeView !== "day") return null;
8793
+ const n = slots.length;
8794
+ const showTime = new Array(n).fill(false);
8795
+ const showEllipsis = new Array(n).fill(false);
8796
+ for (const ev of normalizedEvents) {
8797
+ const startIdx = binarySearchLastLE(slotStarts, ev._start);
8798
+ const endIdxRaw = binarySearchFirstGE(slotStarts, ev._end);
8799
+ const endIdx = clamp3(endIdxRaw, 0, n - 1);
8800
+ if (startIdx >= 0 && startIdx < n) showTime[startIdx] = true;
8801
+ if (endIdx >= 0 && endIdx < n) showTime[endIdx] = true;
8802
+ const span = endIdx - startIdx;
8803
+ if (span >= 3) {
8804
+ const mid = clamp3(Math.floor((startIdx + endIdx) / 2), 0, n - 1);
8805
+ if (!showTime[mid]) showEllipsis[mid] = true;
8806
+ }
8807
+ }
8808
+ const anchor = showTime.map((v, i) => v || showEllipsis[i]);
8809
+ return { showTime, showEllipsis, anchor };
8810
+ }, [activeView, normalizedEvents, slotStarts, slots.length]);
8811
+ const slotMetrics = React28.useMemo(() => {
8812
+ const n = slots.length;
8813
+ const widths = new Array(n).fill(fixedSlotWidth);
8814
+ const isAdaptiveView = activeView === "month" || activeView === "day";
8815
+ const adaptiveCfg = adaptiveSlotWidths;
8816
+ const adaptiveEnabled = Boolean(adaptiveCfg) && isAdaptiveView;
8817
+ if (!adaptiveEnabled || n === 0) {
8818
+ const lefts2 = new Array(n + 1);
8819
+ lefts2[0] = 0;
8820
+ for (let i = 0; i < n; i++) lefts2[i + 1] = lefts2[i] + widths[i];
8821
+ const gridWidth3 = lefts2[n] ?? 0;
8822
+ const xToSlotIdx3 = (x) => clamp3(Math.floor(x / Math.max(1, fixedSlotWidth)), 0, Math.max(0, n - 1));
8823
+ return { slotWidths: widths, slotLefts: lefts2, slotHasEvent: null, gridWidth: gridWidth3, xToSlotIdx: xToSlotIdx3 };
8824
+ }
8825
+ const cfg = typeof adaptiveCfg === "object" ? adaptiveCfg : {};
8826
+ const mode = cfg.mode ?? "shrink";
8827
+ const defaultEmptySlotWidth = Math.max(18, Math.round(effectiveSlotMinWidth * 0.6));
8828
+ const minEmptySlotWidth = activeView === "month" ? Math.max(24, Math.round(effectiveSlotMinWidth * 0.45)) : 12;
8829
+ const emptySlotWidth = Math.max(minEmptySlotWidth, Math.min(fixedSlotWidth, cfg.emptySlotWidth ?? defaultEmptySlotWidth));
8830
+ const dayAnchorCompression = activeView === "day" && Boolean(dayHeaderMarks?.anchor);
8831
+ if (dayAnchorCompression) {
8832
+ const hasEvent2 = dayHeaderMarks.anchor.slice(0, n);
8833
+ const compressedEmptySlotWidth = clamp3(emptySlotWidth, 12, 20);
8834
+ for (let i = 0; i < n; i++) widths[i] = hasEvent2[i] ? fixedSlotWidth : compressedEmptySlotWidth;
8835
+ const lefts2 = new Array(n + 1);
8836
+ lefts2[0] = 0;
8837
+ for (let i = 0; i < n; i++) lefts2[i + 1] = lefts2[i] + widths[i];
8838
+ const gridWidth3 = lefts2[n] ?? 0;
8839
+ const xToSlotIdx3 = (x) => {
8840
+ const xc = clamp3(x, 0, Math.max(0, gridWidth3 - 1e-3));
8841
+ let lo = 0;
8842
+ let hi = n - 1;
8843
+ while (lo <= hi) {
8844
+ const mid = lo + hi >> 1;
8845
+ const left = lefts2[mid] ?? 0;
8846
+ const right = lefts2[mid + 1] ?? gridWidth3;
8847
+ if (xc < left) hi = mid - 1;
8848
+ else if (xc >= right) lo = mid + 1;
8849
+ else return mid;
8850
+ }
8851
+ return clamp3(lo, 0, Math.max(0, n - 1));
8852
+ };
8853
+ return { slotWidths: widths, slotLefts: lefts2, slotHasEvent: hasEvent2, gridWidth: gridWidth3, xToSlotIdx: xToSlotIdx3 };
8854
+ }
8855
+ const diff = new Array(n + 1).fill(0);
8856
+ for (const ev of normalizedEvents) {
8857
+ const startIdx = binarySearchLastLE(slotStarts, ev._start);
8858
+ const endIdx = clamp3(binarySearchFirstGE(slotStarts, ev._end), startIdx + 1, n);
8859
+ diff[startIdx] = (diff[startIdx] ?? 0) + 1;
8860
+ diff[endIdx] = (diff[endIdx] ?? 0) - 1;
8861
+ }
8862
+ const hasEvent = new Array(n);
8863
+ let running = 0;
8864
+ let eventCount = 0;
8865
+ for (let i = 0; i < n; i++) {
8866
+ running += diff[i] ?? 0;
8867
+ const covered = running > 0;
8868
+ hasEvent[i] = covered;
8869
+ if (covered) eventCount++;
8870
+ }
8871
+ if (eventCount === 0 || eventCount === n) {
8872
+ const lefts2 = new Array(n + 1);
8873
+ lefts2[0] = 0;
8874
+ for (let i = 0; i < n; i++) lefts2[i + 1] = lefts2[i] + widths[i];
8875
+ const gridWidth3 = lefts2[n] ?? 0;
8876
+ const xToSlotIdx3 = (x) => clamp3(Math.floor(x / Math.max(1, fixedSlotWidth)), 0, Math.max(0, n - 1));
8877
+ return { slotWidths: widths, slotLefts: lefts2, slotHasEvent: null, gridWidth: gridWidth3, xToSlotIdx: xToSlotIdx3 };
8878
+ }
8879
+ const emptyCount = n - eventCount;
8880
+ let eventSlotWidth = fixedSlotWidth;
8881
+ if (mode === "redistribute") {
8882
+ const targetTotal = n * fixedSlotWidth;
8883
+ const remaining = Math.max(0, targetTotal - emptyCount * emptySlotWidth);
8884
+ const raw = remaining / Math.max(1, eventCount);
8885
+ const maxEventSlotWidth = cfg.maxEventSlotWidth ?? fixedSlotWidth * 2.5;
8886
+ eventSlotWidth = clamp3(raw, fixedSlotWidth, Math.max(fixedSlotWidth, maxEventSlotWidth));
8887
+ }
8888
+ for (let i = 0; i < n; i++) widths[i] = hasEvent[i] ? eventSlotWidth : emptySlotWidth;
8889
+ const lefts = new Array(n + 1);
8890
+ lefts[0] = 0;
8891
+ for (let i = 0; i < n; i++) lefts[i + 1] = lefts[i] + widths[i];
8892
+ const gridWidth2 = lefts[n] ?? 0;
8893
+ const xToSlotIdx2 = (x) => {
8894
+ const xc = clamp3(x, 0, Math.max(0, gridWidth2 - 1e-3));
8895
+ let lo = 0;
8896
+ let hi = n - 1;
8897
+ while (lo <= hi) {
8898
+ const mid = lo + hi >> 1;
8899
+ const left = lefts[mid] ?? 0;
8900
+ const right = lefts[mid + 1] ?? gridWidth2;
8901
+ if (xc < left) hi = mid - 1;
8902
+ else if (xc >= right) lo = mid + 1;
8903
+ else return mid;
8904
+ }
8905
+ return clamp3(lo, 0, Math.max(0, n - 1));
8906
+ };
8907
+ return { slotWidths: widths, slotLefts: lefts, slotHasEvent: hasEvent, gridWidth: gridWidth2, xToSlotIdx: xToSlotIdx2 };
8908
+ }, [activeView, adaptiveSlotWidths, dayHeaderMarks, effectiveSlotMinWidth, fixedSlotWidth, normalizedEvents, slotStarts, slots.length]);
8909
+ const { slotWidths, slotLefts, slotHasEvent, gridWidth, xToSlotIdx } = slotMetrics;
8789
8910
  const eventsByResource = React28.useMemo(() => {
8790
8911
  return eventsByResourceId(normalizedEvents);
8791
8912
  }, [normalizedEvents]);
@@ -9034,7 +9155,20 @@ function CalendarTimeline({
9034
9155
  setCreateStartIdx(startIdx);
9035
9156
  setCreateEndIdx(Math.min(slots.length, startIdx + 1));
9036
9157
  setCreateOpen(true);
9037
- }, [activeDate, activeEventSheetOpen, activeView, canCreate, range.end, range.start, resolvedNow, resolvedTimeZone, resources, setEventSheetOpen, slotStarts, slots.length]);
9158
+ }, [
9159
+ activeDate,
9160
+ activeEventSheetOpen,
9161
+ activeView,
9162
+ canCreate,
9163
+ range.end,
9164
+ range.start,
9165
+ resolvedNow,
9166
+ resolvedTimeZone,
9167
+ resources,
9168
+ setEventSheetOpen,
9169
+ slotStarts,
9170
+ slots.length
9171
+ ]);
9038
9172
  React28.useEffect(() => {
9039
9173
  setCreateEndIdx((prev) => Math.min(slots.length, Math.max(prev, createStartIdx + 1)));
9040
9174
  }, [createStartIdx, slots.length]);
@@ -9087,13 +9221,13 @@ function CalendarTimeline({
9087
9221
  const el = document.elementFromPoint(probeX, probeY);
9088
9222
  const x = probeX - bodyRect.left + body.scrollLeft;
9089
9223
  const epsilon = opts?.biasLeft ? 0.01 : 0;
9090
- const slotIdx = clamp3(Math.floor((x - epsilon) / slotWidth), 0, Math.max(0, slots.length - 1));
9224
+ const slotIdx = xToSlotIdx(x - epsilon);
9091
9225
  const rowEl = el && body.contains(el) ? el.closest?.("[data-uv-ct-row]") ?? null : null;
9092
9226
  const rid = rowEl?.dataset?.uvCtRow ?? opts?.fallbackResourceId ?? null;
9093
9227
  if (!rid) return null;
9094
9228
  return { slotIdx, resourceId: rid, x };
9095
9229
  },
9096
- [slotWidth, slots.length]
9230
+ [xToSlotIdx]
9097
9231
  );
9098
9232
  const slotToDate = React28.useCallback(
9099
9233
  (slotIdx) => {
@@ -9110,7 +9244,11 @@ function CalendarTimeline({
9110
9244
  (clientX, clientY) => {
9111
9245
  const drag = dragRef.current;
9112
9246
  if (!drag) return;
9113
- const ctx = getPointerContext(clientX, clientY, drag.mode === "create" ? { biasLeft: true, fallbackResourceId: drag.resourceId } : { fallbackResourceId: drag.resourceId });
9247
+ const ctx = getPointerContext(
9248
+ clientX,
9249
+ clientY,
9250
+ drag.mode === "create" ? { biasLeft: true, fallbackResourceId: drag.resourceId } : { fallbackResourceId: drag.resourceId }
9251
+ );
9114
9252
  if (!ctx) return;
9115
9253
  const { slotIdx } = ctx;
9116
9254
  const movedEnough = Math.abs(clientX - drag.startClientX) > 3 || Math.abs(clientY - drag.startClientY) > 3 || slotIdx !== drag.startSlotIdx || ctx.resourceId !== drag.startRowResourceId;
@@ -9360,16 +9498,24 @@ function CalendarTimeline({
9360
9498
  "div",
9361
9499
  {
9362
9500
  className: cn(
9363
- "shrink-0 border-l border-border/30 flex items-center justify-center transition-colors duration-150",
9501
+ "shrink-0 border-l flex items-center justify-center transition-colors duration-150 overflow-hidden",
9502
+ activeView === "day" && dayHeaderMarks?.anchor ? dayHeaderMarks.anchor[idx] ? "border-border/30" : "border-border/10" : "border-border/30",
9364
9503
  sizeConfig.slotHeaderClass,
9365
- s.isToday && "bg-primary/8 border-l-primary/40"
9504
+ activeView !== "day" && s.isToday && "bg-primary/8 border-l-primary/40"
9366
9505
  ),
9367
- style: { width: slotWidth, minWidth: slotWidth },
9506
+ style: { width: slotWidths[idx], minWidth: slotWidths[idx] },
9368
9507
  "aria-label": formatters?.ariaSlotLabel?.(s.start, { view: activeView, locale: resolvedLocale, timeZone: resolvedTimeZone }),
9369
- children: /* @__PURE__ */ jsxs31("div", { className: cn("flex flex-col items-center", s.isToday && "relative"), children: [
9370
- s.isToday && /* @__PURE__ */ jsx36(Dot, { className: "absolute -top-2.5 h-4 w-4 text-primary animate-pulse" }),
9371
- s.label
9372
- ] })
9508
+ children: (() => {
9509
+ const label = typeof s.label === "string" || typeof s.label === "number" ? /* @__PURE__ */ jsx36("span", { className: "truncate whitespace-nowrap", children: s.label }) : s.label;
9510
+ if (activeView === "day" && dayHeaderMarks) {
9511
+ if (dayHeaderMarks.showEllipsis[idx]) return /* @__PURE__ */ jsx36("span", { className: "text-xs text-muted-foreground/70 select-none", children: "\u2026" });
9512
+ if (!dayHeaderMarks.showTime[idx]) return null;
9513
+ }
9514
+ return /* @__PURE__ */ jsxs31("div", { className: cn("flex flex-col items-center min-w-0 overflow-hidden", activeView !== "day" && s.isToday && "relative"), children: [
9515
+ activeView !== "day" && s.isToday && /* @__PURE__ */ jsx36(Dot, { className: "absolute -top-2.5 h-4 w-4 text-primary animate-pulse" }),
9516
+ label
9517
+ ] });
9518
+ })()
9373
9519
  },
9374
9520
  `${s.start.toISOString()}_${idx}`
9375
9521
  ))
@@ -9422,14 +9568,25 @@ function CalendarTimeline({
9422
9568
  visible: visible.map((p) => ({
9423
9569
  ev: p.ev,
9424
9570
  lane: p.lane,
9425
- left: p.startIdx * slotWidth,
9426
- width: Math.max(1, (p.endIdx - p.startIdx) * slotWidth)
9571
+ left: slotLefts[p.startIdx] ?? 0,
9572
+ width: Math.max(1, (slotLefts[p.endIdx] ?? 0) - (slotLefts[p.startIdx] ?? 0))
9427
9573
  })),
9428
9574
  hidden: hidden.map((h) => h.ev)
9429
9575
  });
9430
9576
  }
9431
9577
  return map;
9432
- }, [eventsByResource, getResourceRowHeight, laneGap, lanePaddingY, slotStarts, slots.length, slotWidth, effectiveMaxLanesPerRow, preview, eventHeight]);
9578
+ }, [
9579
+ eventsByResource,
9580
+ eventHeight,
9581
+ effectiveMaxLanesPerRow,
9582
+ getResourceRowHeight,
9583
+ laneGap,
9584
+ lanePaddingY,
9585
+ preview,
9586
+ slotLefts,
9587
+ slotStarts,
9588
+ slots.length
9589
+ ]);
9433
9590
  return /* @__PURE__ */ jsxs31(
9434
9591
  "div",
9435
9592
  {
@@ -9487,7 +9644,13 @@ function CalendarTimeline({
9487
9644
  const rowIndex = startRow + idx;
9488
9645
  const h = rowHeightsArray[rowIndex] ?? effectiveRowHeight;
9489
9646
  if (row.kind === "group") {
9490
- return /* @__PURE__ */ jsx36("div", { className: "flex", style: { height: h }, children: /* @__PURE__ */ jsx36("div", { className: "border-b border-border/30 bg-linear-to-r from-muted/15 to-muted/5", style: { width: gridWidth, minWidth: gridWidth } }) }, `rg_${row.group.id}_${rowIndex}`);
9647
+ return /* @__PURE__ */ jsx36("div", { className: "flex", style: { height: h }, children: /* @__PURE__ */ jsx36(
9648
+ "div",
9649
+ {
9650
+ className: "border-b border-border/30 bg-linear-to-r from-muted/15 to-muted/5",
9651
+ style: { width: gridWidth, minWidth: gridWidth }
9652
+ }
9653
+ ) }, `rg_${row.group.id}_${rowIndex}`);
9491
9654
  }
9492
9655
  const r = row.resource;
9493
9656
  const layout = layoutsByResource.get(r.id) ?? { visible: [], hidden: [], baseTop: lanePaddingY, eventHeight };
@@ -9505,11 +9668,12 @@ function CalendarTimeline({
9505
9668
  "div",
9506
9669
  {
9507
9670
  className: cn(
9508
- "h-full border-l border-border/20 transition-colors duration-100",
9509
- s.isToday && "bg-primary/5 border-l-primary/30",
9671
+ "h-full border-l transition-colors duration-100",
9672
+ activeView === "day" && dayHeaderMarks?.anchor ? !dayHeaderMarks.anchor[i2] ? "border-border/10" : "border-border/20" : "border-border/20",
9673
+ activeView !== "day" && s.isToday && "bg-primary/5 border-l-primary/30",
9510
9674
  "hover:bg-muted/10"
9511
9675
  ),
9512
- style: { width: slotWidth, minWidth: slotWidth }
9676
+ style: { width: slotWidths[i2], minWidth: slotWidths[i2] }
9513
9677
  },
9514
9678
  `${r.id}_${i2}`
9515
9679
  )) }) }),
@@ -9553,28 +9717,17 @@ function CalendarTimeline({
9553
9717
  /* @__PURE__ */ jsx36("div", { className: "text-xs opacity-80", children: timeText }),
9554
9718
  resource?.label ? /* @__PURE__ */ jsx36("div", { className: "text-xs opacity-70", children: resource.label }) : null
9555
9719
  ] });
9720
+ const shouldCompact = activeView === "day" && dayEventStyle === "compact";
9721
+ const defaultMaxVisual = clamp3(Math.round(fixedSlotWidth * 1.2), 160, 360);
9722
+ const maxVisual = clamp3(Math.round(dayEventMaxWidth ?? defaultMaxVisual), 80, 1200);
9723
+ const visualWidth = shouldCompact ? Math.min(width, maxVisual) : width;
9724
+ const isClipped = shouldCompact && width > visualWidth + 1;
9556
9725
  return /* @__PURE__ */ jsx36(Tooltip, { content: tooltipContent, placement: "top", delay: { open: 250, close: 0 }, children: /* @__PURE__ */ jsxs31(
9557
9726
  "div",
9558
9727
  {
9559
- className: cn(
9560
- "absolute rounded-lg border select-none cursor-pointer",
9561
- "shadow-sm hover:shadow-md hover:scale-[1.02] hover:z-10",
9562
- "transition-all duration-150 ease-out",
9563
- "backdrop-blur-sm",
9564
- "overflow-hidden",
9565
- ev.className,
9566
- isPreview && "ring-2 ring-primary/50 ring-offset-1 ring-offset-background scale-[1.02] z-10"
9567
- ),
9728
+ className: cn("absolute select-none cursor-pointer", isPreview && "z-10"),
9568
9729
  "data-uv-ct-event": true,
9569
- style: {
9570
- left,
9571
- top,
9572
- width,
9573
- height: layout.eventHeight,
9574
- background: bg,
9575
- borderColor: border,
9576
- borderLeftWidth: 3
9577
- },
9730
+ style: { left, top, width, height: layout.eventHeight },
9578
9731
  role: "button",
9579
9732
  tabIndex: 0,
9580
9733
  "aria-label": aria,
@@ -9602,6 +9755,31 @@ function CalendarTimeline({
9602
9755
  onDoubleClick: () => onEventDoubleClick?.(ev),
9603
9756
  onPointerDown: (e) => onPointerDownEvent(e, ev, "move"),
9604
9757
  children: [
9758
+ /* @__PURE__ */ jsxs31(
9759
+ "div",
9760
+ {
9761
+ className: cn(
9762
+ "relative h-full rounded-lg border overflow-hidden",
9763
+ "shadow-sm hover:shadow-md hover:scale-[1.02]",
9764
+ "transition-all duration-150 ease-out",
9765
+ "backdrop-blur-sm",
9766
+ ev.className,
9767
+ isPreview && "ring-2 ring-primary/50 ring-offset-1 ring-offset-background scale-[1.02]"
9768
+ ),
9769
+ style: {
9770
+ width: visualWidth,
9771
+ maxWidth: "100%",
9772
+ height: "100%",
9773
+ background: bg,
9774
+ borderColor: border,
9775
+ borderLeftWidth: 3
9776
+ },
9777
+ children: [
9778
+ node,
9779
+ isClipped ? /* @__PURE__ */ jsx36("div", { className: "pointer-events-none absolute inset-y-0 right-0 w-10 bg-linear-to-l from-background/50 to-transparent flex items-center justify-end pr-2", children: /* @__PURE__ */ jsx36("span", { className: "text-xs text-muted-foreground/80", children: "\u2026" }) }) : null
9780
+ ]
9781
+ }
9782
+ ),
9605
9783
  !isViewOnly && (interactions?.resizableEvents ?? true) && ev.resizable !== false ? /* @__PURE__ */ jsxs31(Fragment10, { children: [
9606
9784
  /* @__PURE__ */ jsx36(
9607
9785
  "div",
@@ -9617,8 +9795,7 @@ function CalendarTimeline({
9617
9795
  onPointerDown: (e) => onPointerDownEvent(e, ev, "resize-end")
9618
9796
  }
9619
9797
  )
9620
- ] }) : null,
9621
- node
9798
+ ] }) : null
9622
9799
  ]
9623
9800
  }
9624
9801
  ) }, ev.id);
@@ -9626,8 +9803,8 @@ function CalendarTimeline({
9626
9803
  preview && preview.resourceId === r.id && !preview.eventId ? (() => {
9627
9804
  const startIdx = binarySearchLastLE(slotStarts, preview.start);
9628
9805
  const endIdx = clamp3(binarySearchFirstGE(slotStarts, preview.end), startIdx + 1, slots.length);
9629
- const left = startIdx * slotWidth;
9630
- const width = Math.max(1, (endIdx - startIdx) * slotWidth);
9806
+ const left = slotLefts[startIdx] ?? 0;
9807
+ const width = Math.max(1, (slotLefts[endIdx] ?? 0) - (slotLefts[startIdx] ?? 0));
9631
9808
  return /* @__PURE__ */ jsx36(
9632
9809
  "div",
9633
9810
  {
@@ -9647,7 +9824,7 @@ function CalendarTimeline({
9647
9824
  "flex items-center justify-center"
9648
9825
  ),
9649
9826
  style: {
9650
- left: hoverCell.slotIdx * slotWidth + slotWidth / 2 - 10,
9827
+ left: (slotLefts[hoverCell.slotIdx] ?? 0) + (slotWidths[hoverCell.slotIdx] ?? fixedSlotWidth) / 2 - 10,
9651
9828
  top: clamp3(Math.round(hoverCell.y - 10), 6, Math.max(6, h - 26))
9652
9829
  },
9653
9830
  "aria-hidden": true,
@@ -9736,27 +9913,11 @@ function CalendarTimeline({
9736
9913
  /* @__PURE__ */ jsxs31("div", { className: "grid grid-cols-2 gap-3", children: [
9737
9914
  /* @__PURE__ */ jsxs31("div", { className: "space-y-2", children: [
9738
9915
  /* @__PURE__ */ jsx36("div", { className: "text-xs text-muted-foreground", children: l.start }),
9739
- /* @__PURE__ */ jsx36(
9740
- Combobox,
9741
- {
9742
- options: createStartOptions,
9743
- value: createStartIdx,
9744
- onChange: (v) => setCreateStartIdx(Number(v)),
9745
- placeholder: l.start
9746
- }
9747
- )
9916
+ /* @__PURE__ */ jsx36(Combobox, { options: createStartOptions, value: createStartIdx, onChange: (v) => setCreateStartIdx(Number(v)), placeholder: l.start })
9748
9917
  ] }),
9749
9918
  /* @__PURE__ */ jsxs31("div", { className: "space-y-2", children: [
9750
9919
  /* @__PURE__ */ jsx36("div", { className: "text-xs text-muted-foreground", children: l.end }),
9751
- /* @__PURE__ */ jsx36(
9752
- Combobox,
9753
- {
9754
- options: createEndOptions,
9755
- value: createEndIdx,
9756
- onChange: (v) => setCreateEndIdx(Number(v)),
9757
- placeholder: l.end
9758
- }
9759
- )
9920
+ /* @__PURE__ */ jsx36(Combobox, { options: createEndOptions, value: createEndIdx, onChange: (v) => setCreateEndIdx(Number(v)), placeholder: l.end })
9760
9921
  ] })
9761
9922
  ] }),
9762
9923
  /* @__PURE__ */ jsxs31("div", { className: "flex items-center justify-end gap-2 pt-2", children: [