@underverse-ui/underverse 0.2.102 → 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
@@ -1129,6 +1129,14 @@ interface CalendarTimelineProps<TResourceMeta = unknown, TEventMeta = unknown> e
1129
1129
  * Week view is unaffected.
1130
1130
  */
1131
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;
1132
1140
  dayTimeStepMinutes?: number;
1133
1141
  /**
1134
1142
  * Day view horizontal range:
@@ -1201,7 +1209,7 @@ interface CalendarTimelineProps<TResourceMeta = unknown, TEventMeta = unknown> e
1201
1209
  virtualization?: CalendarTimelineVirtualization;
1202
1210
  }
1203
1211
 
1204
- 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, 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;
1205
1213
 
1206
1214
  type ComboboxOption = string | {
1207
1215
  label: string;
package/dist/index.d.ts CHANGED
@@ -1129,6 +1129,14 @@ interface CalendarTimelineProps<TResourceMeta = unknown, TEventMeta = unknown> e
1129
1129
  * Week view is unaffected.
1130
1130
  */
1131
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;
1132
1140
  dayTimeStepMinutes?: number;
1133
1141
  /**
1134
1142
  * Day view horizontal range:
@@ -1201,7 +1209,7 @@ interface CalendarTimelineProps<TResourceMeta = unknown, TEventMeta = unknown> e
1201
1209
  virtualization?: CalendarTimelineVirtualization;
1202
1210
  }
1203
1211
 
1204
- 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, 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;
1205
1213
 
1206
1214
  type ComboboxOption = string | {
1207
1215
  label: string;
package/dist/index.js CHANGED
@@ -8588,6 +8588,8 @@ function CalendarTimeline({
8588
8588
  enableLayoutResize,
8589
8589
  slotMinWidth,
8590
8590
  adaptiveSlotWidths,
8591
+ dayEventStyle = "span",
8592
+ dayEventMaxWidth,
8591
8593
  dayTimeStepMinutes = 60,
8592
8594
  dayRangeMode,
8593
8595
  workHours,
@@ -8786,6 +8788,26 @@ function CalendarTimeline({
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]);
8789
8811
  const slotMetrics = React28.useMemo(() => {
8790
8812
  const n = slots.length;
8791
8813
  const widths = new Array(n).fill(fixedSlotWidth);
@@ -8798,12 +8820,38 @@ function CalendarTimeline({
8798
8820
  for (let i = 0; i < n; i++) lefts2[i + 1] = lefts2[i] + widths[i];
8799
8821
  const gridWidth3 = lefts2[n] ?? 0;
8800
8822
  const xToSlotIdx3 = (x) => clamp3(Math.floor(x / Math.max(1, fixedSlotWidth)), 0, Math.max(0, n - 1));
8801
- return { slotWidths: widths, slotLefts: lefts2, gridWidth: gridWidth3, xToSlotIdx: xToSlotIdx3 };
8823
+ return { slotWidths: widths, slotLefts: lefts2, slotHasEvent: null, gridWidth: gridWidth3, xToSlotIdx: xToSlotIdx3 };
8802
8824
  }
8803
8825
  const cfg = typeof adaptiveCfg === "object" ? adaptiveCfg : {};
8804
8826
  const mode = cfg.mode ?? "shrink";
8805
8827
  const defaultEmptySlotWidth = Math.max(18, Math.round(effectiveSlotMinWidth * 0.6));
8806
- const emptySlotWidth = Math.max(12, Math.min(fixedSlotWidth, cfg.emptySlotWidth ?? defaultEmptySlotWidth));
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
+ }
8807
8855
  const diff = new Array(n + 1).fill(0);
8808
8856
  for (const ev of normalizedEvents) {
8809
8857
  const startIdx = binarySearchLastLE(slotStarts, ev._start);
@@ -8826,7 +8874,7 @@ function CalendarTimeline({
8826
8874
  for (let i = 0; i < n; i++) lefts2[i + 1] = lefts2[i] + widths[i];
8827
8875
  const gridWidth3 = lefts2[n] ?? 0;
8828
8876
  const xToSlotIdx3 = (x) => clamp3(Math.floor(x / Math.max(1, fixedSlotWidth)), 0, Math.max(0, n - 1));
8829
- return { slotWidths: widths, slotLefts: lefts2, gridWidth: gridWidth3, xToSlotIdx: xToSlotIdx3 };
8877
+ return { slotWidths: widths, slotLefts: lefts2, slotHasEvent: null, gridWidth: gridWidth3, xToSlotIdx: xToSlotIdx3 };
8830
8878
  }
8831
8879
  const emptyCount = n - eventCount;
8832
8880
  let eventSlotWidth = fixedSlotWidth;
@@ -8856,9 +8904,9 @@ function CalendarTimeline({
8856
8904
  }
8857
8905
  return clamp3(lo, 0, Math.max(0, n - 1));
8858
8906
  };
8859
- return { slotWidths: widths, slotLefts: lefts, gridWidth: gridWidth2, xToSlotIdx: xToSlotIdx2 };
8860
- }, [activeView, adaptiveSlotWidths, effectiveSlotMinWidth, fixedSlotWidth, normalizedEvents, slotStarts, slots.length]);
8861
- const { slotWidths, slotLefts, gridWidth, xToSlotIdx } = slotMetrics;
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;
8862
8910
  const eventsByResource = React28.useMemo(() => {
8863
8911
  return eventsByResourceId(normalizedEvents);
8864
8912
  }, [normalizedEvents]);
@@ -9450,16 +9498,24 @@ function CalendarTimeline({
9450
9498
  "div",
9451
9499
  {
9452
9500
  className: cn(
9453
- "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",
9454
9503
  sizeConfig.slotHeaderClass,
9455
- s.isToday && "bg-primary/8 border-l-primary/40"
9504
+ activeView !== "day" && s.isToday && "bg-primary/8 border-l-primary/40"
9456
9505
  ),
9457
9506
  style: { width: slotWidths[idx], minWidth: slotWidths[idx] },
9458
9507
  "aria-label": formatters?.ariaSlotLabel?.(s.start, { view: activeView, locale: resolvedLocale, timeZone: resolvedTimeZone }),
9459
- children: /* @__PURE__ */ jsxs31("div", { className: cn("flex flex-col items-center", s.isToday && "relative"), children: [
9460
- s.isToday && /* @__PURE__ */ jsx36(Dot, { className: "absolute -top-2.5 h-4 w-4 text-primary animate-pulse" }),
9461
- s.label
9462
- ] })
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
+ })()
9463
9519
  },
