refactor(editor): delete editingHole + activeHandleDrag legacy flags
Migrate the two pure-mirror interaction flags off `useEditor` onto the authoritative `useInteractionScope`. Both carried payloads byte-identical to the scope union, so this is a zero-behaviour-change refactor: readers use the reference-stable `useEditingHole()` / `useActiveHandleDrag()` hooks (or the `getEditingHole()` imperative read), and producers drive the scope directly with guarded `endIf` so clearing one interaction never stomps an unrelated scope. Adds the `holeEditScope` builder + a no-leaked-flag invariant test. Closes the first slice of the legacy-flag deletion; the rich-payload flags (movingNode, curving*, *Endpoint, placementDragMode) remain. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
f773e6b8c5
commit
2f2c3ef8f9
@@ -4,11 +4,14 @@ import { type AnyNode, type SlabNode, useScene } from '@pascal-app/core'
|
||||
import {
|
||||
ActionButton,
|
||||
ActionGroup,
|
||||
holeEditScope,
|
||||
PanelSection,
|
||||
PanelWrapper,
|
||||
SliderControl,
|
||||
triggerSFX,
|
||||
useEditingHole,
|
||||
useEditor,
|
||||
useInteractionScope,
|
||||
} from '@pascal-app/editor'
|
||||
import { useViewer } from '@pascal-app/viewer'
|
||||
import { Edit, Move, Plus, Trash2 } from 'lucide-react'
|
||||
@@ -28,8 +31,7 @@ import { useCallback, useEffect, useRef } from 'react'
|
||||
export function SlabPanel() {
|
||||
const selectedId = useViewer((s) => s.selection.selectedIds[0])
|
||||
const setSelection = useViewer((s) => s.setSelection)
|
||||
const editingHole = useEditor((s) => s.editingHole)
|
||||
const setEditingHole = useEditor((s) => s.setEditingHole)
|
||||
const editingHole = useEditingHole()
|
||||
const setMovingNode = useEditor((s) => s.setMovingNode)
|
||||
|
||||
const node = useScene((s) =>
|
||||
@@ -52,20 +54,26 @@ export function SlabPanel() {
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
setSelection({ selectedIds: [] })
|
||||
setEditingHole(null)
|
||||
}, [setSelection, setEditingHole])
|
||||
useInteractionScope
|
||||
.getState()
|
||||
.endIf((scope) => scope.kind === 'reshaping' && scope.reshape === 'hole')
|
||||
}, [setSelection])
|
||||
|
||||
useEffect(() => {
|
||||
if (!node) {
|
||||
setEditingHole(null)
|
||||
useInteractionScope
|
||||
.getState()
|
||||
.endIf((scope) => scope.kind === 'reshaping' && scope.reshape === 'hole')
|
||||
}
|
||||
}, [node, setEditingHole])
|
||||
}, [node])
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
setEditingHole(null)
|
||||
useInteractionScope
|
||||
.getState()
|
||||
.endIf((scope) => scope.kind === 'reshaping' && scope.reshape === 'hole')
|
||||
}
|
||||
}, [setEditingHole])
|
||||
}, [])
|
||||
|
||||
const handleAddHole = useCallback(() => {
|
||||
if (!(node && selectedId)) return
|
||||
@@ -95,15 +103,17 @@ export function SlabPanel() {
|
||||
holes: [...currentHoles, newHole],
|
||||
holeMetadata: [...currentMetadata, { source: 'manual' }],
|
||||
})
|
||||
setEditingHole({ nodeId: selectedId, holeIndex: currentHoles.length })
|
||||
}, [node, selectedId, handleUpdate, setEditingHole])
|
||||
useInteractionScope
|
||||
.getState()
|
||||
.begin(holeEditScope({ nodeId: selectedId, holeIndex: currentHoles.length }))
|
||||
}, [node, selectedId, handleUpdate])
|
||||
|
||||
const handleEditHole = useCallback(
|
||||
(index: number) => {
|
||||
if (!selectedId) return
|
||||
setEditingHole({ nodeId: selectedId, holeIndex: index })
|
||||
useInteractionScope.getState().begin(holeEditScope({ nodeId: selectedId, holeIndex: index }))
|
||||
},
|
||||
[selectedId, setEditingHole],
|
||||
[selectedId],
|
||||
)
|
||||
|
||||
const handleDeleteHole = useCallback(
|
||||
@@ -118,10 +128,12 @@ export function SlabPanel() {
|
||||
const newMetadata = currentMetadata.filter((_, i) => i !== index)
|
||||
handleUpdate({ holes: newHoles, holeMetadata: newMetadata })
|
||||
if (editingHole?.nodeId === selectedId && editingHole?.holeIndex === index) {
|
||||
setEditingHole(null)
|
||||
useInteractionScope
|
||||
.getState()
|
||||
.endIf((scope) => scope.kind === 'reshaping' && scope.reshape === 'hole')
|
||||
}
|
||||
},
|
||||
[selectedId, node?.holes, node?.holeMetadata, handleUpdate, editingHole, setEditingHole],
|
||||
[selectedId, node?.holes, node?.holeMetadata, handleUpdate, editingHole],
|
||||
)
|
||||
|
||||
const handleMove = useCallback(() => {
|
||||
@@ -219,7 +231,13 @@ export function SlabPanel() {
|
||||
<ActionButton
|
||||
className="h-7 bg-primary text-primary-foreground hover:bg-primary/90"
|
||||
label="Done"
|
||||
onClick={() => setEditingHole(null)}
|
||||
onClick={() =>
|
||||
useInteractionScope
|
||||
.getState()
|
||||
.endIf(
|
||||
(scope) => scope.kind === 'reshaping' && scope.reshape === 'hole',
|
||||
)
|
||||
}
|
||||
/>
|
||||
) : isAutoHole ? (
|
||||
<div className="rounded-md bg-[#2C2C2E] px-2 py-1 text-[10px] text-muted-foreground">
|
||||
|
||||
Reference in New Issue
Block a user