npm package: @npoci/pdfform
Description: Modern PDF form renderer with HTML overlay fields - view, fill, and map PDF forms in the browser
Author: npoci
Latest version: 0.0.1-beta.16

# @npoci/pdfform

Modern PDF form renderer with HTML overlay fields. View, fill, validate, and map PDF forms directly in the browser.

[![npm version](https://img.shields.io/npm/v/@npoci/pdfform.svg)](https://www.npmjs.com/package/@npoci/pdfform)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## Features

- 🎯 **HTML Overlay Fields** - Real HTML inputs positioned over PDF forms
- 📝 **Form Filling** - Fill and export PDF forms programmatically  
- 🔍 **Field Mapping** - Visual field mapper to create user-friendly field definitions
- ✅ **Validation** - Built-in validation with custom patterns and error messages
- 🎨 **Customizable** - Override field renderers and styles
- 📦 **Framework Agnostic** - Works with React, Vue, Angular, or vanilla JS
- 🔒 **Type Safe** - Full TypeScript support

## Installation

```bash
npm install @npoci/pdfform
```

## Quick Start

### Basic PDF Form Renderer

```javascript
import { PDFFormRenderer } from '@npoci/pdfform'

const renderer = new PDFFormRenderer({
  container: document.getElementById('pdf-container'),
  pdfUrl: 'path/to/form.pdf'
})

// Listen for field changes
renderer.on('fieldChange', (field, validationState) => {
  console.log(`${field.name}: ${field.value}`, validationState)
})

// Render the PDF
await renderer.render()

// Get form values
const values = renderer.getFieldValues()
// { email: 'user@example.com', name: 'John Doe' }

// Get validation states
const states = renderer.getFieldStates()
// { email: { valid: true }, name: { valid: false, error: 'Required' } }
```

### Field Definitions

Make PDF fields user-friendly with custom definitions:

```javascript
const renderer = new PDFFormRenderer({
  container: document.getElementById('pdf-container'),
  pdfUrl: 'form.pdf',
  fieldDefinitions: [
    {
      key: 'field_12_a',  // Original PDF field name
      name: 'email',      // User-friendly name for getFieldValues()
      title: 'Email Address',
      placeholder: 'Enter your email',
      required: true,
      pattern: '^[^@]+@[^@]+\\.[^@]+$',
      errorMessage: 'Please enter a valid email'
    }
  ]
})
```

### Custom Field Renderers

Override how specific fields are rendered:

```javascript
const renderer = new PDFFormRenderer({
  container: document.getElementById('pdf-container'),
  pdfUrl: 'form.pdf',
  fieldOverrides: {
    'signature_field': {
      createField(field, bounds, setValue) {
        const canvas = document.createElement('canvas')
        canvas.width = bounds.width
        canvas.height = bounds.height
        // Add your signature drawing logic
        return canvas
      },
      getValue(element) {
        return element.toDataURL()
      },
      setValue(element, value) {
        // Load signature from data URL
      }
    }
  }
})
```

### Fill and Download PDFs

```javascript
import { PDFFiller } from '@npoci/pdfform'

const filler = new PDFFiller()
const values = renderer.getRawFieldValues()

// Fill the PDF
const filledPdfBytes = await filler.fillFromUrl('form.pdf', values)

// Download
const blob = new Blob([filledPdfBytes], { type: 'application/pdf' })
const url = URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
link.download = 'filled-form.pdf'
link.click()
```

## Field Mapper

Create field definitions visually with the built-in mapper:

```javascript
import { PDFFieldMapper } from '@npoci/pdfform'

const mapper = new PDFFieldMapper({
  container: document.getElementById('mapper-container'),
  pdfUrl: 'form.pdf'
})

// Listen for field selection
mapper.on('fieldSelected', ({ field, currentMapping }) => {
  console.log('Selected:', field.key)
})

// Export field definitions
const definitions = mapper.getFieldDefinitions()
console.log(JSON.stringify(definitions, null, 2))
```

## API Reference

### PDFFormRenderer

#### Options

```typescript
interface PDFFormRendererOptions {
  container: HTMLElement
  pdfUrl: string
  fieldDefinitions?: FieldDefinition[]
  fieldRenderers?: Record<string, FieldRenderer>
  fieldOverrides?: Record<string, FieldRenderer>
  scale?: number
  page?: number
  highlightColor?: string      // Default: '#ffffcc'
  highlightColorFocus?: string  // Default: '#ffffaa'
}
```

#### Methods

- `render(): Promise<void>` - Render the PDF
- `setPage(pageNumber: number): void` - Change page
- `getFieldValues(): Record<string, any>` - Get form values with user-friendly names
- `getRawFieldValues(): Record<string, any>` - Get values with original PDF field names
- `getFieldStates(): Record<string, ValidationState>` - Get validation states
- `setFieldValues(values: Record<string, any>): void` - Set multiple field values
- `destroy(): void` - Clean up resources

#### Events

- `ready` - PDF loaded and fields discovered
- `fieldChange` - Field value changed with validation
- `pageChange` - Page changed
- `error` - Error occurred

### PDFFieldMapper

#### Options

```typescript
interface PDFFieldMapperOptions {
  container: HTMLElement
  pdfUrl: string
  fieldDefinitions?: FieldDefinition[]
}
```

#### Methods

- `render(): Promise<void>` - Render the mapper
- `setFieldDefinition(key: string, definition: FieldDefinition): void` - Map a field
- `removeFieldDefinition(key: string): void` - Remove mapping
- `getFieldDefinitions(): FieldDefinition[]` - Get all mappings
- `exportDefinitions(): string` - Export as JSON
- `importDefinitions(json: string): void` - Import mappings
- `clearMappings(): void` - Clear all mappings

## Browser Compatibility

- Chrome/Edge 88+
- Firefox 85+
- Safari 14+

## License

MIT © npoci

## Contributing

Issues and PRs welcome! Please check existing issues before creating new ones.

## Acknowledgments

Built on top of [PDF.js](https://mozilla.github.io/pdf.js/) and [pdf-lib](https://pdf-lib.js.org/).