@superdoc-dev/esign 1.0.0-next.2 → 1.0.0-next.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @superdoc-dev/esign
2
2
 
3
- A React eSignature component for SuperDoc that handles document acceptance workflows.
3
+ React eSignature component for document signing workflows with SuperDoc.
4
4
 
5
5
  ## Installation
6
6
 
@@ -11,164 +11,427 @@ npm install @superdoc-dev/esign superdoc
11
11
  ## Quick Start
12
12
 
13
13
  ```jsx
14
- import React, { useRef, useState } from 'react';
15
14
  import SuperDocESign from '@superdoc-dev/esign';
16
15
  import 'superdoc/dist/style.css';
17
16
 
18
17
  function App() {
19
- const esignRef = useRef();
20
- const [status, setStatus] = useState({});
21
-
22
- const handleAccept = async () => {
23
- const auditData = await esignRef.current?.accept();
24
- if (auditData) {
25
- // Send to your API
26
- await api.saveSignature(auditData);
27
- }
28
- };
29
-
30
18
  return (
31
- <div>
32
- {/* Document viewer */}
33
- <SuperDocESign
34
- ref={esignRef}
35
- document="https://example.com/agreement.docx"
36
- requirements={{
37
- scroll: true,
38
- signature: true,
39
- consents: ['terms', 'privacy']
40
- }}
41
- onChange={setStatus}
42
- onAccept={handleAccept}
43
- />
44
-
45
- {/* Your signature UI */}
46
- <input
47
- type="text"
48
- data-esign-signature
49
- placeholder="Type your full name"
50
- disabled={!status.scroll}
51
- />
52
-
53
- {/* Your consent UI */}
54
- <label>
55
- <input
56
- type="checkbox"
57
- data-esign-consent="terms"
58
- disabled={!status.scroll || !status.signature}
59
- />
60
- I accept the terms
61
- </label>
62
-
63
- {/* Accept button */}
64
- <button
65
- onClick={() => esignRef.current?.accept()}
66
- disabled={!status.isValid}
67
- >
68
- Accept Agreement
69
- </button>
70
- </div>
19
+ <SuperDocESign
20
+ eventId="unique-session-id"
21
+
22
+ document={{
23
+ source: "contract.pdf",
24
+ mode: "full",
25
+ displayOptions: {
26
+ scrollRequired: true
27
+ }
28
+ }}
29
+
30
+ fields={{
31
+ document: [
32
+ { alias: 'company', value: 'Acme Corp' }
33
+ ],
34
+ signer: [
35
+ {
36
+ id: 'signature',
37
+ type: 'signature',
38
+ validation: { required: true },
39
+ label: 'Your Signature'
40
+ }
41
+ ]
42
+ }}
43
+
44
+ onSubmit={async (data) => {
45
+ await api.saveSignature(data);
46
+ }}
47
+ />
71
48
  );
72
49
  }
73
50
  ```
74
51
 
75
- ## Props
52
+ ## API Reference
53
+
54
+ ### Props
55
+
56
+ | Prop | Type | Required | Description |
57
+ |------|------|----------|-------------|
58
+ | `eventId` | string | ✓ | Unique identifier for signing session |
59
+ | `document` | object | ✓ | Document configuration |
60
+ | `fields` | object | | Field definitions |
61
+ | `download` | object | | Download button config |
62
+ | `submit` | object | | Submit button config |
63
+ | `onSubmit` | function | ✓ | Submit handler |
64
+ | `onDownload` | function | | Download handler |
65
+ | `onStateChange` | function | | State change handler |
66
+ | `onFieldChange` | function | | Field change handler |
67
+ | `isDisabled` | boolean | | Disable all interactions |
76
68
 
77
- | Prop | Type | Description |
78
- |------|------|-------------|
79
- | `document` | `string \| File \| Blob` | Document to display |
80
- | `requirements` | `Object` | What users must complete |
81
- | `fields` | `Array` | Initial field values |
82
- | `signatureSelector` | `string` | CSS selector for signature element (default: `[data-esign-signature]`) |
83
- | `consentSelector` | `string` | CSS selector for consent checkboxes (default: `[data-esign-consent]`) |
84
- | `onChange` | `(status) => void` | Called when requirements change |
85
- | `onAccept` | `(data) => void` | Called when document is accepted |
86
- | `onReady` | `() => void` | Called when component is ready |
87
- | `onFieldsDiscovered` | `(fields) => void` | Called when document fields are found |
69
+ ### Document Configuration
88
70
 
