Skip to content
This repository was archived by the owner on Jan 30, 2026. It is now read-only.

Commit 1124775

Browse files
committed
feat: implement download functionality for document export in SuperDoc eSign
1 parent 038a5dd commit 1124775

2 files changed

Lines changed: 98 additions & 3 deletions

File tree

demo/src/App.tsx

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { useState, useRef, useEffect, useCallback } from 'react';
22
import SuperDocESign from '@superdoc-dev/esign';
3-
import type { SuperDocESignHandle, Status, AuditData, FieldInfo } from '@superdoc-dev/esign';
3+
import type { SuperDocESignHandle, Status, AuditData, FieldInfo, DownloadRequestData } from '@superdoc-dev/esign';
44
import 'superdoc/dist/style.css';
55
import './App.css';
66

@@ -115,6 +115,28 @@ export function App() {
115115
setAuditData(data);
116116
}, [log]);
117117

118+
const handleDownloadRequest = useCallback(async (data: DownloadRequestData) => {
119+
log(`Download requested - ${data.fields.length} fields included`);
120+
121+
// Simulate sending to server for PDF conversion
122+
// In production, you would send to your backend:
123+
// const formData = new FormData();
124+
// formData.append('document', data.blob, 'document.docx');
125+
// formData.append('fields', JSON.stringify(data.fields));
126+
// const response = await fetch('/api/convert-to-pdf', { method: 'POST', body: formData });
127+
// const pdfBlob = await response.blob();
128+
129+
// For demo: just download the DOCX
130+
const url = URL.createObjectURL(data.blob);
131+
const a = document.createElement('a');
132+
a.href = url;
133+
a.download = `agreement-${Date.now()}.docx`;
134+
a.click();
135+
URL.revokeObjectURL(url);
136+
137+
log('Download complete');
138+
}, [log]);
139+
118140
const handleReset = () => {
119141
esignRef.current?.reset();
120142
setIsAccepted(false);
@@ -286,7 +308,22 @@ export function App() {
286308
<>
287309
{/* Document Viewer */}
288310
<div className="document-section">
289-
<label>Employment Agreement</label>
311+
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '8px' }}>
312+
<label style={{ margin: 0 }}>Employment Agreement</label>
313+
<a
314+
href="#"
315+
data-esign-download
316+
style={{
317+
color: '#6366f1',
318+
textDecoration: 'none',
319+
fontSize: '14px',
320+
opacity: isReady ? 1 : 0.5,
321+
pointerEvents: isReady ? 'auto' : 'none'
322+
}}
323+
>
324+
Download
325+
</a>
326+
</div>
290327
<SuperDocESign
291328
ref={esignRef}
292329
document="https://storage.googleapis.com/public_statichosting/word_documents/agreement_template.docx"
@@ -305,6 +342,7 @@ export function App() {
305342
onChange={handleStatusChange}
306343
onAccept={handleAccept}
307344
onFieldsDiscovered={handleFieldsDiscovered}
345+
onDownloadRequest={handleDownloadRequest}
308346
className="document-container"
309347
/>
310348
{!status.scroll && config.scroll && (

src/index.tsx

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ export interface FieldInfo {
3838
value?: any;
3939
}
4040

41+
export interface DownloadRequestData {
42+
blob: Blob;
43+
fields: FieldInfo[];
44+
}
45+
4146
export interface SuperDocESignProps {
4247
// Document
4348
document: string | File | Blob;
@@ -55,12 +60,14 @@ export interface SuperDocESignProps {
5560
// Element selectors (for finding signature/consent elements)
5661
signatureSelector?: string;
5762
consentSelector?: string;
63+
downloadSelector?: string;
5864

5965
// Callbacks
6066
onReady?: () => void;
6167
onChange?: (status: Status) => void;
6268
onAccept?: (data: AuditData) => void | Promise<void>;
6369
onFieldsDiscovered?: (fields: FieldInfo[]) => void;
70+
onDownloadRequest?: (data: DownloadRequestData) => void | Promise<void>;
6471

6572
// Style
6673
className?: string;
@@ -73,6 +80,7 @@ export interface SuperDocESignHandle {
7380
updateFields: (fields: FieldUpdate[]) => void;
7481
getStatus: () => Status;
7582
getFields: () => FieldInfo[];
83+
requestDownload: () => Promise<DownloadRequestData | false>;
7684
superdoc: SuperDoc | null;
7785
}
7886

@@ -84,10 +92,12 @@ const SuperDocESign = forwardRef<SuperDocESignHandle, SuperDocESignProps>(
8492
fields: initialFields = [],
8593
signatureSelector = "[data-esign-signature]",
8694
consentSelector = "[data-esign-consent]",
95+
downloadSelector = "[data-esign-download]",
8796
onReady,
8897
onChange,
8998
onAccept,
9099
onFieldsDiscovered,
100+
onDownloadRequest,
91101
className,
92102
style,
93103
},
@@ -452,6 +462,52 @@ const SuperDocESign = forwardRef<SuperDocESignHandle, SuperDocESignProps>(
452462
return Array.from(fields.values());
453463
}, [fields]);
454464

465+
const requestDownload = useCallback(async (): Promise<DownloadRequestData | false> => {
466+
if (!superdocRef.current) return false;
467+
468+
try {
469+
const result = await superdocRef.current.export({
470+
exportType: ['docx'],
471+
isFinalDoc: true,
472+
triggerDownload: false,
473+
});
474+
475+
if (!result) return false;
476+
477+
const downloadData: DownloadRequestData = {
478+
blob: result,
479+
fields: Array.from(fields.values()),
480+
};
481+
482+
await onDownloadRequest?.(downloadData);
483+
return downloadData;
484+
} catch (error) {
485+
console.error('Download request failed:', error);
486+
return false;
487+
}
488+
}, [fields, onDownloadRequest]);
489+
490+
// Track download button clicks
491+
useEffect(() => {
492+
if (!isReady) return;
493+
494+
const handleDownloadClick = (e: Event) => {
495+
e.preventDefault();
496+
requestDownload();
497+
};
498+
499+
const downloadElements = globalThis.document.querySelectorAll(downloadSelector);
500+
downloadElements.forEach((el) => {
501+
el.addEventListener('click', handleDownloadClick);
502+
});
503+
504+
return () => {
505+
downloadElements.forEach((el) => {
506+
el.removeEventListener('click', handleDownloadClick);
507+
});
508+
};
509+
}, [downloadSelector, isReady, requestDownload]);
510+
455511
// Expose methods via ref
456512
useImperativeHandle(
457513
ref,
@@ -461,9 +517,10 @@ const SuperDocESign = forwardRef<SuperDocESignHandle, SuperDocESignProps>(
461517
updateFields,
462518
getStatus,
463519
getFields,
520+
requestDownload,
464521
superdoc: superdocRef.current,
465522
}),
466-
[accept, reset, updateFields, getStatus, getFields],
523+
[accept, reset, updateFields, getStatus, getFields, requestDownload],
467524
);
468525

469526
return <div ref={containerRef} className={className} style={style} />;

0 commit comments

Comments
 (0)