my-multiplayer-app-2 / components /BrushManager.tsx
Jaimodiji's picture
Sync all client files to fix build
e1753d8 verified
Raw
History Blame
6.12 kB
import { useEffect } from 'react'
import { useEditor, react } from 'tldraw'
import { toolBrushStylesAtom } from '../utils/brushUtils'
export function BrushManager() {
const editor = useEditor()
// Tools that should have completely independent styles
const DRAWING_TOOLS = ['draw', 'highlight']
// 1. Capture tools' brushes ONLY when user actively changes them (not on tool switch)
useEffect(() => {
let previousStyles: Record<string, any> = {}
let previousTool = editor.getCurrentToolId()
const unreact = react('capture-user-brush', () => {
const selection = editor.getSelectedShapeIds()
const toolId = editor.getCurrentToolId()
const activeStyles = editor.getInstanceState().stylesForNextShape
// Skip select tool
if (toolId === 'select') return
// Detect if tool changed
const toolChanged = toolId !== previousTool
previousTool = toolId
// For drawing tools: ONLY capture if user changes style while already on the tool
// Do NOT capture when switching TO the tool (prevents contamination)
if (DRAWING_TOOLS.includes(toolId)) {
if (toolChanged) {
// Just switched to this tool - don't capture, just record current state
previousStyles[toolId] = JSON.parse(JSON.stringify(activeStyles))
return
}
// Already on this tool - check if user changed something
const prevForThisTool = previousStyles[toolId]
if (prevForThisTool && JSON.stringify(prevForThisTool) !== JSON.stringify(activeStyles)) {
// User actively changed the style! Save it.
const currentStored = toolBrushStylesAtom.get()
toolBrushStylesAtom.set({
...currentStored,
[toolId]: JSON.parse(JSON.stringify(activeStyles))
})
previousStyles[toolId] = JSON.parse(JSON.stringify(activeStyles))
}
return
}
// For non-drawing tools: capture when no selection
if (selection.length === 0) {
const currentStored = toolBrushStylesAtom.get()
if (JSON.stringify(currentStored[toolId]) !== JSON.stringify(activeStyles)) {
toolBrushStylesAtom.set({
...currentStored,
[toolId]: JSON.parse(JSON.stringify(activeStyles))
})
}
}
})
return () => {
unreact()
}
}, [editor])
// 2. Restore the saved brush for ALL tools (including drawing tools)
useEffect(() => {
const restoreBrush = () => {
const toolId = editor.getCurrentToolId()
// Skip select tool only
if (toolId === 'select') return
const storedStyles = toolBrushStylesAtom.get()[toolId]
if (storedStyles && Object.keys(storedStyles).length > 0) {
editor.run(() => {
for (const [id, value] of Object.entries(storedStyles)) {
// Use the internal style ID to set the next style
editor.setStyleForNextShapes({ id } as any, value, { history: 'ignore' })
}
}, { history: 'ignore' })
}
}
// Restore when:
// - Tool changes
// - Selection is cleared
// - A pointer operation finishes (to overwrite tldraw's auto-sync-to-selection)
const handleEvent = (e: any) => {
if (e.name === 'tool_change') {
restoreBrush()
}
if (e.name === 'pointer_up') {
// Wait for tldraw to finish its own sync-to-selection
setTimeout(restoreBrush, 20)
}
}
editor.on('event', handleEvent)
// Also watch for selection becoming empty via react
const unreact = react('restore-on-deselect', () => {
const selection = editor.getSelectedShapeIds()
if (selection.length === 0) {
restoreBrush()
}
})
return () => {
editor.off('event', handleEvent)
unreact()
}
}, [editor])
// 3. EXPLICIT PROTECTION: Prevent drawing tools from syncing styles from selections
useEffect(() => {
let lastToolId = editor.getCurrentToolId()
return react('block-drawing-tool-sync', () => {
const toolId = editor.getCurrentToolId()
const selection = editor.getSelectedShapeIds()
// Detect tool change
if (toolId !== lastToolId) {
lastToolId = toolId
// If we switched TO a drawing tool AND there's a selection
// Force restore the drawing tool's saved styles immediately
if (DRAWING_TOOLS.includes(toolId) && selection.length > 0) {
const storedStyles = toolBrushStylesAtom.get()[toolId]
if (storedStyles && Object.keys(storedStyles).length > 0) {
// Multiple aggressive restores to override tldraw's sync
for (let i = 0; i < 3; i++) {
setTimeout(() => {
editor.run(() => {
for (const [id, value] of Object.entries(storedStyles)) {
editor.setStyleForNextShapes({ id } as any, value, { history: 'ignore' })
}
}, { history: 'ignore' })
}, i * 10)
}
}
}
}
})
}, [editor])
return null
}