# Migrating to @blinksgg/canvas v1.0

This guide covers breaking changes and migration steps from v0.x to v1.0.

## Requirements

- **React 19.0+** — React 18 is not supported (React Compiler, context-as-JSX)
- **Jotai 2.6+** — Required for atom families and store API
- **Node 18+** — For ESM support

## Breaking Changes Summary

### From v0.14+ (Gesture System v2)

**`onAction` callback type changed**: `GestureEvent` → `InputEvent`

The `Canvas` component's `onAction` prop now receives `InputEvent` (union of pointer + keyboard events) instead of `GestureEvent` (pointer only).

```typescript
// Before (v0.x)
onAction={(event: GestureEvent, resolution) => {
  const { subject, worldPosition } = event;
}}

// After (v1.0)
onAction={(event: InputEvent, resolution) => {
  if (event.kind === 'key') return; // skip keyboard events
  const { subject, worldPosition } = event; // narrowed to pointer
}}
```

**Old gesture config replaced**: The v1 gesture config shape (event-to-action mapping objects) was replaced by the v2 specificity-based binding system.

```typescript
// Before (v0.x) — removed
<Canvas gestureConfig={{ onNodeDoubleTap: 'fit-to-view' }} />

// After (v1.0) — use binding contexts
import { gesturesV2 } from '@blinksgg/canvas';
// Bindings are configured via contexts, not flat config
```

### From v0.23+ (Removed Exports)

These were deprecated in v0.16 and removed in v0.23:

| Removed | Replacement |
|---------|-------------|
| `findPortAtPosition()` | Use `hitTestPort()` from `@blinksgg/canvas/utils` |
| `resolveGestureIntent()` | Use `gesturesV2.resolve()` |
| `isBackgroundGesture()` | Check `event.subject.kind === 'background'` |
| `useSupabaseClient()` | Use `CanvasDbProvider` with storage adapter |

### From v0.6+ (React 19)

- `Context.Provider` syntax → `<Context>` (React 19 style)
- Manual `React.memo()` / `useCallback()` / `useMemo()` removed — React Compiler handles memoization
- Ref cleanup functions used instead of `useEffect` return for pointer capture

## Import Path Changes

All import paths are stable and unchanged since v0.14:

```typescript
import { Canvas, useCanvasSelection, graphAtom } from '@blinksgg/canvas';
import { commandRegistry } from '@blinksgg/canvas/commands';
import { graphAtom, selectedNodeIdsAtom } from '@blinksgg/canvas/core';
import { useNodeDrag, useFitToBounds } from '@blinksgg/canvas/hooks';
import { gesturesV2 } from '@blinksgg/canvas'; // or from '@blinksgg/canvas/gestures'
import { CanvasStorageAdapter } from '@blinksgg/canvas/db';
```

## Storage Adapter Migration

If you were using the old Supabase provider props:

```typescript
// Before (v0.x) — Supabase-specific props
<Canvas supabaseUrl="..." supabaseKey="..." />

// After (v1.0) — adapter pattern
import { CanvasDbProvider, SupabaseStorageAdapter } from '@blinksgg/canvas/db';

const adapter = new SupabaseStorageAdapter(supabaseClient);
<CanvasDbProvider adapter={adapter}>
  <Canvas ... />
</CanvasDbProvider>
```

Or use callback props for simple persistence (no adapter needed):

```typescript
<Canvas
  onNodePersist={async (nodeId, graphId, uiProps) => {
    await saveToYourBackend(nodeId, graphId, uiProps);
  }}
/>
```

## Peer Dependencies

Required:
- `react` ^19.0.0
- `react-dom` ^19.0.0
- `jotai` ^2.6.0

Optional (install only if using the feature):
- `d3-force` ^3.0.0 — for `useForceLayout` hook
- `@tanstack/react-query` ^5.17.0 — for query-based atoms
- `jotai-tanstack-query` — for `atomsWithQuery` integration
- `@blocknote/core`, `@blocknote/react`, `@blocknote/shadcn` ^0.45.0 — for `NoteNode`

## Gesture System v1 → v2 Mapping

| v1 Gesture Config | v2 Equivalent |
|-------------------|---------------|
| `onNodeDoubleTap: 'fit-to-view'` | Default binding: double-tap node → `fit-to-view` |
| `onBackgroundDoubleTap: 'create-node'` | Default binding: double-tap background → `create-node` |
| `onNodeRightClick: 'context-menu'` | Default binding: right-click node → `context-menu` |
| `onNodeLongPress: 'toggle-lock'` | Default binding: long-press node → `toggle-lock` |

All default bindings are pre-configured. Override via `gestureConfig` prop or `addGestureRuleAtom`.

## Quick Start (v1.0)

```tsx
import { Provider as JotaiProvider } from 'jotai';
import { Canvas, CanvasStyleProvider, graphAtom } from '@blinksgg/canvas';

function App() {
  return (
    <JotaiProvider>
      <CanvasStyleProvider isDark={true}>
        <Canvas
          renderNode={({ node, isSelected }) => (
            <div>{node.label}</div>
          )}
          onAction={(event, resolution) => {
            if (event.kind === 'key') return;
            console.log(resolution.actionId, event.subject);
          }}
        />
      </CanvasStyleProvider>
    </JotaiProvider>
  );
}
```
