mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-20 07:26:19 +00:00
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:
@@ -77,8 +77,10 @@ export const WiredCreatorToolsView: FC<{}> = () =>
|
|||||||
const setIsManagedGiveOpen = useWiredCreatorToolsUiStore(s => s.setIsManagedGiveOpen);
|
const setIsManagedGiveOpen = useWiredCreatorToolsUiStore(s => s.setIsManagedGiveOpen);
|
||||||
const [ managedGiveVariableItemId, setManagedGiveVariableItemId ] = useState(0);
|
const [ managedGiveVariableItemId, setManagedGiveVariableItemId ] = useState(0);
|
||||||
const [ managedGiveValue, setManagedGiveValue ] = useState('0');
|
const [ managedGiveValue, setManagedGiveValue ] = useState('0');
|
||||||
const [ isVariableHighlightActive, setIsVariableHighlightActive ] = useState(false);
|
const isVariableHighlightActive = useWiredCreatorToolsUiStore(s => s.isVariableHighlightActive);
|
||||||
const [ variableHighlightOverlays, setVariableHighlightOverlays ] = useState<VariableHighlightOverlay[]>([]);
|
const setIsVariableHighlightActive = useWiredCreatorToolsUiStore(s => s.setIsVariableHighlightActive);
|
||||||
|
const variableHighlightOverlays = useWiredCreatorToolsUiStore(s => s.variableHighlightOverlays);
|
||||||
|
const setVariableHighlightOverlays = useWiredCreatorToolsUiStore(s => s.setVariableHighlightOverlays);
|
||||||
const variableHighlightObjectsRef = useRef<Array<{ category: number; objectId: number; }>>([]);
|
const variableHighlightObjectsRef = useRef<Array<{ category: number; objectId: number; }>>([]);
|
||||||
const shouldPauseVariableSnapshotRefresh = (!!editingVariable || !!editingManagedHolderVariableId || isInspectionGiveOpen || isManagedGiveOpen);
|
const shouldPauseVariableSnapshotRefresh = (!!editingVariable || !!editingManagedHolderVariableId || isInspectionGiveOpen || isManagedGiveOpen);
|
||||||
const [ selectedVariableKeys, setSelectedVariableKeys ] = useState<Record<VariablesElementType, string>>({
|
const [ selectedVariableKeys, setSelectedVariableKeys ] = useState<Record<VariablesElementType, string>>({
|
||||||
@@ -3145,8 +3147,6 @@ export const WiredCreatorToolsView: FC<{}> = () =>
|
|||||||
selectedVariableDefinition={ selectedVariableDefinition }
|
selectedVariableDefinition={ selectedVariableDefinition }
|
||||||
onPickVariable={ key => setSelectedVariableKeys(prev => ({ ...prev, [variablesType]: key })) }
|
onPickVariable={ key => setSelectedVariableKeys(prev => ({ ...prev, [variablesType]: key })) }
|
||||||
canVariableHighlight={ canVariableHighlight }
|
canVariableHighlight={ canVariableHighlight }
|
||||||
isVariableHighlightActive={ isVariableHighlightActive }
|
|
||||||
onToggleVariableHighlight={ () => setIsVariableHighlightActive(value => !value) }
|
|
||||||
variableManageCanOpen={ variableManageCanOpen }
|
variableManageCanOpen={ variableManageCanOpen }
|
||||||
onOpenManagePanel={ () =>
|
onOpenManagePanel={ () =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ export interface WiredVariablesTabViewProps
|
|||||||
selectedVariableDefinition: VariableDefinition | null;
|
selectedVariableDefinition: VariableDefinition | null;
|
||||||
onPickVariable: (key: string) => void;
|
onPickVariable: (key: string) => void;
|
||||||
canVariableHighlight: boolean;
|
canVariableHighlight: boolean;
|
||||||
isVariableHighlightActive: boolean;
|
|
||||||
onToggleVariableHighlight: () => void;
|
|
||||||
variableManageCanOpen: boolean;
|
variableManageCanOpen: boolean;
|
||||||
onOpenManagePanel: () => void;
|
onOpenManagePanel: () => void;
|
||||||
selectedVariableProperties: { key: string; value: string; }[];
|
selectedVariableProperties: { key: string; value: string; }[];
|
||||||
@@ -30,8 +28,6 @@ export const WiredVariablesTabView: FC<WiredVariablesTabViewProps> = ({
|
|||||||
selectedVariableDefinition,
|
selectedVariableDefinition,
|
||||||
onPickVariable,
|
onPickVariable,
|
||||||
canVariableHighlight,
|
canVariableHighlight,
|
||||||
isVariableHighlightActive,
|
|
||||||
onToggleVariableHighlight,
|
|
||||||
variableManageCanOpen,
|
variableManageCanOpen,
|
||||||
onOpenManagePanel,
|
onOpenManagePanel,
|
||||||
selectedVariableProperties,
|
selectedVariableProperties,
|
||||||
@@ -40,6 +36,8 @@ export const WiredVariablesTabView: FC<WiredVariablesTabViewProps> = ({
|
|||||||
{
|
{
|
||||||
const variablesType = useWiredCreatorToolsUiStore(s => s.variablesType);
|
const variablesType = useWiredCreatorToolsUiStore(s => s.variablesType);
|
||||||
const setVariablesType = useWiredCreatorToolsUiStore(s => s.setVariablesType);
|
const setVariablesType = useWiredCreatorToolsUiStore(s => s.setVariablesType);
|
||||||
|
const isVariableHighlightActive = useWiredCreatorToolsUiStore(s => s.isVariableHighlightActive);
|
||||||
|
const setIsVariableHighlightActive = useWiredCreatorToolsUiStore(s => s.setIsVariableHighlightActive);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-3 min-h-[360px] flex gap-4">
|
<div className="p-3 min-h-[360px] flex gap-4">
|
||||||
@@ -83,7 +81,7 @@ export const WiredVariablesTabView: FC<WiredVariablesTabViewProps> = ({
|
|||||||
<Button
|
<Button
|
||||||
disabled={ !canVariableHighlight }
|
disabled={ !canVariableHighlight }
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
onClick={ onToggleVariableHighlight }>
|
onClick={ () => setIsVariableHighlightActive(value => !value) }>
|
||||||
{ isVariableHighlightActive ? 'Undo' : 'Highlight' }
|
{ isVariableHighlightActive ? 'Undo' : 'Highlight' }
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -22,7 +22,9 @@ const INITIAL = {
|
|||||||
selectedFurniLiveState: null,
|
selectedFurniLiveState: null,
|
||||||
selectedUser: null,
|
selectedUser: null,
|
||||||
selectedUserLiveState: null,
|
selectedUserLiveState: null,
|
||||||
selectedUserActionVersion: 0
|
selectedUserActionVersion: 0,
|
||||||
|
isVariableHighlightActive: false,
|
||||||
|
variableHighlightOverlays: []
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('useWiredCreatorToolsUiStore', () =>
|
describe('useWiredCreatorToolsUiStore', () =>
|
||||||
@@ -56,6 +58,8 @@ describe('useWiredCreatorToolsUiStore', () =>
|
|||||||
expect(state.selectedUser).toBeNull();
|
expect(state.selectedUser).toBeNull();
|
||||||
expect(state.selectedUserLiveState).toBeNull();
|
expect(state.selectedUserLiveState).toBeNull();
|
||||||
expect(state.selectedUserActionVersion).toBe(0);
|
expect(state.selectedUserActionVersion).toBe(0);
|
||||||
|
expect(state.isVariableHighlightActive).toBe(false);
|
||||||
|
expect(state.variableHighlightOverlays).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('setIsVisible', () =>
|
describe('setIsVisible', () =>
|
||||||
@@ -314,4 +318,42 @@ describe('useWiredCreatorToolsUiStore', () =>
|
|||||||
expect(useWiredCreatorToolsUiStore.getState().selectedFurni).toEqual(furniSelection);
|
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 ]);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { createNitroStore } from '../../state/createNitroStore';
|
import { createNitroStore } from '../../state/createNitroStore';
|
||||||
import { createEmptyMonitorSnapshot } from './WiredCreatorTools.helpers';
|
import { createEmptyMonitorSnapshot } from './WiredCreatorTools.helpers';
|
||||||
import { InspectionElementType, InspectionFurniLiveState, InspectionFurniSelection, InspectionUserLiveState, InspectionUserSelection, MonitorSnapshot, VariablesElementType, WiredToolsTab } from './WiredCreatorTools.types';
|
import { InspectionElementType, InspectionFurniLiveState, InspectionFurniSelection, InspectionUserLiveState, InspectionUserSelection, MonitorSnapshot, VariableHighlightOverlay, VariablesElementType, WiredToolsTab } from './WiredCreatorTools.types';
|
||||||
|
|
||||||
type MonitorSeverityFilter = 'ALL' | 'ERROR' | 'WARNING';
|
type MonitorSeverityFilter = 'ALL' | 'ERROR' | 'WARNING';
|
||||||
type Updater<T> = T | ((prev: T) => T);
|
type Updater<T> = T | ((prev: T) => T);
|
||||||
@@ -55,6 +55,16 @@ interface WiredCreatorToolsUiState
|
|||||||
selectedUserLiveState: InspectionUserLiveState | null;
|
selectedUserLiveState: InspectionUserLiveState | null;
|
||||||
selectedUserActionVersion: number;
|
selectedUserActionVersion: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variable highlight feature: the toggle UI flag (`isActive`) plus
|
||||||
|
* the computed screen-space overlays the parent's effect populates
|
||||||
|
* from `WiredSelectionVisualizer` + `GetRoomObjectScreenLocation`.
|
||||||
|
* Stored together so a panel close/reopen cycle keeps the active
|
||||||
|
* highlight visible instead of re-toggling from scratch.
|
||||||
|
*/
|
||||||
|
isVariableHighlightActive: boolean;
|
||||||
|
variableHighlightOverlays: VariableHighlightOverlay[];
|
||||||
|
|
||||||
setIsVisible: (next: Updater<boolean>) => void;
|
setIsVisible: (next: Updater<boolean>) => void;
|
||||||
setActiveTab: (next: WiredToolsTab) => void;
|
setActiveTab: (next: WiredToolsTab) => void;
|
||||||
setInspectionType: (next: InspectionElementType) => void;
|
setInspectionType: (next: InspectionElementType) => void;
|
||||||
@@ -81,6 +91,9 @@ interface WiredCreatorToolsUiState
|
|||||||
setSelectedUser: (next: InspectionUserSelection | null) => void;
|
setSelectedUser: (next: InspectionUserSelection | null) => void;
|
||||||
setSelectedUserLiveState: (next: Updater<InspectionUserLiveState | null>) => void;
|
setSelectedUserLiveState: (next: Updater<InspectionUserLiveState | null>) => void;
|
||||||
setSelectedUserActionVersion: (next: Updater<number>) => void;
|
setSelectedUserActionVersion: (next: Updater<number>) => void;
|
||||||
|
|
||||||
|
setIsVariableHighlightActive: (next: Updater<boolean>) => void;
|
||||||
|
setVariableHighlightOverlays: (next: VariableHighlightOverlay[]) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useWiredCreatorToolsUiStore = createNitroStore<WiredCreatorToolsUiState>()((set) => ({
|
export const useWiredCreatorToolsUiStore = createNitroStore<WiredCreatorToolsUiState>()((set) => ({
|
||||||
@@ -110,6 +123,9 @@ export const useWiredCreatorToolsUiStore = createNitroStore<WiredCreatorToolsUiS
|
|||||||
selectedUserLiveState: null,
|
selectedUserLiveState: null,
|
||||||
selectedUserActionVersion: 0,
|
selectedUserActionVersion: 0,
|
||||||
|
|
||||||
|
isVariableHighlightActive: false,
|
||||||
|
variableHighlightOverlays: [],
|
||||||
|
|
||||||
setIsVisible: (next) => set(state => ({ isVisible: apply(state.isVisible, next) })),
|
setIsVisible: (next) => set(state => ({ isVisible: apply(state.isVisible, next) })),
|
||||||
setActiveTab: (next) => set({ activeTab: next }),
|
setActiveTab: (next) => set({ activeTab: next }),
|
||||||
setInspectionType: (next) => set({ inspectionType: next }),
|
setInspectionType: (next) => set({ inspectionType: next }),
|
||||||
@@ -135,5 +151,8 @@ export const useWiredCreatorToolsUiStore = createNitroStore<WiredCreatorToolsUiS
|
|||||||
setSelectedFurniLiveState: (next) => set(state => ({ selectedFurniLiveState: apply(state.selectedFurniLiveState, next) })),
|
setSelectedFurniLiveState: (next) => set(state => ({ selectedFurniLiveState: apply(state.selectedFurniLiveState, next) })),
|
||||||
setSelectedUser: (next) => set({ selectedUser: next }),
|
setSelectedUser: (next) => set({ selectedUser: next }),
|
||||||
setSelectedUserLiveState: (next) => set(state => ({ selectedUserLiveState: apply(state.selectedUserLiveState, next) })),
|
setSelectedUserLiveState: (next) => set(state => ({ selectedUserLiveState: apply(state.selectedUserLiveState, next) })),
|
||||||
setSelectedUserActionVersion: (next) => set(state => ({ selectedUserActionVersion: apply(state.selectedUserActionVersion, next) }))
|
setSelectedUserActionVersion: (next) => set(state => ({ selectedUserActionVersion: apply(state.selectedUserActionVersion, next) })),
|
||||||
|
|
||||||
|
setIsVariableHighlightActive: (next) => set(state => ({ isVariableHighlightActive: apply(state.isVariableHighlightActive, next) })),
|
||||||
|
setVariableHighlightOverlays: (next) => set({ variableHighlightOverlays: next })
|
||||||
}));
|
}));
|
||||||
|
|||||||
Reference in New Issue
Block a user