@blueprintjs/core
Version:
Core styles & components
91 lines (83 loc) • 3.78 kB
text/typescript
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 {};
}
}