import { TLGroupShape, groupShapeMigrations, groupShapeProps } from '@tldraw/tlschema' import { SVGContainer } from '../../../components/SVGContainer' import { Geometry2d } from '../../../primitives/geometry/Geometry2d' import { Group2d } from '../../../primitives/geometry/Group2d' import { Rectangle2d } from '../../../primitives/geometry/Rectangle2d' import { ShapeUtil } from '../ShapeUtil' import { DashedOutlineBox } from './DashedOutlineBox' /** @public */ export class GroupShapeUtil extends ShapeUtil { static override type = 'group' as const static override props = groupShapeProps static override migrations = groupShapeMigrations override hideSelectionBoundsFg() { return true } override canBind() { return false } canResize() { return true } canResizeChildren() { return true } getDefaultProps(): TLGroupShape['props'] { return {} } getGeometry(shape: TLGroupShape): Geometry2d { const children = this.editor.getSortedChildIdsForParent(shape.id) if (children.length === 0) { return new Rectangle2d({ width: 1, height: 1, isFilled: false }) } return new Group2d({ children: children.map((childId) => { const shape = this.editor.getShape(childId)! return this.editor .getShapeGeometry(childId) .transform(this.editor.getShapeLocalTransform(shape)!, { isLabel: false }) }), }) } component(shape: TLGroupShape) { const isErasing = this.editor.getErasingShapeIds().includes(shape.id) const { hintingShapeIds } = this.editor.getCurrentPageState() const isHintingOtherGroup = hintingShapeIds.length > 0 && hintingShapeIds.some( (id) => id !== shape.id && this.editor.isShapeOfType(this.editor.getShape(id)!, 'group') ) const isFocused = this.editor.getCurrentPageState().focusedGroupId !== shape.id if ( !isErasing && // always show the outline while we're erasing the group // show the outline while the group is focused unless something outside of the group is being hinted // this happens dropping shapes from a group onto some outside group (isFocused || isHintingOtherGroup) ) { return null } const bounds = this.editor.getShapeGeometry(shape).bounds return ( ) } indicator(shape: TLGroupShape) { // Not a class component, but eslint can't tell that :( const bounds = this.editor.getShapeGeometry(shape).bounds return } override onChildrenChange(group: TLGroupShape) { const children = this.editor.getSortedChildIdsForParent(group.id) if (children.length === 0) { if (this.editor.getCurrentPageState().focusedGroupId === group.id) { this.editor.popFocusedGroupId() } this.editor.deleteShapes([group.id]) return } else if (children.length === 1) { if (this.editor.getCurrentPageState().focusedGroupId === group.id) { this.editor.popFocusedGroupId() } this.editor.reparentShapes(children, group.parentId) this.editor.deleteShapes([group.id]) return } } }