@npoci/pdfform
Version:
Modern PDF form renderer with HTML overlay fields - view, fill, and map PDF forms in the browser
51 lines (50 loc) • 41.2 kB
JavaScript
(function(d,u){typeof exports=="object"&&typeof module<"u"?u(exports,require("pdfjs-dist"),require("pdf-lib")):typeof define=="function"&&define.amd?define(["exports","pdfjs-dist","pdf-lib"],u):(d=typeof globalThis<"u"?globalThis:d||self,u(d.PDFForm={},d.pdfjsLib,d.PDFLib))})(this,function(d,u,v){"use strict";function E(l){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(l){for(const t in l)if(t!=="default"){const i=Object.getOwnPropertyDescriptor(l,t);Object.defineProperty(e,t,i.get?i:{enumerable:!0,get:()=>l[t]})}}return e.default=l,Object.freeze(e)}const h=E(u);class g{constructor(){this.events=new Map}on(e,t){return this.events.has(e)||this.events.set(e,[]),this.events.get(e).push(t),this}off(e,t){const i=this.events.get(e);if(i){const s=i.indexOf(t);s!==-1&&i.splice(s,1)}return this}emit(e,...t){const i=this.events.get(e);i&&i.forEach(s=>{try{s(...t)}catch(r){console.error(`Error in event listener for "${e}":`,r)}})}once(e,t){const i=(...s)=>{this.off(e,i),t(...s)};return this.on(e,i)}removeAllListeners(e){return e?this.events.delete(e):this.events.clear(),this}listenerCount(e){const t=this.events.get(e);return t?t.length:0}}class F{constructor(){this.parsers=[],this.unparsedFields=[]}static getInstance(){return this.instance||(this.instance=new F),this.instance}registerParser(e,t="first"){return t==="first"?this.parsers.unshift(e):this.parsers.length>0?this.parsers.splice(-1,0,e):this.parsers.push(e),this}parseField(e){for(const i of this.parsers)try{const s=i.parse(e);if(s)return console.log(`Field "${s.key}" parsed by ${i.constructor.name}`),s}catch(s){console.warn(`Parser ${i.constructor.name} threw error:`,s)}const t={key:e.getName(),type:"unknown",originalType:e.constructor.name,position:this.getBasicPosition(e),rawData:{constructorName:e.constructor.name,methods:this.getAvailableMethods(e),flags:this.getFieldFlags(e)},reason:"No parser could identify this field type"};return this.unparsedFields.push(t),console.warn(`Field "${t.key}" could not be parsed. Type: ${t.originalType}`),t}getUnparsedFields(){return[...this.unparsedFields]}clearUnparsedFields(){this.unparsedFields=[]}getBasicPosition(e){try{const t=e.acroField.getWidgets();if(t&&t.length>0){const i=t[0].getRectangle();return{x:i.x,y:i.y,width:i.width,height:i.height,page:1}}}catch{console.warn("Could not extract position for unparsed field")}return{x:0,y:0,width:0,height:0,page:1}}getAvailableMethods(e){const t=[];for(const i in e)typeof e[i]=="function"&&t.push(i);return t}getFieldFlags(e){try{return e.acroField.getFlags()||0}catch{return 0}}}class p{getPosition(e){const t=e.acroField.getWidgets();if(!t||t.length===0)return{x:0,y:0,width:0,height:0,page:1};const i=t[0],s=i.getRectangle();let r=1;try{const a=i.P();a&&e.acroField.doc&&(r=e.acroField.doc.getPages().findIndex(c=>c.ref===a)+1)}catch{console.warn("Could not determine page number for field",e.getName())}const n=this.getPageHeight(e,r);return{x:s.x,y:n-(s.y+s.height),width:s.width,height:s.height,page:r}}getPageHeight(e,t){var i;try{const s=(i=e.acroField.doc)==null?void 0:i.getPages();if(s&&s[t-1])return s[t-1].getHeight()}catch{console.warn("Could not get page height")}return 792}getBasicInfo(e){return{key:e.getName(),position:this.getPosition(e),defaultValue:this.extractDefaultValue(e)}}extractDefaultValue(e){try{if(e.getText)return e.getText();if(e.isChecked)return e.isChecked();if(e.getSelected)return e.getSelected();if(e.getValue)return e.getValue()}catch{console.warn("Could not extract default value for field",e.getName())}return null}hasMethod(e,t){return typeof e[t]=="function"}getFieldFlags(e){try{return e.acroField.getFlags()||0}catch{return 0}}}class C extends p{canHandle(e){return e.constructor.name.includes("PDFTextField")||this.hasMethod(e,"setText")||this.hasMethod(e,"getText")}parse(e){if(!this.canHandle(e))return null;const t=this.getFieldFlags(e);return{...this.getBasicInfo(e),type:"text",originalType:e.constructor.name,maxLength:this.getMaxLength(e),multiline:!!(t&4096),password:!!(t&8192),comb:!!(t&16777216),defaultValue:this.getText(e)}}getText(e){try{if(e.getText)return e.getText()||""}catch{}return""}getMaxLength(e){try{if(e.getMaxLength){const t=e.getMaxLength();return t>0?t:void 0}}catch{}}}class R extends p{canHandle(e){if(!e.constructor.name.includes("PDFTextField"))return!1;const t=e.getName().toLowerCase();return t.includes("email")||t.includes("e-mail")||t.includes("mail")||t.includes("correo")}parse(e){return this.canHandle(e)?{...this.getBasicInfo(e),type:"email",detectedType:"email",originalType:e.constructor.name,pattern:"^[^@]+@[^@]+\\.[^@]+$",inputType:"email",defaultValue:this.getText(e)}:null}getText(e){try{if(e.getText)return e.getText()||""}catch{}return""}}class V extends p{canHandle(e){const t=e.getName().toLowerCase(),s=this.getPosition(e).height>60;return e.constructor.name.includes("PDFSignature")||t.includes("signature")||t.includes("sign")||t.includes("firma")||e.constructor.name.includes("PDFTextField")&&s}parse(e){return this.canHandle(e)?{...this.getBasicInfo(e),type:"signature",detectedType:"signature",originalType:e.constructor.name,detectedFrom:this.getDetectionReason(e),requiresDrawing:!0,acceptsUpload:!0}:null}getDetectionReason(e){if(e.constructor.name.includes("PDFSignature"))return"PDFSignature field type";const t=e.getName().toLowerCase();return t.includes("signature")||t.includes("sign")?"Field name contains signature":"Large text field detected as signature"}}class T extends p{canHandle(e){const t=e.constructor.name,i=this.getFieldFlags(e),s=t.includes("PDFButton")||t.includes("PDFCheckBox")||t.includes("Checkbox"),r=!(i&32768);return s&&r||this.hasMethod(e,"check")||this.hasMethod(e,"isChecked")}parse(e){return this.canHandle(e)?{...this.getBasicInfo(e),type:"checkbox",originalType:e.constructor.name,checked:this.isChecked(e),defaultValue:this.isChecked(e)}:null}isChecked(e){var t;try{if(e.isChecked)return e.isChecked();const i=(t=e.acroField)==null?void 0:t.getWidgets();if(i&&i.length>0){const s=i[0].getAppearanceState();return s&&s.toString()!=="/Off"}}catch{console.warn("Could not determine checkbox state")}return!1}}class L extends p{canHandle(e){return e.constructor.name.includes("PDFDropdown")||e.constructor.name.includes("PDFComboBox")||e.constructor.name.includes("PDFChoice")||this.hasMethod(e,"getOptions")||this.hasMethod(e,"select")}parse(e){if(!this.canHandle(e))return null;const t=this.getFieldFlags(e),i=!!(t&131072),s=!!(t&2097152),r=this.extractOptions(e),n=this.getSelectedValue(e),a={...this.getBasicInfo(e),originalType:e.constructor.name,options:r,value:n,defaultValue:n};return i||!s?{...a,type:"dropdown",multiSelect:!1,value:Array.isArray(n)?n[0]:n}:{...a,type:"listbox",multiSelect:s}}extractOptions(e){var i,s;const t=[];try{if(e.getOptions)return e.getOptions().map(a=>({value:a,display:a}));const r=(s=(i=e.acroField)==null?void 0:i.dict)==null?void 0:s.get("Opt");if(r){const n=r.asArray();n&&n.forEach(a=>{if(typeof a=="string")t.push({value:a,display:a});else if(a.asArray){const o=a.asArray();o&&o.length>=2&&t.push({value:o[0].toString(),display:o[1].toString()})}})}}catch{console.warn("Could not extract options for dropdown",e.getName())}return t}getSelectedValue(e){try{if(e.getSelected){const t=e.getSelected();return Array.isArray(t)?t.length>0?t:void 0:t||void 0}}catch{console.warn("Could not get selected value")}}}class B extends p{canHandle(e){const t=e.constructor.name,s=!!(this.getFieldFlags(e)&32768);return t.includes("PDFRadioGroup")||t.includes("PDFRadio")||s||this.hasMethod(e,"getOptions")}parse(e){return this.canHandle(e)?{...this.getBasicInfo(e),type:"radio",originalType:e.constructor.name,options:this.extractOptions(e),value:this.getSelectedValue(e),defaultValue:this.getSelectedValue(e)}:null}extractOptions(e){var i;const t=[];try{if(e.getOptions)return e.getOptions().map(n=>({value:n,display:n}));const s=(i=e.acroField)==null?void 0:i.getWidgets();if(s){const r=new Set;s.forEach(n=>{try{const a=n.getAppearanceStates();a&&a.forEach(o=>{o!=="Off"&&r.add(o)})}catch{}}),r.forEach(n=>{t.push({value:n,display:n})})}}catch{console.warn("Could not extract radio options",e.getName())}return t}getSelectedValue(e){var t;try{if(e.getSelected)return e.getSelected()||void 0;const i=(t=e.acroField)==null?void 0:t.getWidgets();if(i)for(const s of i){const r=s.getAppearanceState();if(r&&r.toString()!=="/Off")return r.toString().replace("/","")}}catch{console.warn("Could not get selected radio value")}}}class P{constructor(){this.fieldDefinitions=new Map,this.parserChain=F.getInstance(),this.initializeParsers()}initializeParsers(){this.parserChain.registerParser(new V,"first").registerParser(new R,"first").registerParser(new T).registerParser(new B).registerParser(new L).registerParser(new C)}setFieldDefinitions(e){this.fieldDefinitions.clear(),e.forEach(t=>{this.fieldDefinitions.set(t.key,t)})}async discoverFields(e){this.parserChain.clearUnparsedFields();try{const t=await v.PDFDocument.load(e),s=t.getForm().getFields();s.forEach(n=>{n.acroField&&(n.acroField.doc=t)});const r=[];for(const n of s){const a=this.parserChain.parseField(n),o=this.fieldDefinitions.get(a.key),c={...a,definition:o};o&&o.pattern&&a.type==="text"&&o.pattern.includes("@")&&(c.detectedType="email"),r.push(c)}return{fields:r,unparsedFields:this.parserChain.getUnparsedFields()}}catch(t){throw console.error("Error discovering fields:",t),new Error(`Failed to discover fields: ${t}`)}}getFieldMappings(e){const t={};return e.forEach(i=>{var r;const s=((r=i.definition)==null?void 0:r.name)||i.key;t[s]={originalKey:i.key,type:i.detectedType||i.type,value:i.defaultValue}}),t}}const k={highlightColor:"#ffffcc",highlightColorFocus:"#ffffaa"};class f{constructor(e){this.config=e||k}getState(e,t){var r,n,a,o;const i=this.getValue(t),s=this.validateValue(e,i);return{key:e.key,name:(r=e.definition)==null?void 0:r.name,value:i,type:e.type,detectedType:e.detectedType,valid:s.valid,error:s.error,required:(n=e.definition)==null?void 0:n.required,metadata:{title:(a=e.definition)==null?void 0:a.title,placeholder:(o=e.definition)==null?void 0:o.placeholder}}}validateValue(e,t){if(!e.definition)return{valid:!0};if(e.definition.pattern&&typeof t=="string"&&t)try{if(!new RegExp(e.definition.pattern).test(t))return{valid:!1,error:e.definition.errorMessage||"Invalid format"}}catch{console.error("Invalid regex pattern:",e.definition.pattern)}if(e.definition.validator){const i=e.definition.validator(t);if(i)return{valid:!1,error:i}}return{valid:!0}}createBaseElement(e,t){const i=document.createElement(e);return i.style.width="100%",i.style.height="100%",i.style.border="none",i.style.padding="0",i.style.margin="0",i.style.outline="none",i.style.fontFamily="Arial, sans-serif",i.style.background=this.config.highlightColor,t.definition&&(t.definition.placeholder&&"placeholder"in i&&(i.placeholder=t.definition.placeholder),t.definition.required&&(i.style.borderLeft="3px solid #ff9800"),t.definition.title&&(i.title=t.definition.title)),i}applyValidation(e,t,i){t.definition&&e.addEventListener("input",s=>{const n=s.target.value;let a=!0,o="";if(t.definition.pattern&&(new RegExp(t.definition.pattern).test(n)||(a=!1,o=t.definition.errorMessage||"Invalid format")),t.definition.validator){const c=t.definition.validator(n);c&&(a=!1,o=c)}!a&&n?(e.style.borderColor="red",e.style.borderWidth="2px",e.style.borderStyle="solid",e.title=o):(e.style.borderColor="",e.style.borderWidth="",e.style.borderStyle="",e.title=t.definition.title||""),i(n)})}}class O extends f{validateValue(e,t){var s;const i=super.validateValue(e,t);return i.valid?(s=e.definition)!=null&&s.required&&(!t||typeof t=="string"&&!t.trim())?{valid:!1,error:"This field is required"}:{valid:!0}:i}createField(e,t,i){const s=this.createBaseElement("input",e);if(s.type="text",s.style.fontSize=t.fontSize+"px",s.style.lineHeight="1",s.style.verticalAlign="top",e.defaultValue&&(s.value=e.defaultValue),e.multiline){const r=this.createBaseElement("textarea",e);return r.style.fontSize=t.fontSize+"px",r.style.resize="none",r.style.lineHeight="1.2",e.defaultValue&&(r.value=e.defaultValue),r.addEventListener("input",()=>i(r.value)),this.applyValidation(r,e,i),r.addEventListener("focus",()=>{r.style.background=this.config.highlightColorFocus}),r.addEventListener("blur",()=>{r.style.background=this.config.highlightColor}),r}return e.password&&(s.type="password"),e.maxLength&&(s.maxLength=e.maxLength),(e.detectedType==="email"||e.type==="email")&&(s.type="email"),s.addEventListener("input",()=>i(s.value)),this.applyValidation(s,e,i),s.addEventListener("focus",()=>{s.style.background=this.config.highlightColorFocus}),s.addEventListener("blur",()=>{s.style.background=this.config.highlightColor}),s}getValue(e){return e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement?e.value:""}setValue(e,t){(e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement)&&(e.value=String(t||""))}}class W extends f{createField(e,t,i){var r;const s=document.createElement("input");return s.type="checkbox",s.style.width="100%",s.style.height="100%",s.style.cursor="pointer",s.style.margin="0",s.style.padding="0",s.style.accentColor=this.config.highlightColor,s.style.outline=`3px solid ${this.config.highlightColor}`,s.style.outlineOffset="-3px",s.style.verticalAlign="top",(e.defaultValue===!0||e.checked)&&(s.checked=!0),s.addEventListener("change",()=>{i(s.checked)}),(r=e.definition)!=null&&r.title&&(s.title=e.definition.title),s}getValue(e){return e instanceof HTMLInputElement?e.checked:!1}setValue(e,t){e instanceof HTMLInputElement&&(e.checked=!!t)}}class A extends f{createField(e,t,i){var n;const s=this.createBaseElement("select",e);if(s.style.fontSize=t.fontSize+"px",s.style.lineHeight="1",s.style.verticalAlign="top",s.style.cursor="pointer",!((n=e.definition)!=null&&n.required)){const a=document.createElement("option");a.value="",a.textContent="-- Select --",s.appendChild(a)}return(e.options||[]).forEach(a=>{const o=document.createElement("option");o.value=a.value,o.textContent=a.display,s.appendChild(o)}),e.defaultValue&&(s.value=e.defaultValue),e.multiSelect&&(s.multiple=!0,s.style.height="100%"),s.addEventListener("change",()=>{if(s.multiple){const a=Array.from(s.selectedOptions).map(o=>o.value);i(a)}else i(s.value)}),s.addEventListener("focus",()=>{s.style.background=this.config.highlightColorFocus}),s.addEventListener("blur",()=>{s.style.background=this.config.highlightColor}),s}getValue(e){return e instanceof HTMLSelectElement?e.multiple?Array.from(e.selectedOptions).map(t=>t.value):e.value:""}setValue(e,t){e instanceof HTMLSelectElement&&(e.multiple&&Array.isArray(t)?(Array.from(e.options).forEach(i=>i.selected=!1),t.forEach(i=>{const s=e.querySelector(`option[value="${i}"]`);s&&(s.selected=!0)})):e.value=String(t||""))}}class $ extends f{constructor(){super(...arguments),this.inputs=[]}createField(e,t,i){const s=document.createElement("div");s.style.display="flex",s.style.width="100%",s.style.height="100%",s.style.gap="2px";const r=e.maxLength||9,n=(t.width-(r-1)*2)/r;for(let a=0;a<r;a++){const o=document.createElement("input");o.type="text",o.maxLength=1,o.style.width=n+"px",o.style.height="100%",o.style.textAlign="center",o.style.border="none",o.style.background=this.config.highlightColor,o.style.fontSize=t.fontSize+"px",o.style.fontFamily="monospace",o.style.padding="0",o.style.margin="0",o.style.outline="none",o.style.boxSizing="border-box",o.addEventListener("input",c=>{c.target.value.length===1&&a<r-1&&this.inputs[a+1].focus(),this.updateValue(i)}),o.addEventListener("keydown",c=>{c.key==="Backspace"&&!o.value&&a>0&&(c.preventDefault(),this.inputs[a-1].focus(),this.inputs[a-1].value="",this.updateValue(i))}),o.addEventListener("paste",c=>{var M;c.preventDefault();const b=(((M=c.clipboardData)==null?void 0:M.getData("text"))||"").replace(/[^a-zA-Z0-9]/g,"").split("");b.forEach((D,y)=>{a+y<this.inputs.length&&(this.inputs[a+y].value=D)});const S=this.inputs.findIndex((D,y)=>y>=a&&!D.value);S!==-1?this.inputs[S].focus():this.inputs[Math.min(a+b.length,this.inputs.length-1)].focus(),this.updateValue(i)}),o.addEventListener("focus",()=>{o.style.background="rgba(255, 255, 0, 0.5)"}),o.addEventListener("blur",()=>{o.style.background=this.config.highlightColor}),this.inputs.push(o),s.appendChild(o)}return e.defaultValue&&String(e.defaultValue).split("").forEach((o,c)=>{c<this.inputs.length&&(this.inputs[c].value=o)}),s}updateValue(e){const t=this.inputs.map(i=>i.value).join("");e(t)}getValue(e){return this.inputs.map(t=>t.value).join("")}setValue(e,t){const i=String(t||"").split("");this.inputs.forEach((s,r)=>{s.value=i[r]||""})}}class q{constructor(e){this.globalRenderers=new Map,this.fieldOverrides=new Map,this.config={...k,...e},this.registerDefaults()}registerDefaults(){const e=new O(this.config),t=new W(this.config),i=new A(this.config);this.globalRenderers.set("text",e),this.globalRenderers.set("email",e),this.globalRenderers.set("password",e),this.globalRenderers.set("textarea",e),this.globalRenderers.set("signature",e),this.globalRenderers.set("checkbox",t),this.globalRenderers.set("radio",i),this.globalRenderers.set("dropdown",i),this.globalRenderers.set("listbox",i)}registerGlobalRenderer(e,t){this.globalRenderers.set(e,t)}registerFieldOverride(e,t){this.fieldOverrides.set(e,t)}getRenderer(e){return this.fieldOverrides.has(e.key)?this.fieldOverrides.get(e.key):e.type==="text"&&e.comb?new $(this.config):e.detectedType&&this.globalRenderers.has(e.detectedType)?this.globalRenderers.get(e.detectedType):this.globalRenderers.has(e.type)?this.globalRenderers.get(e.type):(console.warn(`No renderer found for field "${e.key}" of type "${e.type}", using text renderer`),this.globalRenderers.get("text"))}}class H extends g{constructor(){super(...arguments),this.fieldValues=new Map,this.fieldMappings=new Map,this.fields=[]}setFields(e){this.fields=e,this.fieldMappings.clear(),e.forEach(t=>{var s;const i=((s=t.definition)==null?void 0:s.name)||t.key;this.fieldMappings.set(i,t.key),t.defaultValue!==void 0&&t.defaultValue!==null&&this.fieldValues.set(t.key,t.defaultValue)})}setValue(e,t,i=!0){const s=this.fieldValues.get(e);this.fieldValues.set(e,t);const r=this.fields.find(c=>c.key===e);if(!r){console.warn(`Field not found: ${e}`);return}if(!i)return;const n={...r,value:t},a=this.validateField(r,t),o={field:n,validationState:a,oldValue:s,newValue:t,timestamp:Date.now()};this.emit("fieldChange",o)}getValue(e){return this.fieldValues.get(e)}getValues(){const e={};for(const[t,i]of this.fieldMappings.entries()){const s=this.fieldValues.get(i);s!==void 0&&(e[t]=s)}return e}getRawValues(){const e={};return this.fieldValues.forEach((t,i)=>{e[i]=t}),e}setValues(e){Object.entries(e).forEach(([t,i])=>{if(this.fieldMappings.has(t)){const s=this.fieldMappings.get(t);this.setValue(s,i,!1)}else this.setValue(t,i,!1)})}reset(){this.fields.forEach(e=>{e.defaultValue!==void 0&&e.defaultValue!==null?this.setValue(e.key,e.defaultValue,!1):this.setValue(e.key,null,!1)})}getFieldByKey(e){return this.fields.find(t=>t.key===e)}getFieldByName(e){const t=this.fieldMappings.get(e);if(t)return this.getFieldByKey(t)}getFields(){return this.fields}validateField(e,t){if(!e.definition)return{valid:!0};if(e.definition.pattern&&typeof t=="string")try{if(!new RegExp(e.definition.pattern).test(t))return{valid:!1,error:e.definition.errorMessage||"Invalid format"}}catch{console.error("Invalid regex pattern:",e.definition.pattern)}if(e.definition.validator){const i=e.definition.validator(t);if(i)return{valid:!1,error:i}}return e.definition.required&&e.type==="text"&&(!t||typeof t=="string"&&!t.trim())?{valid:!1,error:"This field is required"}:{valid:!0}}}function w(l,e){const t=document.createElement(l);return e&&Object.entries(e).forEach(([i,s])=>{i==="style"&&typeof s=="object"?x(t,s):i==="className"?t.className=s:i==="textContent"?t.textContent=s:i.startsWith("on")||t.setAttribute(i,s)}),t}function x(l,e){Object.entries(e).forEach(([t,i])=>{i!==void 0&&(l.style[t]=i)})}function I(l){const e=Math.floor(l*.6);return Math.min(Math.max(e,8),16)}class Z{constructor(e,t){this.registry=e,this.stateManager=t,this.container=null,this.scale=1,this.currentPage=1,this.fieldElements=new Map}setContainer(e){this.container=e}setScale(e){this.scale=e}setCurrentPage(e){this.currentPage=e,this.renderFields()}renderFields(){if(!this.container)return;this.fieldElements.forEach(i=>i.remove()),this.fieldElements.clear(),this.stateManager.getFields().filter(i=>i.position.page===this.currentPage).forEach(i=>{const s=this.createFieldElement(i);s&&this.container&&(this.container.appendChild(s),this.fieldElements.set(i.key,s))})}createFieldElement(e){if(!e.position)return null;const t=w("div",{className:"pdf-form-field",style:{position:"absolute",left:`${e.position.x*this.scale}px`,top:`${e.position.y*this.scale}px`,width:`${e.position.width*this.scale}px`,height:`${e.position.height*this.scale}px`,zIndex:"10"}}),i=this.registry.getRenderer(e),s={width:e.position.width*this.scale,height:e.position.height*this.scale,fontSize:I(e.position.height*this.scale)},r=i.createField(e,s,a=>this.stateManager.setValue(e.key,a)),n=this.stateManager.getValue(e.key);return n!=null&&i.setValue(r,n),t.appendChild(r),t}updateFieldValues(){this.fieldElements.forEach((e,t)=>{const i=this.stateManager.getFieldByKey(t);if(!i)return;const s=e.firstElementChild;if(!s)return;const r=this.registry.getRenderer(i),n=this.stateManager.getValue(t);n!=null&&r.setValue(s,n)})}destroy(){this.fieldElements.forEach(e=>e.remove()),this.fieldElements.clear()}}class N extends g{constructor(e){var t;super(),this.options=e,this.pdfDoc=null,this.pdfArrayBuffer=null,this.currentPage=1,this.totalPages=0,this.scale=1,this.renderTask=null,this.pageWrapper=null,this.canvas=null,this.fields=[],this.unparsedFields=[],this.pdfPageWidth=0,this.pdfPageHeight=0,e.workerSrc&&!((t=h.GlobalWorkerOptions)!=null&&t.workerSrc)&&(h.GlobalWorkerOptions.workerSrc=e.workerSrc),this.container=e.container,this.pdfUrl=e.pdfUrl,this.scale=e.scale||1,this.currentPage=e.page||1,this.discoveryService=new P,this.rendererRegistry=new q({highlightColor:e.highlightColor,highlightColorFocus:e.highlightColorFocus}),this.stateManager=new H,this.overlayRenderer=new Z(this.rendererRegistry,this.stateManager),e.fieldDefinitions&&this.discoveryService.setFieldDefinitions(e.fieldDefinitions),e.fieldRenderers&&Object.entries(e.fieldRenderers).forEach(([i,s])=>{this.rendererRegistry.registerGlobalRenderer(i,s)}),e.fieldOverrides&&Object.entries(e.fieldOverrides).forEach(([i,s])=>{this.rendererRegistry.registerFieldOverride(i,s)}),this.stateManager.on("fieldChange",i=>{this.emit("fieldChange",i.field,i.validationState)})}async render(){try{x(this.container,{position:"relative",width:"100%",display:"flex",justifyContent:"center"}),await this.loadPDF()}catch(e){this.handleError(e)}}async loadPDF(){try{const e=await fetch(this.pdfUrl);this.pdfArrayBuffer=await e.arrayBuffer(),this.options.preprocessor&&(this.pdfArrayBuffer=await this.options.preprocessor(this.pdfArrayBuffer));const{fields:t,unparsedFields:i}=await this.discoveryService.discoverFields(this.pdfArrayBuffer);this.fields=t,this.unparsedFields=i,this.stateManager.setFields(t),this.emit("fieldsDiscovered",t),this.options.onFieldsDiscovered&&this.options.onFieldsDiscovered(t,i);const s=h.getDocument(this.pdfArrayBuffer.slice(0));this.pdfDoc=await s.promise,this.totalPages=this.pdfDoc.numPages,this.emit("ready",t),this.emit("pageCountChange",this.totalPages);const n=(await this.pdfDoc.getPage(1)).getViewport({scale:1});this.pdfPageWidth=n.width,this.pdfPageHeight=n.height,await this.renderPage(this.currentPage)}catch(e){throw new Error(`Failed to load PDF: ${e}`)}}calculateScale(){const e=this.container.clientWidth,t=Math.min(e,900);this.scale=Math.min(t/this.pdfPageWidth,1.5)}cancelRender(){this.renderTask&&(this.renderTask.cancel(),this.renderTask=null)}async renderPage(e){if(!this.pdfDoc)return;this.cancelRender();const t=await this.pdfDoc.getPage(e);this.calculateScale();const i=t.getViewport({scale:this.scale});this.pageWrapper||(this.pageWrapper=w("div",{style:{position:"relative",background:"white",boxShadow:"0 2px 8px rgba(0, 0, 0, 0.1)",margin:"0 auto"}}),this.container.appendChild(this.pageWrapper)),x(this.pageWrapper,{width:`${i.width}px`,height:`${i.height}px`}),this.canvas||(this.canvas=w("canvas",{style:{display:"block"}}),this.pageWrapper.appendChild(this.canvas));const s=this.canvas.getContext("2d"),r=window.devicePixelRatio||1;this.canvas.width=Math.floor(i.width*r),this.canvas.height=Math.floor(i.height*r),this.canvas.style.width=`${Math.floor(i.width)}px`,this.canvas.style.height=`${Math.floor(i.height)}px`;const a={canvasContext:s,viewport:i,transform:r!==1?[r,0,0,r,0,0]:void 0,intent:"display"};this.renderTask=t.render(a);try{await this.renderTask.promise,this.overlayRenderer.setContainer(this.pageWrapper),this.overlayRenderer.setScale(this.scale),this.overlayRenderer.setCurrentPage(e),this.overlayRenderer.renderFields(),this.emit("pageChange",e)}catch{}}handleError(e){console.error("PDFFormRenderer Error:",e),this.emit("error",e)}setPage(e){e<1||e>this.totalPages||(this.currentPage=e,this.renderPage(e))}getCurrentPage(){return this.currentPage}getTotalPages(){return this.totalPages}getFieldValues(){return this.stateManager.getValues()}getRawFieldValues(){return this.stateManager.getRawValues()}setFieldValues(e){this.stateManager.setValues(e),this.overlayRenderer.updateFieldValues()}getUnparsedFields(){return[...this.unparsedFields]}getFieldStates(){const e={};return this.fields.forEach(t=>{var n;const i=this.stateManager.getValue(t.key),s=this.stateManager.validateField(t,i),r=((n=t.definition)==null?void 0:n.name)||t.key;e[r]=s}),e}destroy(){this.cancelRender(),this.overlayRenderer.destroy(),this.stateManager.removeAllListeners(),this.removeAllListeners(),this.pdfDoc&&(this.pdfDoc.destroy(),this.pdfDoc=null),this.container.innerHTML=""}}class U{async fillFromArrayBuffer(e,t){const i=await v.PDFDocument.load(e);return this.fillDocument(i,t)}async fillFromBytes(e,t){const i=await v.PDFDocument.load(e);return this.fillDocument(i,t)}async fillFromUrl(e,t){const s=await(await fetch(e)).arrayBuffer();return this.fillFromArrayBuffer(s,t)}async fillDocument(e,t){const i=e.getForm();return Object.entries(t).forEach(([s,r])=>{try{const n=i.getField(s);if(n.constructor.name.includes("PDFTextField"))n.setText(String(r||""));else if(n.constructor.name.includes("PDFCheckBox")){const a=n;r?a.check():a.uncheck()}else n.constructor.name.includes("PDFRadioGroup")?r&&n.select(r):n.constructor.name.includes("PDFDropdown")&&r&&n.select(r)}catch(n){console.error(`Error setting field ${s}:`,n)}}),e.save()}}class j extends g{constructor(e,t){super(),this.clickZones=new Map,this.container=e,this.mappingStateManager=t}renderZones(e,t,i){this.clearZones(),e.filter(r=>r.position.page===t).forEach(r=>{const n=this.createClickZone(r,i);n&&(this.container.appendChild(n),this.clickZones.set(r.key,n))})}createClickZone(e,t){const i=document.createElement("div");i.className="pdfform-field-zone";const s=this.mappingStateManager.getFieldDefinition(e.key),r=s!==void 0;if(i.classList.add(r?"mapped":"unmapped"),i.style.position="absolute",i.style.left=`${e.position.x*t}px`,i.style.top=`${e.position.y*t}px`,i.style.width=`${e.position.width*t}px`,i.style.height=`${e.position.height*t}px`,i.style.zIndex="100",i.title=r?`${s.name} (${e.key})`:`Unmapped: ${e.key}`,r&&s.name){const n=document.createElement("span");n.className="pdfform-field-label",n.textContent=s.name,i.appendChild(n)}return i.addEventListener("click",n=>{n.stopPropagation(),this.emit("fieldClicked",e)}),i}updateFieldStates(){this.clickZones.forEach((e,t)=>{const i=this.mappingStateManager.getFieldDefinition(t),s=i!==void 0;e.classList.remove("mapped","unmapped"),e.classList.add(s?"mapped":"unmapped"),e.title=s?`${i.name} (${t})`:`Unmapped: ${t}`;const r=e.querySelector(".pdfform-field-label");if(r&&r.remove(),s&&i.name){const n=document.createElement("span");n.className="pdfform-field-label",n.textContent=i.name,e.appendChild(n)}})}clearZones(){this.clickZones.forEach(e=>e.remove()),this.clickZones.clear()}destroy(){this.clearZones()}}class z extends g{constructor(){super(...arguments),this.fieldDefinitions=new Map,this.fields=[]}setFields(e){this.fields=e,this.emitStats()}setFieldDefinition(e,t){for(const[i,s]of this.fieldDefinitions.entries())if(i!==e&&s.name===t.name)throw new Error(`Field name "${t.name}" is already used by another field`);this.fieldDefinitions.set(e,t),this.emitStats(e,t)}getFieldDefinition(e){return this.fieldDefinitions.get(e)}removeFieldDefinition(e){this.fieldDefinitions.delete(e),this.emitStats(e)}getAllDefinitions(){return Array.from(this.fieldDefinitions.values())}getMappingStats(){return{total:this.fields.length,mapped:this.fieldDefinitions.size}}clearMappings(){this.fieldDefinitions.clear(),this.emitStats()}importDefinitions(e){const t=new Set;e.forEach(i=>{if(i.name){if(t.has(i.name))throw new Error(`Duplicate field name "${i.name}" in imported definitions`);t.add(i.name)}}),this.fieldDefinitions.clear(),e.forEach(i=>{i.key&&i.name&&this.fieldDefinitions.set(i.key,i)}),this.emitStats()}emitStats(e,t){const i={total:this.fields.length,mapped:this.fieldDefinitions.size,fieldKey:e,definition:t};this.emit("mappingChanged",i)}}class G{constructor(){this.modal=null,this.form=null,this.currentField=null,this.onSave=null,this.onRemove=null,this.createModal()}createModal(){this.modal=document.createElement("div"),this.modal.className="pdfform-modal",this.modal.innerHTML=`
<div class="pdfform-modal-content">
<div class="pdfform-modal-header">
<h2>Define Field Properties</h2>
<button type="button" class="pdfform-modal-close">×</button>
</div>
<form class="pdfform-modal-form">
<div class="pdfform-form-group">
<label>PDF Field Key:</label>
<input type="text" name="key" readonly class="pdfform-input-readonly">
</div>
<div class="pdfform-form-group">
<label>Property Name <span class="pdfform-required">*</span>:</label>
<input type="text" name="name" required placeholder="e.g., email, firstName" class="pdfform-input">
<small>Required - this is the key used in form data (e.g., formData.email)</small>
<div class="pdfform-error" data-field="name"></div>
</div>
<div class="pdfform-form-group">
<label>Display Label:</label>
<input type="text" name="title" placeholder="e.g., Email Address, First Name" class="pdfform-input">
<small>User-friendly label shown in tooltips</small>
</div>
<div class="pdfform-form-group">
<label>Placeholder:</label>
<input type="text" name="placeholder" placeholder="e.g., Enter your email" class="pdfform-input">
</div>
<div class="pdfform-form-group">
<label class="pdfform-checkbox-label">
<input type="checkbox" name="required">
Required Field
</label>
</div>
<div class="pdfform-form-group">
<label>Validation Pattern (regex):</label>
<input type="text" name="pattern" placeholder="e.g., ^[^@]+@[^@]+\\.[^@]+$" class="pdfform-input">
</div>
<div class="pdfform-form-group">
<label>Error Message:</label>
<input type="text" name="errorMessage" placeholder="e.g., Please enter a valid email" class="pdfform-input">
</div>
<div class="pdfform-form-actions">
<button type="button" class="pdfform-btn pdfform-btn-danger pdfform-remove-btn" style="display: none;">
Remove Mapping
</button>
<button type="button" class="pdfform-btn pdfform-cancel-btn">Cancel</button>
<button type="submit" class="pdfform-btn pdfform-btn-primary">Save Field Definition</button>
</div>
</form>
</div>
`,document.body.appendChild(this.modal),this.form=this.modal.querySelector(".pdfform-modal-form"),this.setupEventListeners()}setupEventListeners(){this.modal.querySelector(".pdfform-modal-close").addEventListener("click",()=>this.hide()),this.modal.querySelector(".pdfform-cancel-btn").addEventListener("click",()=>this.hide()),this.modal.querySelector(".pdfform-remove-btn").addEventListener("click",()=>{this.currentField&&this.onRemove&&(this.onRemove(this.currentField),this.hide())}),this.form.addEventListener("submit",r=>{r.preventDefault(),this.handleSubmit()}),this.modal.addEventListener("click",r=>{r.target===this.modal&&this.hide()});const s=this.form.querySelector('input[name="name"]');s.addEventListener("input",()=>this.validateName(s.value))}validateName(e){const t=this.form.querySelector('[data-field="name"]');return e.trim()?(t.style.display="none",!0):(t.textContent="Name is required",t.style.display="block",!1)}handleSubmit(){var i,s,r,n;const e=new FormData(this.form),t=e.get("name");if(this.validateName(t)&&this.currentField&&this.onSave){const a={key:this.currentField.key,name:t.trim(),title:((i=e.get("title"))==null?void 0:i.trim())||t.trim(),placeholder:(s=e.get("placeholder"))==null?void 0:s.trim(),required:e.get("required")==="on",pattern:((r=e.get("pattern"))==null?void 0:r.trim())||void 0,errorMessage:((n=e.get("errorMessage"))==null?void 0:n.trim())||void 0};this.onSave(this.currentField,a),this.hide()}}show(e,t){this.currentField=e,this.form.reset();const i=this.form.querySelector('input[name="key"]');i.value=e.key;const s=this.form.querySelector(".pdfform-remove-btn");if(s.style.display=t?"block":"none",t){const n={name:t.name,title:t.title||"",placeholder:t.placeholder||"",pattern:t.pattern||"",errorMessage:t.errorMessage||""};Object.entries(n).forEach(([o,c])=>{const m=this.form.querySelector(`input[name="${o}"]`);m&&(m.value=c)});const a=this.form.querySelector('input[name="required"]');a.checked=t.required||!1}this.modal.style.display="block",this.form.querySelector('input[name="name"]').focus()}hide(){this.modal.style.display="none",this.currentField=null}onFieldSave(e){this.onSave=e}onFieldRemove(e){this.onRemove=e}destroy(){this.modal&&(this.modal.remove(),this.modal=null,this.form=null)}}class J extends g{constructor(e){var t;super(),this.pdfDoc=null,this.currentPage=1,this.pageWrapper=null,this.canvas=null,this.scale=1,this.fields=[],this.renderTask=null,e.workerSrc&&!((t=h.GlobalWorkerOptions)!=null&&t.workerSrc)&&(h.GlobalWorkerOptions.workerSrc=e.workerSrc),this.container=e.container,this.pdfUrl=e.pdfUrl,this.discoveryService=new P,this.mappingStateManager=new z,this.modalManager=new G,e.fieldDefinitions&&this.mappingStateManager.importDefinitions(e.fieldDefinitions),this.clickZoneRenderer=null,this.setupEventHandlers()}setupEventHandlers(){this.mappingStateManager.on("mappingChanged",e=>{this.clickZoneRenderer&&this.clickZoneRenderer.updateFieldStates(),this.emit("mappingChanged",e)}),this.modalManager.onFieldSave((e,t)=>{this.mappingStateManager.setFieldDefinition(e.key,t)}),this.modalManager.onFieldRemove(e=>{this.mappingStateManager.removeFieldDefinition(e.key)})}async render(){try{this.container.innerHTML="",this.container.style.position="relative";const e=await this.loadPDF(),{fields:t,unparsedFields:i}=await this.discoveryService.discoverFields(e);this.fields=t,this.mappingStateManager.setFields(t),this.pdfDoc=await h.getDocument({data:e}).promise,await this.renderPage(),this.emit("ready",this.fields),this.emit("mappingChanged",this.mappingStateManager.getMappingStats()),i.length>0&&console.warn("Unparsed fields:",i)}catch(e){throw console.error("Failed to render PDF:",e),this.emit("error",e),e}}async loadPDF(){const e=await fetch(this.pdfUrl);if(!e.ok)throw new Error(`Failed to load PDF: ${e.statusText}`);return e.arrayBuffer()}async renderPage(){if(!this.pdfDoc)return;this.renderTask&&(this.renderTask.cancel(),this.renderTask=null);const e=await this.pdfDoc.getPage(this.currentPage),t=e.getViewport({scale:1}),i=this.container.clientWidth-40;this.scale=i/t.width;const s=e.getViewport({scale:this.scale});this.pageWrapper||(this.pageWrapper=document.createElement("div"),this.pageWrapper.style.position="relative",this.pageWrapper.style.background="white",this.pageWrapper.style.boxShadow="0 2px 8px rgba(0, 0, 0, 0.1)",this.pageWrapper.style.margin="0 auto",this.container.appendChild(this.pageWrapper),this.clickZoneRenderer=new j(this.pageWrapper,this.mappingStateManager),this.clickZoneRenderer.on("fieldClicked",a=>{const o=this.mappingStateManager.getFieldDefinition(a.key);this.modalManager.show(a,o)})),this.pageWrapper.style.width=`${s.width}px`,this.pageWrapper.style.height=`${s.height}px`,this.canvas||(this.canvas=document.createElement("canvas"),this.canvas.style.display="block",this.pageWrapper.appendChild(this.canvas)),this.canvas.width=s.width,this.canvas.height=s.height,this.canvas.style.width=`${s.width}px`,this.canvas.style.height=`${s.height}px`;const r=this.canvas.getContext("2d");if(!r)return;const n={canvasContext:r,viewport:s};this.renderTask=e.render(n),await this.renderTask.promise,this.clickZoneRenderer.clearZones(),this.clickZoneRenderer.renderZones(this.fields,this.currentPage,this.scale)}async setPage(e){if(!this.pdfDoc)return;const t=this.pdfDoc.numPages;e<1||e>t||(this.currentPage=e,await this.renderPage())}getPageCount(){var e;return((e=this.pdfDoc)==null?void 0:e.numPages)||0}getCurrentPage(){return this.currentPage}setFieldDefinition(e,t){if(!t.name)throw new Error("Field name is required");const i={key:e,name:t.name,title:t.title,placeholder:t.placeholder,required:t.required,pattern:t.pattern,errorMessage:t.errorMessage};this.mappingStateManager.setFieldDefinition(e,i)}removeFieldDefinition(e){this.mappingStateManager.removeFieldDefinition(e)}getFieldDefinitions(){return this.mappingStateManager.getAllDefinitions()}exportDefinitions(){const e=this.getFieldDefinitions();return JSON.stringify(e,null,2)}importDefinitions(e){this.mappingStateManager.importDefinitions(e),this.clickZoneRenderer.updateFieldStates()}getUnmappedFields(){return this.fields.filter(e=>!this.mappingStateManager.getFieldDefinition(e.key))}clearMappings(){this.mappingStateManager.clearMappings(),this.clickZoneRenderer.updateFieldStates()}destroy(){this.renderTask&&this.renderTask.cancel(),this.clickZoneRenderer&&this.clickZoneRenderer.destroy(),this.modalManager&&this.modalManager.destroy(),this.container.innerHTML="",this.pageWrapper=null,this.canvas=null}}class _{constructor(e){var t;this.options=e,this.pdfDoc=null,this.pages=[],this.renderedPages=new Map,this.container=e.container,this.pdfUrl=e.pdfUrl,this.scale=e.scale||1,e.workerSrc&&!((t=h.GlobalWorkerOptions)!=null&&t.workerSrc)&&(h.GlobalWorkerOptions.workerSrc=e.workerSrc),this.container.innerHTML="",this.loadPDF()}async loadPDF(){try{const e=h.getDocument(this.pdfUrl);this.pdfDoc=await e.promise,this.pages=[];for(let t=1;t<=this.pdfDoc.numPages;t++){const s=(await this.pdfDoc.getPage(t)).getViewport({scale:this.scale});this.pages.push({pageNumber:t,width:s.width,height:s.height,scale:this.scale,rotation:s.rotation,viewBox:[0,0,s.width,s.height]})}this.options.onPagesLoaded&&this.options.onPagesLoaded(this.pages)}catch(e){throw console.error("Error loading PDF:",e),e}}async renderPage(e){if(!this.pdfDoc)throw new Error("PDF document not loaded");const t=this.renderedPages.get(e);if(t)return t;const i=await this.pdfDoc.getPage(e),s=i.getViewport({scale:this.scale}),r=document.createElement("canvas"),n=r.getContext("2d");if(!n)throw new Error("Failed to get canvas context");r.width=s.width,r.height=s.height,r.style.width=`${s.width}px`,r.style.height=`${s.height}px`;const a={canvasContext:n,viewport:s,canvas:r};return await i.render(a).promise,this.renderedPages.set(e,r),this.options.onPageRendered&&this.options.onPageRendered(e),r}async renderAllPages(){if(!this.pdfDoc)throw new Error("PDF document not loaded");this.container.innerHTML="";for(let e=1;e<=this.pdfDoc.numPages;e++){const t=await this.renderPage(e),i=document.createElement("div");i.className="pdf-page-wrapper",i.style.position="relative",i.style.marginBottom="10px",i.dataset.pageNumber=e.toString(),i.appendChild(t),this.container.appendChild(i)}}async renderSinglePage(e){if(!this.pdfDoc||e<1||e>this.pdfDoc.numPages)throw new Error("Invalid page number");this.container.innerHTML="";const t=await this.renderPage(e),i=document.createElement("div");i.className="pdf-page-wrapper",i.style.position="relative",i.dataset.pageNumber=e.toString(),i.appendChild(t),this.container.appendChild(i)}getPageInfo(e){return this.pages.find(t=>t.pageNumber===e)||null}getAllPagesInfo(){return this.pages}getTotalPages(){var e;return((e=this.pdfDoc)==null?void 0:e.numPages)||0}async setScale(e){this.scale=e,this.renderedPages.clear(),await this.loadPDF()}destroy(){this.renderedPages.clear(),this.container.innerHTML="",this.pdfDoc&&(this.pdfDoc.destroy(),this.pdfDoc=null)}}d.PDFFieldMapper=J,d.PDFFiller=U,d.PDFFormRenderer=N,d.PDFViewer=_,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})});