@underverse-ui/underverse 0.2.99 → 0.2.101
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 +91 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +94 -15
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -8759,6 +8759,7 @@ function CalendarTimeline({
|
|
|
8759
8759
|
rowHeights,
|
|
8760
8760
|
defaultRowHeights,
|
|
8761
8761
|
onRowHeightsChange,
|
|
8762
|
+
autoRowHeight,
|
|
8762
8763
|
enableLayoutResize,
|
|
8763
8764
|
slotMinWidth,
|
|
8764
8765
|
dayTimeStepMinutes = 60,
|
|
@@ -8811,6 +8812,10 @@ function CalendarTimeline({
|
|
|
8811
8812
|
[isControlledEventSheetOpen, onEventSheetOpenChange, setSelectedEventId]
|
|
8812
8813
|
);
|
|
8813
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;
|
|
8814
8819
|
const canResizeColumn = React28.useMemo(() => {
|
|
8815
8820
|
const cfg = enableLayoutResize;
|
|
8816
8821
|
if (!cfg) return false;
|
|
@@ -8998,13 +9003,43 @@ function CalendarTimeline({
|
|
|
8998
9003
|
setInternalRowHeights(defaultRowHeights);
|
|
8999
9004
|
}, [defaultRowHeights, isControlledRowHeights]);
|
|
9000
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]);
|
|
9001
9034
|
const getResourceRowHeight = React28.useCallback(
|
|
9002
9035
|
(resourceId) => {
|
|
9003
9036
|
const h = activeRowHeights[resourceId];
|
|
9004
|
-
|
|
9005
|
-
|
|
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;
|
|
9006
9041
|
},
|
|
9007
|
-
[activeRowHeights, effectiveRowHeight]
|
|
9042
|
+
[activeRowHeights, autoRowHeightsByResource, effectiveRowHeight]
|
|
9008
9043
|
);
|
|
9009
9044
|
const setRowHeightForResource = React28.useCallback(
|
|
9010
9045
|
(resourceId, height) => {
|
|
@@ -9137,10 +9172,6 @@ function CalendarTimeline({
|
|
|
9137
9172
|
const fmt = getDtf(resolvedLocale, resolvedTimeZone, { weekday: "long", year: "numeric", month: "long", day: "numeric" });
|
|
9138
9173
|
return fmt.format(range.start);
|
|
9139
9174
|
}, [activeDate, activeView, formatters, l.week, range.end, range.start, resolvedLocale, resolvedTimeZone]);
|
|
9140
|
-
const densityClass = sizeConfig.densityClass;
|
|
9141
|
-
const eventHeight = sizeConfig.eventHeight;
|
|
9142
|
-
const laneGap = sizeConfig.laneGap;
|
|
9143
|
-
const lanePaddingY = sizeConfig.lanePaddingY;
|
|
9144
9175
|
const createMode = interactions?.createMode ?? "drag";
|
|
9145
9176
|
const canCreate = !isViewOnly && (interactions?.creatable ?? false) && !!onCreateEvent;
|
|
9146
9177
|
const [createOpen, setCreateOpen] = React28.useState(false);
|
|
@@ -9207,6 +9238,7 @@ function CalendarTimeline({
|
|
|
9207
9238
|
const dragRef = React28.useRef(null);
|
|
9208
9239
|
const [preview, setPreview] = React28.useState(null);
|
|
9209
9240
|
const suppressNextEventClickRef = React28.useRef(false);
|
|
9241
|
+
const [hoverCell, setHoverCell] = React28.useState(null);
|
|
9210
9242
|
const autoScrollStateRef = React28.useRef({
|
|
9211
9243
|
dir: 0,
|
|
9212
9244
|
speed: 0,
|
|
@@ -9416,7 +9448,32 @@ function CalendarTimeline({
|
|
|
9416
9448
|
};
|
|
9417
9449
|
const onPointerMove = (e) => {
|
|
9418
9450
|
const drag = dragRef.current;
|
|
9419
|
-
if (!drag
|
|
9451
|
+
if (!drag) {
|
|
9452
|
+
if (isViewOnly) return;
|
|
9453
|
+
if (!(interactions?.creatable ?? false)) return;
|
|
9454
|
+
const target = e.target;
|
|
9455
|
+
if (target?.closest?.("[data-uv-ct-event]")) {
|
|
9456
|
+
if (hoverCell) setHoverCell(null);
|
|
9457
|
+
return;
|
|
9458
|
+
}
|
|
9459
|
+
const ctx = getPointerContext(e.clientX, e.clientY);
|
|
9460
|
+
if (!ctx) {
|
|
9461
|
+
if (hoverCell) setHoverCell(null);
|
|
9462
|
+
return;
|
|
9463
|
+
}
|
|
9464
|
+
const rowEl = target?.closest?.("[data-uv-ct-row]");
|
|
9465
|
+
if (!rowEl) {
|
|
9466
|
+
if (hoverCell) setHoverCell(null);
|
|
9467
|
+
return;
|
|
9468
|
+
}
|
|
9469
|
+
const rect = rowEl.getBoundingClientRect();
|
|
9470
|
+
const y = clamp3(e.clientY - rect.top, 0, rect.height);
|
|
9471
|
+
if (!hoverCell || hoverCell.resourceId !== ctx.resourceId || hoverCell.slotIdx !== ctx.slotIdx || Math.abs(hoverCell.y - y) > 0.5) {
|
|
9472
|
+
setHoverCell({ resourceId: ctx.resourceId, slotIdx: ctx.slotIdx, y });
|
|
9473
|
+
}
|
|
9474
|
+
return;
|
|
9475
|
+
}
|
|
9476
|
+
if (drag.pointerId !== e.pointerId) return;
|
|
9420
9477
|
updateAutoScrollFromPointer(e.clientX, e.clientY);
|
|
9421
9478
|
updateDragPreview(e.clientX, e.clientY);
|
|
9422
9479
|
};
|
|
@@ -9425,6 +9482,7 @@ function CalendarTimeline({
|
|
|
9425
9482
|
if (!drag || drag.pointerId !== e.pointerId) return;
|
|
9426
9483
|
dragRef.current = null;
|
|
9427
9484
|
stopAutoScroll();
|
|
9485
|
+
setHoverCell(null);
|
|
9428
9486
|
if (!preview) {
|
|
9429
9487
|
setPreview(null);
|
|
9430
9488
|
return;
|
|
@@ -9525,10 +9583,10 @@ function CalendarTimeline({
|
|
|
9525
9583
|
return { ev: { ...ev, _start: s, _end: e }, startIdx, endIdx };
|
|
9526
9584
|
});
|
|
9527
9585
|
const { packed, laneCount } = intervalPack(mapped);
|
|
9528
|
-
const visible = packed.filter((p) => p.lane <
|
|
9529
|
-
const hidden = packed.filter((p) => p.lane >=
|
|
9586
|
+
const visible = packed.filter((p) => p.lane < effectiveMaxLanesPerRow);
|
|
9587
|
+
const hidden = packed.filter((p) => p.lane >= effectiveMaxLanesPerRow);
|
|
9530
9588
|
const rowHeightPx = getResourceRowHeight(resourceId);
|
|
9531
|
-
const visibleLaneCount = Math.max(1, Math.min(laneCount,
|
|
9589
|
+
const visibleLaneCount = Math.max(1, Math.min(laneCount, effectiveMaxLanesPerRow));
|
|
9532
9590
|
const available = Math.max(0, rowHeightPx - lanePaddingY * 2 - laneGap * Math.max(0, visibleLaneCount - 1));
|
|
9533
9591
|
const fitPerLane = visibleLaneCount > 0 ? Math.floor(available / visibleLaneCount) : eventHeight;
|
|
9534
9592
|
const perLaneHeight = Math.max(9, Math.min(eventHeight, fitPerLane || eventHeight));
|
|
@@ -9546,7 +9604,7 @@ function CalendarTimeline({
|
|
|
9546
9604
|
});
|
|
9547
9605
|
}
|
|
9548
9606
|
return map;
|
|
9549
|
-
}, [eventsByResource, getResourceRowHeight, laneGap, lanePaddingY, slotStarts, slots.length, slotWidth,
|
|
9607
|
+
}, [eventsByResource, getResourceRowHeight, laneGap, lanePaddingY, slotStarts, slots.length, slotWidth, effectiveMaxLanesPerRow, preview, eventHeight]);
|
|
9550
9608
|
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
9551
9609
|
"div",
|
|
9552
9610
|
{
|
|
@@ -9597,6 +9655,7 @@ function CalendarTimeline({
|
|
|
9597
9655
|
className: "relative flex-1 overflow-auto scrollbar-thin scrollbar-thumb-muted scrollbar-track-transparent",
|
|
9598
9656
|
onPointerMove,
|
|
9599
9657
|
onPointerUp,
|
|
9658
|
+
onPointerLeave: () => setHoverCell(null),
|
|
9600
9659
|
children: [
|
|
9601
9660
|
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { style: { height: topSpacer } }),
|
|
9602
9661
|
rows.slice(startRow, endRow).map((row, idx) => {
|
|
@@ -9608,6 +9667,7 @@ function CalendarTimeline({
|
|
|
9608
9667
|
const r = row.resource;
|
|
9609
9668
|
const layout = layoutsByResource.get(r.id) ?? { visible: [], hidden: [], baseTop: lanePaddingY, eventHeight };
|
|
9610
9669
|
const canMore = layout.hidden.length > 0 && !!onMoreClick;
|
|
9670
|
+
const showCreateHint = !isViewOnly && (interactions?.creatable ?? false) && !preview && hoverCell?.resourceId === r.id;
|
|
9611
9671
|
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
9612
9672
|
"div",
|
|
9613
9673
|
{
|
|
@@ -9680,6 +9740,7 @@ function CalendarTimeline({
|
|
|
9680
9740
|
ev.className,
|
|
9681
9741
|
isPreview && "ring-2 ring-primary/50 ring-offset-1 ring-offset-background scale-[1.02] z-10"
|
|
9682
9742
|
),
|
|
9743
|
+
"data-uv-ct-event": true,
|
|
9683
9744
|
style: {
|
|
9684
9745
|
left,
|
|
9685
9746
|
top,
|
|
@@ -9750,6 +9811,24 @@ function CalendarTimeline({
|
|
|
9750
9811
|
}
|
|
9751
9812
|
);
|
|
9752
9813
|
})() : null,
|
|
9814
|
+
showCreateHint ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
9815
|
+
"div",
|
|
9816
|
+
{
|
|
9817
|
+
className: cn(
|
|
9818
|
+
"pointer-events-none absolute z-20",
|
|
9819
|
+
"h-5 w-5 rounded-full",
|
|
9820
|
+
"bg-background/80 backdrop-blur-sm",
|
|
9821
|
+
"border border-border/60 shadow-xs",
|
|
9822
|
+
"flex items-center justify-center"
|
|
9823
|
+
),
|
|
9824
|
+
style: {
|
|
9825
|
+
left: hoverCell.slotIdx * slotWidth + slotWidth / 2 - 10,
|
|
9826
|
+
top: clamp3(Math.round(hoverCell.y - 10), 6, Math.max(6, h - 26))
|
|
9827
|
+
},
|
|
9828
|
+
"aria-hidden": true,
|
|
9829
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_lucide_react20.Plus, { className: "h-3.5 w-3.5 text-muted-foreground" })
|
|
9830
|
+
}
|
|
9831
|
+
) : null,
|
|
9753
9832
|
canMore ? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
9754
9833
|
"button",
|
|
9755
9834
|
{
|