Files
next-ai-draw-io/stores/canvas-store.ts
T
dayuan.jiang 899b6a3b5b refactor(canvas): decouple the canvas from the chat engine
The canvas components will be reused by the MCP server's browser shell,
which has no chat and no Next.js. They now read everything they need
from small contexts and the canvas store instead of the chat engine:

- components/canvas/versions-context.tsx: VersionsProvider and
  useVersionsContext give the version cards, the strip and the compare
  dialog a VersionsSource (versions, onCanvasId, undoneId, isBusy,
  canUndo, canRedo, restore, undo, redo). The chat fills it from the
  versions store and the engine in components/chat/chat-versions.tsx.
- stores/canvas-store.ts: isBusy and busyReason; the chat engine sets
  them while a turn runs, SelectionAsk and the version UI read them.
- components/canvas/version-card.tsx: the visual version card and the
  thumbnail, out of tool-activity.tsx; the chat's card composes it and
  adds its "Show XML" link and code panel.
- compare-dialog.tsx and version-strip.tsx move to components/canvas;
  the strip takes the minimum number of versions to show as a prop, the
  chat panel computes it from the cards it has.
- components/canvas/locale-context.tsx: LocaleProvider and useLocale,
  fed by the [lang] layout; CanvasStage no longer uses next/navigation.
  The overlay (SelectionAsk) is a slot and the wait for the saved
  language is a prop, so the shell can leave both out.
- lib/version-text.ts: describeChanges is now describeChangeSummary, so
  it can be imported next to the MCP core's describeChanges.
2026-10-11 20:56:07 +09:00

55 lines
1.5 KiB
TypeScript

import { create } from "zustand"
export interface SelectedCell {
id: string
label: string
isEdge: boolean
}
/** Rectangle relative to the draw.io iframe's top-left corner */
interface CanvasRect {
x: number
y: number
width: number
height: number
}
interface CanvasPage {
id: string
name: string
}
interface CanvasState {
/** The page can call the draw.io editor directly (same-origin iframe) */
hasEditor: boolean
pages: CanvasPage[]
currentPageId: string | null
selection: SelectedCell[]
selectionRect: CanvasRect | null
/** Freehand drawing is on */
isFreehand: boolean
/** One of draw.io's menus or dialogs is open over the canvas */
isDrawioPopupOpen: boolean
/** Something is changing the canvas (an answer streams in, a sync
* runs): version actions and "ask AI" wait */
isBusy: boolean
/** Who set the busy flag ("chat", "sync"); null when not busy */
busyReason: string | null
set: (partial: Partial<Omit<CanvasState, "set" | "setBusy">>) => void
setBusy: (reason: string | null) => void
}
export const useCanvasStore = create<CanvasState>((set) => ({
hasEditor: false,
pages: [],
currentPageId: null,
selection: [],
selectionRect: null,
isFreehand: false,
isDrawioPopupOpen: false,
isBusy: false,
busyReason: null,
set: (partial) => set(partial),
setBusy: (reason) => set({ isBusy: reason !== null, busyReason: reason }),
}))