import {forwardRef, useMemo} from 'react'; import {PopperProps} from 'react-popper'; import styled from '@emotion/styled'; import domId from 'sentry/utils/domId'; import {ColorOrAlias} from 'sentry/utils/theme'; type Props = React.HTMLAttributes & { background?: ColorOrAlias; border?: ColorOrAlias; placement?: PopperProps['placement']; size?: number; strokeWidth?: number; }; const BaseOverlayArrow: React.ForwardRefRenderFunction = ( { size = 16, strokeWidth = 1, placement, background = 'backgroundElevated', border = 'translucentBorder', ...props }, ref ) => { /** * SVG height */ const h = Math.round(size * 0.4); /** * SVG width */ const w = size; /** * SVG stroke width */ const s = strokeWidth; const arrowPath = [ `M 0 ${h - s / 2}`, `C ${w * 0.25} ${h - s / 2} ${w * 0.45} ${s / 2} ${w / 2} ${s / 2}`, `C ${w * 0.55} ${s / 2} ${w * 0.75} ${h - s / 2} ${w} ${h - s / 2}`, ].join(''); const strokeMaskId = useMemo(() => domId('stroke-mask'), []); const fillMaskId = useMemo(() => domId('fill-mask'), []); return ( ); }; const OverlayArrow = forwardRef(BaseOverlayArrow); export default OverlayArrow; const Wrap = styled('div')<{size: number; placement?: PopperProps['placement']}>` position: relative; display: flex; width: ${p => p.size}px; height: ${p => p.size}px; ${p => p.placement?.startsWith('top') && `bottom: 0; transform: translateY(50%) rotate(180deg);`} ${p => p.placement?.startsWith('bottom') && `top: 0; transform: translateY(-50%) ;`} ${p => p.placement?.startsWith('left') && `right: 0; transform: translateX(50%) rotate(90deg);`} ${p => p.placement?.startsWith('right') && `left: 0; transform: translateX(-50%) rotate(-90deg);`} `; const SVG = styled('svg')<{background: ColorOrAlias; border: ColorOrAlias}>` position: absolute; bottom: 50%; fill: none; stroke: none; path.stroke { stroke: ${p => p.theme[p.border]}; } path.fill { fill: ${p => p.theme[p.background]}; } `;