diff --git a/demo/src/App.tsx b/demo/src/App.tsx index b94600c..266f771 100644 --- a/demo/src/App.tsx +++ b/demo/src/App.tsx @@ -4,18 +4,19 @@ import type { SuperDocTemplateBuilderHandle, TemplateField, FieldDefinition, + ExportEvent, } from "@superdoc-dev/template-builder"; -import "superdoc/dist/style.css"; +import "superdoc/style.css"; import "./App.css"; const availableFields: FieldDefinition[] = [ - { id: '1242142770', label: 'Agreement Date' }, - { id: '1242142771', label: 'User Name' }, - { id: '1242142772', label: 'Company Name' }, - { id: '1242142773', label: 'Service Type' }, - { id: '1242142774', label: 'Agreement Jurisdiction' }, - { id: '1242142775', label: 'Company Address' }, - { id: '1242142776', label: 'Signature' }, + { id: "1242142770", label: "Agreement Date" }, + { id: "1242142771", label: "User Name" }, + { id: "1242142772", label: "Company Name" }, + { id: "1242142773", label: "Service Type" }, + { id: "1242142774", label: "Agreement Jurisdiction" }, + { id: "1242142775", label: "Company Address" }, + { id: "1242142776", label: "Signature" }, ]; export function App() { @@ -34,32 +35,44 @@ export function App() { const log = useCallback((msg: string) => { const time = new Date().toLocaleTimeString(); console.log(`[${time}] ${msg}`); - setEvents(prev => [...prev.slice(-4), `${time} - ${msg}`]); + setEvents((prev) => [...prev.slice(-4), `${time} - ${msg}`]); }, []); - const handleFieldsChange = useCallback((updatedFields: TemplateField[]) => { - setFields(updatedFields); - log(`Fields: ${updatedFields.length} total`); - }, [log]); + const handleFieldsChange = useCallback( + (updatedFields: TemplateField[]) => { + setFields(updatedFields); + log(`Fields: ${updatedFields.length} total`); + }, + [log], + ); - const handleFieldInsert = useCallback((field: TemplateField) => { - log(`✓ Inserted: ${field.alias}`); - }, [log]); + const handleFieldInsert = useCallback( + (field: TemplateField) => { + log(`✓ Inserted: ${field.alias}`); + }, + [log], + ); - const handleFieldDelete = useCallback((fieldId: string | number) => { - log(`✗ Deleted: ${fieldId}`); - }, [log]); + const handleFieldDelete = useCallback( + (fieldId: string | number) => { + log(`✗ Deleted: ${fieldId}`); + }, + [log], + ); - const handleFieldSelect = useCallback((field: TemplateField | null) => { - if (field) { - log(`Selected: ${field.alias}`); - } - }, [log]); + const handleFieldSelect = useCallback( + (field: TemplateField | null) => { + if (field) { + log(`Selected: ${field.alias}`); + } + }, + [log], + ); const handleReady = useCallback(() => { - log('✓ Template builder ready'); + log("✓ Template builder ready"); if (importingRef.current) { - log('📄 Document imported'); + log("📄 Document imported"); importingRef.current = false; setImportError(null); setIsImporting(false); @@ -67,9 +80,23 @@ export function App() { }, [log]); const handleTrigger = useCallback(() => { - log('⌨ Trigger detected'); + log("⌨ Trigger detected"); }, [log]); + const handleExport = useCallback( + (event: ExportEvent) => { + console.log("Export Event:", event); + console.log("Fields:", JSON.stringify(event.fields, null, 2)); + log(`Exported ${event.fields.length} fields`); + event.fields.forEach((f) => { + console.log( + ` - ${f.alias} (id: ${f.id}, mode: ${f.mode}, group: ${f.group || "none"})`, + ); + }); + }, + [log], + ); + const handleExportTemplate = useCallback(async () => { if (!builderRef.current) { return; @@ -92,7 +119,7 @@ export function App() { }, [log]); const handleKeyDown = (e: React.KeyboardEvent) => { - if (e.key === 'Tab') { + if (e.key === "Tab") { e.preventDefault(); if (e.shiftKey) { builderRef.current?.previousField(); @@ -102,45 +129,57 @@ export function App() { } }; - const documentConfig = useMemo(() => ({ - source: documentSource, - mode: 'editing' as const - }), [documentSource]); + const documentConfig = useMemo( + () => ({ + source: documentSource, + mode: "editing" as const, + }), + [documentSource], + ); const handleImportButtonClick = useCallback(() => { if (isImporting) return; fileInputRef.current?.click(); }, [isImporting]); - const handleFileInputChange = useCallback((event: React.ChangeEvent) => { - const file = event.target.files?.[0]; - event.target.value = ""; + const handleFileInputChange = useCallback( + (event: React.ChangeEvent) => { + const file = event.target.files?.[0]; + event.target.value = ""; - if (!file) return; + if (!file) return; - const extension = file.name.split('.').pop()?.toLowerCase(); - if (extension !== 'docx') { - const message = 'Invalid file type. Please choose a .docx file.'; - setImportError(message); - log('⚠️ ' + message); - return; - } + const extension = file.name.split(".").pop()?.toLowerCase(); + if (extension !== "docx") { + const message = "Invalid file type. Please choose a .docx file."; + setImportError(message); + log("⚠️ " + message); + return; + } - importingRef.current = true; - setImportError(null); - setIsImporting(true); - setDocumentSource(file); - log(`📥 Importing "${file.name}"`); - }, [log]); + importingRef.current = true; + setImportError(null); + setIsImporting(true); + setDocumentSource(file); + log(`📥 Importing "${file.name}"`); + }, + [log], + ); - const fieldsConfig = useMemo(() => ({ - available: availableFields, - allowCreate: true - }), []); + const fieldsConfig = useMemo( + () => ({ + available: availableFields, + allowCreate: true, + }), + [], + ); - const listConfig = useMemo(() => ({ - position: 'right' as const - }), []); + const listConfig = useMemo( + () => ({ + position: "right" as const, + }), + [], + ); return (
@@ -148,16 +187,27 @@ export function App() {

- + @superdoc-dev/template-builder

- React template builder from SuperDoc + React template builder from{" "} + + SuperDoc +

- + GitHub @@ -170,7 +220,7 @@ export function App() {
- Type {'{{'} to insert a field + Type {"{{"} to insert a field | Tab/Shift+Tab to navigate
@@ -179,7 +229,7 @@ export function App() { type="file" accept=".docx" ref={fileInputRef} - style={{ display: 'none' }} + style={{ display: "none" }} onChange={handleFileInputChange} />
); diff --git a/src/index.tsx b/src/index.tsx index 3e843e0..3d95267 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -137,6 +137,7 @@ const SuperDocTemplateBuilder = forwardRef< onFieldsChange, onFieldSelect, onFieldCreate, + onExport, className, style, documentHeight = "600px", @@ -666,9 +667,16 @@ const SuperDocTemplateBuilder = forwardRef< triggerDownload, }); + const editor = superdocRef.current?.activeEditor; + if (editor) { + const fields = getTemplateFieldsFromEditor(editor); + const blob = triggerDownload ? undefined : (result as Blob); + onExport?.({ fields, blob, fileName }); + } + return result; }, - [], + [onExport], ); useImperativeHandle(ref, () => ({ diff --git a/src/types.ts b/src/types.ts index 0fc8d50..5e1cf23 100644 --- a/src/types.ts +++ b/src/types.ts @@ -23,6 +23,12 @@ export interface TriggerEvent { cleanup: () => void; } +export interface ExportEvent { + fields: TemplateField[]; + blob?: Blob; + fileName: string; +} + export interface FieldMenuProps { isVisible: boolean; position?: DOMRect; @@ -116,6 +122,7 @@ export interface SuperDocTemplateBuilderProps { onFieldCreate?: ( field: FieldDefinition, ) => void | Promise; + onExport?: (event: ExportEvent) => void; // UI className?: string;