@@ -14,6 +14,7 @@ import { copyToClipboard } from '../helper'
1414import { CHAT_OPEN } from '@services/eventsHub'
1515import { ChatLeftSVG , ArrowDownSVG } from '@icons'
1616import { db } from '@db/headingCrinckleDB'
17+ import { useStore } from '@stores'
1718
1819// Plugin-specific types
1920interface HeadingBlock {
@@ -159,94 +160,74 @@ const appendButtonsDec = (doc: ProseMirrorNode, editor: TipTapEditor): Decoratio
159160 return DecorationSet . create ( doc , decos )
160161}
161162
162- const handleHeadingToggle = ( editor : TipTapEditor , { headingId } : EditorEventData ) : void => {
163- // Safety check: ensure editor view is available
164- if ( ! editor ?. view ?. dom ) {
165- console . warn ( '[headingButtonsPlugin] Editor view not available' )
166- return
167- }
168-
169- if ( isProcessing ) return
163+ const handleHeadingToggle = ( _editor : TipTapEditor , { headingId } : EditorEventData ) : void => {
164+ if ( isProcessing || ! headingId ) return
170165 isProcessing = true
171166
172- const { tr } = editor . state
173- const headingNodeEl = editor . view . dom . querySelector (
167+ // Get editor from store - safer than using passed reference
168+ const editor = useStore . getState ( ) . settings . editor . instance
169+ const headingNodeEl = document . querySelector (
174170 `.ProseMirror .heading[data-id="${ headingId } "]`
175- )
171+ ) as HTMLElement | null
176172
177- if ( ! headingNodeEl ) {
173+ if ( ! editor ?. view || ! headingNodeEl ) {
178174 isProcessing = false
179175 return
180176 }
181177
182- let nodePos
183- try {
184- nodePos = editor . view . state . doc . resolve ( editor . view . posAtDOM ( headingNodeEl , 0 ) )
185- } catch {
186- isProcessing = false
187- return
188- }
178+ const view = editor . view
179+ const tr = editor . state . tr
180+ const nodePos = view . state . doc . resolve ( view . posAtDOM ( headingNodeEl , 0 ) )
181+ const currentNode = tr . doc . nodeAt ( nodePos . pos )
189182
190- if ( ! nodePos ) {
183+ if ( ! currentNode ) {
191184 isProcessing = false
192185 return
193186 }
194187
195- // if (editor.isEditable) {
196- const pos = nodePos . pos
197- const currentNode = tr . doc . nodeAt ( pos )
198- // Mark as fold/unfold transaction - TOC will be updated via PubSub with delay
199188 tr . setMeta ( TRANSACTION_META . FOLD_AND_UNFOLD , true )
200189
201190 const documentId = localStorage . getItem ( 'docId' )
202191 const headingMapString = localStorage . getItem ( 'headingMap' )
203192 const headingMap : HeadingState [ ] = headingMapString ? JSON . parse ( headingMapString ) : [ ]
204- const nodeState = headingMap . find ( ( h : HeadingState ) => h . headingId === headingId ) || {
205- crinkleOpen : true
206- }
193+ const nodeState = headingMap . find ( ( h ) => h . headingId === headingId ) || { crinkleOpen : true }
207194 const filterMode = document . body . classList . contains ( 'filter-mode' )
208- let database = filterMode ? db . docFilter : db . meta
195+ const database = filterMode ? db . docFilter : db . meta
209196
210- // In filter mode, avoid saving the heading map to prevent overwriting the primary heading filter.
211- if ( filterMode ) {
212- if ( editor . view ) {
213- editor . view . dispatch ( tr )
214- dispatchToggleHeadingSection ( headingNodeEl )
215- }
197+ const dispatch = ( ) => {
198+ view . dispatch ( tr )
199+ dispatchToggleHeadingSection ( headingNodeEl )
216200 isProcessing = false
201+ }
202+
203+ // In filter mode, skip saving to DB
204+ if ( filterMode ) {
205+ dispatch ( )
217206 return
218207 }
219208
220- if ( documentId && currentNode && headingId ) {
221- database
222- . put ( {
223- docId : documentId ,
224- headingId,
225- crinkleOpen : ! nodeState . crinkleOpen ,
226- level : currentNode . attrs . level
227- } )
228- . then ( ( ) => {
229- database . toArray ( ) . then ( ( data : any [ ] ) => {
230- localStorage . setItem ( 'headingMap' , JSON . stringify ( data ) )
231- } )
232- // Safety check: editor view may be destroyed during async operation
233- if ( editor . view ) {
234- editor . view . dispatch ( tr )
235- dispatchToggleHeadingSection ( headingNodeEl )
236- }
237- isProcessing = false
238- } )
239- . catch ( ( err : Error ) => {
240- console . error ( err )
241- isProcessing = false
242- } )
243- } else {
244- console . error ( 'headingId is not defined' )
209+ if ( ! documentId ) {
245210 isProcessing = false
211+ return
246212 }
247- // } else {
248- // isProcessing = false
249- // }
213+
214+ database
215+ . put ( {
216+ docId : documentId ,
217+ headingId,
218+ crinkleOpen : ! nodeState . crinkleOpen ,
219+ level : currentNode . attrs . level
220+ } )
221+ . then ( ( ) => {
222+ database . toArray ( ) . then ( ( data : any [ ] ) => {
223+ localStorage . setItem ( 'headingMap' , JSON . stringify ( data ) )
224+ } )
225+ dispatch ( )
226+ } )
227+ . catch ( ( err : Error ) => {
228+ console . error ( err )
229+ isProcessing = false
230+ } )
250231}
251232
252233/**
0 commit comments