Tldraw/packages/tldraw/src/lib/tools/selection-logic/selectOnCanvasPointerUp.ts

97 wiersze
3.3 KiB
TypeScript

import { Editor, TLShape, isShapeId } from '@tldraw/editor'
import { tldrawConstants } from '../../tldraw-constants'
const { HIT_TEST_MARGIN } = tldrawConstants
export function selectOnCanvasPointerUp(editor: Editor) {
const selectedShapeIds = editor.getSelectedShapeIds()
const { shiftKey, altKey, currentPagePoint } = editor.inputs
const hitShape = editor.getShapeAtPoint(currentPagePoint, {
hitInside: false,
margin: HIT_TEST_MARGIN / editor.getZoomLevel(),
hitLabels: true,
renderingOnly: true,
filter: (shape) => !shape.isLocked,
})
// Note at the start: if we select a shape that is inside of a group,
// the editor will automatically adjust the selection to the outermost
// selectable shape (the group)
// If the shape's outermost selected id (e.g. the group that contains
// the shape) is not the same as the editor's only selected shape, then
// we want to select the outermost selected shape instead of the shape
if (hitShape) {
const outermostSelectableShape = editor.getOutermostSelectableShape(hitShape)
// If the user is holding shift, they're either adding to or removing from
// their selection.
if (shiftKey && !altKey) {
editor.cancelDoubleClick() // fuckin eh
if (selectedShapeIds.includes(outermostSelectableShape.id)) {
// Remove it from selected shapes
editor.mark('deselecting shape')
editor.deselect(outermostSelectableShape)
} else {
// Add it to selected shapes
editor.mark('shift selecting shape')
editor.setSelectedShapes([...selectedShapeIds, outermostSelectableShape.id])
}
} else {
let shapeToSelect: TLShape | undefined = undefined
if (outermostSelectableShape === hitShape) {
// There's no group around the shape, so we can select it.
shapeToSelect = hitShape
} else {
// There's a group around the hit shape.
// If the group is the current focus layer, OR if the group is
// already selected, then we can select the shape inside the group.
// Otherwise, if the group isn't selected and isn't our current
// focus layer, then we need to select the group instead.
if (
outermostSelectableShape.id === editor.getFocusedGroupId() ||
selectedShapeIds.includes(outermostSelectableShape.id)
) {
shapeToSelect = hitShape
} else {
shapeToSelect = outermostSelectableShape
}
}
if (shapeToSelect && !selectedShapeIds.includes(shapeToSelect.id)) {
editor.mark('selecting shape')
editor.select(shapeToSelect.id)
}
}
} else {
// We didn't hit anything...
if (shiftKey) {
// If we were holding shift, then it's a noop. We keep the
// current selection because we didn't add anything to it
return
} else {
// Otherwise, we clear the selction because the user selected
// nothing instead of their current selection.
if (selectedShapeIds.length > 0) {
editor.mark('selecting none')
editor.selectNone()
}
// If the click was inside of the current focused group, then
// we keep that focused group; otherwise we clear the focused
// group (reset it to the page)
const focusedGroupId = editor.getFocusedGroupId()
if (isShapeId(focusedGroupId)) {
const groupShape = editor.getShape(focusedGroupId)!
if (!editor.isPointInShape(groupShape, currentPagePoint, { margin: 0, hitInside: true })) {
editor.setFocusedGroup(null)
}
}
}
}
}