@zanecoder/zc-sign-editor

Embeddable ZC Sign field editor and send shell for host apps (e.g. Retail Origination)
4,950
Install
npm install @zanecoder/zc-sign-editor
Latest Version:0.1.11
Vue:3
License:Proprietary
Last Updated:Sep 3, 2026
Links: npm
Maintainer: hanz-archer

@zanecoder/zc-sign-editor

Embeddable Vue Send Document UI for host apps (Retail Origination, etc.). Upload a PDF, add recipients, place signature / initials / date fields, and prepare a send payload — without an iframe.

UI matches zc-sign’s send page. Creating a signing session still goes through the zc-sign backend. This package only prepares the document; your host BFF talks to zc-sign.

Source: github.com/zaneCoder/zc-sign-fe → packages/zc-sign-editor

Changelog (recent)

0.1.10

  • Bug fix: PDF field placement stays aligned after scroll/zoom (fields stored in base viewport coords).
  • Bug fix: Adjust Field Sizes resizes placed fields; removed hidden second PDF load that caused OOM on large docs.

0.1.9

  • Multi-signer / sequential: Only the active signer’s fields can be dragged (other signers’ fields stay red / click-to-reassign). New drops follow Assign new fields to. Preview pageLayouts sync into prepare so metadata ownership matches /send.

0.1.8

  • Feature: Click a placed field on the PDF → Selected field assignee appears in the sidebar so you can move that field to another signer (was broken: selection lived only inside the nested editor).

0.1.7

  • Bug fix: Dragging Signature / Initials / Date onto the PDF no longer hangs the browser tab (“Aw, Snap!”). Field (and recipient) v-model sync now uses equality guards so Vue cannot infinite-loop updates between ZcSignSend and ZcSignEditor.

0.1.6

  • Optional host theme (forwarded into editor empty state + chrome)
  • Sharper HiDPI PDF preview without shifting field coordinates

Do I need integration keys?

Yes for the overall flow — but not inside this SDK / not in the browser.

Needs keys? Where
This package (ZcSignSend) No Browser Vue UI only
Your host BFF / server Yes Server env only
zc-sign API Validates keys POST /api/integration/send-document

Host server env:

Env Used for
ZC_SIGN_PUBLIC_KEY Header ZC-SIGN-PUB-KEY
ZC_SIGN_SECRET_KEY Header ZC-SIGN-SECRET-KEY
ZC_SIGN_API_URL zc-sign API base URL
ZC_SIGN_FRONTEND_URL Signer links

Never put pub/secret keys in this package, Vue client code, or NUXT_PUBLIC_* / Vite VITE_* vars.

How it works

