UNPKG

tldraw

Version:

A tiny little drawing editor.

119 lines (105 loc) 2.83 kB
import { Box, Editor, TLFrameShape, TLShape, TLShapeId, TLShapePartial, Vec, compact, kickoutOccludedShapes, } from '@tldraw/editor' /** * Remove a frame. * * @param editor - tldraw editor instance. * @param ids - Ids of the frames you wish to remove. * * @public */ export function removeFrame(editor: Editor, ids: TLShapeId[]) { const frames = compact( ids .map((id) => editor.getShape<TLFrameShape>(id)) .filter((f) => f && editor.isShapeOfType(f, 'frame')) ) if (!frames.length) return const allChildren: TLShapeId[] = [] editor.run(() => { frames.map((frame) => { const children = editor.getSortedChildIdsForParent(frame.id) if (children.length) { kickoutOccludedShapes(editor, children, { filter: (s) => !frames.find((f) => f.id === s.id), }) allChildren.push(...children) } }) editor.setSelectedShapes(allChildren) editor.deleteShapes(ids) }) } /** @internal */ export const DEFAULT_FRAME_PADDING = 50 export function getFrameChildrenBounds( children: (TLShape | undefined)[], editor: Editor, opts: { padding: number } = { padding: DEFAULT_FRAME_PADDING } ) { const bounds = Box.FromPoints( children.flatMap((shape) => { if (!shape) return [] const geometry = editor.getShapeGeometry(shape.id) const transform = editor.getShapeLocalTransform(shape) return transform?.applyToPoints(geometry.vertices) ?? [] }) ) const padding = opts.padding ?? DEFAULT_FRAME_PADDING const w = bounds.w + 2 * padding const h = bounds.h + 2 * padding const dx = padding - bounds.minX const dy = padding - bounds.minY return { w, h, dx, dy } } /** * Fit a frame to its content. * * @param id - Id of the frame you wish to fit to content. * @param editor - tlraw editor instance. * @param opts - Options for fitting the frame. * * @public */ export function fitFrameToContent(editor: Editor, id: TLShapeId, opts = {} as { padding: number }) { const frame = editor.getShape<TLFrameShape>(id) if (!frame) return const childIds = editor.getSortedChildIdsForParent(frame.id) const children = compact(childIds.map((id) => editor.getShape(id))) if (!children.length) return const { w, h, dx, dy } = getFrameChildrenBounds(children, editor, opts) // The shapes already perfectly fit the frame. if (dx === 0 && dy === 0 && frame.props.w === w && frame.props.h === h) return const diff = new Vec(dx, dy).rot(frame.rotation) editor.run(() => { const changes: TLShapePartial[] = childIds.map((child) => { const shape = editor.getShape(child)! return { id: shape.id, type: shape.type, x: shape.x + dx, y: shape.y + dy, } }) changes.push({ id: frame.id, type: frame.type, x: frame.x - diff.x, y: frame.y - diff.y, props: { w, h, }, }) editor.updateShapes(changes) }) }