UNPKG

@snipsonian/observable-state

Version:

Observable-state snippets (redux-like)

82 lines (81 loc) 3.45 kB
import isFunction from '@snipsonian/core/es/is/isFunction'; import createStateObserverManager from '../observer/createStateObserverManager'; import { DEFAULT_NR_OF_PARENT_NOTIFICATION_LEVELS_TO_TRIGGER, DEFAULT_PARENT_NOTIFICATIONS_DELIMITER, } from '../observer/extendNotificationsToTrigger'; import { determineInitialState, saveStateToStorage } from './stateStorage'; import { registerStore } from './storeManager'; const LOG_GROUP_LABEL_PREFIX = 'state-change'; const IS_LOG_GROUPING_SUPPORTED = console.group; export default function createObservableStateStore(config) { let state = determineInitialState({ initialState: config.initialState, stateStorageConfig: config.storage, }); const observerManager = createStateObserverManager(); const { nrOfLevels: defaultNrOfParentNotificationLevelsToTrigger = DEFAULT_NR_OF_PARENT_NOTIFICATION_LEVELS_TO_TRIGGER, notificationDelimiter: defaultParentNotificationsDelimiter = DEFAULT_PARENT_NOTIFICATIONS_DELIMITER, } = config.triggerParentNotifications || {}; const store = { getState: () => state, setState: ({ newState, notificationsToTrigger, context, nrOfParentNotificationLevelsToTrigger = defaultNrOfParentNotificationLevelsToTrigger, }) => { const prevState = state; let stateToSet = isToNewState(newState) ? newState(prevState) : newState; if (config.onBeforeStateUpdate) { stateToSet = config.onBeforeStateUpdate({ prevState, newState: stateToSet }); } state = stateToSet; if (config.logStateUpdates || config.logNotifiedObserverNames) { logGroupStart(determineLogGroupLabel(context)); if (context && context.info) { console.log('context', context.info); } if (config.logStateUpdates) { console.log('next state', state); } if (config.logNotifiedObserverNames) { console.log('notifications', notificationsToTrigger); } logGroupEnd(); } saveStateToStorage({ state, stateStorageConfig: config.storage, }); if (config.onAfterStateUpdate) { config.onAfterStateUpdate({ prevState, newState: stateToSet }); } observerManager.notifyObserversOfStateChanges({ notificationsToTrigger, triggerParentNotifications: { nrOfLevels: nrOfParentNotificationLevelsToTrigger, notificationDelimiter: defaultParentNotificationsDelimiter, }, }); }, registerObserver: observerManager.registerObserver, unRegisterObserver: observerManager.unRegisterObserver, }; registerStore(store); return store; } function isToNewState(newState) { return isFunction(newState); } function determineLogGroupLabel(context) { if (context) { return `${LOG_GROUP_LABEL_PREFIX}: ${context.title}`; } return LOG_GROUP_LABEL_PREFIX; } function logGroupStart(title) { if (IS_LOG_GROUPING_SUPPORTED) { console.groupCollapsed(title); } else { console.log(`[${title}]`); } } function logGroupEnd() { if (IS_LOG_GROUPING_SUPPORTED) { console.groupEnd(); } }