0f4bb76b41
Clicking an NPC tile opens description cards (multi-select accordion); Show puts avatars on screen. Optional URL opens a webview tab. Avatar pan in the editor commits on pointer up. Co-authored-by: Cursor <cursoragent@cursor.com>
41 lines
1.1 KiB
TypeScript
41 lines
1.1 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
|
|
import { ipcChannels } from '../../../shared/ipc/contracts';
|
|
import type { NpcsOverlayEvent, NpcsOverlayState } from '../../../shared/types';
|
|
import { getDndApi } from '../dndApi';
|
|
|
|
export function useNpcsOverlayState(): readonly [
|
|
NpcsOverlayState | null,
|
|
{ dispatch: (event: NpcsOverlayEvent) => Promise<void> },
|
|
] {
|
|
const api = getDndApi();
|
|
const [state, setState] = useState<NpcsOverlayState | null>(null);
|
|
|
|
useEffect(() => {
|
|
void api.invoke(ipcChannels.npcsOverlay.getState, {}).then((r) => {
|
|
const next = r.state;
|
|
setState({
|
|
...next,
|
|
inspectNpcIds: next.inspectNpcIds ?? [],
|
|
inspectFocusNpcId: next.inspectFocusNpcId ?? null,
|
|
});
|
|
});
|
|
return api.on(ipcChannels.npcsOverlay.stateChanged, ({ state: next }) => {
|
|
setState({
|
|
...next,
|
|
inspectNpcIds: next.inspectNpcIds ?? [],
|
|
inspectFocusNpcId: next.inspectFocusNpcId ?? null,
|
|
});
|
|
});
|
|
}, [api]);
|
|
|
|
return [
|
|
state,
|
|
{
|
|
dispatch: async (event) => {
|
|
await api.invoke(ipcChannels.npcsOverlay.dispatch, { event });
|
|
},
|
|
},
|
|
] as const;
|
|
}
|