@@ -15,6 +15,59 @@ export { FieldMenu, FieldList };
1515
1616type Editor = NonNullable < SuperDoc [ "activeEditor" ] > ;
1717
18+ const getTemplateFieldsFromEditor = (
19+ editor : Editor ,
20+ ) : Types . TemplateField [ ] => {
21+ const structuredContentHelpers =
22+ ( editor . helpers as any ) ?. structuredContentCommands ;
23+
24+ if ( ! structuredContentHelpers ?. getStructuredContentTags ) {
25+ return [ ] ;
26+ }
27+
28+ const tags =
29+ structuredContentHelpers . getStructuredContentTags ( editor . state ) || [ ] ;
30+
31+ return tags
32+ . map ( ( entry : any ) => {
33+ const node = entry ?. node ?? entry ;
34+ const attrs = node ?. attrs ?? { } ;
35+
36+ return {
37+ id : attrs . id ,
38+ alias : attrs . alias || attrs . label || "" ,
39+ tag : attrs . tag ,
40+ } as Types . TemplateField ;
41+ } )
42+ . filter ( ( field : Types . TemplateField ) => Boolean ( field . id ) ) ;
43+ } ;
44+
45+ const areTemplateFieldsEqual = (
46+ a : Types . TemplateField [ ] ,
47+ b : Types . TemplateField [ ] ,
48+ ) : boolean => {
49+ if ( a === b ) return true ;
50+ if ( a . length !== b . length ) return false ;
51+
52+ for ( let index = 0 ; index < a . length ; index += 1 ) {
53+ const left = a [ index ] ;
54+ const right = b [ index ] ;
55+
56+ if ( ! right ) return false ;
57+
58+ if (
59+ left . id !== right . id ||
60+ left . alias !== right . alias ||
61+ left . tag !== right . tag ||
62+ left . position !== right . position
63+ ) {
64+ return false ;
65+ }
66+ }
67+
68+ return true ;
69+ } ;
70+
1871const SuperDocTemplateBuilder = forwardRef <
1972 Types . SuperDocTemplateBuilderHandle ,
2073 Types . SuperDocTemplateBuilderProps
@@ -173,21 +226,73 @@ const SuperDocTemplateBuilder = forwardRef<
173226
174227 const deleteField = useCallback (
175228 ( id : string ) : boolean => {
176- if ( ! superdocRef . current ?. activeEditor ) return false ;
229+ const editor = superdocRef . current ?. activeEditor ;
177230
178- const editor = superdocRef . current . activeEditor ;
179- const success = editor . commands . deleteStructuredContentById ?.( id ) ;
231+ if ( ! editor ) {
232+ console . warn (
233+ "[SuperDocTemplateBuilder] deleteField called without active editor" ,
234+ ) ;
180235
181- if ( success ) {
236+ let removed = false ;
182237 setTemplateFields ( ( prev ) => {
183- const updated = prev . filter ( ( f ) => f . id !== id ) ;
238+ if ( ! prev . some ( ( field ) => field . id === id ) ) return prev ;
239+
240+ const updated = prev . filter ( ( field ) => field . id !== id ) ;
241+ removed = true ;
184242 onFieldsChange ?.( updated ) ;
185243 return updated ;
186244 } ) ;
245+
246+ if ( removed ) {
247+ onFieldDelete ?.( id ) ;
248+ setSelectedFieldId ( ( current ) => ( current === id ? null : current ) ) ;
249+ }
250+
251+ return removed ;
252+ }
253+
254+ let commandResult = false ;
255+ try {
256+ commandResult =
257+ editor . commands . deleteStructuredContentById ?.( id ) ?? false ;
258+ } catch ( error ) {
259+ console . error (
260+ "[SuperDocTemplateBuilder] Delete command failed:" ,
261+ error ,
262+ ) ;
263+ }
264+
265+ let documentFields = getTemplateFieldsFromEditor ( editor ) ;
266+ const fieldStillPresent = documentFields . some ( ( field ) => field . id === id ) ;
267+
268+ if ( ! commandResult && fieldStillPresent ) {
269+ documentFields = documentFields . filter ( ( field ) => field . id !== id ) ;
270+ }
271+
272+ let removedFromState = false ;
273+
274+ setTemplateFields ( ( prev ) => {
275+ if ( areTemplateFieldsEqual ( prev , documentFields ) ) {
276+ return prev ;
277+ }
278+
279+ const prevHadField = prev . some ( ( field ) => field . id === id ) ;
280+ const nextHasField = documentFields . some ( ( field ) => field . id === id ) ;
281+
282+ if ( prevHadField && ! nextHasField ) {
283+ removedFromState = true ;
284+ }
285+
286+ onFieldsChange ?.( documentFields ) ;
287+ return documentFields ;
288+ } ) ;
289+
290+ if ( removedFromState ) {
187291 onFieldDelete ?.( id ) ;
292+ setSelectedFieldId ( ( current ) => ( current === id ? null : current ) ) ;
188293 }
189294
190- return success ;
295+ return commandResult || removedFromState ;
191296 } ,
192297 [ onFieldDelete , onFieldsChange ] ,
193298 ) ;
@@ -210,21 +315,16 @@ const SuperDocTemplateBuilder = forwardRef<
210315 ( editor : Editor ) => {
211316 if ( ! editor ) return ;
212317
213- const tags =
214- editor . helpers . structuredContentCommands . getStructuredContentTags (
215- editor . state ,
216- ) ;
318+ const discovered = getTemplateFieldsFromEditor ( editor ) ;
217319
218- const discovered : Types . TemplateField [ ] = tags
219- . map ( ( { node } : any ) => ( {
220- id : node . attrs . id ,
221- alias : node . attrs . alias || node . attrs . label || "" ,
222- tag : node . attrs . tag ,
223- } ) )
224- . filter ( ( f : Types . TemplateField ) => f . id ) ;
320+ setTemplateFields ( ( prev ) => {
321+ if ( areTemplateFieldsEqual ( prev , discovered ) ) {
322+ return prev ;
323+ }
225324
226- setTemplateFields ( discovered ) ;
227- onFieldsChange ?.( discovered ) ;
325+ onFieldsChange ?.( discovered ) ;
326+ return discovered ;
327+ } ) ;
228328 } ,
229329 [ onFieldsChange ] ,
230330 ) ;
0 commit comments