@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.cjs +223 -62
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +25 -1
- package/dist/index.d.ts +25 -1
- package/dist/index.js +223 -62
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
8779
|
-
const baseSlotWidth = activeView === "month"
|
|
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
|
-
}, [
|
|
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 =
|
|
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
|
-
[
|
|
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(
|
|
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
|
|
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:
|
|
9506
|
+
style: { width: slotWidths[idx], minWidth: slotWidths[idx] },
|
|
9368
9507
|
"aria-label": formatters?.ariaSlotLabel?.(s.start, { view: activeView, locale: resolvedLocale, timeZone: resolvedTimeZone }),
|
|
9369
|
-
children:
|
|
9370
|
-
s.
|
|
9371
|
-
|
|
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
|
|
9426
|
-
width: Math.max(1, (p.endIdx - p.startIdx
|
|
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
|
-
}, [
|
|
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(
|
|
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
|
|
9509
|
-
|
|
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:
|
|
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
|
|
9630
|
-
const width = Math.max(1, (endIdx - startIdx
|
|
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
|
|
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: [
|