import { html, nothing } from 'lit'; import { type IVec } from '../../../../surface-block/index.js'; export enum HandleDirection { Left = 'left', Top = 'top', Right = 'right', Bottom = 'bottom', TopLeft = 'top-left', BottomLeft = 'bottom-left', TopRight = 'top-right', BottomRight = 'bottom-right', } function ResizeHandle( handleDirection: HandleDirection, onPointerDown?: (e: PointerEvent, direction: HandleDirection) => void, updateCursor?: ( dragging: boolean, options?: { type: 'resize' | 'rotate'; target?: HTMLElement; point?: IVec; } ) => void, hideEdgeHandle?: boolean ) { const handlerPointerDown = (e: PointerEvent) => { e.stopPropagation(); onPointerDown && onPointerDown(e, handleDirection); }; const pointerEnter = (type: 'resize' | 'rotate') => (e: PointerEvent) => { e.stopPropagation(); if (e.buttons === 1 || !updateCursor) return; const { clientX, clientY } = e; const target = e.target as HTMLElement; const point = [clientX, clientY]; updateCursor(true, { type, point, target }); }; const pointerLeave = (e: PointerEvent) => { e.stopPropagation(); if (e.buttons === 1 || !updateCursor) return; updateCursor(false); }; const rotationTpl = handleDirection === HandleDirection.Top || handleDirection === HandleDirection.Bottom || handleDirection === HandleDirection.Left || handleDirection === HandleDirection.Right ? nothing : html`
`; return html`
${rotationTpl}
`; } /** * Indicate how selected elements can be resized. * * - edge: The selected elements can only be resized dragging edge, usually when note element is selected * - all: The selected elements can be resize both dragging edge or corner, usually when all elements are `shape` * - none: The selected elements can't be resized, usually when all elements are `connector` * - corner: The selected elements can only be resize dragging corner, this is by default mode * - edgeAndCorner: The selected elements can be resize both dragging left right edge or corner, usually when all elements are 'text' */ export type ResizeMode = 'edge' | 'all' | 'none' | 'corner' | 'edgeAndCorner'; export function ResizeHandles( resizeMode: ResizeMode, onPointerDown: (e: PointerEvent, direction: HandleDirection) => void, updateCursor?: ( dragging: boolean, options?: { type: 'resize' | 'rotate'; target?: HTMLElement; point?: IVec; } ) => void ) { const getCornerHandles = () => { const handleTopLeft = ResizeHandle( HandleDirection.TopLeft, onPointerDown, updateCursor ); const handleTopRight = ResizeHandle( HandleDirection.TopRight, onPointerDown, updateCursor ); const handleBottomLeft = ResizeHandle( HandleDirection.BottomLeft, onPointerDown, updateCursor ); const handleBottomRight = ResizeHandle( HandleDirection.BottomRight, onPointerDown, updateCursor ); return { handleTopLeft, handleTopRight, handleBottomLeft, handleBottomRight, }; }; const getEdgeHandles = (hideEdgeHandle?: boolean) => { const handleLeft = ResizeHandle( HandleDirection.Left, onPointerDown, updateCursor, hideEdgeHandle ); const handleRight = ResizeHandle( HandleDirection.Right, onPointerDown, updateCursor, hideEdgeHandle ); return { handleLeft, handleRight }; }; const getEdgeVerticalHandles = (hideEdgeHandle?: boolean) => { const handleTop = ResizeHandle( HandleDirection.Top, onPointerDown, updateCursor, hideEdgeHandle ); const handleBottom = ResizeHandle( HandleDirection.Bottom, onPointerDown, updateCursor, hideEdgeHandle ); return { handleTop, handleBottom }; }; switch (resizeMode) { case 'corner': { const { handleTopLeft, handleTopRight, handleBottomLeft, handleBottomRight, } = getCornerHandles(); // prettier-ignore return html` ${handleTopLeft} ${handleTopRight} ${handleBottomLeft} ${handleBottomRight} `; } case 'edge': { const { handleLeft, handleRight } = getEdgeHandles(); return html`${handleLeft} ${handleRight}`; } case 'all': { const { handleTopLeft, handleTopRight, handleBottomLeft, handleBottomRight, } = getCornerHandles(); const { handleLeft, handleRight } = getEdgeHandles(true); const { handleTop, handleBottom } = getEdgeVerticalHandles(true); // prettier-ignore return html` ${handleTopLeft} ${handleTop} ${handleTopRight} ${handleRight} ${handleBottomRight} ${handleBottom} ${handleBottomLeft} ${handleLeft} `; } case 'edgeAndCorner': { const { handleTopLeft, handleTopRight, handleBottomLeft, handleBottomRight, } = getCornerHandles(); const { handleLeft, handleRight } = getEdgeHandles(true); return html` ${handleTopLeft} ${handleTopRight} ${handleRight} ${handleBottomRight} ${handleBottomLeft} ${handleLeft} `; } case 'none': { return nothing; } } }