import { create } from 'zustand' import type { Viewport } from '@/lib/geometry' import type { EditorObject } from './types' // Ephemeral editor state only (per DESIGN § State): the viewport, the current // selection, the object being live-edited mid-gesture, and the palette kind // armed for tap-to-place. All server state stays in react-query. export const MIN_SCALE = 0.05 // px per cm — fully zoomed out export const MAX_SCALE = 20 // px per cm — fully zoomed in interface EditorState { viewport: Viewport setViewport: (next: Viewport | ((prev: Viewport) => Viewport)) => void selectedId: number | null select: (id: number | null) => void focusedObjectId: number | null setFocusedObject: (id: number | null) => void // During a move/resize/rotate, the object's live geometry is held here so the // canvas renders it instantly; the PATCH fires only on gesture end. liveObject: EditorObject | null setLiveObject: (o: EditorObject | null) => void // The palette kind armed for tap-to-place (mobile-friendly; also set while // dragging a kind from the palette). null when nothing is armed. armedKind: string | null setArmedKind: (kind: string | null) => void // True while an object move/resize/rotate is in progress, so the viewport's // pan gesture stands down (both listen on the same svg). objectDragging: boolean setObjectDragging: (v: boolean) => void } export const useEditorStore = create((set) => ({ viewport: { tx: 0, ty: 0, scale: 1 }, setViewport: (next) => set((s) => ({ viewport: typeof next === 'function' ? next(s.viewport) : next })), selectedId: null, select: (id) => set({ selectedId: id }), focusedObjectId: null, setFocusedObject: (id) => set({ focusedObjectId: id }), liveObject: null, setLiveObject: (o) => set({ liveObject: o }), armedKind: null, setArmedKind: (kind) => set({ armedKind: kind }), objectDragging: false, setObjectDragging: (v) => set({ objectDragging: v }), }))