@redocly/theme
Version:
Shared UI components lib
92 lines • 3.63 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getDefaultFallbackPlacements = getDefaultFallbackPlacements;
exports.calcAnchorPoint = calcAnchorPoint;
exports.fitsInViewport = fitsInViewport;
exports.resolvePlacement = resolvePlacement;
const PLACEMENT_MARGIN = 10;
const COUNTER_CLOCKWISE = ['top', 'left', 'bottom', 'right'];
function getDefaultFallbackPlacements(placement) {
const index = COUNTER_CLOCKWISE.indexOf(placement);
const result = [];
for (let i = 1; i < COUNTER_CLOCKWISE.length; i++) {
result.push(COUNTER_CLOCKWISE[(index + i) % COUNTER_CLOCKWISE.length]);
}
return result;
}
function calcAnchorPoint(triggerRect, placement, arrowPosition) {
const horizontalLeft = () => arrowPosition === 'left'
? triggerRect.left - 24
: arrowPosition === 'right'
? triggerRect.right + 24
: triggerRect.left + triggerRect.width / 2;
const verticalTop = () => triggerRect.top + triggerRect.height / 2;
switch (placement) {
case 'top':
return { top: triggerRect.top, left: horizontalLeft() };
case 'bottom':
return { top: triggerRect.bottom, left: horizontalLeft() };
case 'left':
return { top: verticalTop(), left: triggerRect.left };
case 'right':
return { top: verticalTop(), left: triggerRect.right };
}
}
function fitsInViewport({ anchor, tooltipWidth, tooltipHeight, placement, arrowPosition, }) {
const horizontalLeft = () => arrowPosition === 'left'
? anchor.left
: arrowPosition === 'right'
? anchor.left - tooltipWidth
: anchor.left - tooltipWidth / 2;
const verticalTop = () => anchor.top - tooltipHeight / 2;
let top;
let left;
switch (placement) {
case 'top':
top = anchor.top - tooltipHeight - PLACEMENT_MARGIN;
left = horizontalLeft();
break;
case 'bottom':
top = anchor.top + PLACEMENT_MARGIN;
left = horizontalLeft();
break;
case 'left':
top = verticalTop();
left = anchor.left - tooltipWidth - PLACEMENT_MARGIN;
break;
case 'right':
top = verticalTop();
left = anchor.left + PLACEMENT_MARGIN;
break;
}
return (top >= 0 &&
left >= 0 &&
left + tooltipWidth <= window.innerWidth &&
top + tooltipHeight <= window.innerHeight);
}
/**
* Given the trigger rect, tooltip dimensions, primary placement/arrow, and
* fallback list, returns the first placement that keeps the tooltip fully
* inside the viewport. Falls back to the primary when nothing fits.
*/
function resolvePlacement({ triggerRect, tooltipWidth, tooltipHeight, placement, arrowPosition, fallbackPlacements, }) {
if (!(fallbackPlacements === null || fallbackPlacements === void 0 ? void 0 : fallbackPlacements.length) || tooltipWidth === 0 || tooltipHeight === 0) {
return placement;
}
const candidates = [placement, ...fallbackPlacements];
for (const candidate of candidates) {
const candidateArrow = candidate === placement ? arrowPosition : 'center';
const pos = calcAnchorPoint(triggerRect, candidate, candidateArrow);
if (fitsInViewport({
anchor: pos,
tooltipWidth,
tooltipHeight,
placement: candidate,
arrowPosition: candidateArrow,
})) {
return candidate;
}
}
return placement;
}
//# sourceMappingURL=tooltip-placement.js.map