wired-tools: hoist variable-highlight toggle + overlays to the store

Move the highlight feature pair into useWiredCreatorToolsUiStore:
isVariableHighlightActive (toggle UI flag) and variableHighlightOverlays
(computed screen-space overlay positions). The two screen-coords effects
in WiredCreatorToolsView stay where they are (they need React's
lifecycle to install / tear down WiredSelectionVisualizer highlights on
the active room objects) but now write to setVariableHighlightOverlays.

WiredVariablesTabView drops the isVariableHighlightActive +
onToggleVariableHighlight props and consumes the store directly — same
shape as the previous tab-prop reductions on this branch. The toggle
button keeps the same UX (Highlight ↔ Undo) but no longer crosses the
prop boundary.

Direct benefit: closing and reopening the panel while a variable
highlight is active no longer flickers the overlays off and back on —
the active flag + the last-computed overlay set both persist in
zustand and the effect re-runs from the same starting point.

Tests: three new cases on the store (toggle via direct + updater,
overlay replace + clear, close/reopen persistence). 190/190 passing.

variableHighlightObjectsRef stays a useRef inside the component: it
tracks the live PIXI objects WiredSelectionVisualizer drew onto, used
only for the cleanup pass — refs don't trigger renders and don't need
to live in the store.
This commit is contained in:
simoleo89
2026-05-16 12:31:19 +02:00
parent 50fd908d5a
commit 0fc32a1e19
4 changed files with 71 additions and 12 deletions
@@ -22,7 +22,9 @@ const INITIAL = {
selectedFurniLiveState: null,
selectedUser: null,
selectedUserLiveState: null,
selectedUserActionVersion: 0
selectedUserActionVersion: 0,
isVariableHighlightActive: false,
variableHighlightOverlays: []
};
describe('useWiredCreatorToolsUiStore', () =>
@@ -56,6 +58,8 @@ describe('useWiredCreatorToolsUiStore', () =>
expect(state.selectedUser).toBeNull();
expect(state.selectedUserLiveState).toBeNull();
expect(state.selectedUserActionVersion).toBe(0);
expect(state.isVariableHighlightActive).toBe(false);
expect(state.variableHighlightOverlays).toEqual([]);
});
describe('setIsVisible', () =>
@@ -314,4 +318,42 @@ describe('useWiredCreatorToolsUiStore', () =>
expect(useWiredCreatorToolsUiStore.getState().selectedFurni).toEqual(furniSelection);
});
});
describe('variable highlight', () =>
{
const overlay = { itemId: 1, key: 'foo', x: 100, y: 200, screenX: 100, screenY: 200, value: '42', objectId: 7, category: 10 } as never;
it('setIsVariableHighlightActive accepts a direct boolean and a toggle updater', () =>
{
useWiredCreatorToolsUiStore.getState().setIsVariableHighlightActive(true);
expect(useWiredCreatorToolsUiStore.getState().isVariableHighlightActive).toBe(true);
useWiredCreatorToolsUiStore.getState().setIsVariableHighlightActive(prev => !prev);
expect(useWiredCreatorToolsUiStore.getState().isVariableHighlightActive).toBe(false);
useWiredCreatorToolsUiStore.getState().setIsVariableHighlightActive(prev => !prev);
expect(useWiredCreatorToolsUiStore.getState().isVariableHighlightActive).toBe(true);
});
it('setVariableHighlightOverlays replaces the overlay array', () =>
{
useWiredCreatorToolsUiStore.getState().setVariableHighlightOverlays([ overlay ]);
expect(useWiredCreatorToolsUiStore.getState().variableHighlightOverlays).toEqual([ overlay ]);
useWiredCreatorToolsUiStore.getState().setVariableHighlightOverlays([]);
expect(useWiredCreatorToolsUiStore.getState().variableHighlightOverlays).toEqual([]);
});
it('the highlight survives a panel close/reopen lifecycle', () =>
{
useWiredCreatorToolsUiStore.getState().setIsVariableHighlightActive(true);
useWiredCreatorToolsUiStore.getState().setVariableHighlightOverlays([ overlay ]);
useWiredCreatorToolsUiStore.getState().setIsVisible(false);
useWiredCreatorToolsUiStore.getState().setIsVisible(true);
expect(useWiredCreatorToolsUiStore.getState().isVariableHighlightActive).toBe(true);
expect(useWiredCreatorToolsUiStore.getState().variableHighlightOverlays).toEqual([ overlay ]);
});
});
});