89
- ## Methods (via ref)
71
+ ```jsx
72
+ document={{
73
+ source: File | Blob | string, // Required
74
+ mode: 'full' | 'download_only' | 'preview',
75
+ displayOptions: {
76
+ scrollRequired: boolean,
77
+ watermark: boolean
78
+ }
79
+ }}
80
+ ```
90
81
 
91
- - `accept()` - Process acceptance and return audit data
92
- - `reset()` - Clear all state
93
- - `updateFields(fields)` - Update document field values
94
- - `getStatus()` - Get current requirement status
95
- - `getFields()` - Get all document fields
82
+ ### Field Reference System
96
83
 
97
- ## Requirements
84
+ Fields can be referenced using either `id` or `alias`:
98
85
 
99
- Configure what users must complete before accepting:
86
+ - **`id`**: System identifier (e.g., "field_123")
87
+ - **`alias`**: Human-readable name (e.g., "customer_name")
88
+
89
+ This allows the same value to appear multiple places in a document:
100
90
 
101
91
  ```jsx
102
- <SuperDocESign
103
- requirements={{
104
- scroll: true, // Must scroll to bottom
105
- signature: true, // Must provide signature
106
- consents: ['terms', 'privacy'] // Must check these boxes
107
- }}
108
- />
92
+ // Document template might have:
93
+ // "Dear {{customer_name}},"
94
+ // "Agreement between {{company}} and {{customer_name}}"
95
+ // "Signed by: {{customer_name}}"
96
+
97
+ fields={{
98
+ document: [
99
+ {
100
+ alias: 'customer_name', // Used in document {{customer_name}}
101
+ value: 'John Doe'
102
+ },
103
+ {
104
+ alias: 'company',
105
+ value: 'Acme Corp'
106
+ },
107
+ {
108
+ id: 'date_field',
109
+ alias: 'sign_date', // Can have both id and alias
110
+ value: '2024-01-15'
111
+ }
112
+ ],
113
+
114
+ signer: [
115
+ {
116
+ id: 'sig_001',
117
+ alias: 'signature', // Document shows {{signature}}
118
+ type: 'signature',
119
+ validation: { required: true }
120
+ },
121
+ {
122
+ id: 'consent_terms',
123
+ alias: 'terms_accepted', // Can reference as {{terms_accepted}}
124
+ type: 'consent',
125
+ label: 'I accept the terms'
126
+ }
127
+ ]
128
+ }}
109
129
  ```
110
130
 
111
- ## Signature Input
131
+ **How it works:**
132
+ 1. Document fields are injected on load using their id/alias
133
+ 2. Signer fields are collected and can replace placeholders using their alias
134
+ 3. The same alias can appear multiple times in the document
135
+ 4. All instances get the same value
112
136
 
113
- Use the `data-esign-signature` attribute on any input or canvas:
137
+ ### Field Configuration
114
138
 
115
139
  ```jsx
116
- {/* Text input */}
117
- <input type="text" data-esign-signature placeholder="Type your name" />
140
+ fields={{
141
+ // Values to inject into document
142
+ document: [
143
+ {
144
+ id: 'field_id', // Optional
145
+ alias: 'field_name', // Optional (at least one of id or alias required)
146
+ value: 'any value'
147
+ }
148
+ ],
149
+
150
+ // Fields for signer to complete
151
+ signer: [
152
+ {
153
+ id: 'unique_id', // Required for signer fields
154
+ alias: 'field_ref', // Optional alias for document references
155
+ type: 'signature' | 'consent' | 'checkbox' | 'text',
156
+ validation: {
157
+ required: boolean,
158
+ minLength: number,
159
+ maxLength: number
160
+ },
161
+ label: 'Field Label',
162
+ component: CustomComponent // Optional - consistent with download/submit!
163
+ }
164
+ ]
165
+ }}
166
+ ```
118
167
 
119
- {/* Canvas signature pad */}
120
- <canvas data-esign-signature width="400" height="200" />
168
+ ### UI Customization
121
169
 