9464
9520
  `${s.start.toISOString()}_${idx}`
9465
9521
  ))
@@ -9612,8 +9668,9 @@ function CalendarTimeline({
9612
9668
  "div",
9613
9669
  {
9614
9670
  className: cn(
9615
- "h-full border-l border-border/20 transition-colors duration-100",
9616
- 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",
9617
9674
  "hover:bg-muted/10"
9618
9675
  ),
9619
9676
  style: { width: slotWidths[i2], minWidth: slotWidths[i2] }
@@ -9660,28 +9717,17 @@ function CalendarTimeline({
9660
9717
  /* @__PURE__ */ jsx36("div", { className: "text-xs opacity-80", children: timeText }),
9661
9718
  resource?.label ? /* @__PURE__ */ jsx36("div", { className: "text-xs opacity-70", children: resource.label }) : null
9662
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;
9663
9725
  return /* @__PURE__ */ jsx36(Tooltip, { content: tooltipContent, placement: "top", delay: { open: 250, close: 0 }, children: /* @__PURE__ */ jsxs31(
9664
9726
  "div",
9665
9727
  {
9666
- className: cn(
9667
- "absolute rounded-lg border select-none cursor-pointer",
9668
- "shadow-sm hover:shadow-md hover:scale-[1.02] hover:z-10",
9669
- "transition-all duration-150 ease-out",
9670
- "backdrop-blur-sm",
9671
- "overflow-hidden",
9672
- ev.className,
9673
- isPreview && "ring-2 ring-primary/50 ring-offset-1 ring-offset-background scale-[1.02] z-10"
9674
- ),
9728
+ className: cn("absolute select-none cursor-pointer", isPreview && "z-10"),
9675
9729
  "data-uv-ct-event": true,
9676
- style: {
9677
- left,
9678
- top,
9679
- width,
9680
- height: layout.eventHeight,
9681
- background: bg,
9682
- borderColor: border,
9683
- borderLeftWidth: 3
9684
- },
9730
+ style: { left, top, width, height: layout.eventHeight },
9685
9731
  role: "button",
9686
9732
  tabIndex: 0,
9687
9733
  "aria-label": aria,
@@ -9709,6 +9755,31 @@ function CalendarTimeline({
9709
9755
  onDoubleClick: () => onEventDoubleClick?.(ev),
9710
9756
  onPointerDown: (e) => onPointerDownEvent(e, ev, "move"),
9711
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
+ ),
9712
9783
  !isViewOnly && (interactions?.resizableEvents ?? true) && ev.resizable !== false ? /* @__PURE__ */ jsxs31(Fragment10, { children: [
9713
9784
  /* @__PURE__ */ jsx36(
9714
9785
  "div",
@@ -9724,8 +9795,7 @@ function CalendarTimeline({
9724
9795
  onPointerDown: (e) => onPointerDownEvent(e, ev, "resize-end")
9725
9796
  }
9726
9797
  )
9727
- ] }) : null,
9728
- node
9798
+ ] }) : null
9729
9799
  ]
9730
9800
  }
9731
9801
  ) }, ev.id);