104 lines
2.8 KiB
JavaScript
104 lines
2.8 KiB
JavaScript
/**
|
|
* @file helpAutomat.js
|
|
* @description Manages global interactive help badges and active popper state.
|
|
* Persisted in IndexedDB across browser reloads.
|
|
*
|
|
* Upstream Triggers:
|
|
* - UI / User interaction: Calls to `toggle()`, `setEnabled()`, `openPopper()`,
|
|
* and `closePopper()`.
|
|
*/
|
|
|
|
import { Automat } from 'react-automat';
|
|
|
|
/**
|
|
* @typedef {Object} HelpState
|
|
* @property {boolean} enabled Whether interactive help badges are enabled systemwide.
|
|
* @property {string|null} activeHelpId ID of the currently open help popper (only one can be open at a time).
|
|
*/
|
|
|
|
/** @type {HelpState} */
|
|
const initialState = {
|
|
enabled: false,
|
|
activeHelpId: null,
|
|
};
|
|
|
|
/**
|
|
* Global reactive state for systemwide help badges mode.
|
|
* Persisted in IndexedDB so the setting survives page reloads and sessions.
|
|
* Registered as a named automat ('help') on window.__AUTOMATS__.
|
|
*
|
|
* @type {Automat<HelpState>}
|
|
*/
|
|
const helpAutomat = new Automat(
|
|
initialState,
|
|
{
|
|
/**
|
|
* Toggles the systemwide help mode on or off.
|
|
*/
|
|
toggle() {
|
|
helpAutomat.setState((prev) => {
|
|
const nextEnabled = !prev?.enabled;
|
|
return {
|
|
enabled: nextEnabled,
|
|
activeHelpId: nextEnabled ? prev?.activeHelpId ?? null : null,
|
|
};
|
|
});
|
|
},
|
|
/**
|
|
* Explicitly set whether help mode is enabled.
|
|
* @param {boolean} enabled
|
|
*/
|
|
setEnabled(enabled) {
|
|
const nextEnabled = Boolean(enabled);
|
|
helpAutomat.setState((prev) => ({
|
|
enabled: nextEnabled,
|
|
activeHelpId: nextEnabled ? prev?.activeHelpId ?? null : null,
|
|
}));
|
|
},
|
|
/**
|
|
* Open a specific help popper, automatically closing any other currently open popper.
|
|
* @param {string} id
|
|
*/
|
|
openPopper(id) {
|
|
helpAutomat.setState({ activeHelpId: id });
|
|
},
|
|
/**
|
|
* Close the currently active help popper.
|
|
*/
|
|
closePopper() {
|
|
helpAutomat.setState({ activeHelpId: null });
|
|
},
|
|
/**
|
|
* Toggle a specific help popper open/closed.
|
|
* @param {string} id
|
|
*/
|
|
togglePopper(id) {
|
|
helpAutomat.setState((prev) => ({
|
|
activeHelpId: prev?.activeHelpId === id ? null : id,
|
|
}));
|
|
},
|
|
},
|
|
{
|
|
name: 'help',
|
|
persist: true,
|
|
}
|
|
);
|
|
|
|
// Clear active popper on initial boot / persistence hydration
|
|
void helpAutomat.ready.then(() => {
|
|
if (helpAutomat.state?.activeHelpId) {
|
|
helpAutomat.setState({ activeHelpId: null });
|
|
}
|
|
});
|
|
|
|
export default helpAutomat;
|
|
export const {
|
|
toggle: toggleHelp,
|
|
setEnabled: setHelpEnabled,
|
|
openPopper: openHelpPopper,
|
|
closePopper: closeHelpPopper,
|
|
togglePopper: toggleHelpPopper,
|
|
} = helpAutomat.actions;
|
|
export const isHelpEnabled = (state = helpAutomat.state) => Boolean(state?.enabled);
|
|
export const selectActiveHelpId = (state = helpAutomat.state) => state?.activeHelpId ?? null;
|