Loading skill
Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Global dialogs Redux slice pattern for MVVM dialog state management
.claude/skills/ledgerhq-dialogs-slice/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-02 | ✗→✓ | ▲ Improved | -12% | 0% |
| case-07 | ✗→✓ | ▲ Improved | -40% | 0% |
| case-08 | ✗→✓ | ▲ Improved | -1% | 0% |
| case-22 | ✗→✓ | ▲ Improved | 6% | 0% |
| case-11 | ✗→✓ | ▲ Improved | -12% | 0% |
Centralized Redux state for global dialog open/close, avoiding one slice per dialog.
Use this pattern for dialogs that are:
Default.tsx)Do NOT use this for dialogs that are local to a single component or screen -- prefer a simple useState instead.
renderer/reducers/dialogs.ts manages all global dialog states via a Record<DialogId, boolean>DIALOG_IDS runtime array defines all IDs; DialogId type is derived from it via (typeof DIALOG_IDS)[number]*Dialog.ts file that re-exports typed helpers bound to its IDmvvm/features/GlobalDialogs/index.tsx renders all global dialog components at the app rootAdd the new ID to the DIALOG_IDS array in renderer/reducers/dialogs.ts. The DialogId type updates automatically:
typescriptexport const DIALOG_IDS = ["RELEASE_NOTES", "MY_NEW_DIALOG"] as const; // DialogId is now "RELEASE_NOTES" | "MY_NEW_DIALOG"
Create myFeature/myNewDialog.ts in the feature folder:
typescriptimport { openDialog, closeDialog, selectIsDialogOpen, type DialogId, } from "~/renderer/reducers/dialogs"; import type { State } from "~/renderer/reducers"; const DIALOG_ID: DialogId = "MY_NEW_DIALOG"; export const openMyNewDialog = () => openDialog(DIALOG_ID); export const closeMyNewDialog = () => closeDialog(DIALOG_ID); export const selectIsMyNewDialogOpen = (state: State) => selectIsDialogOpen(state, DIALOG_ID);
typescriptimport { selectIsMyNewDialogOpen, closeMyNewDialog } from "../myNewDialog"; const useMyNewDialogViewModel = () => { const isOpen = useSelector(selectIsMyNewDialogOpen); const dispatch = useDispatch(); const onClose = useCallback(() => dispatch(closeMyNewDialog()), [dispatch]); return { isOpen, onClose }; };
Add the dialog component to mvvm/features/GlobalDialogs/index.tsx:
typescriptimport MyNewDialog from "LLD/features/MyFeature"; const GlobalDialogs = () => ( <> <ModularDialogRoot /> <SendFlowRoot /> <ReleaseNotes /> <MyNewDialog /> </> );
typescriptimport { openMyNewDialog } from "LLD/features/MyFeature/myNewDialog"; dispatch(openMyNewDialog());
useState insteadDIALOG_IDS array (the type is derived automatically)GlobalDialogs/index.tsx, not directly in Default.tsxreducers/index.ts or Default.tsx is needed when adding new dialogsapps/ledger-live-desktop/src/renderer/reducers/dialogs.tsapps/ledger-live-desktop/src/mvvm/features/GlobalDialogs/index.tsxapps/ledger-live-desktop/src/mvvm/features/ReleaseNotes/releaseNotesDialog.tsOther measured skills in the registry, with their headline benchmark lift.