feat: floor plan selection handles, dbl-click edit, bottom z-index

- Resize handles only render when the plan is selected (click to select,
  click outside to deselect); previously always shown when unlocked.
- Double-clicking an unlocked plan opens the canvas edit modal (via a
  floorMapEditNonce signal the Sidebar watches).
- Floor plan always sits at the bottom of the canvas (z-index -1), behind
  nodes and edges, locked or not.
- Remount the edit modal on every open (key bump) so it re-seeds from the
  current floor plan; fixes Save clobbering a canvas-side resize/move with
  stale modal dimensions.
- Drop the no-op history snapshot on floor-plan edits (floorMap isn't part
  of undo history).
This commit is contained in:
Pouzor
2026-07-03 00:03:16 +02:00
parent 6160090919
commit bdde03cdfa
7 changed files with 190 additions and 16 deletions
@@ -1337,5 +1337,12 @@ describe('canvasStore — custom style apply', () => {
useCanvasStore.getState().updateFloorMap({ posX: 5 })
expect(useCanvasStore.getState().floorMap).toBeNull()
})
it('requestFloorMapEdit bumps the nonce each call', () => {
const start = useCanvasStore.getState().floorMapEditNonce
useCanvasStore.getState().requestFloorMapEdit()
useCanvasStore.getState().requestFloorMapEdit()
expect(useCanvasStore.getState().floorMapEditNonce).toBe(start + 2)
})
})
})
+7
View File
@@ -38,6 +38,10 @@ interface CanvasState {
floorMap: FloorMapConfig | null
setFloorMap: (config: FloorMapConfig | null) => void
updateFloorMap: (patch: Partial<FloorMapConfig>) => void
// Bumped when the user double-clicks the floor plan on the canvas, asking the
// Sidebar to open the active canvas's edit modal (floor plan section).
floorMapEditNonce: number
requestFloorMapEdit: () => void
// History
past: HistoryEntry[]
@@ -103,6 +107,7 @@ export const useCanvasStore = create<CanvasState>((set) => ({
scanEventTs: 0,
serviceStatuses: {},
floorMap: null,
floorMapEditNonce: 0,
fitViewPending: false,
past: [],
@@ -760,6 +765,8 @@ export const useCanvasStore = create<CanvasState>((set) => ({
hasUnsavedChanges: true,
})),
requestFloorMapEdit: () => set((s) => ({ floorMapEditNonce: s.floorMapEditNonce + 1 })),
loadCanvas: (nodes, edges) => {
// React Flow requires parents before children in the array
const parents = nodes.filter((n) => !n.parentId)