# @hiyve/react-whiteboard

Real-time collaborative whiteboard component with full multi-user synchronization.

## Installation

```bash
npx @hiyve/cli login
npm install @hiyve/react-whiteboard
```

## Quick Start

```tsx
import { Whiteboard, WhiteboardToolbar, ZoomToolbar } from '@hiyve/react-whiteboard';
import { HiyveProvider } from '@hiyve/react';

function App() {
  return (
    <HiyveProvider generateRoomToken={generateToken}>
      <WhiteboardRoom />
    </HiyveProvider>
  );
}

function WhiteboardRoom() {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: '100vh' }}>
      <WhiteboardToolbar />
      <div style={{ flex: 1, position: 'relative' }}>
        <Whiteboard />
        <ZoomToolbar />
      </div>
    </div>
  );
}
```

## Components

| Component | Description |
|-----------|-------------|
| `Whiteboard` | Main canvas component with drawing, selection, and collaboration |
| `WhiteboardToolbar` | Drawing tools, color picker, stroke width, undo/redo |
| `ZoomToolbar` | Zoom in, zoom out, reset, and fit-to-screen controls |
| `ObjectActionMenu` | Context menu for selected objects (delete, duplicate, etc.) |
| `LaserPointer` | Laser pointer visualization for presentations |
| `WhiteboardSession` | Session viewer for loading saved whiteboard files |

## Hooks

| Hook | Description |
|------|-------------|
| `useWhiteboardCanvas(options)` | Canvas initialization, zoom, pan, and object management |
| `useWhiteboardTools(options)` | Tool selection, drawing mode, color, and stroke width |
| `useWhiteboardSync(options)` | Real-time synchronization of canvas changes across users |
| `useLaserPointer(options)` | Laser pointer broadcast and remote pointer rendering |
| `useWhiteboardFile(options)` | File save, load, auto-save, and sharing operations |

## Dialogs

| Component | Description |
|-----------|-------------|
| `UnsavedChangesDialog` | Prompts to save, discard, or cancel before closing |
| `FileSharingDialog` | Share a whiteboard file with selected participants |
| `CreateWhiteboardDialog` | Create a new whiteboard with a name and optional sharing |

## Add-in System

Extend the whiteboard with custom tools using the add-in API. Add-ins can contribute toolbar buttons, context menu items, and custom object types.

| Export | Description |
|--------|-------------|
| `WhiteboardAddin` | Base class for creating custom add-ins |
| `WhiteboardAddinRegistry` | Registry for managing add-in lifecycle |
| `StickyNotesAddin` | Built-in add-in for colorful sticky notes |

### Using Built-in Add-ins

```tsx
import { Whiteboard } from '@hiyve/react-whiteboard';

<Whiteboard
  fileId={fileId}
  enableAddins
  enabledAddins={['sticky-notes']}
/>
```

### Creating a Custom Add-in

```tsx
import { WhiteboardAddin } from '@hiyve/react-whiteboard';
import type { ToolbarButton, ContextMenuItem, WhiteboardObject } from '@hiyve/react-whiteboard';

class StampAddin extends WhiteboardAddin {
  constructor() {
    super({
      id: 'stamps',
      name: 'Stamps',
      description: 'Add stamp annotations to the whiteboard',
    });
  }

  getToolbarButtons(): ToolbarButton[] {
    return [{
      id: 'add-stamp',
      label: 'Add Stamp',
      icon: <StampIcon />,
      action: () => this.placeStamp(),
    }];
  }

  getContextMenuItems(object: WhiteboardObject): ContextMenuItem[] {
    if (!this.isAddinObject(object)) return [];
    return [{ id: 'remove-stamp', label: 'Remove Stamp', action: () => { /* ... */ } }];
  }

  getObjectTypes(): string[] {
    return ['stamp'];
  }

  onMessage(message: unknown, fromUserId: string): void {
    // Handle messages from other users
  }

  exportData(): unknown {
    // Return data to persist
    return {};
  }

  private placeStamp(): void {
    // Create and add stamp to canvas
  }
}
```

### Using the Registry Directly

