UNPKG

@blueprintjs/core

Version:
91 lines (83 loc) 3.78 kB
import { CSSProperties } from "react"; import { Position } from "../../common/position"; // this value causes popover and target edges to line up on 50px targets export const MIN_ARROW_SPACING = 18; export interface IDimensions { height: number; width: number; } export interface IArrowPositionStyles { arrow?: CSSProperties; container?: CSSProperties; } export function computeArrowOffset(sideLength: number, arrowSize: number, minimum = MIN_ARROW_SPACING) { return Math.max(Math.round((sideLength - arrowSize) / 2), minimum); } export function getPopoverTransformOrigin(position: Position, arrowSize: number, targetDimensions: IDimensions): string { const offsetX = computeArrowOffset(targetDimensions.width, arrowSize); const offsetY = computeArrowOffset(targetDimensions.height, arrowSize); switch (position) { case Position.TOP_LEFT: return `${offsetX}px bottom`; case Position.TOP_RIGHT: return `calc(100% - ${offsetX}px) bottom`; case Position.BOTTOM_LEFT: return `${offsetX}px top`; case Position.BOTTOM_RIGHT: return `calc(100% - ${offsetX}px) top`; case Position.LEFT_TOP: return `right ${offsetY}px`; case Position.LEFT_BOTTOM: return `right calc(100% - ${offsetY}px)`; case Position.RIGHT_TOP: return `left ${offsetY}px`; case Position.RIGHT_BOTTOM: return `left calc(100% - ${offsetY}px)`; default: return undefined; } } export function getArrowPositionStyles(position: Position, arrowSize: number, ignoreTargetDimensions: boolean, targetDimensions: IDimensions, inline: boolean): IArrowPositionStyles { // compute the offset to center an arrow with given hypotenuse in a side of the given length const popoverOffset = (sideLength: number) => { const offset = computeArrowOffset(sideLength, arrowSize, 0); return offset < MIN_ARROW_SPACING ? MIN_ARROW_SPACING - offset : 0; }; const popoverOffsetX = popoverOffset(targetDimensions.width); const popoverOffsetY = popoverOffset(targetDimensions.height); // TOP, RIGHT, BOTTOM, LEFT are handled purely in CSS because of centering transforms switch (position) { case Position.TOP_LEFT: case Position.BOTTOM_LEFT: return { arrow: ignoreTargetDimensions ? {} : { left: computeArrowOffset(targetDimensions.width, arrowSize) }, container: { marginLeft: -popoverOffsetX }, }; case Position.TOP_RIGHT: case Position.BOTTOM_RIGHT: return { arrow: ignoreTargetDimensions ? {} : { right: computeArrowOffset(targetDimensions.width, arrowSize) }, container: { marginLeft: popoverOffsetX }, }; case Position.RIGHT_TOP: case Position.LEFT_TOP: return { arrow: ignoreTargetDimensions ? {} : { top: computeArrowOffset(targetDimensions.height, arrowSize) }, container: inline ? { top: -popoverOffsetY } : { marginTop: -popoverOffsetY }, }; case Position.RIGHT_BOTTOM: case Position.LEFT_BOTTOM: return { arrow: ignoreTargetDimensions ? {} : { bottom: computeArrowOffset(targetDimensions.height, arrowSize) }, container: inline ? { bottom: -popoverOffsetY} : { marginTop: popoverOffsetY }, }; default: return {}; } }