{ "version": 3, "sources": ["../../../../../src/lib/tools/SelectTool/children/PointingShape.ts"], "sourcesContent": ["import {\n\tGroup2d,\n\tHIT_TEST_MARGIN,\n\tStateNode,\n\tTLArrowShape,\n\tTLEventHandlers,\n\tTLGeoShape,\n\tTLPointerEventInfo,\n\tTLShape,\n} from '@tldraw/editor'\n\nexport class PointingShape extends StateNode {\n\tstatic override id = 'pointing_shape'\n\n\thitShape = {} as TLShape\n\thitShapeForPointerUp = {} as TLShape\n\n\tdidSelectOnEnter = false\n\n\toverride onEnter = (info: TLPointerEventInfo & { target: 'shape' }) => {\n\t\tconst {\n\t\t\tselectedShapeIds,\n\t\t\tfocusedGroupId,\n\t\t\tselectionRotatedPageBounds: selectionBounds,\n\t\t\tinputs: { currentPagePoint, shiftKey, altKey },\n\t\t} = this.editor\n\n\t\tthis.hitShape = info.shape\n\t\tconst outermostSelectingShape = this.editor.getOutermostSelectableShape(info.shape)\n\n\t\tif (\n\t\t\t// If the shape has an onClick handler\n\t\t\tthis.editor.getShapeUtil(info.shape).onClick ||\n\t\t\t// ...or if the shape is the focused layer (e.g. group)\n\t\t\toutermostSelectingShape.id === focusedGroupId ||\n\t\t\t// ...or if the shape is within the selection\n\t\t\tselectedShapeIds.includes(outermostSelectingShape.id) ||\n\t\t\tthis.editor.isAncestorSelected(outermostSelectingShape.id) ||\n\t\t\t// ...or if the current point is NOT within the selection bounds\n\t\t\t(selectedShapeIds.length > 1 && selectionBounds?.containsPoint(currentPagePoint))\n\t\t) {\n\t\t\t// We won't select the shape on enter, though we might select it on pointer up!\n\t\t\tthis.didSelectOnEnter = false\n\t\t\tthis.hitShapeForPointerUp = outermostSelectingShape\n\t\t\treturn\n\t\t}\n\n\t\tthis.didSelectOnEnter = true\n\n\t\tif (shiftKey && !altKey) {\n\t\t\tthis.editor.cancelDoubleClick()\n\t\t\tif (!selectedShapeIds.includes(outermostSelectingShape.id)) {\n\t\t\t\tthis.editor.mark('shift selecting shape')\n\t\t\t\tthis.editor.setSelectedShapes([...selectedShapeIds, outermostSelectingShape.id])\n\t\t\t}\n\t\t} else {\n\t\t\tthis.editor.mark('selecting shape')\n\t\t\tthis.editor.setSelectedShapes([outermostSelectingShape.id])\n\t\t}\n\t}\n\n\toverride onPointerUp: TLEventHandlers['onPointerUp'] = (info) => {\n\t\tconst {\n\t\t\tzoomLevel,\n\t\t\tfocusedGroupId,\n\t\t\tselectedShapeIds,\n\t\t\tinputs: { currentPagePoint, shiftKey },\n\t\t} = this.editor\n\n\t\tconst hitShape =\n\t\t\tthis.editor.getShapeAtPoint(currentPagePoint, {\n\t\t\t\tmargin: HIT_TEST_MARGIN / zoomLevel,\n\t\t\t\thitInside: true,\n\t\t\t\trenderingOnly: true,\n\t\t\t}) ?? this.hitShape\n\n\t\tconst selectingShape = hitShape\n\t\t\t? this.editor.getOutermostSelectableShape(hitShape)\n\t\t\t: this.hitShapeForPointerUp\n\n\t\tif (selectingShape) {\n\t\t\t// If the selecting shape has a click handler, call it instead of selecting the shape\n\t\t\tconst util = this.editor.getShapeUtil(selectingShape)\n\t\t\tif (util.onClick) {\n\t\t\t\tconst change = util.onClick?.(selectingShape)\n\t\t\t\tif (change) {\n\t\t\t\t\tthis.editor.mark('shape on click')\n\t\t\t\t\tthis.editor.updateShapes([change])\n\t\t\t\t\tthis.parent.transition('idle', info)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (selectingShape.id === focusedGroupId) {\n\t\t\t\tif (selectedShapeIds.length > 0) {\n\t\t\t\t\tthis.editor.mark('clearing shape ids')\n\t\t\t\t\tthis.editor.setSelectedShapes([])\n\t\t\t\t} else {\n\t\t\t\t\tthis.editor.popFocusedGroupId()\n\t\t\t\t}\n\t\t\t\tthis.parent.transition('idle', info)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\tif (!this.didSelectOnEnter) {\n\t\t\t// if the shape has an ancestor which is a focusable layer and it is not focused but it is selected\n\t\t\t// then we should focus the layer and select the shape\n\n\t\t\tconst outermostSelectableShape = this.editor.getOutermostSelectableShape(\n\t\t\t\thitShape,\n\t\t\t\t// if a group is selected, we want to stop before reaching that group\n\t\t\t\t// so we can drill down into the group\n\t\t\t\t(parent) => !selectedShapeIds.includes(parent.id)\n\t\t\t)\n\n\t\t\t// If the outermost shape is selected, then either select or deselect the SELECTING shape\n\t\t\tif (selectedShapeIds.includes(outermostSelectableShape.id)) {\n\t\t\t\t// same shape, so deselect it if shift is pressed, otherwise deselect all others\n\t\t\t\tif (shiftKey) {\n\t\t\t\t\tthis.editor.mark('deselecting on pointer up')\n\t\t\t\t\tthis.editor.deselect(selectingShape)\n\t\t\t\t} else {\n\t\t\t\t\tif (selectedShapeIds.includes(selectingShape.id)) {\n\t\t\t\t\t\t// todo\n\t\t\t\t\t\t// if the shape is editable and we're inside of an editable part of that shape, e.g. the label of a geo shape,\n\t\t\t\t\t\t// then we would want to begin editing the shape. At the moment we're relying on the shape label's onPointerUp\n\t\t\t\t\t\t// handler to do this logic, and prevent the regular pointer up event, so we won't be here in that case.\n\n\t\t\t\t\t\t// ! tldraw hack\n\t\t\t\t\t\t// if the shape is a geo shape, and we're inside of the label, then we want to begin editing the label\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tselectedShapeIds.length === 1 &&\n\t\t\t\t\t\t\t(this.editor.isShapeOfType(selectingShape, 'geo') ||\n\t\t\t\t\t\t\t\tthis.editor.isShapeOfType(selectingShape, 'arrow'))\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tconst geometry = this.editor.getShapeGeometry(selectingShape)\n\t\t\t\t\t\t\tconst labelGeometry = (geometry as Group2d).children[1]\n\t\t\t\t\t\t\tif (labelGeometry) {\n\t\t\t\t\t\t\t\tconst pointInShapeSpace = this.editor.getPointInShapeSpace(\n\t\t\t\t\t\t\t\t\tselectingShape,\n\t\t\t\t\t\t\t\t\tcurrentPagePoint\n\t\t\t\t\t\t\t\t)\n\n\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\tlabelGeometry.bounds.containsPoint(pointInShapeSpace, 0) &&\n\t\t\t\t\t\t\t\t\tlabelGeometry.hitTestPoint(pointInShapeSpace)\n\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\tthis.editor.batch(() => {\n\t\t\t\t\t\t\t\t\t\tthis.editor.mark('editing on pointer up')\n\t\t\t\t\t\t\t\t\t\tthis.editor.select(selectingShape.id)\n\n\t\t\t\t\t\t\t\t\t\tconst util = this.editor.getShapeUtil(selectingShape)\n\t\t\t\t\t\t\t\t\t\tif (this.editor.instanceState.isReadonly) {\n\t\t\t\t\t\t\t\t\t\t\tif (!util.canEditInReadOnly(selectingShape)) {\n\t\t\t\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tthis.editor.setEditingShape(selectingShape.id)\n\t\t\t\t\t\t\t\t\t\tthis.editor.setCurrentTool('select.editing_shape')\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// We just want to select the single shape from the selection\n\t\t\t\t\t\tthis.editor.mark('selecting on pointer up')\n\t\t\t\t\t\tthis.editor.select(selectingShape.id)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.editor.mark('selecting on pointer up')\n\t\t\t\t\t\tthis.editor.select(selectingShape)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (shiftKey) {\n\t\t\t\t// Different shape, so we are drilling down into a group with shift key held.\n\t\t\t\t// Deselect any ancestors and add the target shape to the selection\n\t\t\t\tconst ancestors = this.editor.getShapeAncestors(outermostSelectableShape)\n\n\t\t\t\tthis.editor.mark('shift deselecting on pointer up')\n\t\t\t\tthis.editor.setSelectedShapes([\n\t\t\t\t\t...this.editor.selectedShapeIds.filter((id) => !ancestors.find((a) => a.id === id)),\n\t\t\t\t\toutermostSelectableShape.id,\n\t\t\t\t])\n\t\t\t} else {\n\t\t\t\tthis.editor.mark('selecting on pointer up')\n\t\t\t\t// different shape and we are drilling down, but no shift held so just select it straight up\n\t\t\t\tthis.editor.setSelectedShapes([outermostSelectableShape.id])\n\t\t\t}\n\t\t}\n\n\t\tthis.parent.transition('idle', info)\n\t}\n\n\toverride onPointerMove: TLEventHandlers['onPointerMove'] = (info) => {\n\t\tif (this.editor.inputs.isDragging) {\n\t\t\tif (this.editor.instanceState.isReadonly) return\n\t\t\tthis.parent.transition('translating', info)\n\t\t}\n\t}\n\n\toverride onCancel: TLEventHandlers['onCancel'] = () => {\n\t\tthis.cancel()\n\t}\n\n\toverride onComplete: TLEventHandlers['onComplete'] = () => {\n\t\tthis.cancel()\n\t}\n\n\toverride onInterrupt = () => {\n\t\tthis.cancel()\n\t}\n\n\tprivate cancel() {\n\t\tthis.parent.transition('idle', {})\n\t}\n}\n"], "mappings": "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", "names": [] }