import {
track,
useEditor,
useValue,
TldrawUiButton,
TldrawUiButtonIcon,
atom,
Box,
react
} from 'tldraw'
import { useEffect } from 'react'
import { LockIcon } from './Icons'
export const getSelectLockedSignal = (editor: any) => {
if (!editor._selectLockedSignal) {
editor._selectLockedSignal = atom('selectLocked', !!editor._selectLocked)
}
return editor._selectLockedSignal
}
export const SelectOptionsPanel = track(() => {
const editor = useEditor()
const isSelect = useValue('isSelect', () => editor.getCurrentToolId() === 'select', [editor])
const isSelectLocked = useValue('isSelectLocked', () => getSelectLockedSignal(editor).get(), [editor])
if (!isSelect) return null
return (
Select Options
{
const signal = getSelectLockedSignal(editor)
const next = !signal.get()
signal.set(next)
;(editor as any)._selectLocked = next
editor.emit('select-locked-changed' as any)
}}
style={{
justifyContent: 'flex-start',
padding: '4px 8px',
height: '32px',
background: isSelectLocked ? 'var(--tl-color-selected)' : 'transparent',
color: isSelectLocked ? 'white' : 'var(--tl-color-text)',
}}
>
)
})
export const SelectLockedToggle = track(() => {
const editor = useEditor()
const isSelectLocked = useValue('isSelectLocked', () => getSelectLockedSignal(editor).get(), [editor])
return (
{
const signal = getSelectLockedSignal(editor)
const next = !signal.get()
signal.set(next)
;(editor as any)._selectLocked = next
editor.emit('select-locked-changed' as any)
}}
>
)
})
export function SelectLockedLogic() {
const editor = useEditor()
// Handle click-to-select locked shapes
useEffect(() => {
const handleEvent = (event: any) => {
if (event.name !== 'pointer_down') return
const isSelectLocked = getSelectLockedSignal(editor).get()
if (!isSelectLocked) return
if (editor.getCurrentToolId() !== 'select') return
const { x, y } = editor.inputs.currentPagePoint
const pagePoint = { x, y }
const shapes = editor.getCurrentPageShapesSorted()
let target = null
for (let i = shapes.length - 1; i >= 0; i--) {
const shape = shapes[i]
if (shape.isLocked && editor.isPointInShape(shape, pagePoint, { hitInside: true, margin: 0 })) {
target = shape
break
}
}
if (target) {
setTimeout(() => {
editor.setSelectedShapes([target!.id])
}, 50)
}
}
editor.on('event', handleEvent)
return () => {
editor.off('event', handleEvent)
}
}, [editor])
// Handle drag-to-select (brush) locked shapes - OPTIMIZED
useEffect(() => {
return react('check-brush-locked', () => {
const isSelectLocked = getSelectLockedSignal(editor).get()
if (!isSelectLocked) return
if (editor.getCurrentToolId() !== 'select') return
const brushModel = editor.getInstanceState().brush
if (!brushModel) return
const brush = Box.From(brushModel)
const shapes = editor.getCurrentPageShapesSorted()
const lockedInBrush = shapes.filter(shape => {
if (!shape.isLocked) return false
const bounds = editor.getShapePageBounds(shape)
if (!bounds) return false
return brush.collides(bounds)
})
if (lockedInBrush.length > 0) {
const currentSelected = new Set(editor.getSelectedShapeIds())
let changed = false
for (const shape of lockedInBrush) {
if (!currentSelected.has(shape.id)) {
currentSelected.add(shape.id)
changed = true
}
}
if (changed) {
editor.setSelectedShapes(Array.from(currentSelected))
}
}
})
}, [editor])
return null
}