@atlaskit/navigation-system
Version:
The latest navigation system for Atlassian apps.
218 lines (217 loc) • 16.5 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.calculateLayoutAreaStates = calculateLayoutAreaStates;
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _resolveLayoutWidth = require("./resolve-layout-width");
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 clampTargetWidth(_ref) {
var target = _ref.target,
min = _ref.min,
max = _ref.max;
return Math.max(min, Math.min(target, max));
}
function getTargetWidth(area, isSideNavOverlay) {
var _area$compactDefaultW, _area$liveResize, _ref2, _area$requestedWidth;
var defaultWidth = isSideNavOverlay ? (_area$compactDefaultW = area.compactDefaultWidth) !== null && _area$compactDefaultW !== void 0 ? _area$compactDefaultW : area.defaultWidth : area.defaultWidth;
return ((_area$liveResize = area.liveResize) === null || _area$liveResize === void 0 ? void 0 : _area$liveResize.mode) === 'inline' ? area.liveResize.width : (_ref2 = (_area$requestedWidth = area.requestedWidth) !== null && _area$requestedWidth !== void 0 ? _area$requestedWidth : area.preferredWidth) !== null && _ref2 !== void 0 ? _ref2 : defaultWidth;
}
function getOverlayTargetWidth(area, isSideNavOverlay, areaName) {
var _area$compactDefaultW2, _area$liveResize2, _ref3, _area$requestedWidth2;
var defaultWidth = isSideNavOverlay ? (_area$compactDefaultW2 = area.compactDefaultWidth) !== null && _area$compactDefaultW2 !== void 0 ? _area$compactDefaultW2 : area.defaultWidth : area.defaultWidth;
return ((_area$liveResize2 = area.liveResize) === null || _area$liveResize2 === void 0 ? void 0 : _area$liveResize2.mode) === 'overlay' ? area.liveResize.width : (_ref3 = (_area$requestedWidth2 = area.requestedWidth) !== null && _area$requestedWidth2 !== void 0 ? _area$requestedWidth2 : areaName === 'panel' ? area.preferredWidth : area.preferredOverlayWidth) !== null && _ref3 !== void 0 ? _ref3 : defaultWidth;
}
function calculateLayoutAreaStates(_ref4) {
var _ref5, _resizeSession$overla, _baselineWidths$chat, _panel$liveResize, _states$sideNav$widt, _states$sideNav, _states$chatPanel$wi, _states$chatPanel;
var viewportWidth = _ref4.viewportWidth,
_ref4$layoutWidth = _ref4.layoutWidth,
layoutWidth = _ref4$layoutWidth === void 0 ? viewportWidth : _ref4$layoutWidth,
isChatPanelOverlay = _ref4.isChatPanelOverlay,
isSideNavOverlay = _ref4.isSideNavOverlay,
_ref4$occupiedWidth = _ref4.occupiedWidth,
occupiedWidth = _ref4$occupiedWidth === void 0 ? 0 : _ref4$occupiedWidth,
mainMinWidthBound = _ref4.mainMinWidth,
areas = _ref4.areas,
resizeSession = _ref4.resizeSession,
initialModes = _ref4.initialModes;
var mainMinWidth = (0, _resolveLayoutWidth.resolveLayoutWidth)(mainMinWidthBound, viewportWidth);
var availableWidth = Math.max(0, layoutWidth - occupiedWidth);
var sideNav = areas['side-nav'];
var panel = areas.panel;
var chatPanel = areas['chat-panel'];
var sideNavMinWidth = sideNav ? (0, _resolveLayoutWidth.resolveLayoutWidth)(sideNav.minWidth, viewportWidth) : 0;
var panelMinWidth = panel ? (0, _resolveLayoutWidth.resolveLayoutWidth)(panel.minWidth, viewportWidth) : 0;
var chatPanelMinWidth = chatPanel ? (0, _resolveLayoutWidth.resolveLayoutWidth)(chatPanel.minWidth, viewportWidth) : 0;
var resizingArea = resizeSession && areas[resizeSession.area];
var isAcknowledged = (resizeSession === null || resizeSession === void 0 ? void 0 : resizeSession.completedWidth) !== undefined && ((resizingArea === null || resizingArea === void 0 ? void 0 : resizingArea.requestedWidth) === undefined || resizingArea.requestedWidth === resizeSession.completedWidth);
var baselineWidths = (_ref5 = isAcknowledged ? resizeSession === null || resizeSession === void 0 ? void 0 : resizeSession.completedWidths : undefined) !== null && _ref5 !== void 0 ? _ref5 : resizeSession === null || resizeSession === void 0 ? void 0 : resizeSession.baselineWidths;
var layoutModes = (_resizeSession$overla = resizeSession === null || resizeSession === void 0 ? void 0 : resizeSession.overlayModes) !== null && _resizeSession$overla !== void 0 ? _resizeSession$overla : initialModes;
// A growing panel cascades towards inline-start. Chat is on the other side
// of the local rail, so local growth must reserve its full starting width.
var shouldCollapseSideNav = Boolean(resizeSession && resizeSession.area !== 'side-nav' && resizeSession.baselineWidths['side-nav'] !== undefined && resizeSession.baselineWidths[resizeSession.area] !== undefined && resizingArea && !isSideNavOverlay && clampTargetWidth({
target: getTargetWidth(resizingArea, isSideNavOverlay),
min: (0, _resolveLayoutWidth.resolveLayoutWidth)(resizingArea.minWidth, viewportWidth),
max: resizingArea.maxWidth !== undefined ? (0, _resolveLayoutWidth.resolveLayoutWidth)(resizingArea.maxWidth, viewportWidth) : Number.POSITIVE_INFINITY
}) > availableWidth - mainMinWidth - sideNavMinWidth - (resizeSession.area === 'panel' ? resizeSession.baselineWidths['chat-panel'] !== undefined ? (_baselineWidths$chat = baselineWidths === null || baselineWidths === void 0 ? void 0 : baselineWidths['chat-panel']) !== null && _baselineWidths$chat !== void 0 ? _baselineWidths$chat : chatPanelMinWidth : 0 : resizeSession.baselineWidths.panel !== undefined ? panelMinWidth : 0));
var isSideNavOpenInline = Boolean((sideNav === null || sideNav === void 0 ? void 0 : sideNav.isOpen) && !shouldCollapseSideNav && (layoutModes ? layoutModes['side-nav'] === 'inline' : !isSideNavOverlay && availableWidth >= mainMinWidth + sideNavMinWidth));
var isChatPanelOpenInline = Boolean((chatPanel === null || chatPanel === void 0 ? void 0 : chatPanel.isOpen) && (!resizeSession || resizeSession.baselineWidths['chat-panel'] !== undefined) && (layoutModes ? layoutModes['chat-panel'] === 'inline' : !isChatPanelOverlay && availableWidth >= mainMinWidth + chatPanelMinWidth + (isSideNavOpenInline ? sideNavMinWidth : 0)));
var isPanelInline = Boolean((panel === null || panel === void 0 ? void 0 : panel.isOpen) && (!resizeSession || resizeSession.baselineWidths.panel !== undefined) && (layoutModes ? layoutModes.panel === 'inline' : availableWidth >= mainMinWidth + panelMinWidth + (isChatPanelOpenInline ? chatPanelMinWidth : 0) + (isSideNavOpenInline ? sideNavMinWidth : 0)));
var inlineAreas = [isSideNavOpenInline && 'side-nav', isPanelInline && 'panel', isChatPanelOpenInline && 'chat-panel'].filter(function (area) {
return Boolean(area);
});
var widths = new Map();
var minimums = new Map();
var _iterator = _createForOfIteratorHelper(inlineAreas),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var areaName = _step.value;
var area = areas[areaName];
if (!area) {
continue;
}
var min = (0, _resolveLayoutWidth.resolveLayoutWidth)(area.minWidth, viewportWidth);
var max = area.maxWidth ? (0, _resolveLayoutWidth.resolveLayoutWidth)(area.maxWidth, viewportWidth) : Number.POSITIVE_INFINITY;
var baselineWidth = baselineWidths === null || baselineWidths === void 0 ? void 0 : baselineWidths[areaName];
var requestedTarget = resizeSession && areaName !== resizeSession.area ? shouldCollapseSideNav && resizeSession.area === 'chat-panel' ? min : baselineWidth !== null && baselineWidth !== void 0 ? baselineWidth : getTargetWidth(area, isSideNavOverlay) : getTargetWidth(area, isSideNavOverlay);
var target = clampTargetWidth({
target: requestedTarget,
min: min,
max: max
});
minimums.set(areaName, min);
widths.set(areaName, target);
}
// Narrowing Chat moves the shared rail towards inline-end. Give the released
// space to its inline neighbour so local grows instead of sliding across Main.
// Use effective (clamped) widths and the session baseline, not each drag frame,
// so reversing direction and completing a controlled resize do not add it twice.
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
if ((resizeSession === null || resizeSession === void 0 ? void 0 : resizeSession.area) === 'chat-panel' && isChatPanelOpenInline && isPanelInline && panel) {
var _widths$get, _baselineWidths$chat2, _widths$get2;
var chatWidth = (_widths$get = widths.get('chat-panel')) !== null && _widths$get !== void 0 ? _widths$get : 0;
var releasedWidth = Math.max(0, ((_baselineWidths$chat2 = baselineWidths === null || baselineWidths === void 0 ? void 0 : baselineWidths['chat-panel']) !== null && _baselineWidths$chat2 !== void 0 ? _baselineWidths$chat2 : chatWidth) - chatWidth);
var panelMaxWidth = panel.maxWidth !== undefined ? Math.max(panelMinWidth, (0, _resolveLayoutWidth.resolveLayoutWidth)(panel.maxWidth, viewportWidth)) : Number.POSITIVE_INFINITY;
widths.set('panel', Math.min(panelMaxWidth, ((_widths$get2 = widths.get('panel')) !== null && _widths$get2 !== void 0 ? _widths$get2 : 0) + releasedWidth));
}
// Continuing to pull the local rail towards Chat after local reaches its
// minimum gives Main the remaining space available in inline Chat.
if ((resizeSession === null || resizeSession === void 0 ? void 0 : resizeSession.area) === 'panel' && (panel === null || panel === void 0 || (_panel$liveResize = panel.liveResize) === null || _panel$liveResize === void 0 ? void 0 : _panel$liveResize.mode) === 'inline' && isChatPanelOpenInline) {
var _widths$get3;
var remainingDrag = Math.max(0, panelMinWidth - panel.liveResize.width);
var _chatWidth = (_widths$get3 = widths.get('chat-panel')) !== null && _widths$get3 !== void 0 ? _widths$get3 : 0;
widths.set('chat-panel', Math.max(chatPanelMinWidth, _chatWidth - remainingDrag));
}
var overflow = Math.max(0, Array.from(widths.values()).reduce(function (total, width) {
return total + width;
}, 0) - (availableWidth - mainMinWidth));
var compressionOrder = ['panel', 'chat-panel', 'side-nav'];
// Main gives up spare space first. Only regions beyond the moving rail may
// then compress: local growth moves towards SideNav, never towards Chat.
// SideNav and Chat growth can reach both other regions in their direction.
var shrinkOrder = resizeSession ? resizeSession.area === 'panel' ? ['side-nav', 'panel'] : [].concat((0, _toConsumableArray2.default)(compressionOrder.filter(function (area) {
return area !== resizeSession.area;
})), [resizeSession.area]) : compressionOrder;
var _iterator2 = _createForOfIteratorHelper(shrinkOrder),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var _widths$get4, _minimums$get;
var _areaName = _step2.value;
if (overflow <= 0) {
break;
}
var width = (_widths$get4 = widths.get(_areaName)) !== null && _widths$get4 !== void 0 ? _widths$get4 : 0;
var _min = (_minimums$get = minimums.get(_areaName)) !== null && _minimums$get !== void 0 ? _minimums$get : 0;
var reduction = Math.min(overflow, Math.max(0, width - _min));
widths.set(_areaName, width - reduction);
overflow -= reduction;
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
var states = {};
var _iterator3 = _createForOfIteratorHelper(inlineAreas),
_step3;
try {
var _loop = function _loop() {
var _widths$get5, _minimums$get2, _areas$areaName;
var areaName = _step3.value;
var width = (_widths$get5 = widths.get(areaName)) !== null && _widths$get5 !== void 0 ? _widths$get5 : 0;
var min = (_minimums$get2 = minimums.get(areaName)) !== null && _minimums$get2 !== void 0 ? _minimums$get2 : 0;
var maxWidth = (_areas$areaName = areas[areaName]) === null || _areas$areaName === void 0 ? void 0 : _areas$areaName.maxWidth;
var configuredMax = maxWidth !== undefined ? (0, _resolveLayoutWidth.resolveLayoutWidth)(maxWidth, viewportWidth) : Number.POSITIVE_INFINITY;
states[areaName] = {
mode: 'inline',
width: width,
minWidth: min,
resizeBounds: {
min: min,
max: Math.max(min, Math.min(configuredMax, availableWidth - mainMinWidth - inlineAreas.reduce(function (total, sibling) {
var _widths$get6, _minimums$get3;
return sibling === areaName || sibling === 'side-nav' && areaName !== 'side-nav' ? total : total + (areaName === 'panel' && sibling === 'chat-panel' ? (_widths$get6 = widths.get(sibling)) !== null && _widths$get6 !== void 0 ? _widths$get6 : 0 : (_minimums$get3 = minimums.get(sibling)) !== null && _minimums$get3 !== void 0 ? _minimums$get3 : 0);
}, 0)))
}
};
};
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
_loop();
}
} catch (err) {
_iterator3.e(err);
} finally {
_iterator3.f();
}
var inlineSideNavWidth = (_states$sideNav$widt = (_states$sideNav = states['side-nav']) === null || _states$sideNav === void 0 ? void 0 : _states$sideNav.width) !== null && _states$sideNav$widt !== void 0 ? _states$sideNav$widt : 0;
var inlineChatPanelWidth = (_states$chatPanel$wi = (_states$chatPanel = states['chat-panel']) === null || _states$chatPanel === void 0 ? void 0 : _states$chatPanel.width) !== null && _states$chatPanel$wi !== void 0 ? _states$chatPanel$wi : 0;
var mainAreaWidth = Math.max(0, availableWidth - inlineSideNavWidth - inlineChatPanelWidth);
var _iterator4 = _createForOfIteratorHelper(['side-nav', 'panel', 'chat-panel']),
_step4;
try {
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
var _states$_areaName;
var _areaName2 = _step4.value;
var _area = areas[_areaName2];
if (!(_area !== null && _area !== void 0 && _area.isOpen) || ((_states$_areaName = states[_areaName2]) === null || _states$_areaName === void 0 ? void 0 : _states$_areaName.mode) === 'inline' || _areaName2 === 'side-nav' && shouldCollapseSideNav) {
continue;
}
var _min2 = (0, _resolveLayoutWidth.resolveLayoutWidth)(_area.minWidth, viewportWidth);
var configuredMax = _area.maxWidth ? (0, _resolveLayoutWidth.resolveLayoutWidth)(_area.maxWidth, viewportWidth) : Number.POSITIVE_INFINITY;
// Chat covers Root; SideNav and the local panel overlay Main's grid track.
// Occupied tracks and inline chat are not part of that covered region.
var layoutMax = (_areaName2 === 'chat-panel' ? layoutWidth : mainAreaWidth) * 0.9;
var _max = Math.max(0, Math.min(configuredMax, layoutMax));
var effectiveMin = Math.min(_min2, _max);
var _target = getOverlayTargetWidth(_area, isSideNavOverlay, _areaName2);
var _width = clampTargetWidth({
target: _target,
min: effectiveMin,
max: _max
});
states[_areaName2] = {
mode: 'overlay',
width: _width,
minWidth: effectiveMin,
resizeBounds: {
min: effectiveMin,
max: _max
}
};
}
} catch (err) {
_iterator4.e(err);
} finally {
_iterator4.f();
}
return states;
}