canvas/docs/migration-v1.md

148 lines
4.7 KiB
Markdown
Raw Permalink Normal View History

2026-03-11 18:42:08 -07:00
# 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>
);
}
```