Tldraw/packages/tldraw/src/lib/utils/frames/frames.ts

90 wiersze
2.3 KiB
TypeScript

import { Box, Editor, TLFrameShape, TLShapeId, TLShapePartial, Vec, compact } from '@tldraw/editor'
/**
* Remove a frame.
*
* @param editor - tlraw 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<TLFrameShape>(f, 'frame'))
)
if (!frames.length) return
const allChildren: TLShapeId[] = []
frames.map((frame) => {
const children = editor.getSortedChildIdsForParent(frame.id)
if (children.length) {
editor.reparentShapes(children, frame.parentId, frame.index)
allChildren.push(...children)
}
})
editor.setSelectedShapes(allChildren)
editor.deleteShapes(ids)
}
/** @internal */
export const DEFAULT_FRAME_PADDING = 50
/**
* 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 bounds = Box.FromPoints(
children.flatMap((shape) => {
const geometry = editor.getShapeGeometry(shape.id)
return editor.getShapeLocalTransform(shape)!.applyToPoints(geometry.vertices)
})
)
const { padding = DEFAULT_FRAME_PADDING } = opts
const w = bounds.w + 2 * padding
const h = bounds.h + 2 * padding
const dx = padding - bounds.minX
const dy = padding - bounds.minY
// 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)
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)
}