122
- {/* Custom component */}
123
- <SignaturePad data-esign-signature data-signed={isSigned} />
170
+ Simple customization:
171
+ ```jsx
172
+ download={{
173
+ fileName: "contract.pdf",
174
+ label: "Download Contract",
175
+ variant: "secondary"
176
+ }}
177
+
178
+ submit={{
179
+ label: "Sign Document",
180
+ loadingLabel: "Processing...",
181
+ variant: "primary"
182
+ }}
124
183
  ```
125
184
 
126
- ## Consent Checkboxes
185
+ Full custom components:
186
+ ```jsx
187
+ download={{
188
+ component: ({ onClick, fileName, isDisabled }) => (
189
+ <CustomButton onClick={onClick} disabled={isDisabled}>
190
+ Download {fileName}
191
+ </CustomButton>
192
+ )
193
+ }}
194
+
195
+ submit={{
196
+ component: ({ onClick, isValid, isDisabled, isSubmitting }) => (
197
+ <CustomButton
198
+ onClick={onClick}
199
+ disabled={!isValid || isDisabled}
200
+ >
201
+ {isSubmitting ? 'Processing...' : 'Sign & Submit'}
202
+ </CustomButton>
203
+ )
204
+ }}
205
+ ```
127
206
 
128
- Use the `data-esign-consent` attribute with a unique name:
207
+ ### Custom Field Components
129
208
 
130
209
  ```jsx
131
- <label>
132
- <input type="checkbox" data-esign-consent="terms" />
133
- I accept the terms
134
- </label>
135
-
136
- <label>
137
- <input type="checkbox" data-esign-consent="privacy" />
138
- I acknowledge the privacy policy
139
- </label>
210
+ // Custom signature pad component
211
+ const CustomSignaturePad = ({ value, onChange, isDisabled, label }) => (
212
+ <div className="custom-signature">
213
+ <label>{label}</label>
214
+ <canvas
215
+ // ... canvas signature implementation
216
+ onMouseUp={(e) => onChange(canvasDataURL)}
217
+ style={{ border: '1px solid #000', cursor: 'crosshair' }}
218
+ />
219
+ </div>
220
+ );
221
+
222
+ // Use it in fields
223
+ fields={{
224
+ signer: [
225
+ {
226
+ id: 'signature',
227
+ type: 'signature',
228
+ validation: { required: true },
229
+ component: CustomSignaturePad // Consistent with download/submit!
230
+ }
231
+ ]
232
+ }}
140
233
  ```
141
234
 
142
- ## Field Population
235
+ ## Examples
143
236
 
144
- Replace placeholders in your document with dynamic data:
237
+ ### Basic Agreement
145
238
 
146
239
  ```jsx
147
240
  <SuperDocESign
148
- fields={[
149
- { alias: 'userName', value: 'John Doe' },
150
- { alias: 'date', value: new Date().toLocaleDateString() },
151
- { alias: 'company', value: 'Acme Inc.' }
152
- ]}
241
+ eventId="session-123"
242
+ document={{ source: "terms.pdf" }}
243
+ fields={{
244
+ signer: [
245
+ {
246
+ id: 'accept',
247
+ type: 'consent',
248
+ validation: { required: true },
249
+ label: 'I accept the terms'
250
+ }
251
+ ]
252
+ }}
253
+ onSubmit={handleSubmit}
153
254
  />
154
255
  ```
155
256
 
156
- ## Audit Data
257
+ ### Employment Offer with Repeated Fields
157
258
 
