@atlaskit/navigation-system
Version:
The latest navigation system for Atlassian apps.
324 lines (322 loc) • 14.5 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _typeof = require("@babel/runtime/helpers/typeof");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.LayoutAreaSizingProvider = LayoutAreaSizingProvider;
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _react = _interopRequireWildcard(require("react"));
var _bindEventListener = require("bind-event-listener");
var _constants = require("./constants");
var _layoutAreaSizingContext = require("./layout-area-sizing-context");
var _layoutAreaStateContexts = require("./layout-area-state-contexts");
var _useCssLayoutAreaStates = require("./use-css-layout-area-states");
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
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 _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; }
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
/**
* Stable, synchronous boundary for SSR content. The drag/cascade implementation
* is a sibling, not a replacement wrapper, so loading it cannot remount the app.
* CSS handles initial and responsive geometry; only splitter interaction requests
* the asynchronous chunk. The eager observer reads modes without changing widths.
*/
function LayoutAreaSizingProvider(_ref) {
var _states$sideNav$mode, _states$sideNav, _states$chatPanel$mo, _states$chatPanel;
var children = _ref.children,
layoutRef = _ref.layoutRef;
var _useState = (0, _react.useState)(null),
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
Runtime = _useState2[0],
setRuntime = _useState2[1];
var _useState3 = (0, _react.useState)({}),
_useState4 = (0, _slicedToArray2.default)(_useState3, 2),
states = _useState4[0],
setStates = _useState4[1];
var actions = (0, _react.useRef)(null);
var configs = (0, _react.useRef)({});
var _useState5 = (0, _react.useState)(null),
_useState6 = (0, _slicedToArray2.default)(_useState5, 2),
lastOpenedOverlay = _useState6[0],
setLastOpenedOverlay = _useState6[1];
var _useState7 = (0, _react.useState)(0),
_useState8 = (0, _slicedToArray2.default)(_useState7, 2),
configRevision = _useState8[0],
setConfigRevision = _useState8[1];
var cssModes = (0, _useCssLayoutAreaStates.useCssLayoutAreaStates)(layoutRef, configRevision, Runtime === null);
var sideNavMode = (_states$sideNav$mode = (_states$sideNav = states['side-nav']) === null || _states$sideNav === void 0 ? void 0 : _states$sideNav.mode) !== null && _states$sideNav$mode !== void 0 ? _states$sideNav$mode : cssModes['side-nav'];
var chatPanelMode = (_states$chatPanel$mo = (_states$chatPanel = states['chat-panel']) === null || _states$chatPanel === void 0 ? void 0 : _states$chatPanel.mode) !== null && _states$chatPanel$mo !== void 0 ? _states$chatPanel$mo : cssModes['chat-panel'];
// Overlay dismissal is available before the sizing chunk loads. Keep the open
// order here too: replaying registrations into the runtime loses that order.
(0, _react.useEffect)(function () {
var inlineChatQuery = window.matchMedia('(min-width: 40rem)');
var dismissOlderOverlay = function dismissOlderOverlay() {
var _olderOverlay$onReque;
var sideNav = configs.current['side-nav'];
var chatPanel = configs.current['chat-panel'];
if (!(sideNav !== null && sideNav !== void 0 && sideNav.isOpen) || !(chatPanel !== null && chatPanel !== void 0 && chatPanel.isOpen) || !lastOpenedOverlay) {
return;
}
// Before allocation, CSS puts both areas in overlay below 40rem. Once
// sizing is active, also honour overlays caused by custom widths/slots.
if (inlineChatQuery.matches && (sideNavMode !== 'overlay' || chatPanelMode !== 'overlay')) {
return;
}
var olderOverlay = lastOpenedOverlay === 'side-nav' ? chatPanel : sideNav;
(_olderOverlay$onReque = olderOverlay.onRequestClose) === null || _olderOverlay$onReque === void 0 || _olderOverlay$onReque.call(olderOverlay);
};
dismissOlderOverlay();
return (0, _bindEventListener.bind)(inlineChatQuery, {
type: 'change',
listener: dismissOlderOverlay
});
}, [chatPanelMode, lastOpenedOverlay, sideNavMode]);
var splitters = (0, _react.useRef)(new Set());
var registerSplitter = (0, _react.useCallback)(function (element) {
splitters.current.add(element);
return function () {
splitters.current.delete(element);
};
}, []);
var mainMinWidth = (0, _react.useRef)(_constants.defaultMainMinWidth);
var loadRef = (0, _react.useRef)(function () {});
var ready = (0, _react.useRef)(false);
var waiting = (0, _react.useRef)([]);
var pending = (0, _react.useRef)([]);
var prepareResize = (0, _react.useCallback)(function () {
if (ready.current) {
return Promise.resolve(true);
}
return new Promise(function (resolve) {
waiting.current.push(resolve);
loadRef.current();
});
}, []);
(0, _react.useEffect)(function () {
var root = layoutRef === null || layoutRef === void 0 ? void 0 : layoutRef.current;
if (!root) {
return;
}
var cancelled = false;
var loading = false;
var waitingForRuntime = waiting.current;
var load = function load() {
if (loading) {
return;
}
loading = true;
void Promise.resolve().then(function () {
return _interopRequireWildcard(require( /* webpackChunkName: "@atlaskit-internal_navigation-layout-sizing" */'./layout-area-sizing-runtime'));
}).then(function (_ref2) {
var LayoutAreaSizingRuntime = _ref2.LayoutAreaSizingRuntime;
if (!cancelled) {
setRuntime(function () {
return LayoutAreaSizingRuntime;
});
}
}, function () {
loading = false;
pending.current = [];
var _iterator = _createForOfIteratorHelper(waitingForRuntime.splice(0)),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var resolve = _step.value;
resolve(false);
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
});
};
loadRef.current = load;
var loadForSplitter = function loadForSplitter(event) {
if (!(event.target instanceof Node)) {
return;
}
var _iterator2 = _createForOfIteratorHelper(splitters.current),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var splitter = _step2.value;
if (splitter.contains(event.target)) {
load();
return;
}
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
};
var unbindRoot = (0, _bindEventListener.bindAll)(root, [{
type: 'pointerover',
listener: loadForSplitter,
options: {
passive: true
}
}, {
type: 'focusin',
listener: loadForSplitter
}, {
type: 'pointerdown',
listener: loadForSplitter,
options: {
passive: true
}
}]);
return function () {
cancelled = true;
ready.current = false;
pending.current = [];
var _iterator3 = _createForOfIteratorHelper(waitingForRuntime.splice(0)),
_step3;
try {
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
var resolve = _step3.value;
resolve(false);
}
} catch (err) {
_iterator3.e(err);
} finally {
_iterator3.f();
}
loadRef.current = function () {};
unbindRoot();
};
}, [layoutRef]);
var onReady = (0, _react.useCallback)(function (runtime) {
actions.current = runtime;
if (runtime) {
runtime.setMainMinWidth(mainMinWidth.current);
var _iterator4 = _createForOfIteratorHelper(['side-nav', 'panel', 'chat-panel']),
_step4;
try {
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
var area = _step4.value;
var config = configs.current[area];
if (config) {
runtime.registerArea(area, config);
}
}
} catch (err) {
_iterator4.e(err);
} finally {
_iterator4.f();
}
}
}, []);
var onUpdate = (0, _react.useCallback)(function (next) {
setStates(next);
var runtime = actions.current;
if (runtime && Object.values(next).some(Boolean)) {
ready.current = true;
var _iterator5 = _createForOfIteratorHelper(pending.current.splice(0)),
_step5;
try {
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
var action = _step5.value;
action(runtime);
}
} catch (err) {
_iterator5.e(err);
} finally {
_iterator5.f();
}
var _iterator6 = _createForOfIteratorHelper(waiting.current.splice(0)),
_step6;
try {
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
var resolve = _step6.value;
resolve(true);
}
} catch (err) {
_iterator6.e(err);
} finally {
_iterator6.f();
}
}
}, []);
var dispatch = (0, _react.useCallback)(function (action) {
if (ready.current && actions.current) {
action(actions.current);
} else {
pending.current.push(action);
loadRef.current();
}
}, []);
var value = (0, _react.useMemo)(function () {
return {
prepareResize: prepareResize,
registerSplitter: registerSplitter,
registerArea: function registerArea(area, config) {
var _configs$current$area, _actions$current;
if (area !== 'panel' && config.isOpen && !((_configs$current$area = configs.current[area]) !== null && _configs$current$area !== void 0 && _configs$current$area.isOpen)) {
setLastOpenedOverlay(area);
}
configs.current[area] = config;
setConfigRevision(function (revision) {
return revision + 1;
});
(_actions$current = actions.current) === null || _actions$current === void 0 || _actions$current.registerArea(area, config);
},
unregisterArea: function unregisterArea(area) {
var _actions$current2;
delete configs.current[area];
setConfigRevision(function (revision) {
return revision + 1;
});
(_actions$current2 = actions.current) === null || _actions$current2 === void 0 || _actions$current2.unregisterArea(area);
},
setMainMinWidth: function setMainMinWidth(width) {
var _actions$current3;
if (mainMinWidth.current !== width) {
setConfigRevision(function (revision) {
return revision + 1;
});
}
mainMinWidth.current = width;
(_actions$current3 = actions.current) === null || _actions$current3 === void 0 || _actions$current3.setMainMinWidth(width);
},
getResizeBounds: function getResizeBounds(area) {
var _actions$current4;
return (_actions$current4 = actions.current) === null || _actions$current4 === void 0 ? void 0 : _actions$current4.getResizeBounds(area);
},
startResize: function startResize(area, mode) {
return dispatch(function (runtime) {
return runtime.startResize(area, mode);
});
},
resize: function resize(area, mode, width) {
return dispatch(function (runtime) {
return runtime.resize(area, mode, width);
});
},
completeResize: function completeResize(area, mode, width) {
return dispatch(function (runtime) {
return runtime.completeResize(area, mode, width);
});
}
};
}, [dispatch, prepareResize, registerSplitter]);
var SideNavStateProvider = _layoutAreaStateContexts.layoutAreaStateContexts['side-nav'].Provider;
var PanelStateProvider = _layoutAreaStateContexts.layoutAreaStateContexts.panel.Provider;
var ChatPanelStateProvider = _layoutAreaStateContexts.layoutAreaStateContexts['chat-panel'].Provider;
return /*#__PURE__*/_react.default.createElement(_layoutAreaSizingContext.LayoutAreaSizingContext.Provider, {
value: value
}, /*#__PURE__*/_react.default.createElement(SideNavStateProvider, {
value: states['side-nav']
}, /*#__PURE__*/_react.default.createElement(PanelStateProvider, {
value: states.panel
}, /*#__PURE__*/_react.default.createElement(ChatPanelStateProvider, {
value: states['chat-panel']
}, children))), Runtime && /*#__PURE__*/_react.default.createElement(Runtime, {
layoutRef: layoutRef,
onReady: onReady,
onUpdate: onUpdate
}));
}