@mlola-ui/behavior 1.0.11 → 1.0.13
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/package.json +1 -1
- package/src/index.js +9 -0
- package/src/interaction.js +17 -0
- package/src/logic.d.ts +9 -0
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
clampToStep,
|
|
22
22
|
focusTrapIndex,
|
|
23
23
|
percentOf,
|
|
24
|
+
fitTooltip,
|
|
24
25
|
placeFloating,
|
|
25
26
|
rovingIndex,
|
|
26
27
|
sliderValueForKey,
|
|
@@ -487,6 +488,7 @@ const behaviors = {
|
|
|
487
488
|
const trigger = root.firstElementChild;
|
|
488
489
|
if (!tip || !trigger) return [];
|
|
489
490
|
const delay = Number(root.dataset.mlDelay ?? 200);
|
|
491
|
+
const side = tip.dataset.side || "top";
|
|
490
492
|
let timer = null;
|
|
491
493
|
|
|
492
494
|
const show = () => {
|
|
@@ -494,6 +496,13 @@ const behaviors = {
|
|
|
494
496
|
timer = setTimeout(() => {
|
|
495
497
|
tip.hidden = false;
|
|
496
498
|
tip.dataset.state = "open";
|
|
499
|
+
// Measure from the side the markup asks for, then flip or slide to stay on screen.
|
|
500
|
+
tip.dataset.side = side;
|
|
501
|
+
tip.style.removeProperty("--ml-tooltip-shift");
|
|
502
|
+
const a = trigger.getBoundingClientRect();
|
|
503
|
+
const fit = fitTooltip({ x: a.left, y: a.top, width: a.width, height: a.height }, { width: tip.offsetWidth, height: tip.offsetHeight }, { width: document.documentElement.clientWidth, height: window.innerHeight }, side);
|
|
504
|
+
tip.dataset.side = fit.side;
|
|
505
|
+
tip.style.setProperty("--ml-tooltip-shift", `${fit.shift}px`);
|
|
497
506
|
if (tip.id) trigger.setAttribute("aria-describedby", tip.id);
|
|
498
507
|
}, Math.max(0, delay));
|
|
499
508
|
};
|
package/src/interaction.js
CHANGED
|
@@ -166,3 +166,20 @@ export function placeFloating(anchor, floating, viewport, { side = "bottom", ali
|
|
|
166
166
|
y = Math.min(Math.max(y, padding), Math.max(padding, viewport.height - floating.height - padding));
|
|
167
167
|
return { x: Math.round(x), y: Math.round(y), side: chosen };
|
|
168
168
|
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Where a tooltip anchored beside its trigger by CSS should sit to stay on
|
|
172
|
+
* screen: the side it opens on (flipped when the other has more room, or
|
|
173
|
+
* moved above when neither side has room across), and how far to slide it
|
|
174
|
+
* along that edge. The arrow slides back by the same amount, so it still
|
|
175
|
+
* points at the trigger.
|
|
176
|
+
*/
|
|
177
|
+
export function fitTooltip(anchor, tip, viewport, side = "top", { offset = 8, padding = 8 } = {}) {
|
|
178
|
+
const across = side === "left" || side === "right";
|
|
179
|
+
const roomAcross = Math.max(anchor.x, viewport.width - anchor.x - anchor.width) - padding;
|
|
180
|
+
const wanted = across && tip.width + offset > roomAcross ? "top" : side;
|
|
181
|
+
const placed = placeFloating(anchor, tip, viewport, { side: wanted, align: "center", offset, padding });
|
|
182
|
+
const vertical = placed.side === "top" || placed.side === "bottom";
|
|
183
|
+
const centered = vertical ? anchor.x + anchor.width / 2 - tip.width / 2 : anchor.y + anchor.height / 2 - tip.height / 2;
|
|
184
|
+
return { side: placed.side, shift: Math.round((vertical ? placed.x : placed.y) - centered) };
|
|
185
|
+
}
|
package/src/logic.d.ts
CHANGED
|
@@ -134,3 +134,12 @@ export function placeFloating(
|
|
|
134
134
|
viewport: { width: number; height: number },
|
|
135
135
|
options?: { side?: Side; align?: Align; offset?: number; padding?: number },
|
|
136
136
|
): Placement;
|
|
137
|
+
|
|
138
|
+
/** A CSS-anchored tooltip's side and its slide along that edge to stay on screen. */
|
|
139
|
+
export function fitTooltip(
|
|
140
|
+
anchor: Rect,
|
|
141
|
+
tip: { width: number; height: number },
|
|
142
|
+
viewport: { width: number; height: number },
|
|
143
|
+
side?: Side,
|
|
144
|
+
options?: { offset?: number; padding?: number },
|
|
145
|
+
): { side: Side; shift: number };
|