158
- When a user accepts, you receive comprehensive audit data:
259
+ ```jsx
260
+ // Example: Employment offer with repeated fields
261
+ <SuperDocESign
262
+ eventId="offer-123"
263
+
264
+ document={{
265
+ source: offerLetter, // Contains {{employee_name}}, {{salary}}, etc.
266
+ mode: "full",
267
+ displayOptions: {
268
+ scrollRequired: true
269
+ }
270
+ }}
271
+
272
+ fields={{
273
+ document: [
274
+ {
275
+ alias: 'employee_name', // Appears 5 times in document
276
+ value: 'Jane Smith'
277
+ },
278
+ {
279
+ alias: 'position', // Appears 3 times
280
+ value: 'Senior Engineer'
281
+ },
282
+ {
283
+ alias: 'salary', // Appears 2 times
284
+ value: '$120,000'
285
+ },
286
+ {
287
+ alias: 'start_date',
288
+ value: 'February 1, 2024'
289
+ }
290
+ ],
291
+
292
+ signer: [
293
+ {
294
+ id: 'employee_signature',
295
+ alias: 'employee_sig', // {{employee_sig}} in document
296
+ type: 'signature',
297
+ validation: { required: true },
298
+ label: 'Your Signature'
299
+ },
300
+ {
301
+ id: 'accept_offer',
302
+ alias: 'offer_accepted',
303
+ type: 'consent',
304
+ validation: { required: true },
305
+ label: 'I accept this offer'
306
+ }
307
+ ]
308
+ }}
309
+
310
+ submit={{
311
+ label: 'Accept Offer'
312
+ }}
313
+
314
+ onSubmit={handleAcceptOffer}
315
+ />
316
+ ```
159
317
 
160
- ```typescript
161
- {
162
- timestamp: "2024-01-15T10:30:00.000Z",
163
- duration: 45, // seconds spent on document
164
- fields: [
165
- { id: "field1", alias: "userName", value: "John Doe" }
166
- ],
167
- scrolled: true,
168
- signed: true,
169
- consents: ["terms", "privacy"],
170
- signatureImage: "data:image/png;base64,..." // if canvas
171
- }
318
+ ### Full Contract with All Features
319
+
320
+ ```jsx
321
+ <SuperDocESign
322
+ eventId="contract-456"
323
+
324
+ document={{
325
+ source: serviceAgreement,
326
+ mode: "full",
327
+ displayOptions: {
328
+ scrollRequired: true,
329
+ watermark: true
330
+ }
331
+ }}
332
+
333
+ fields={{
334
+ document: [
335
+ { alias: 'client_name', value: 'John Doe' },
336
+ { alias: 'company', value: 'Acme Corp' },
337
+ { alias: 'service_type', value: 'Premium Support' },
338
+ { alias: 'contract_date', value: new Date().toLocaleDateString() }
339
+ ],
340
+ signer: [
341
+ {
342
+ id: 'client_signature',
343
+ alias: 'signature',
344
+ type: 'signature',
345
+ validation: { required: true },
346
+ label: 'Your Signature'
347
+ },
348
+ {
349
+ id: 'consent_terms',
350
+ type: 'consent',
351
+ validation: { required: true },
352
+ label: 'I agree to the terms and conditions'
353
+ },
354
+ {
355
+ id: 'consent_privacy',
356
+ type: 'consent',
357
+ validation: { required: true },
358
+ label: 'I acknowledge the privacy policy'
359
+ },
360
+ {
361
+ id: 'email_updates',
362
+ type: 'checkbox',
363
+ validation: { required: false },
364
+ label: 'Send me email updates'
365
+ }
366
+ ]
367
+ }}
368
+
369
+ download={{
370
+ fileName: 'service_agreement_signed.pdf',
371
+ label: 'Download Agreement',
372
+ variant: 'secondary'
373
+ }}
374
+
375
+ submit={{
376
+ label: 'Sign Agreement',
377
+ loadingLabel: 'Processing...',
378
+ invalidLabel: 'Please complete all required fields',
379
+ variant: 'success'
380
+ }}
381
+
382
+ onSubmit={async (data) => {
383
+ await api.saveSignedContract(data);
384
+ console.log('Signed by:', data.signerFields);
385
+ }}
386
+
387
+ onDownload={(blob, fileName) => {
388
+ console.log('Downloaded:', fileName);
389
+ }}
390
+
391
+ onStateChange={(state) => {
392
+ console.log('Valid:', state.isValid);
393
+ }}
394
+
395
+ isDisabled={false}
396
+ />
397
+ ```
398
+
399
+ ## Progressive Customization
400
+
401
+ The component supports three levels of customization:
402
+
403
+ ```jsx
404
+ // Level 1: Use all defaults
405
+ <SuperDocESign
406
+ eventId="session-1"
407
+ document={{ source: "doc.pdf" }}
408
+ onSubmit={handleSubmit}
409
+ />
410
+
411
+ // Level 2: Simple customization
412
+ <SuperDocESign
413
+ eventId="session-2"
414
+ document={{ source: "doc.pdf" }}
415
+ submit={{ label: "I Agree", variant: "success" }}
416
+ download={{ label: "Get Copy" }}
417
+ onSubmit={handleSubmit}
418
+ />
419
+
420
+ // Level 3: Full custom components
421
+ <SuperDocESign
422
+ eventId="session-3"
423
+ document={{ source: "doc.pdf" }}
424
+ submit={{ component: CustomSubmitButton }}
425
+ download={{ component: CustomDownloadButton }}
426
+ fields={{
427
+ signer: [{
428
+ id: 'sig',
429
+ type: 'signature',
430
+ component: CustomSignaturePad
431
+ }]
432
+ }}
433
+ onSubmit={handleSubmit}
434
+ />
172
435
  ```
173
436
 
174
437
  ## TypeScript
@@ -176,30 +439,17 @@ When a user accepts, you receive comprehensive audit data:
176
439
  Full TypeScript support with exported types:
177
440
 
178
441
  ```typescript
