File size: 6,122 Bytes
e1753d8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
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
}