UNPKG

@elastic/eui

Version:

Elastic UI Component Library

245 lines (234 loc) 10.6 kB
function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); } function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0 and the Server Side Public License, v 1; you may not use this file except * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ import { addFlyout as addFlyoutAction, closeFlyout as closeFlyoutAction, closeAllFlyouts as closeAllFlyoutsAction, setActiveFlyout as setActiveFlyoutAction, setFlyoutWidth as setFlyoutWidthAction, setPagination as setPaginationAction, setPushPadding as setPushPaddingAction, goBack as goBackAction, goToFlyout as goToFlyoutAction, addUnmanagedFlyout as addUnmanagedFlyoutAction, closeUnmanagedFlyout as closeUnmanagedFlyoutAction, setContainerElement as setContainerElementAction } from './actions'; import { flyoutManagerReducer, initialState } from './reducer'; /** * Events emitted by the flyout manager store for external consumers. */ function createStore() { var initial = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : initialState; var currentState = initial; var listeners = new Set(); var eventListeners = new Set(); // Transient, one-shot close annotations keyed by flyoutId. `goBack` stamps the // flyouts it removes so the managed flyout can report `navigation-back`; any // other removal (e.g. closeAllFlyouts cascade) leaves no stamp and defaults to // `navigation-cascade`. Kept off reducer state because it is a per-close // annotation, not persistent state. var pendingCloseMeta = new Map(); var getState = function getState() { return currentState; }; var subscribe = function subscribe(listener) { listeners.add(listener); return function () { listeners.delete(listener); }; }; var subscribeToEvents = function subscribeToEvents(listener) { eventListeners.add(listener); return function () { eventListeners.delete(listener); }; }; var emitEvent = function emitEvent(event) { eventListeners.forEach(function (listener) { listener(event); }); }; // The onClick handlers won't execute until after store is fully assigned. // eslint-disable-next-line prefer-const -- Forward declaration requires 'let' not 'const' var store; var computeHistoryItems = function computeHistoryItems(dispatchFn) { var _currentSession$child; var currentSessionIndex = currentState.sessions.length - 1; var currentSession = currentSessionIndex >= 0 ? currentState.sessions[currentSessionIndex] : null; if (!currentSession) { return []; } var previousSessions = currentState.sessions.slice(0, currentSessionIndex); // Only include sessions in the same history group (same historyKey reference) var previousSessionsInGroup = previousSessions.filter(function (session) { return session.historyKey === currentSession.historyKey; }); var childHistory = (_currentSession$child = currentSession.childHistory) !== null && _currentSession$child !== void 0 ? _currentSession$child : []; var childItems = _toConsumableArray(childHistory).reverse().map(function (entry) { return { title: entry.title, iconType: entry.iconType, onClick: function onClick() { dispatchFn(goToFlyoutAction(entry.flyoutId, 'child')); } }; }); // Previous sessions (same group): list each session's current child then its child history var previousSessionItems = []; var _loop = function _loop() { var _session$childHistory; var session = previousSessionsInGroup[i]; var mainTitle = session.title; var mainFlyoutId = session.mainFlyoutId; var history = (_session$childHistory = session.childHistory) !== null && _session$childHistory !== void 0 ? _session$childHistory : []; var hasChildren = session.childFlyoutId != null && session.childTitle != null || history.length > 0; if (session.childFlyoutId && session.childTitle) { previousSessionItems.push({ title: session.childTitle, iconType: session.childIconType, onClick: function onClick() { dispatchFn(goToFlyoutAction(mainFlyoutId, 'main')); } }); } var _loop2 = function _loop2() { var entry = history[h]; previousSessionItems.push({ title: entry.title, iconType: entry.iconType, onClick: function onClick() { dispatchFn(goToFlyoutAction(mainFlyoutId, 'main')); dispatchFn(goToFlyoutAction(entry.flyoutId, 'child')); } }); }; for (var h = history.length - 1; h >= 0; h--) { _loop2(); } if (!hasChildren) { previousSessionItems.push({ title: mainTitle, iconType: session.iconType, onClick: function onClick() { dispatchFn(goToFlyoutAction(mainFlyoutId, 'main')); } }); } }; for (var i = previousSessionsInGroup.length - 1; i >= 0; i--) { _loop(); } return [].concat(_toConsumableArray(childItems), previousSessionItems); }; var dispatch = function dispatch(action) { var nextState = flyoutManagerReducer(currentState, action); if (nextState !== currentState) { var previousSessions = currentState.sessions; currentState = nextState; // Recompute history items eagerly if sessions changed // This ensures stable references and avoids stale closures if (nextState.sessions !== previousSessions) { store.historyItems = computeHistoryItems(dispatch); // Detect removed sessions and emit CLOSE_SESSION events var nextSessionIds = new Set(nextState.sessions.map(function (s) { return s.mainFlyoutId; })); previousSessions.forEach(function (session) { if (!nextSessionIds.has(session.mainFlyoutId)) { emitEvent({ type: 'CLOSE_SESSION', session: session }); } }); } listeners.forEach(function (l) { l(); }); } }; store = { getState: getState, subscribe: subscribe, subscribeToEvents: subscribeToEvents, dispatch: dispatch, addFlyout: function addFlyout(flyoutId, title, level, size, historyKey, iconType, minWidth) { return dispatch(addFlyoutAction(flyoutId, title, level, size, historyKey, iconType, minWidth)); }, closeFlyout: function closeFlyout(flyoutId) { return dispatch(closeFlyoutAction(flyoutId)); }, closeAllFlyouts: function closeAllFlyouts() { return dispatch(closeAllFlyoutsAction()); }, setActiveFlyout: function setActiveFlyout(flyoutId) { return dispatch(setActiveFlyoutAction(flyoutId)); }, setFlyoutWidth: function setFlyoutWidth(flyoutId, width) { return dispatch(setFlyoutWidthAction(flyoutId, width)); }, setPagination: function setPagination(flyoutId, pagination) { return dispatch(setPaginationAction(flyoutId, pagination)); }, setPushPadding: function setPushPadding(side, width) { return dispatch(setPushPaddingAction(side, width)); }, setContainerElement: function setContainerElement(element) { return dispatch(setContainerElementAction(element)); }, goBack: function goBack() { // Stamp the flyouts goBack removes as `navigation-back` (vs. the default // `navigation-cascade`) BEFORE dispatching. dispatch synchronously flushes // subscribers, which can consume the meta during unmount, so peek the pure // reducer to learn which flyouts go away and stamp them first. var action = goBackAction(); var nextState = flyoutManagerReducer(currentState, action); var remaining = new Set(nextState.flyouts.map(function (f) { return f.flyoutId; })); currentState.flyouts.forEach(function (f) { if (!remaining.has(f.flyoutId)) { pendingCloseMeta.set(f.flyoutId, { reason: 'navigation-back' }); } }); dispatch(action); }, goToFlyout: function goToFlyout(flyoutId, level) { return dispatch(goToFlyoutAction(flyoutId, level)); }, addUnmanagedFlyout: function addUnmanagedFlyout(flyoutId) { return dispatch(addUnmanagedFlyoutAction(flyoutId)); }, closeUnmanagedFlyout: function closeUnmanagedFlyout(flyoutId) { return dispatch(closeUnmanagedFlyoutAction(flyoutId)); }, consumeCloseMeta: function consumeCloseMeta(flyoutId) { var meta = pendingCloseMeta.get(flyoutId); if (meta) { pendingCloseMeta.delete(flyoutId); } return meta; }, historyItems: computeHistoryItems(dispatch) // Initialize with current state }; return store; } // Module-level singleton. A necessary trade-off to avoid global namespace pollution or the need for a third-party library. var storeInstance = null; /** * Returns a singleton store instance shared across all React roots within the same JS context. * Uses module-level singleton to ensure deduplication even if modules are loaded twice. */ export function getFlyoutManagerStore() { if (!storeInstance) { storeInstance = createStore(); } return storeInstance; } /** * For testing purposes - allows resetting the store */ export function _resetFlyoutManagerStore() { storeInstance = null; }