179
- import SuperDocESign, {
180
- SuperDocESignHandle,
181
- Status,
182
- AuditData,
183
- FieldUpdate
442
+ import SuperDocESign from '@superdoc-dev/esign';
443
+ import type {
444
+ SuperDocESignProps,
445
+ SubmitData,
446
+ SigningState,
447
+ DocumentField,
448
+ SignerField,
449
+ FieldComponentProps
184
450
  } from '@superdoc-dev/esign';
185
-
186
- const esignRef = useRef<SuperDocESignHandle>(null);
187
- const [status, setStatus] = useState<Status>({
188
- scroll: false,
189
- signature: false,
190
- consents: [],
191
- isValid: false
192
- });
193
-
194
- const handleAccept = async (data: AuditData) => {
195
- // Process acceptance
196
- };
197
451
  ```
198
452
 
199
- ## Examples
200
-
201
- See the [examples](./examples) directory for complete implementations.
202
-
203
453
  ## License
204
454
 
205
455
  MIT
@@ -0,0 +1,4 @@
1
+ import { default as React } from 'react';
2
+ import { FieldComponentProps } from '../types';
3
+ export declare const ConsentCheckbox: React.FC<FieldComponentProps>;
4
+ //# sourceMappingURL=ConsentCheckbox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConsentCheckbox.d.ts","sourceRoot":"","sources":["../../src/defaults/ConsentCheckbox.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAEpD,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAoBzD,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { default as React } from 'react';
2
+ import { DownloadButtonProps, DownloadConfig } from '../types';
3
+ export declare const createDownloadButton: (config?: DownloadConfig) => React.FC<DownloadButtonProps>;
4
+ //# sourceMappingURL=DownloadButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DownloadButton.d.ts","sourceRoot":"","sources":["../../src/defaults/DownloadButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAEpE,eAAO,MAAM,oBAAoB,GAAI,SAAS,cAAc,kCA+B3D,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { default as React } from 'react';
2
+ import { FieldComponentProps } from '../types';
3
+ export declare const SignatureInput: React.FC<FieldComponentProps>;
4
+ //# sourceMappingURL=SignatureInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SignatureInput.d.ts","sourceRoot":"","sources":["../../src/defaults/SignatureInput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AACxC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAEpD,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAiDxD,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { default as React } from 'react';
2
+ import { SubmitButtonProps, SubmitConfig } from '../types';
3
+ export declare const createSubmitButton: (config?: SubmitConfig) => React.FC<SubmitButtonProps>;
4
+ //# sourceMappingURL=SubmitButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SubmitButton.d.ts","sourceRoot":"","sources":["../../src/defaults/SubmitButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAEhE,eAAO,MAAM,kBAAkB,GAAI,SAAS,YAAY,gCAkCvD,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { SignatureInput } from './SignatureInput';
2
+ export { ConsentCheckbox } from './ConsentCheckbox';
3
+ export { createDownloadButton } from './DownloadButton';
4
+ export { createSubmitButton } from './SubmitButton';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/defaults/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC"}