Skip to content

Commit 34a68a8

Browse files
authored
feat(template-builder): reactive mode changes and refresh method (SD-2406) (#2726)
* feat(template-builder): reactive mode changes and refresh method - Remove document.mode from init effect deps so mode changes don't destroy and recreate the editor (no more scroll jump / content flash) - Add separate useEffect that calls setDocumentMode() imperatively, following the same pattern as the React wrapper - Add refresh() method to the imperative handle for re-discovering fields after async data delivery - Document refresh() in API reference Closes SD-2406 * fix(template-builder): queue mode changes during init If document.mode changes while SuperDoc is still loading, the change is queued and applied once handleReady fires. Follows the same pendingModeRef pattern as the React wrapper. * fix(template-builder): address review findings for mode change logic - Remove redundant prevModeRef — useEffect dep array handles this - Clear pendingModeRef in init cleanup to prevent stale mode on re-init - Clear pendingModeRef when applying mode directly - Extract applyDocumentMode helper to centralize the as-any cast
1 parent 2c27fd9 commit 34a68a8

File tree

3 files changed

+38
-1
lines changed

3 files changed

+38
-1
lines changed

apps/docs/solutions/template-builder/api-reference.mdx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,14 @@ const fields = builderRef.current?.getFields();
361361
// Returns: TemplateField[]
362362
```
363363

364+
### refresh()
365+
366+
Re-discover fields from the editor and trigger `onFieldsChange`. Use this when field data arrives asynchronously or after external changes to the document:
367+
368+
```typescript
369+
builderRef.current?.refresh();
370+
```
371+
364372
### exportTemplate()
365373

366374
Export the template as a .docx file:

packages/template-builder/src/index.tsx

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ export { FieldMenu, FieldList };
1515

1616
type Editor = NonNullable<SuperDoc['activeEditor']>;
1717

18+
const applyDocumentMode = (instance: SuperDoc, mode: string) => {
19+
(instance as any).setDocumentMode(mode);
20+
};
21+
1822
const getTemplateFieldsFromEditor = (editor: Editor): Types.TemplateField[] => {
1923
const structuredContentHelpers = (editor.helpers as any)?.structuredContentCommands;
2024

@@ -443,6 +447,12 @@ const SuperDocTemplateBuilder = forwardRef<Types.SuperDocTemplateBuilderHandle,
443447
discoverFields(editor);
444448
}
445449

450+
// Apply any mode change that arrived during init
451+
if (pendingModeRef.current && instance) {
452+
applyDocumentMode(instance, pendingModeRef.current);
453+
pendingModeRef.current = null;
454+
}
455+
446456
onReady?.();
447457
};
448458

@@ -475,10 +485,10 @@ const SuperDocTemplateBuilder = forwardRef<Types.SuperDocTemplateBuilderHandle,
475485
}
476486

477487
superdocRef.current = null;
488+
pendingModeRef.current = null;
478489
};
479490
}, [
480491
document?.source,
481-
document?.mode,
482492
trigger,
483493
discoverFields,
484494
onReady,
@@ -489,6 +499,18 @@ const SuperDocTemplateBuilder = forwardRef<Types.SuperDocTemplateBuilderHandle,
489499
licenseKey,
490500
]);
491501

502+
// Apply document mode changes without recreating the editor
503+
const pendingModeRef = useRef<string | null>(null);
504+
useEffect(() => {
505+
const mode = document?.mode || 'editing';
506+
if (superdocRef.current) {
507+
applyDocumentMode(superdocRef.current, mode);
508+
pendingModeRef.current = null;
509+
} else {
510+
pendingModeRef.current = mode;
511+
}
512+
}, [document?.mode]);
513+
492514
const handleMenuSelect = useCallback(
493515
async (field: Types.FieldDefinition) => {
494516
if (triggerCleanupRef.current) {
@@ -638,6 +660,11 @@ const SuperDocTemplateBuilder = forwardRef<Types.SuperDocTemplateBuilderHandle,
638660
nextField,
639661
previousField,
640662
getFields: () => templateFields,
663+
refresh: () => {
664+
if (superdocRef.current?.activeEditor) {
665+
discoverFields(superdocRef.current.activeEditor);
666+
}
667+
},
641668
exportTemplate,
642669
getSuperDoc: () => superdocRef.current,
643670
}));

packages/template-builder/src/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ export interface SuperDocTemplateBuilderHandle {
161161
nextField: () => void;
162162
previousField: () => void;
163163
getFields: () => TemplateField[];
164+
/** Re-discover fields from the editor and notify via onFieldsChange */
165+
refresh: () => void;
164166
exportTemplate: (config?: ExportConfig) => Promise<void | Blob>;
165167
/**
166168
* Returns the SuperDoc instance.

0 commit comments

Comments
 (0)