npm package: @micahgoodman/whiteboard
Description: A heterogeneous drag-and-drop whiteboard component for React with multi-module support
Author: Your Name
Latest version: 1.0.0

# @micahgoodman/whiteboard

A heterogeneous drag-and-drop whiteboard component for React with multi-module support. Display multiple types of content (notes, tasks, bookmarks, etc.) on a single canvas.

## Features

✨ **Heterogeneous Support** - Mix different module types on one whiteboard  
🎯 **Drag & Drop** - Smooth, native mouse-based dragging  
💾 **Position Persistence** - Automatic localStorage saving  
🎨 **Customizable** - Full control over styling and behavior  
📱 **Type Safe** - Full TypeScript support  
🔌 **Zero Dependencies** - Only requires React

## Installation

```bash
npm install @micahgoodman/whiteboard
# or
yarn add @micahgoodman/whiteboard
```

## Peer Dependencies

```json
{
  "react": "^18.0.0"
}
```

## Quick Start

### Single Module Example

```tsx
import { Whiteboard, WhiteboardItem, WhiteboardComponentMap } from '@micahgoodman/whiteboard';

// Define your item type
type Note = WhiteboardItem & {
  type: 'note';
  text: string;
};

// Create your card component
const NoteCard = ({ item }: { item: WhiteboardItem }) => {
  const note = item as Note;
  return <div>{note.text}</div>;
};

// Create your detail component
const NoteDetail = ({ item, onClose }: { item: WhiteboardItem; onClose: () => void }) => {
  const note = item as Note;
  return (
    <div>
      <h2>Note Details</h2>
      <p>{note.text}</p>
      <button onClick={onClose}>Close</button>
    </div>
  );
};

// Register components
const componentMap: WhiteboardComponentMap = {
  note: {
    CardComponent: NoteCard,
    DetailComponent: NoteDetail,
  },
};

// Use the whiteboard
function App() {
  const [notes, setNotes] = useState<Note[]>([
    { id: '1', type: 'note', text: 'Hello World!' },
  ]);
  const [selectedId, setSelectedId] = useState<string | null>(null);

  return (
    <Whiteboard
      items={notes}
      selectedId={selectedId}
      onSelect={setSelectedId}
      config={{
        cardWidth: 320,
        cardHeight: 200,
        cardBorderRadius: 12,
        spacing: 40,
        localStorageKey: 'my-whiteboard-positions',
      }}
      componentMap={componentMap}
      toolbarConfig={{
        showCount: true,
        addButtonLabel: '+ New Note',
      }}
      onAddNew={() => {
        const newNote: Note = {
          id: Date.now().toString(),
          type: 'note',
          text: 'New note',
        };
        setNotes([...notes, newNote]);
      }}
    />
  );
}
```

### Multi-Module Example

```tsx
import { Whiteboard, WhiteboardItem, WhiteboardComponentMap } from '@micahgoodman/whiteboard';

type Note = WhiteboardItem & { type: 'note'; text: string };
type Task = WhiteboardItem & { type: 'task'; title: string; done: boolean };
type Bookmark = WhiteboardItem & { type: 'bookmark'; url: string; title: string };

const componentMap: WhiteboardComponentMap = {
  note: {
    CardComponent: NoteCard,
    DetailComponent: NoteDetail,
  },
  task: {
    CardComponent: TaskCard,
    DetailComponent: TaskDetail,
  },
  bookmark: {
    CardComponent: BookmarkCard,
    DetailComponent: BookmarkDetail,
  },
};

function App() {
  const allItems: WhiteboardItem[] = [
    ...notes.map(n => ({ ...n, type: 'note' as const })),
    ...tasks.map(t => ({ ...t, type: 'task' as const })),
    ...bookmarks.map(b => ({ ...b, type: 'bookmark' as const })),
  ];

  return (
    <Whiteboard
      items={allItems}
      selectedId={selectedId}
      onSelect={setSelectedId}
      config={whiteboardConfig}
      componentMap={componentMap}
      toolbarConfig={{
        showCount: true,
        customActions: (
          <>
            <button onClick={addNote}>+ Note</button>
            <button onClick={addTask}>+ Task</button>
            <button onClick={addBookmark}>+ Bookmark</button>
          </>
        ),
      }}
    />
  );
}
```

## API

### `<Whiteboard>`

Main whiteboard component.

#### Props

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `items` | `WhiteboardItem[]` | ✅ | Array of items to display |
| `selectedId` | `string \| null` | ✅ | ID of currently selected item |
| `onSelect` | `(id: string) => void` | ✅ | Called when item is selected |
| `config` | `WhiteboardConfig` | ✅ | Whiteboard configuration |
| `componentMap` | `WhiteboardComponentMap` | ✅ | Component registry |
| `onAddNew` | `() => void` | ❌ | Called when add button clicked |
| `emptyStateConfig` | `EmptyStateConfig` | ❌ | Empty state customization |
| `toolbarConfig` | `ToolbarConfig` | ❌ | Toolbar customization |

### Types

#### `WhiteboardItem`

```ts
interface WhiteboardItem {
  id: string;
  type: string; // Module discriminator
}
```

#### `WhiteboardConfig`

```ts
type WhiteboardConfig = {
  cardWidth: number;
  cardHeight: number;
  cardBorderRadius: number;
  spacing: number;
  localStorageKey: string;
};
```

#### `WhiteboardComponentMap`

```ts
type WhiteboardComponentMap = {
  [moduleType: string]: {
    CardComponent: React.ComponentType<{
      item: WhiteboardItem;
      isSelected: boolean;
      onClick: () => void;
      onCardClick: (e: React.MouseEvent) => void;
    }>;
    DetailComponent: React.ComponentType<{
      item: WhiteboardItem;
      onClose: () => void;
    }>;
  };
};
```

### Lower-Level Components

The package also exports lower-level draggable components:

#### `<DraggableCanvas>`

Container for draggable items with optional grid.

```tsx
<DraggableCanvas showGrid gridSize={20}>
  {/* Draggable items */}
</DraggableCanvas>
```

#### `<DraggableCard>`

Individual draggable item wrapper.

```tsx
<DraggableCard
  id="card-1"
  position={{ x: 100, y: 100 }}
  onPositionChange={(id, pos) => console.log(id, pos)}
  width={300}
>
  <YourContent />
</DraggableCard>
```

## Styling

The whiteboard comes with minimal default styling. For custom styling:

1. **Override inline styles** via `toolbarConfig` and component props
2. **Use CSS classes** - components accept `className` props
3. **Global CSS** - Target `.btn.primary` and other classes

## TypeScript

Full TypeScript support with exported types:

```ts
import type {
  WhiteboardItem,
  WhiteboardConfig,
  WhiteboardComponentMap,
  WhiteboardProps,
  Position,
} from '@micahgoodman/whiteboard';
```

## Browser Support

- Modern browsers (Chrome, Firefox, Safari, Edge)
- Requires `localStorage` for position persistence

## License

MIT

## Contributing

Issues and pull requests welcome!