# Integration Guide

Complete guide for integrating Form Builder into your application.

## CDN Integration

### Basic Iframe Embedding

```html
<iframe src="https://picazru.github.io/form-builder/dist/index.html" 
        width="100%" height="600px" frameborder="0"></iframe>
```

### With Custom Schema

```html
<iframe src="https://picazru.github.io/form-builder/dist/index.html?schema=BASE64_SCHEMA" 
        width="100%" height="600px"></iframe>
```

**Encoding Schema:**
```javascript
const schema = { version: "0.3", title: "My Form", elements: [...] };
const encodedSchema = btoa(JSON.stringify(schema));
const url = `https://picazru.github.io/form-builder/dist/index.html?schema=${encodedSchema}`;
```

## NPM Integration

### Installation

```bash
npm install @dmitryvim/form-builder
```

### Direct HTML Integration

Copy the form builder HTML directly into your application:

```javascript
import formBuilderHTML from '@dmitryvim/form-builder/dist/index.html';

// Insert into your page
document.getElementById('form-container').innerHTML = formBuilderHTML;
```

## Configuration

### File Upload Handler

The upload handler **must return a resource ID** that can be used for downloads and form submission:

```javascript
window.addEventListener('message', (event) => {
    if (event.origin !== 'https://picazru.github.io') return;
    
    if (event.data.type === 'formBuilderReady') {
        const iframe = document.getElementById('formBuilder');
        iframe.contentWindow.postMessage({
            type: 'configure',
            config: {
                uploadHandler: async (file) => {
                    const formData = new FormData();
                    formData.append('file', file);
                    
                    const response = await fetch('/api/upload', {
                        method: 'POST',
                        body: formData
                    });
                    
                    const result = await response.json();
                    return result.resourceId; // Return ID, not URL
                },
                downloadHandler: async (resourceId) => {
                    window.open(`/api/download/${resourceId}`, '_blank');
                },
                thumbnailHandler: async (resourceId) => {
                    return `/api/thumbnail/${resourceId}`;
                }
            }
        }, 'https://picazru.github.io');
    }
});
```

### Read-Only Mode

Display form data without editing capabilities:

```javascript
iframe.contentWindow.postMessage({
    type: 'configure',
    options: {
        readonly: true
    }
}, 'https://picazru.github.io');
```

### Tailwind CSS Integration

Always uses Tailwind CSS styling. Add to your CSS:

```css
/* Custom properties for consistent styling */
:root {
    --form-primary: 59 130 246;      /* Blue */
    --form-secondary: 100 116 139;   /* Gray */ 
    --form-accent: 16 185 129;       /* Green */
}

/* Override form builder styles if needed */
.form-builder-container {
    @apply max-w-none; /* Remove max-width constraints */
}
```

## Events

### Form Submission

Listen for form submissions:

```javascript
window.addEventListener('message', (event) => {
    if (event.data.type === 'formSubmit') {
        const { data, schema } = event.data;
        console.log('Form submitted:', data);
        
        // Handle the submission
        handleFormSubmission(data);
    }
});
```

### Draft Saving

Listen for draft save events:

```javascript
window.addEventListener('message', (event) => {
    if (event.data.type === 'draftSave') {
        const { data, schema } = event.data;
        console.log('Draft saved:', data);
        
        // Save draft without validation
        saveDraft(data);
    }
});
```

## API Communication

### Send Schema

```javascript
iframe.contentWindow.postMessage({
    type: 'setSchema',
    schema: {
        version: "0.3",
        title: "Contact Form",
        elements: [...]
    }
}, 'https://picazru.github.io');
```

### Prefill Form Data

```javascript
iframe.contentWindow.postMessage({
    type: 'setData',
    data: {
        name: "John Doe",
        email: "john@example.com"
    }
}, 'https://picazru.github.io');
```

### Get Current Data

```javascript
// Request data
iframe.contentWindow.postMessage({
    type: 'getData'
}, 'https://picazru.github.io');

// Listen for response
window.addEventListener('message', (event) => {
    if (event.data.type === 'currentData') {
        console.log('Current form data:', event.data.data);
    }
});
```

### Validate Form

```javascript
// Request validation
iframe.contentWindow.postMessage({
    type: 'validate'
}, 'https://picazru.github.io');

