UNPKG

@atlaskit/navigation-system

Version:

The latest navigation system for Atlassian apps.

314 lines (312 loc) • 13 kB
import _slicedToArray from "@babel/runtime/helpers/slicedToArray"; 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; } import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { bind, bindAll } from 'bind-event-listener'; import { defaultMainMinWidth } from './constants'; import { LayoutAreaSizingContext } from './layout-area-sizing-context'; import { layoutAreaStateContexts } from './layout-area-state-contexts'; import { useCssLayoutAreaStates } from './use-css-layout-area-states'; /** * 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. */ export function LayoutAreaSizingProvider(_ref) { var _states$sideNav$mode, _states$sideNav, _states$chatPanel$mo, _states$chatPanel; var children = _ref.children, layoutRef = _ref.layoutRef; var _useState = useState(null), _useState2 = _slicedToArray(_useState, 2), Runtime = _useState2[0], setRuntime = _useState2[1]; var _useState3 = useState({}), _useState4 = _slicedToArray(_useState3, 2), states = _useState4[0], setStates = _useState4[1]; var actions = useRef(null); var configs = useRef({}); var _useState5 = useState(null), _useState6 = _slicedToArray(_useState5, 2), lastOpenedOverlay = _useState6[0], setLastOpenedOverlay = _useState6[1]; var _useState7 = useState(0), _useState8 = _slicedToArray(_useState7, 2), configRevision = _useState8[0], setConfigRevision = _useState8[1]; var cssModes = 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. 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 bind(inlineChatQuery, { type: 'change', listener: dismissOlderOverlay }); }, [chatPanelMode, lastOpenedOverlay, sideNavMode]); var splitters = useRef(new Set()); var registerSplitter = useCallback(function (element) { splitters.current.add(element); return function () { splitters.current.delete(element); }; }, []); var mainMinWidth = useRef(defaultMainMinWidth); var loadRef = useRef(function () {}); var ready = useRef(false); var waiting = useRef([]); var pending = useRef([]); var prepareResize = useCallback(function () { if (ready.current) { return Promise.resolve(true); } return new Promise(function (resolve) { waiting.current.push(resolve); loadRef.current(); }); }, []); 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 import( /* 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 = 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 = 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 = 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 = useCallback(function (action) { if (ready.current && actions.current) { action(actions.current); } else { pending.current.push(action); loadRef.current(); } }, []); var value = 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['side-nav'].Provider; var PanelStateProvider = layoutAreaStateContexts.panel.Provider; var ChatPanelStateProvider = layoutAreaStateContexts['chat-panel'].Provider; return /*#__PURE__*/React.createElement(LayoutAreaSizingContext.Provider, { value: value }, /*#__PURE__*/React.createElement(SideNavStateProvider, { value: states['side-nav'] }, /*#__PURE__*/React.createElement(PanelStateProvider, { value: states.panel }, /*#__PURE__*/React.createElement(ChatPanelStateProvider, { value: states['chat-panel'] }, children))), Runtime && /*#__PURE__*/React.createElement(Runtime, { layoutRef: layoutRef, onReady: onReady, onUpdate: onUpdate })); }