npm package: @melihbirim/signature-pad
Description: A React signature pad component with draw and type modes
Author: Melih Birim
Latest version: 1.0.0

# @melihbirim/signature-pad

A lightweight React component for collecting signatures with draw and type modes. Zero dependencies beyond React.

## Installation

```bash
npm install @melihbirim/signature-pad
```

Requires React 18+.

## Quick Start

```tsx
import { SignaturePad } from '@melihbirim/signature-pad';
import { useState } from 'react';

function App() {
  const [signature, setSignature] = useState<string>();

  const handleUpload = async (file: File): Promise<string> => {
    const formData = new FormData();
    formData.append('file', file);
    const response = await fetch('/api/upload', { method: 'POST', body: formData });
    const data = await response.json();
    return data.path;
  };

  return (
    <SignaturePad
      value={signature}
      onChange={setSignature}
      onUpload={handleUpload}
    />
  );
}
```

## Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `value` | `string \| undefined` | - | Current signature path/URL |
| `onChange` | `(value?: string) => void` | - | Called when signature changes |
| `onUpload` | `(file: File) => Promise<string>` | Required | Upload function, returns path/URL |
| `width` | `number` | `600` | Canvas width in pixels |
| `height` | `number` | `200` | Canvas height in pixels |
| `getFullUrl` | `(path: string) => string` | `(p) => p` | Convert path to full URL for display |
| `watermark` | `WatermarkConfig` | - | Add metadata overlay (IP, timestamp, timezone) |
| `typedFont` | `string` | `"Brush Script MT", cursive` | Font for typed signatures |
| `labels` | `LabelsConfig` | - | Customize button/label text |
| `styles` | `StylesConfig` | - | Custom CSS styles |
| `headless` | `boolean` | `false` | Render only canvas, no UI |
| `renderToolbar` | `(props) => ReactNode` | - | Custom toolbar component |
| `renderSignature` | `(props) => ReactNode` | - | Custom signature display |
| `onUploadStart` | `() => void` | - | Called before upload starts |
| `onUploadEnd` | `(path: string) => void` | - | Called after upload succeeds |
| `onUploadError` | `(error: Error) => void` | - | Called on upload failure |
| `onMessage` | `(type, text) => void` | - | Custom message handler |

## Imperative API

Access methods via ref:

```tsx
const ref = useRef<SignaturePadRef>(null);

<SignaturePad ref={ref} onUpload={handleUpload} />

// Methods
ref.current?.clear();                    // Clear canvas
ref.current?.uploadSignature();          // Trigger upload
ref.current?.setMode('draw' | 'type');   // Switch modes
ref.current?.getCanvas();                // Get canvas element
```

## Upload Examples

### AWS S3 with Presigned URL

```tsx
const handleUpload = async (file: File): Promise<string> => {
  const { data } = await axios.post('/api/s3/presigned-url', {
    filename: file.name,
    contentType: file.type,
  });
  await axios.put(data.uploadUrl, file, {
    headers: { 'Content-Type': file.type },
  });
  return data.key;
};
```

### Direct Server Upload

```tsx
const handleUpload = async (file: File): Promise<string> => {
  const formData = new FormData();
  formData.append('signature', file);
  const response = await fetch('/api/signatures', {
    method: 'POST',
    headers: { 'Authorization': `Bearer ${token}` },
    body: formData,
  });
  const { filePath } = await response.json();
  return filePath;
};
```

## Customization

### Custom Labels

```tsx
<SignaturePad
  onUpload={handleUpload}
  labels={{
    draw: 'Draw',
    type: 'Type',
    clear: 'Clear',
    useSignature: 'Save',
    removeSignature: 'Remove',
    typePlaceholder: 'Your name',
  }}
/>
```

### Custom Styles

```tsx
<SignaturePad
  onUpload={handleUpload}
  styles={{
    container: { border: '2px solid #000' },
    canvas: { borderRadius: 8 },
    preview: { maxWidth: 400 },
  }}
/>
```

### Watermark

```tsx
<SignaturePad
  onUpload={handleUpload}
  watermark={{
    enabled: true,
    ipAddress: '192.168.1.1',
    timezone: 'America/New_York',
    fontSize: 10,
    color: '#666',
  }}
/>
```

### Headless Mode

```tsx
<SignaturePad
  value={signature}
  onChange={setSignature}
  onUpload={handleUpload}
  headless={true}
  renderToolbar={({ mode, onModeChange, onClear, onUpload }) => (
    <div>
      <button onClick={() => onModeChange('draw')}>Draw</button>
      <button onClick={() => onModeChange('type')}>Type</button>
      <button onClick={onClear}>Clear</button>
      <button onClick={onUpload}>Save</button>
    </div>
  )}
/>
```

### Upload State Tracking

```tsx
function App() {
  const [uploading, setUploading] = useState(false);

  return (
    <SignaturePad
      onUpload={handleUpload}
      onUploadStart={() => setUploading(true)}
      onUploadEnd={() => setUploading(false)}
      onUploadError={(err) => {
        setUploading(false);
        console.error(err);
      }}
    />
  );
}
```

## Features

- Draw with mouse or touch (smooth Bezier curves)
- Type signatures with custom fonts
- DPI-aware rendering for Retina displays
- Imperative API via ref
- Upload lifecycle hooks
- Watermark support
- Headless mode for custom UI
- TypeScript support
- Zero dependencies

## License

MIT