@johly/bits-ui 2.18.8 → 2.18.9
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.
|
@@ -139,7 +139,7 @@
|
|
|
139
139
|
<MenuSubContent
|
|
140
140
|
sideOffset={8}
|
|
141
141
|
align={getSubmenuAlign(meta)}
|
|
142
|
-
collisionAvoidance={{ side: "
|
|
142
|
+
collisionAvoidance={{ side: "flip", align: "shift" }}
|
|
143
143
|
>
|
|
144
144
|
{#if column && meta?.kind === "column" && meta.editor === "text"}
|
|
145
145
|
<FilterTextEditor column={column as Column<unknown, "text">} {actions} />
|
|
@@ -128,6 +128,13 @@
|
|
|
128
128
|
.requestAnimationFrame(measureListAlign);
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
function measureListAlignAndQueueRemeasure() {
|
|
132
|
+
if (align !== "list") return;
|
|
133
|
+
clearMeasureFrame();
|
|
134
|
+
measureListAlign();
|
|
135
|
+
queueMeasureListAlign();
|
|
136
|
+
}
|
|
137
|
+
|
|
131
138
|
$effect(() => {
|
|
132
139
|
if (align !== "list") {
|
|
133
140
|
listAlignOffset = 0;
|
|
@@ -137,7 +144,7 @@
|
|
|
137
144
|
listAlignOffset = 0;
|
|
138
145
|
return;
|
|
139
146
|
}
|
|
140
|
-
afterTick(
|
|
147
|
+
afterTick(measureListAlignAndQueueRemeasure);
|
|
141
148
|
});
|
|
142
149
|
|
|
143
150
|
$effect(() => {
|
|
@@ -205,7 +212,7 @@
|
|
|
205
212
|
|
|
206
213
|
function handlePlaced() {
|
|
207
214
|
onPlaced();
|
|
208
|
-
|
|
215
|
+
measureListAlignAndQueueRemeasure();
|
|
209
216
|
}
|
|
210
217
|
|
|
211
218
|
function handleOnFocusOutside(e: FocusEvent) {
|
|
@@ -12,6 +12,72 @@ const OPPOSITE_SIDE = {
|
|
|
12
12
|
bottom: "top",
|
|
13
13
|
left: "right",
|
|
14
14
|
};
|
|
15
|
+
function getPaddingForSide(padding, side) {
|
|
16
|
+
if (typeof padding === "number")
|
|
17
|
+
return padding;
|
|
18
|
+
return padding?.[side] ?? 0;
|
|
19
|
+
}
|
|
20
|
+
function parsePixelValue(value) {
|
|
21
|
+
const parsed = Number.parseFloat(value);
|
|
22
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
23
|
+
}
|
|
24
|
+
function replacePlacementSide(placement, side) {
|
|
25
|
+
const [, align] = placement.split("-");
|
|
26
|
+
return (side + (align ? `-${align}` : ""));
|
|
27
|
+
}
|
|
28
|
+
function getFloatingContentNode(floating) {
|
|
29
|
+
return floating.firstElementChild instanceof HTMLElement
|
|
30
|
+
? floating.firstElementChild
|
|
31
|
+
: floating instanceof HTMLElement
|
|
32
|
+
? floating
|
|
33
|
+
: null;
|
|
34
|
+
}
|
|
35
|
+
function getIntendedFloatingWidth(floating, measuredWidth) {
|
|
36
|
+
const contentNode = getFloatingContentNode(floating);
|
|
37
|
+
if (!contentNode)
|
|
38
|
+
return measuredWidth;
|
|
39
|
+
const style = contentNode.ownerDocument.defaultView?.getComputedStyle(contentNode);
|
|
40
|
+
const rowWidth = style ? parsePixelValue(style.getPropertyValue("--row-width")) : 0;
|
|
41
|
+
const isSubmenu = contentNode.hasAttribute("data-menu-sub-content") ||
|
|
42
|
+
contentNode.hasAttribute("data-dropdown-menu-sub-content") ||
|
|
43
|
+
contentNode.hasAttribute("data-context-menu-sub-content") ||
|
|
44
|
+
contentNode.hasAttribute("data-menubar-sub-content");
|
|
45
|
+
return Math.max(measuredWidth, rowWidth, isSubmenu ? 250 : 0);
|
|
46
|
+
}
|
|
47
|
+
function preferOppositeSideWithRoom(opts) {
|
|
48
|
+
return {
|
|
49
|
+
name: "preferOppositeSideWithRoom",
|
|
50
|
+
async fn(state) {
|
|
51
|
+
const side = getSideFromPlacement(state.placement);
|
|
52
|
+
if (side !== "right" && side !== "left")
|
|
53
|
+
return {};
|
|
54
|
+
const referenceNode = state.elements.reference;
|
|
55
|
+
if (!("getBoundingClientRect" in referenceNode))
|
|
56
|
+
return {};
|
|
57
|
+
const referenceRect = referenceNode.getBoundingClientRect();
|
|
58
|
+
const floatingNode = state.elements.floating;
|
|
59
|
+
const win = getWindow(floatingNode);
|
|
60
|
+
const padding = opts.collisionPadding();
|
|
61
|
+
const sideOffset = opts.sideOffset();
|
|
62
|
+
const desiredWidth = getIntendedFloatingWidth(floatingNode, state.rects.floating.width);
|
|
63
|
+
const leftRoom = referenceRect.left - getPaddingForSide(padding, "left") - sideOffset;
|
|
64
|
+
const rightRoom = win.innerWidth -
|
|
65
|
+
referenceRect.right -
|
|
66
|
+
getPaddingForSide(padding, "right") -
|
|
67
|
+
sideOffset;
|
|
68
|
+
const currentRoom = side === "right" ? rightRoom : leftRoom;
|
|
69
|
+
const oppositeSide = OPPOSITE_SIDE[side];
|
|
70
|
+
const oppositeRoom = oppositeSide === "right" ? rightRoom : leftRoom;
|
|
71
|
+
if (currentRoom >= desiredWidth || oppositeRoom < desiredWidth)
|
|
72
|
+
return {};
|
|
73
|
+
return {
|
|
74
|
+
reset: {
|
|
75
|
+
placement: replacePlacementSide(state.placement, oppositeSide),
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
15
81
|
const FloatingRootContext = new Context("Floating.Root");
|
|
16
82
|
const FloatingContentContext = new Context("Floating.Content");
|
|
17
83
|
const FloatingTooltipRootContext = new Context("Floating.Root");
|
|
@@ -96,6 +162,12 @@ export class FloatingContentState {
|
|
|
96
162
|
mainAxis: this.opts.sideOffset.current + this.#arrowHeight,
|
|
97
163
|
alignmentAxis: this.opts.alignOffset.current,
|
|
98
164
|
}),
|
|
165
|
+
this.opts.avoidCollisions.current &&
|
|
166
|
+
this.#collisionAvoidance.side === "flip" &&
|
|
167
|
+
preferOppositeSideWithRoom({
|
|
168
|
+
sideOffset: () => this.opts.sideOffset.current + this.#arrowHeight,
|
|
169
|
+
collisionPadding: () => this.opts.collisionPadding.current,
|
|
170
|
+
}),
|
|
99
171
|
this.opts.avoidCollisions.current &&
|
|
100
172
|
(this.#collisionAvoidance.side === "shift" ||
|
|
101
173
|
this.#collisionAvoidance.align === "shift") &&
|