UNPKG

@atlaskit/navigation-system

Version:

The latest navigation system for Atlassian apps.

154 lines (152 loc) • 8.03 kB
import _slicedToArray from "@babel/runtime/helpers/slicedToArray"; import React, { useCallback, useContext, useEffect, useRef, useState } from 'react'; import invariant from 'tiny-invariant'; import useStableRef from '@atlaskit/ds-lib/use-stable-ref'; import ExitingPersistence from '@atlaskit/motion/exiting-persistence'; import { fg } from '@atlaskit/platform-feature-flags/fg'; import { getPanelLayoutDefaults } from './get-panel-layout-defaults'; import { LayoutAreaSizingContext } from './layout-area-sizing-context'; import { LayoutAreaSizingProvider } from './layout-area-sizing-provider'; import { LocalPanelSurface } from './local-panel-surface'; import { PanelLayoutShell } from './panel-layout-shell'; import { useLayoutAreaSizing } from './use-layout-area-sizing'; // 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 = useState(getPanelLayoutDefaults), _useState2 = _slicedToArray(_useState, 1), defaults = _useState2[0]; var panelMinWidth = suppliedMinWidth !== null && suppliedMinWidth !== void 0 ? suppliedMinWidth : defaults.panelMinWidth; var coordinator = useContext(LayoutAreaSizingContext); useEffect(function () { if (process.env.NODE_ENV !== 'production' && coordinator) { invariant(!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 = useState((_ref2 = defaultPanelWidth !== null && defaultPanelWidth !== void 0 ? defaultPanelWidth : panelWidth) !== null && _ref2 !== void 0 ? _ref2 : defaults.panelWidth), _useState4 = _slicedToArray(_useState3, 1), defaultWidth = _useState4[0]; var _useState5 = useState((_ref3 = (_ref4 = compactDefaultPanelWidth !== null && compactDefaultPanelWidth !== void 0 ? compactDefaultPanelWidth : defaultPanelWidth) !== null && _ref4 !== void 0 ? _ref4 : panelWidth) !== null && _ref3 !== void 0 ? _ref3 : defaults.compactPanelWidth), _useState6 = _slicedToArray(_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 = 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 = useStableRef(onPanelWidthChange); var onResizeEndRef = useStableRef(onResizeEnd); var handleWidthChange = 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 = 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 = fg('platform-dst-motion-uplift-panel'); var surface = isPanelOpen && /*#__PURE__*/React.createElement(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.createElement(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.createElement(ExitingPersistence, 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. */ export function PanelLayout(props) { var parentSizing = useContext(LayoutAreaSizingContext); var layoutRef = useRef(null); var content = /*#__PURE__*/React.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.createElement(LayoutAreaSizingProvider, { layoutRef: layoutRef }, content); }