@elastic/eui
Version:
Elastic UI Component Library
249 lines (239 loc) • 10.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports._resetFlyoutManagerStore = _resetFlyoutManagerStore;
exports.getFlyoutManagerStore = getFlyoutManagerStore;
var _actions = require("./actions");
var _reducer = require("./reducer");
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.
*/
/**
* Events emitted by the flyout manager store for external consumers.
*/
function createStore() {
var initial = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _reducer.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((0, _actions.goToFlyout)(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((0, _actions.goToFlyout)(mainFlyoutId, 'main'));
}
});
}
var _loop2 = function _loop2() {
var entry = history[h];
previousSessionItems.push({
title: entry.title,
iconType: entry.iconType,
onClick: function onClick() {
dispatchFn((0, _actions.goToFlyout)(mainFlyoutId, 'main'));
dispatchFn((0, _actions.goToFlyout)(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((0, _actions.goToFlyout)(mainFlyoutId, 'main'));
}
});
}
};
for (var i = previousSessionsInGroup.length - 1; i >= 0; i--) {
_loop();
}
return [].concat(_toConsumableArray(childItems), previousSessionItems);
};
var dispatch = function dispatch(action) {
var nextState = (0, _reducer.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((0, _actions.addFlyout)(flyoutId, title, level, size, historyKey, iconType, minWidth));
},
closeFlyout: function closeFlyout(flyoutId) {
return dispatch((0, _actions.closeFlyout)(flyoutId));
},
closeAllFlyouts: function closeAllFlyouts() {
return dispatch((0, _actions.closeAllFlyouts)());
},
setActiveFlyout: function setActiveFlyout(flyoutId) {
return dispatch((0, _actions.setActiveFlyout)(flyoutId));
},
setFlyoutWidth: function setFlyoutWidth(flyoutId, width) {
return dispatch((0, _actions.setFlyoutWidth)(flyoutId, width));
},
setPagination: function setPagination(flyoutId, pagination) {
return dispatch((0, _actions.setPagination)(flyoutId, pagination));
},
setPushPadding: function setPushPadding(side, width) {
return dispatch((0, _actions.setPushPadding)(side, width));
},
setContainerElement: function setContainerElement(element) {
return dispatch((0, _actions.setContainerElement)(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 = (0, _actions.goBack)();
var nextState = (0, _reducer.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((0, _actions.goToFlyout)(flyoutId, level));
},
addUnmanagedFlyout: function addUnmanagedFlyout(flyoutId) {
return dispatch((0, _actions.addUnmanagedFlyout)(flyoutId));
},
closeUnmanagedFlyout: function closeUnmanagedFlyout(flyoutId) {
return dispatch((0, _actions.closeUnmanagedFlyout)(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.
*/
function getFlyoutManagerStore() {
if (!storeInstance) {
storeInstance = createStore();
}
return storeInstance;
}
/**
* For testing purposes - allows resetting the store
*/
function _resetFlyoutManagerStore() {
storeInstance = null;
}