```tsx
import { WhiteboardAddinRegistry, StickyNotesAddin } from '@hiyve/react-whiteboard';

const registry = new WhiteboardAddinRegistry();
registry.register(new StickyNotesAddin());
registry.register(new StampAddin());

// Enable specific add-ins
registry.enable('sticky-notes');
registry.enable('stamps');

// Get toolbar buttons from all enabled add-ins
const buttons = registry.getToolbarButtons();

// Listen for lifecycle events
registry.addEventListener('addin-enabled', ({ addinId }) => {
  console.log(`${addinId} was enabled`);
});
```

## Props

### Whiteboard

| Prop | Type | Description |
|------|------|-------------|
| `width` | `number` | Canvas width |
| `height` | `number` | Canvas height |
| `readOnly` | `boolean` | Disable editing |
| `showGrid` | `boolean` | Show background grid |
| `fileId` | `string` | File ID for persistence |
| `enableAddins` | `boolean` | Enable the add-in system |
| `enabledAddins` | `string[]` | IDs of add-ins to enable |
| `labels` | `Partial<WhiteboardLabels>` | Custom labels |
| `icons` | `Partial<WhiteboardIcons>` | Custom icons |
| `colors` | `Partial<WhiteboardColors>` | Custom colors |
| `styles` | `Partial<WhiteboardStyles>` | Custom styles |
| `renderProps` | `WhiteboardRenderProps` | Custom renderers |
| `onError` | `(error: Error) => void` | Error callback |

### WhiteboardToolbar

| Prop | Type | Description |
|------|------|-------------|
| `orientation` | `'horizontal' \| 'vertical'` | Toolbar orientation |
| `tools` | `ToolbarButton[]` | Available tools |
| `showColorPicker` | `boolean` | Show color picker |
| `showStrokeWidth` | `boolean` | Show stroke width selector |
| `labels` | `Partial<WhiteboardLabels>` | Custom labels |
| `icons` | `Partial<WhiteboardIcons>` | Custom icons |
| `colors` | `Partial<WhiteboardColors>` | Custom colors |

### ZoomToolbar

| Prop | Type | Description |
|------|------|-------------|
| `labels` | `Partial<WhiteboardLabels>` | Custom labels |
| `icons` | `Partial<WhiteboardIcons>` | Custom icons |

## Features

- Real-time collaboration across all connected users
- Drawing tools: pencil, shapes (rectangle, circle, triangle), text
- Shape fill modes: filled or outlined
- Zoom and pan with mouse wheel and touch gestures
- Undo/redo with full history
- Laser pointer for presentations (multiple colors per user)
- File persistence with auto-save
- Owner presence detection (read-only when owner leaves)
- Extensible add-in system for custom tools and objects
- Keyboard shortcuts for common operations

## Keyboard Shortcuts

| Shortcut | Action |
|----------|--------|
| `Ctrl+Z` / `Cmd+Z` | Undo |
| `Ctrl+Y` / `Cmd+Y` | Redo |
| `Delete` / `Backspace` | Delete selected objects |
| `Escape` | Deselect all |

## Utility Functions

Coordinate, serialization, and file utilities are exported for advanced use cases.

### Coordinate Utilities

```tsx
import {
  viewportToCanvas,
  canvasToViewport,
  getViewportCenter,
  calculateBoundingBox,
  distance,
  interpolatePosition,
} from '@hiyve/react-whiteboard';
```

### Canvas Object Helpers

```tsx
import {
  findObjectById,
  removeObjectById,
  serializeObject,
  serializeCanvas,
  recreateObject,
  createShape,
  loadCanvasFromJSON,
  clearCanvas,
  getSyncableObjects,
} from '@hiyve/react-whiteboard';
```

### Object ID Utilities

```tsx
import {
  createObjectIdGenerator,
  parseObjectId,
  isObjectOwnedBy,
  generateAddinObjectId,
} from '@hiyve/react-whiteboard';
```

### File Creation

```tsx
import { createWhiteboardFile, createAndShareWhiteboardFile } from '@hiyve/react-whiteboard';
import type { CreateWhiteboardFileOptions, WhiteboardFileClient } from '@hiyve/react-whiteboard';
```

### Additional Utilities