Host UI (Retail, etc.)
  └─ <ZcSignSend />                 ← this package
       • pick PDF, recipients, fields
       • tokenize PDF (@signature#id, …)
       • build metadata JSON
       └─ submit(payload)           ← you provide this callback
            └─ Host BFF             ← auth + server keys
                 • upload PDF
                 • POST zc-sign /api/integration/send-document
                      headers: ZC-SIGN-PUB-KEY, ZC-SIGN-SECRET-KEY
                 └─ session uuid
Signers open zc-sign FE
  /signature-signing?session=…&email=…
Webhook → your host (e.g. /api/webhooks/zc-sign)
Layer Responsibility
SDK (ZcSignSend) UI, place fields, prepare PDF + metadata, call submit
Host BFF Auth, storage, call zc-sign with server keys, save session
zc-sign BE Session, emails, signing order, completed PDF
zc-sign FE Actual signing experience (not this package)

What this SDK prepares

  • Tokenized PDF (@signature#id, @initials#id, @date#id baked in)
  • Recipient list + field layout / size metadata (integration FormData shape)

What stays on zc-sign

  • Session UUID, signing links, email queue, sequential / parallel delivery
  • Signer UI, completed PDF, webhooks back to your host

If you omit the submit prop, the SDK only emits a prepared event — still no keys; your app must send to the BFF afterward.

Install

npm install @zanecoder/zc-sign-editor

Peer dependency: Vue ^3.4.

import { ZcSignSend, ZcSignEditor } from '@zanecoder/zc-sign-editor'
import '@zanecoder/zc-sign-editor/style.css'

Quick usage

<script setup lang="ts">
import { ref } from 'vue'
import { ZcSignSend, createRecipient } from '@zanecoder/zc-sign-editor'
import type { ZcSignPreparedSend, ZcSignRecipient, ZcSignSendResult } from '@zanecoder/zc-sign-editor'
import '@zanecoder/zc-sign-editor/style.css'

const recipients = ref<ZcSignRecipient[]>([createRecipient(1)])

async function submit(payload: ZcSignPreparedSend): Promise<ZcSignSendResult> {
  // Browser → your BFF only (never call zc-sign with secret from the client)
  const form = new FormData()
  form.append('file', payload.pdf, payload.documentName || 'document.pdf')
  form.append('metadata', JSON.stringify(payload.metadata))
  form.append('documentName', payload.documentName)
  form.append('subject', payload.subject)
  form.append('message', payload.message)
  form.append('signingMode', payload.signingMode)

  const res = await fetch('/api/your-create-signing-session', {
    method: 'POST',
    body: form,
  })
  return res.json()
}
</script>

<template>
  <ZcSignSend v-model:recipients="recipients" :submit="submit" />
</template>

ZcSignSend props

Prop Type Default Description
recipients ZcSignRecipient[] required Signers / viewers (use v-model:recipients)
submit (payload) => Promise<ZcSignSendResult> — Host callback; if omitted, only prepared is emitted
file File | null null Optional preloaded PDF
documentName string '' Document title
subject string '' Email subject
message string '' Email message
signingMode 'default' | 'sequential' | 'parallel' 'sequential' Signing order mode
initialFields ZcSignField[] [] Pre-placed fields

Also supports v-model:documentName, v-model:message, v-model:signingMode, v-model:fields.

ZcSignSend events

Event Payload When
prepared ZcSignPreparedSend PDF + metadata ready (always before/alongside send)
sent ZcSignSendResult | ZcSignPreparedSend After submit resolves, or prepared-only flow
cancel — User cancels
error { code: string; message: string } Prepare / submit failure
update:recipients ZcSignRecipient[] Recipients changed
update:fields ZcSignField[] Fields changed
update:documentName string Name changed
update:message string Message changed
update:signingMode ZcSignSigningMode Mode changed

ZcSignPreparedSend shape

What submit / prepared receive:

interface ZcSignPreparedSend {
  pdf: Blob                 // tokenized PDF (not the original upload alone)
  documentName: string
  subject: string
  message: string
  signingMode: 'default' | 'sequential' | 'parallel'
  recipients: ZcSignRecipient[]
  metadata: ZcSignMetadataItem[]  // per-recipient field layouts for zc-sign
  fields: ZcSignField[]           // editor field list
}

interface ZcSignRecipient {
  id: string
  name: string
  email: string
  signeeType: 'signer' | 'viewer' | 'approver' | 'client'
}

interface ZcSignMetadataItem {
  name: string
  email: string
  signee_type: ZcSignRecipient['signeeType']
  signing_order: number
  field_sizes: Record<'signature' | 'initials' | 'date', { width: number; height: number }>
  field_ids: string[]
  field_layouts: ZcSignFieldLayout[]
  signatory_variable?: '@signature'
  initial_variable?: '@initials'
  date_variable?: '@date'
}

Helper: appendZcSignMetadata(formData, payload.metadata) appends the metadata field your BFF / zc-sign expect.

Host BFF checklist

Use this on the server (Retail, etc.):

  1. Auth the logged-in user before accepting the upload
  2. Accept PDF (payload.pdf) + metadata JSON (+ name / subject / message / mode)
  3. Store the PDF (your storage / bucket) if required by your app
  4. Call zc-sign:
POST {ZC_SIGN_API_URL}/api/integration/send-document
ZC-SIGN-PUB-KEY: {ZC_SIGN_PUBLIC_KEY}
ZC-SIGN-SECRET-KEY: {ZC_SIGN_SECRET_KEY}
Content-Type: multipart/form-data
  1. Persist returned session uuid / signing links in your DB
  2. Return { sessionUuid } (or your shape) to the SDK submit promise
  3. Handle webhooks from zc-sign when signing completes
Do Don't
Keep keys in server env / secrets manager Put keys in the Vue app or this SDK
Send FormData from browser → your BFF only Call zc-sign directly from the browser with the secret
Validate recipients + PDF size / type on BFF Trust client-only checks

Exports

Export Role
ZcSignSend Full send shell (recipients + field placement)
ZcSignEditor Field editor surface alone
useZcSignSend / useZcSignEditor Composables for custom UIs
createRecipient Build a default recipient row
prepareZcSignPdf Bake field tokens into the PDF
buildZcSignMetadata / appendZcSignMetadata Build / attach integration metadata
configurePdfJsWorker Optional PDF.js worker override
resolveZcSignThemeStyle / ZcSignTheme Optional host brand colors for Send / Editor

Styles: @zanecoder/zc-sign-editor/style.css

Theme (optional)

Pass any valid CSS colors (including host tokens like hsl(var(--company-primary))):

<ZcSignSend
  :recipients="recipients"
  :theme="{
    primary: 'hsl(var(--company-primary))',
    primaryHover: 'hsl(var(--company-secondary))',
    background: 'hsl(var(--company-background))',
    border: 'hsl(var(--company-border-soft) / 0.35)',
    contrast: 'hsl(var(--company-primary-contrast))',
  }"
  :submit="submitPrepared"
/>

Keys: primary, primaryHover, accent, background, border, contrast.
If theme is omitted (or a key is blank), the built-in zc-sign palette is used (ZC_SIGN_DEFAULT_THEME).
ZcSignSend forwards theme into the nested ZcSignEditor (empty state + document preview chrome).

FAQ

Question Answer
Does create-session go through zc-sign? Yes — via your host BFF
Does the SDK need integration keys? No — only your server does
Keys in the browser? Never
Iframe? No — native Vue components
Where do signers sign? zc-sign FE, not inside this package
Can I use helpers without the UI? Yes — prepareZcSignPdf, metadata utils, composables
PDF preview “Cannot read from private field”? Fixed in 0.1.4+ — single host pdfjs-dist + non-reactive PDF.js handles; upgrade the package
Worker “Failed to fetch … jsdelivr …”? Use a same-origin worker (?url or /pdfjs/pdf.worker.min.mjs); fixed default in 0.1.5+
PDF preview looks blurry on Retina? Preview paints at capped devicePixelRatio; field coords stay CSS pixels — rebuild/upgrade after HiDPI canvas fix
Tab hangs / “Aw, Snap!” when dragging Signature/Date fields? Fixed in 0.1.7+ — field (and recipient) prop sync used to infinite-loop Vue updates; upgrade and pin ^0.1.7
Can’t change which signer owns a placed field? Fixed in 0.1.8+ — click the field, then use Selected field assignee in the sidebar
Signer 1 can place/move Signer 2’s fields? Fixed in 0.1.9+ — use Assign new fields to; other signers’ fields are locked (click to reassign only)

PDF.js worker

Under Nuxt, prefer a same-origin Nitro/static worker URL via configurePdfJsWorker('/api/…/pdf-worker'). Vite ?worker is often broken by dep optimization (missing default export); CDN and workerSrc pointing at node_modules / @fs often fail too.

Retail: app/utils/signing/setupZcSignPdfJsWorker.ts (called from CreateSigningSessionPanel).

import * as pdfjsLib from 'pdfjs-dist'
import PdfWorker from 'pdfjs-dist/build/pdf.worker.min.mjs?worker'
import { configurePdfJsWorker } from '@zanecoder/zc-sign-editor'

pdfjsLib.GlobalWorkerOptions.workerPort = new PdfWorker()
configurePdfJsWorker()

Call this on the client before mounting ZcSignSend.

Links

npm https://www.npmjs.com/package/@zanecoder/zc-sign-editor
GitHub https://github.com/zaneCoder/zc-sign-fe/tree/developv3/packages/zc-sign-editor
How it works (detail) docs/how-it-works.md
SDK overview docs/zc-sign-send-sdk.md
Publish / versioning docs/publish.md

License

UNLICENSED — internal / proprietary use under Zanecoder.

Related Packages

vue-pdf-embed

PDF embed component for Vue

5,620,218 1,044
@tato30/vue-pdf

PDF component for Vue 3

2,130,711 692
vue-pdf

vue.js pdf viewer

864,848 2,295
pdfobject-vue

Official PDFObject component for Vue 3

199,735
@teckel/vue-pdf

vue.js pdf viewer

163,440 2

Version History

Version Released License
0.1.11 Proprietary
0.1.10 Proprietary
0.1.9 Proprietary
0.1.8 Proprietary
0.1.7 Proprietary