export interface ApplicationWorkspaceSnapshot { navigationOpen: boolean; activeView: ViewId | null; contentOpen: boolean; contentExpanded: boolean; } export interface ApplicationWorkspaceController { getState: () => ApplicationWorkspaceSnapshot; openNavigation: () => void; toggleNavigation: () => void; closeNavigation: () => void; openView: (view: ViewId) => void; closeView: () => void; setContentExpanded: (expanded: boolean) => void; } export interface ApplicationWorkspaceOptions { root?: HTMLElement; navigationOpen?: boolean; activeView?: ViewId | null; contentExpanded?: boolean; onChange?: (state: ApplicationWorkspaceSnapshot) => void; } export function createApplicationWorkspaceController({ root, navigationOpen = false, activeView = null, contentExpanded = true, onChange, }: ApplicationWorkspaceOptions = {}): ApplicationWorkspaceController { let state: ApplicationWorkspaceSnapshot = { navigationOpen: navigationOpen || activeView !== null, activeView, contentOpen: activeView !== null, contentExpanded, }; const commit = (patch: Partial>) => { state = { ...state, ...patch }; state.contentOpen = state.activeView !== null; root?.toggleAttribute("data-navigation-open", state.navigationOpen); root?.toggleAttribute("data-content-open", state.contentOpen); root?.toggleAttribute("data-content-expanded", state.contentOpen && state.contentExpanded); onChange?.({ ...state }); }; commit({}); return { getState: () => ({ ...state }), openNavigation: () => commit({ navigationOpen: true }), toggleNavigation: () => commit({ navigationOpen: !state.navigationOpen, activeView: state.navigationOpen ? null : state.activeView }), closeNavigation: () => commit({ navigationOpen: false, activeView: null }), openView: (view) => commit({ navigationOpen: true, activeView: view, contentExpanded: true }), closeView: () => commit({ activeView: null }), setContentExpanded: (expanded) => commit({ contentExpanded: expanded }), }; }