// Listen for result
window.addEventListener('message', (event) => {
    if (event.data.type === 'validationResult') {
        console.log('Form is valid:', event.data.isValid);
    }
});
```

## Backend Integration

### File Upload Endpoint

Your backend must handle file uploads and return resource IDs:

```javascript
// Express.js example
app.post('/api/upload', upload.single('file'), (req, res) => {
    const file = req.file;
    
    // Store file (S3, local storage, etc.)
    const resourceId = generateResourceId();
    storeFile(resourceId, file);
    
    res.json({
        resourceId: resourceId,
        filename: file.originalname,
        size: file.size,
        mimetype: file.mimetype
    });
});
```

### File Download Endpoint

```javascript
app.get('/api/download/:resourceId', (req, res) => {
    const { resourceId } = req.params;
    
    // Retrieve file info
    const fileInfo = getFileInfo(resourceId);
    if (!fileInfo) {
        return res.status(404).json({ error: 'File not found' });
    }
    
    // Stream file to client
    const fileStream = getFileStream(resourceId);
    res.setHeader('Content-Disposition', `attachment; filename="${fileInfo.filename}"`);
    res.setHeader('Content-Type', fileInfo.mimetype);
    fileStream.pipe(res);
});
```

### Form Submission Handler

```javascript
app.post('/api/forms/submit', (req, res) => {
    const { schema, data } = req.body;
    
    // Process form data
    // File fields will contain resource IDs
    
    console.log('Received form:', data);
    // Example: { name: "John", avatar: "res_abc123", documents: ["res_def456", "res_ghi789"] }
    
    // Validate and save
    const result = processFormSubmission(schema, data);
    
    res.json({ success: true, id: result.id });
});
```

## Framework-Specific Examples

### React Integration

```jsx
import { useEffect, useRef } from 'react';

function FormBuilder({ schema, onSubmit }) {
    const iframeRef = useRef(null);
    
    useEffect(() => {
        const handleMessage = (event) => {
            if (event.data.type === 'formBuilderReady') {
                // Configure form builder
                iframeRef.current.contentWindow.postMessage({
                    type: 'setSchema',
                    schema: schema
                }, 'https://picazru.github.io');
            }
            
            if (event.data.type === 'formSubmit') {
                onSubmit(event.data.data);
            }
        };
        
        window.addEventListener('message', handleMessage);
        return () => window.removeEventListener('message', handleMessage);
    }, [schema, onSubmit]);
    
    return (
        <iframe
            ref={iframeRef}
            src="https://picazru.github.io/form-builder/dist/index.html"
            width="100%"
            height="600px"
            frameBorder="0"
        />
    );
}
```

### Vue.js Integration

```vue
<template>
    <iframe
        ref="formBuilder"
        src="https://picazru.github.io/form-builder/dist/index.html"
        width="100%"
        height="600px"
        frameborder="0"
        @load="onIframeLoad"
    />
</template>

<script>
export default {
    props: ['schema'],
    
    mounted() {
        window.addEventListener('message', this.handleMessage);
    },
    
    beforeUnmount() {
        window.removeEventListener('message', this.handleMessage);
    },
    
    methods: {
        handleMessage(event) {
            if (event.data.type === 'formBuilderReady') {
                this.$refs.formBuilder.contentWindow.postMessage({
                    type: 'setSchema',
                    schema: this.schema
                }, 'https://picazru.github.io');
            }
            
            if (event.data.type === 'formSubmit') {
                this.$emit('submit', event.data.data);
            }
        }
    }
};
</script>
```

## Security Considerations

### Origin Validation

Always validate message origins:

```javascript
window.addEventListener('message', (event) => {
    // Only accept messages from form builder origin
    if (event.origin !== 'https://picazru.github.io') {
        return;
    }
    
    // Process message...
});
```

### File Upload Security

- **Validate file types** on server
- **Limit file sizes** appropriately  
- **Scan for viruses** if possible
- **Use secure file storage** (S3 with proper permissions)
- **Generate secure resource IDs** (UUID, crypto.randomUUID())

### Content Security Policy

Add to your CSP headers:

```
Content-Security-Policy: 
    default-src 'self'; 
    frame-src https://picazru.github.io; 
    connect-src 'self' https://your-api.com;
```

## Troubleshooting

### Common Issues

**Form builder not loading**: Check CSP settings and iframe src URL

**File uploads failing**: Verify upload handler returns resource ID, not URL

**Messages not working**: Confirm origin validation and message format

**Schema not applying**: Check schema format against [Schema Reference](schema.md)

### Debugging

Enable console logging in iframe:

```javascript
iframe.contentWindow.postMessage({
    type: 'configure',
    config: {
        debug: true
    }
}, 'https://picazru.github.io');
```

This will log all form builder events to the browser console.

## Migration

### From v0.1.x to v0.2.x

- Upload handlers must return resource IDs instead of URLs
- Added support for draft saving
- Improved Tailwind CSS integration

### Updating Handlers

```javascript
// Old (v0.1.x)
uploadHandler: async (file) => {
    // ... upload logic
    return result.fileUrl; // URL
}

// New (v0.2.x)  
uploadHandler: async (file) => {
    // ... upload logic
    return result.resourceId; // ID
}
```

This integration guide covers all aspects of using Form Builder in production applications.