UNPKG

@openmrs/esm-state

Version:

Frontend stores & state management for OpenMRS

100 lines (99 loc) 3.44 kB
/** @module @category Store */ import { shallowEqual } from "@openmrs/esm-utils"; import { createStore } from "zustand/vanilla"; import { isTestEnvironment } from "./utils.js"; const availableStores = {}; // spaEnv isn't available immediately. Wait a bit before making stores available // on window in development mode. globalThis.setTimeout?.(()=>{ if (typeof window !== 'undefined' && window.spaEnv === 'development') { window['stores'] = availableStores; } }, 1000); /** * Creates a Zustand store. * * @param name A name by which the store can be looked up later. * Must be unique across the entire application. * @param initialState An object which will be the initial state of the store. * @returns The newly created store. */ export function createGlobalStore(name, initialState) { const available = availableStores[name]; if (available) { if (available.active) { if (!isTestEnvironment()) { console.error(`Attempted to override the existing store ${name}. Make sure that stores are only created once.`); } } else { available.value.setState(initialState, true); } available.active = true; return available.value; } else { const store = createStore()(()=>initialState); availableStores[name] = { value: store, active: true }; return store; } } /** * Registers an existing Zustand store. * * @param name A name by which the store can be looked up later. * Must be unique across the entire application. * @param store The Zustand store to use for this. * @returns The newly registered store. */ export function registerGlobalStore(name, store) { const available = availableStores[name]; if (available) { if (available.active) { if (!isTestEnvironment()) { console.error(`Attempted to override the existing store ${name}. Make sure that stores are only created once.`); } } else { available.value = store; } available.active = true; return available.value; } else { availableStores[name] = { value: store, active: true }; return store; } } /** * Returns the existing store named `name`, * or creates a new store named `name` if none exists. * * @param name The name of the store to look up. * @param fallbackState The initial value of the new store if no store named `name` exists. * @returns The found or newly created store. */ export function getGlobalStore(name, fallbackState) { const available = availableStores[name]; if (!available) { const store = createStore()(()=>fallbackState ?? {}); availableStores[name] = { value: store, active: false }; return store; } return available.value; } export function subscribeTo(...args) { const [store, select, handle] = args; const handler = typeof handle === 'undefined' ? select : handle; const selector = typeof handle === 'undefined' ? (state)=>state : select; let previous = selector(store.getState()); handler(previous); return store.subscribe((state)=>{ const current = selector(state); if (!shallowEqual(previous, current)) { previous = current; handler(current); } }); }