UNPKG

clickwrap

Version:

Complete clickwrap solution with built-in document viewing. Track agreements, signatures, and consents.

294 lines (233 loc) 7.84 kB
# SuperDoc Clickwrap Orchestrate legal agreements with SuperDoc. Track document reading, signatures, and consent checkboxes without the UI overhead. ## Why this exists SuperDoc is great at rendering documents. But legal agreements need more - scroll tracking, signatures, consent checkboxes. This orchestrator handles that coordination while you keep full control of your UI. **Note:** Clickwrap includes SuperDoc internally. You don't need to install or initialize SuperDoc separately. ## Install ```bash npm install clickwrap ``` ## Quick Start ```javascript import Clickwrap from 'clickwrap' import SignaturePad from 'signature_pad' // Initialize Clickwrap with built-in SuperDoc const clickwrap = new Clickwrap({ // Document configuration - Clickwrap handles SuperDoc internally! document: '/terms.pdf', // PDF/DOCX file or URL documentElement: '#document', // Where to render documentId: 'terms-v2.1', // Optional document identifier // UI Components signaturePad: new SignaturePad(canvas), consentElements: document.querySelectorAll('.consent'), acceptButton: document.querySelector('#accept'), // Requirements requirements: { scrollThreshold: 0.95, signature: true, consents: ['terms', 'privacy'] }, // Callbacks onReady: () => console.log('Document loaded!'), onAccept: async (data) => { // Send to your backend await api.saveAgreement(data) } }) ``` ## What it does ✅ Handles SuperDoc initialization internally ✅ Tracks document scroll progress ✅ Validates signatures (bring your own signature library) ✅ Manages consent checkboxes ✅ Enables accept button when requirements are met ✅ Collects timestamped agreement data ✅ Provides progress tracking and validation states ## What it doesn't do ❌ No UI components - you build the interface ❌ No backend - you handle data storage ❌ No styling - you control the look ## The Data You Get When a user accepts, you receive everything needed for legal compliance: ```javascript { timestamp: "2024-01-15T10:30:00Z", documentId: "terms-v2.1", documentUrl: "/terms.pdf", // if document was a URL duration: 47, // seconds spent scrollProgress: "100%", // how far they scrolled signature: "data:image/png;...", // signature image (if required) consents: { terms: true, privacy: true, marketing: false }, action: "accepted" // or "declined" } ``` ## API ### Config Options ```javascript new Clickwrap({ // Document configuration document: '/terms.pdf', // URL or File object (PDF/DOCX) documentElement: '#document', // Selector or element where to render documentId: 'terms-v2.1', // Optional document identifier superdocConfig: {}, // Optional SuperDoc configuration // Components (bring your own) signaturePad: pad, // SignaturePad or compatible consentElements: checkboxes, // Your checkbox elements acceptButton: button, // Gets enabled when valid declineButton: button, // Optional decline // Requirements requirements: { scrollThreshold: 0.95, // 0-1 (95% = nearly complete) signature: true, // Signature required? consents: ['terms', 'privacy'] // Required checkbox names }, // Callbacks onReady: () => {}, // Document loaded and ready onProgress: (state) => {}, // Track completion onAccept: async (data) => {}, // Handle acceptance onDecline: async (data) => {} // Handle rejection }) ``` ### Methods - `validate()` - Check if all requirements are met - `getData()` - Get current agreement data - `reset()` - Clear all inputs and start over - `getProgress()` - Get completion percentage (returns {completed, total, percentage}) - `destroy()` - Clean up instance and SuperDoc ## React Example ```jsx function AgreementModal({ document }) { const canvasRef = useRef() const clickwrapRef = useRef() useEffect(() => { // Initialize Clickwrap with built-in SuperDoc const signaturePad = new SignaturePad(canvasRef.current) clickwrapRef.current = new Clickwrap({ // Document configuration document: document.url, // PDF/DOCX URL documentElement: '#agreement-doc', // Where to render documentId: document.id, // UI Components signaturePad, consentElements: document.querySelectorAll('.consent'), acceptButton: document.querySelector('#accept'), // Requirements requirements: { scrollThreshold: 0.95, signature: true, consents: ['terms'] }, // Callbacks onReady: () => { console.log('Document loaded!') }, onAccept: async (data) => { await api.recordAgreement(data) closeModal() } }) return () => { clickwrapRef.current?.destroy() } }, [document]) return ( <div className="agreement-modal"> <div id="agreement-doc" /> <canvas ref={canvasRef} /> <label> <input type="checkbox" name="terms" className="consent" /> I accept the terms </label> <button id="accept">Accept</button> </div> ) } ``` ## Vue Example ```vue <template> <div class="agreement"> <div id="documentViewer"></div> <canvas ref="signatureCanvas"></canvas> <label> <input type="checkbox" name="terms" ref="termsCheck"> Accept terms </label> <button ref="acceptBtn">Accept</button> </div> </template> <script setup> import { onMounted, onUnmounted, ref } from 'vue' import Clickwrap from 'clickwrap' import SignaturePad from 'signature_pad' const props = defineProps(['documentUrl']) const emit = defineEmits(['accepted']) const signatureCanvas = ref() const termsCheck = ref() const acceptBtn = ref() let clickwrap = null onMounted(() => { clickwrap = new Clickwrap({ // Document configuration document: props.documentUrl, documentElement: '#documentViewer', // UI Components signaturePad: new SignaturePad(signatureCanvas.value), consentElements: [termsCheck.value], acceptButton: acceptBtn.value, // Requirements requirements: { signature: true, consents: ['terms'] }, // Callbacks onReady: () => { console.log('Document ready!') }, onAccept: async (data) => { await saveAgreement(data) emit('accepted') } }) }) onUnmounted(() => { clickwrap?.destroy() }) </script> ``` ## Without SuperDoc Works with any scrollable element if you don't need document rendering: ```javascript const clickwrap = new Clickwrap({ // No 'document' parameter - just track existing element documentElement: document.querySelector('.terms-text'), documentId: 'terms-v2.1', signaturePad: new SignaturePad(canvas), consentElements: document.querySelectorAll('.consent'), acceptButton: document.querySelector('#accept'), requirements: { scrollThreshold: 0.95, signature: true, consents: ['terms'] }, onAccept: async (data) => { await api.saveAgreement(data) } }) ``` ## Signature Libraries Works with any signature library that has `isEmpty()` and `clear()` methods: - [signature_pad](https://github.com/szimek/signature_pad) ✅ - [React Signature Canvas](https://github.com/agilgur5/react-signature-canvas) ✅ - [Vue Signature Pad](https://github.com/neighborhood999/vue-signature-pad) ✅ - Custom implementations ✅ ## Browser Support Modern browsers only. No IE11. ## License MIT ## About Built by the SuperDoc team to make legal agreements easier. Part of the [SuperDoc](https://github.com/Harbour-Enterprises/SuperDoc) ecosystem.