| Utility | Description |
|---------|-------------|
| `generateRandomId()` | Generate a random string ID |
| `normalizeCoordinatesForBroadcast(obj, zoom, pan)` | Normalize object coordinates for broadcasting to remote users |
| `isPositionInBox(pos, box)` | Check whether a position is inside a bounding box |
| `calculateScrollToCenter(target, container)` | Calculate scroll offsets to center a target within a container |
| `clampScrollPosition(scroll, bounds)` | Clamp scroll position to valid bounds |
| `applyObjectChanges(canvas, id, changes)` | Apply property changes to a canvas object by ID |
| `getFabricClass(type)` | Get the Fabric.js class for a given object type string |
| `isAddinObject(obj)` | Check whether a canvas object belongs to an add-in |
| `isBoundsIndicator(obj)` | Check whether a canvas object is a bounds indicator |
| `fixTextboxInObject(obj)` | Fix known textbox serialization issues in a canvas object |
| `prepareCanvasForSave(canvas)` | Prepare canvas state for file persistence |
| `getObjectsBoundingBox(objects)` | Calculate the bounding box of multiple canvas objects |

## Constants

Pre-defined configuration values are available for reference or customization.

| Constant | Description |
|----------|-------------|
| `DEFAULT_COLOR_PALETTE` | 12 drawing colors |
| `LASER_COLOR_PALETTE` | Laser pointer colors (one per user) |
| `CANVAS_DIMENSIONS` | Default, min, and max canvas sizes |
| `ZOOM_SETTINGS` | Min, max, step, and default zoom levels |
| `STROKE_SETTINGS` | Min, max, and default stroke widths |
| `LASER_SETTINGS` | Laser pointer radius and trail length |
| `KEYBOARD_SHORTCUTS` | Keyboard shortcut definitions |
| `UNDO_REDO_SETTINGS` | Max undo history size |
| `DATA_MESSAGE_TYPES` | Data message type identifiers for whiteboard sync |
| `WHITEBOARD_EVENTS` | Event names used in whiteboard sync payloads |
| `TIMING` | Timing configuration (auto-save interval, heartbeat, debounce) |
| `SHAPE_DEFAULTS` | Default dimensions for shapes (rectangle, circle, triangle, text) |
| `FABRIC_CUSTOM_PROPERTIES` | Custom property names included in object serialization |
| `ADDIN_CONSTANTS` | Add-in system constants (event prefix, object ID prefix, max add-ins) |
| `FABRIC_OBJECT_TYPES` | Mapping of Fabric.js object type names to class names |

## Customization

### Colors

```tsx
import { Whiteboard, mergeWhiteboardColors } from '@hiyve/react-whiteboard';

<Whiteboard
  colors={mergeWhiteboardColors({
    canvasBackground: '#f5f5f5',
    gridColor: '#e0e0e0',
    toolbarBackground: '#1e1e1e',
    activeToolHighlight: '#ff9800',
    defaultDrawColor: '#333333',
  })}
/>
```

### Labels

```tsx
import { Whiteboard, mergeWhiteboardLabels } from '@hiyve/react-whiteboard';

<Whiteboard
  labels={mergeWhiteboardLabels({
    pencilTool: 'Draw',
    clearCanvas: 'Erase All',
    readOnlyMode: 'Viewing Mode',
  })}
/>
```

### Styles

```tsx
import { Whiteboard, mergeWhiteboardStyles } from '@hiyve/react-whiteboard';

<Whiteboard
  styles={mergeWhiteboardStyles({
    defaultStrokeWidth: 3,
    toolbarHeight: 64,
    buttonBorderRadius: 8,
    autoSaveInterval: 10000,
  })}
/>
```

### Icons

```tsx
import { Whiteboard, mergeWhiteboardIcons } from '@hiyve/react-whiteboard';
import BrushIcon from '@mui/icons-material/Brush';

<Whiteboard
  icons={mergeWhiteboardIcons({
    pencil: <BrushIcon />,
  })}
/>
```

## Requirements

- React 18+
- `@hiyve/react` with `HiyveProvider`
- `@mui/material` v5 or v6
- `@mui/icons-material` v5 or v6
- Canvas rendering library is bundled -- no separate installation needed
- `@hiyve/react-collaboration` (optional, for file sharing features)

## License

Proprietary - Hiyve SDK
