@atlaskit/navigation-system
Version:
The latest navigation system for Atlassian apps.
162 lines (160 loc) • 9.43 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _typeof = require("@babel/runtime/helpers/typeof");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.PanelLayout = PanelLayout;
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _react = _interopRequireWildcard(require("react"));
var _tinyInvariant = _interopRequireDefault(require("tiny-invariant"));
var _useStableRef = _interopRequireDefault(require("@atlaskit/ds-lib/use-stable-ref"));
var _exitingPersistence = _interopRequireDefault(require("@atlaskit/motion/exiting-persistence"));
var _fg = require("@atlaskit/platform-feature-flags/fg");
var _getPanelLayoutDefaults = require("./get-panel-layout-defaults");
var _layoutAreaSizingContext = require("./layout-area-sizing-context");
var _layoutAreaSizingProvider = require("./layout-area-sizing-provider");
var _localPanelSurface = require("./local-panel-surface");
var _panelLayoutShell = require("./panel-layout-shell");
var _useLayoutAreaSizing2 = require("./use-layout-area-sizing");
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); }
// Development-only ownership checks are scoped to each coordinator, not the whole page.
var mountedPanelLayouts = new WeakSet();
function CoordinatedPanelLayout(_ref) {
var _ref2, _ref3, _ref4, _state$width;
var children = _ref.children,
panel = _ref.panel,
isPanelOpen = _ref.isPanelOpen,
panelKey = _ref.panelKey,
panelWidth = _ref.panelWidth,
defaultPanelWidth = _ref.defaultPanelWidth,
compactDefaultPanelWidth = _ref.compactDefaultPanelWidth,
suppliedMinWidth = _ref.panelMinWidth,
panelMaxWidth = _ref.panelMaxWidth,
onPanelWidthChange = _ref.onPanelWidthChange,
onResizeEnd = _ref.onResizeEnd,
_ref$panelLabel = _ref.panelLabel,
panelLabel = _ref$panelLabel === void 0 ? 'Panel' : _ref$panelLabel,
_ref$resizeLabel = _ref.resizeLabel,
resizeLabel = _ref$resizeLabel === void 0 ? 'Resize panel' : _ref$resizeLabel,
testId = _ref.testId,
layoutRef = _ref.layoutRef;
var _useState = (0, _react.useState)(_getPanelLayoutDefaults.getPanelLayoutDefaults),
_useState2 = (0, _slicedToArray2.default)(_useState, 1),
defaults = _useState2[0];
var panelMinWidth = suppliedMinWidth !== null && suppliedMinWidth !== void 0 ? suppliedMinWidth : defaults.panelMinWidth;
var coordinator = (0, _react.useContext)(_layoutAreaSizingContext.LayoutAreaSizingContext);
(0, _react.useEffect)(function () {
if (process.env.NODE_ENV !== 'production' && coordinator) {
(0, _tinyInvariant.default)(!mountedPanelLayouts.has(coordinator), 'Only one PanelLayout may be mounted per navigation Root/sizing coordinator, including closed hosts and LayoutWithPanel. Reuse the host to switch panel content.');
mountedPanelLayouts.add(coordinator);
return function () {
mountedPanelLayouts.delete(coordinator);
};
}
}, [coordinator]);
var _useState3 = (0, _react.useState)((_ref2 = defaultPanelWidth !== null && defaultPanelWidth !== void 0 ? defaultPanelWidth : panelWidth) !== null && _ref2 !== void 0 ? _ref2 : defaults.panelWidth),
_useState4 = (0, _slicedToArray2.default)(_useState3, 1),
defaultWidth = _useState4[0];
var _useState5 = (0, _react.useState)((_ref3 = (_ref4 = compactDefaultPanelWidth !== null && compactDefaultPanelWidth !== void 0 ? compactDefaultPanelWidth : defaultPanelWidth) !== null && _ref4 !== void 0 ? _ref4 : panelWidth) !== null && _ref3 !== void 0 ? _ref3 : defaults.compactPanelWidth),
_useState6 = (0, _slicedToArray2.default)(_useState5, 1),
compactWidth = _useState6[0];
// Use the controlled request before measurement too, without changing the mount-time default.
var fallbackWidth = Math.max(panelMinWidth, Math.min(panelWidth !== null && panelWidth !== void 0 ? panelWidth : defaultWidth, panelMaxWidth !== null && panelMaxWidth !== void 0 ? panelMaxWidth : Infinity));
var _useLayoutAreaSizing = (0, _useLayoutAreaSizing2.useLayoutAreaSizing)({
area: 'panel',
config: {
isOpen: isPanelOpen,
requestedWidth: panelWidth,
defaultWidth: defaultWidth,
compactDefaultWidth: compactWidth,
minWidth: panelMinWidth,
maxWidth: panelMaxWidth
}
}),
state = _useLayoutAreaSizing.state,
prepareResize = _useLayoutAreaSizing.prepareResize,
getResizeBounds = _useLayoutAreaSizing.getResizeBounds,
startResize = _useLayoutAreaSizing.startResize,
resize = _useLayoutAreaSizing.resize,
completeResize = _useLayoutAreaSizing.completeResize;
// Host callback identity is unrelated to sizing. Keep drag bindings stable while
// still delivering completions to the latest product-owned state and analytics.
var onWidthChangeRef = (0, _useStableRef.default)(onPanelWidthChange);
var onResizeEndRef = (0, _useStableRef.default)(onResizeEnd);
var handleWidthChange = (0, _react.useCallback)(function (width) {
var _onWidthChangeRef$cur;
return (_onWidthChangeRef$cur = onWidthChangeRef.current) === null || _onWidthChangeRef$cur === void 0 ? void 0 : _onWidthChangeRef$cur.call(onWidthChangeRef, width);
}, [onWidthChangeRef]);
var handleResizeEnd = (0, _react.useCallback)(function (event) {
var _onResizeEndRef$curre;
return (_onResizeEndRef$curre = onResizeEndRef.current) === null || _onResizeEndRef$curre === void 0 ? void 0 : _onResizeEndRef$curre.call(onResizeEndRef, event);
}, [onResizeEndRef]);
var isMotionEnabled = (0, _fg.fg)('platform-dst-motion-uplift-panel');
var surface = isPanelOpen && /*#__PURE__*/_react.default.createElement(_localPanelSurface.LocalPanelSurface, {
key: "local-panel",
contentKey: panelKey,
defaultWidth: fallbackWidth,
minWidth: panelMinWidth,
maxWidth: panelMaxWidth,
layoutRef: layoutRef,
managedSizing: state,
getManagedResizeBounds: getResizeBounds,
prepareResize: prepareResize,
onManagedResizeStart: startResize,
onManagedResize: resize,
onManagedResizeEnd: completeResize,
onWidthChange: handleWidthChange,
onResizeEnd: handleResizeEnd,
label: panelLabel,
resizeLabel: resizeLabel,
testId: testId && "".concat(testId, "--panel-slot")
}, panel);
return /*#__PURE__*/_react.default.createElement(_panelLayoutShell.PanelLayoutShell, {
isPanelOpen: isPanelOpen,
panelWidth: (_state$width = state === null || state === void 0 ? void 0 : state.width) !== null && _state$width !== void 0 ? _state$width : fallbackWidth,
compactPanelWidth: Math.max(panelMinWidth, Math.min(panelWidth !== null && panelWidth !== void 0 ? panelWidth : compactWidth, panelMaxWidth !== null && panelMaxWidth !== void 0 ? panelMaxWidth : Infinity)),
panelMinWidth: panelMinWidth,
mode: state === null || state === void 0 ? void 0 : state.mode,
layoutRef: layoutRef,
shouldClipOverflow: isMotionEnabled,
testId: testId,
panel: isMotionEnabled ? /*#__PURE__*/_react.default.createElement(_exitingPersistence.default, null, surface) : surface
}, children);
}
/**
* A coordinated local panel with caller-owned content and state. Keep this host mounted
* while closed to retain resized widths. Unmount it to reset its width preferences.
*
* Mount only one local-panel host per navigation Root/sizing coordinator, including
* closed hosts and panel-system's LayoutWithPanel. Switch content through the same host;
* separate Roots may each own a local panel.
*
* With chat layout enabled it shares Root's sizing coordinator. Otherwise it measures
* its own Main region, leaving existing navigation/chat behavior unchanged.
* Local-panel placement and resize constraints use this layout in both cases; disabling
* the chat-layout gate does not restore the previous panel-system layout engine.
*/
function PanelLayout(props) {
var parentSizing = (0, _react.useContext)(_layoutAreaSizingContext.LayoutAreaSizingContext);
var layoutRef = (0, _react.useRef)(null);
var content = /*#__PURE__*/_react.default.createElement(CoordinatedPanelLayout, {
layoutRef: layoutRef,
panel: props.panel,
isPanelOpen: props.isPanelOpen,
panelKey: props.panelKey,
panelWidth: props.panelWidth,
defaultPanelWidth: props.defaultPanelWidth,
compactDefaultPanelWidth: props.compactDefaultPanelWidth,
panelMinWidth: props.panelMinWidth,
panelMaxWidth: props.panelMaxWidth,
onPanelWidthChange: props.onPanelWidthChange,
onResizeEnd: props.onResizeEnd,
panelLabel: props.panelLabel,
resizeLabel: props.resizeLabel,
testId: props.testId
}, props.children);
return parentSizing ? content : /*#__PURE__*/_react.default.createElement(_layoutAreaSizingProvider.LayoutAreaSizingProvider, {
layoutRef: layoutRef
}, content);
}