UNPKG

@atlaskit/navigation-system

Version:

The latest navigation system for Atlassian apps.

1,091 lines • 53.1 kB
/* side-nav.tsx generated by @compiled/babel-plugin v3.0.2 */
"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _typeof = require("@babel/runtime/helpers/typeof");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.SideNav = SideNav;
exports.onPeekStartDelayMs = void 0;
require("./side-nav.compiled.css");
var _runtime = require("@compiled/react/runtime");
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _react = _interopRequireWildcard(require("react"));
var _reactDom = require("react-dom");
var _bindEventListener = require("bind-event-listener");
var _useAnalyticsEvents2 = require("@atlaskit/analytics-next/useAnalyticsEvents");
var _mergeRefs = _interopRequireDefault(require("@atlaskit/ds-lib/merge-refs"));
var _useStableRef = _interopRequireDefault(require("@atlaskit/ds-lib/use-stable-ref"));
var _openLayerObserverNamespaceProvider = require("@atlaskit/layering/open-layer-observer-namespace-provider");
var _useOpenLayerObserver = require("@atlaskit/layering/use-open-layer-observer");
var _fg = require("@atlaskit/platform-feature-flags/fg");
var _elementAdapter = require("@atlaskit/pragmatic-drag-and-drop/adapter/element-adapter");
var _hasOpenDialogOrPopover = require("@atlaskit/top-layer/page-surface/has-open-dialog-or-popover");
var _useSkipLinkInternal = require("../../../context/skip-links/use-skip-link-internal");
var _topNavStartElement = require("../../../context/top-nav-start/top-nav-start-element");
var _constants = require("../constants");
var _dangerouslyHoistCssVarToDocumentRoot = require("../dangerously-hoist-css-var-to-document-root");
var _hoistSlotSizesContext = require("../hoist-slot-sizes-context");
var _convertResizeBoundToPixels = require("../panel-splitter/convert-resize-bound-to-pixels");
var _provider = require("../panel-splitter/provider");
var _resolveLayoutWidth = require("../resolve-layout-width");
var _root = require("../root");
var _useLayoutAreaSizing2 = require("../use-layout-area-sizing");
var _useLayoutId = require("../use-layout-id");
var _useResizingWidthCssVarOnRootElement = require("../use-resizing-width-css-var-on-root-element");
var _useSafeDefaultWidth = require("../use-safe-default-width");
var _bindOpenLayerChange = require("./bind-open-layer-change");
var _flyoutCloseDelayMs = require("./flyout-close-delay-ms");
var _setSideNavVisibilityState = require("./set-side-nav-visibility-state");
var _sideNavToggleButtonElement = require("./side-nav-toggle-button-element");
var _sideNavToggleTooltipKeyboardShortcut = require("./side-nav-toggle-tooltip-keyboard-shortcut");
var _sideNavVisibilityState = require("./side-nav-visibility-state");
var _useExpandSideNav = require("./use-expand-side-nav");
var _useIsSideNavShortcutEnabled = require("./use-is-side-nav-shortcut-enabled");
var _useSideNavRef = require("./use-side-nav-ref");
var _useSideNavToggleKeyboardShortcut = require("./use-side-nav-toggle-keyboard-shortcut");
var _useSideNavVisibility2 = require("./use-side-nav-visibility");
var _useSideNavVisibilityCallbacks = require("./use-side-nav-visibility-callbacks");
var _useToggleSideNav = require("./use-toggle-side-nav");
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); }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } // eslint-disable-next-line @atlaskit/design-system/no-emotion-primitives -- TODO: migrate to @atlaskit/primitives/compiled
var panelSplitterResizingVar = '--n_snvRsz';
var fallbackMinWidth = '240px';
function getPixelCustomProperty(element, propertyName, fallback) {
  var raw = getComputedStyle(element).getPropertyValue(propertyName).trim();
  var value = Number.parseFloat(raw);
  return Number.isFinite(value) ? (0, _resolveLayoutWidth.resolveLayoutWidth)(raw.endsWith('vw') ? "".concat(value, "vw") : value, window.innerWidth) : fallback;
}

/**
 * We are using JS to detect Firefox and disable animations, instead of using CSS, as Compiled currently does not merge duplicate
 * CSS at-rules when at-rules are nested: https://github.com/atlassian-labs/compiled/blob/e04a325915e1d13010205089e4915de0e53bc2d4/packages/css/src/plugins/merge-duplicate-at-rules.ts#L5
 * Avoiding nesting the `@supports` at-rule inside of `@media` means Compiled can remove duplicate styles from the generated CSS.
 */
var isFirefox = typeof navigator !== 'undefined' && navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
var textEntryInputTypes = new Set(['text', 'search', 'email', 'url', 'tel', 'password', 'number']);
function isEditableContent(_ref) {
  var element = _ref.element;
  if (element instanceof HTMLElement && typeof element.isContentEditable === 'boolean') {
    return element.isContentEditable;
  }
  // Fallback for DOM implementations without `isContentEditable`.
  var editingHost = element.closest('[contenteditable]');
  return editingHost !== null && editingHost.getAttribute('contenteditable') !== 'false';
}

/**
 * Returns `true` for an element that the user can type text into.
 */
function isTextEntryElement(_ref2) {
  var element = _ref2.element;
  if (element instanceof HTMLInputElement) {
    return textEntryInputTypes.has(element.type) && !element.readOnly && !element.disabled;
  }
  if (element instanceof HTMLTextAreaElement) {
    return !element.readOnly && !element.disabled;
  }
  return isEditableContent({
    element: element
  });
}

/**
 * Used when the `platform-dst-top-layer` gate is on.
 *
 * The flyout stays open while a layer opened from the side nav is open, or while the user
 * is typing in a text field inside the side nav (for example while renaming an item inline).
 */
function isFlyoutHeldOpen(_ref3) {
  var nav = _ref3.nav;
  if ((0, _hasOpenDialogOrPopover.hasOpenDialogOrPopover)({
    within: nav
  })) {
    return true;
  }
  var activeElement = nav.ownerDocument.activeElement;
  return activeElement !== null && nav.contains(activeElement) && isTextEntryElement({
    element: activeElement
  });
}
var styles = {
  root: "_191wglyw _t51zglyw _bfhk1bhr _16qs130s _vchhusvi _4t3ieqxy _152timx3 _kqsw1if8 _1bsb1ego _1pbycs5v _14b5hc79 _qilnk0mc _p5clia51 _4ap3vuon _scbpglyw _89fi1b6c",
  chatPanelSizing: "_1bsbhc79",
  managedOverlay: "_cpcf1gzg _6kttglyw _w8v11bhr _1jug130s",
  flyoutOpen: "_qiln1gzg _p5clglyw _4ap31bhr _scbp130s _139f8iot _1tpvfnf5 _sylc1a5r _oyeijq3t",
  flyoutAnimateClosed: "_1e0cglyw _qiln1gzg _139f8iot _1tpvfnf5 _sylc1a5r _1uwsjq3t",
  flexContainer: "_4t3i1osq _1e0c1txw _2lx21bp4 _1bah1yb4",
  hiddenMobileAndDesktop: "_1e0cglyw",
  hiddenMobileOnly: "_1e0cglyw _dm2518uv",
  hiddenDesktopOnly: "_dm25glyw"
};

/**
 * Styles for the side nav enter/exit animations when `platform-dst-motion-uplift-sidenav` is enabled.
 *
 * These use the `motion.sidenav.*` tokens (keyframe animations) instead of the `transform` transitions
 * with `@starting-style` used by `styles`.
 *
 * ⚠️ The `transition-duration` values below need to stay in sync with the duration baked into the tokens
 * (`motion.sidenav.enter.*` is 250ms, `motion.sidenav.exit.*` is 200ms). The `display` property is
 * transitioned (with `allow-discrete`) so the element stays rendered for the length of the exit animation —
 * if the transition is shorter than the animation, `display: none` applies early and the exit animation
 * never runs.
 */
var motionUpliftStyles = {
  animationRTLSupport: "_cjprp6j8 _1p2s1vfh _1jq41dy6 _2qe0jwwr",
  animationBaseStyles: "_10t81t0s _1vrh1a5r _xrrpi9qs",
  expandAnimationMobile: "_k1af10ed",
  collapseAnimationMobile: "_1lh81gzg _k1affm5y",
  flyoutOpen: "_qiln1gzg _p5clglyw _4ap31bhr _scbp130s _4xci10ed _1tpv1mzy _sylc1a5r",
  flyoutAnimateClosed: "_1e0cglyw _qiln1gzg _4xcifm5y _1tpvi9qs _sylc1a5r",
  expandAnimationDesktop: "_1sg8k0mc _n2in10ed _1xpz1gzg _17ly1q8v _hjoi147i _1wxo4so3",
  collapseAnimationDesktop: "_1sg81gzg _n2infm5y _17ly1wzp _hjoi1wsm _1wxo1cio"
};
var fallbackDefaultWidth = 320;
var onPeekStartDelayMs = exports.onPeekStartDelayMs = 500;

/**
 * We need an additional component layer so we can wrap the side nav in a `OpenLayerObserver` and have access to the
 * context value.
 */
function SideNavInternal(_ref4) {
  var _managedSizing$mode, _managedSizing$width, _sideNavState$lastTri;
  var children = _ref4.children,
    defaultCollapsed = _ref4.defaultCollapsed,
    _ref4$defaultWidth = _ref4.defaultWidth,
    defaultWidthProp = _ref4$defaultWidth === void 0 ? fallbackDefaultWidth : _ref4$defaultWidth,
    _ref4$minWidth = _ref4.minWidth,
    minWidth = _ref4$minWidth === void 0 ? fallbackMinWidth : _ref4$minWidth,
    maxWidth = _ref4.maxWidth,
    testId = _ref4.testId,
    _ref4$label = _ref4.label,
    label = _ref4$label === void 0 ? 'Sidebar' : _ref4$label,
    _ref4$skipLinkLabel = _ref4.skipLinkLabel,
    skipLinkLabel = _ref4$skipLinkLabel === void 0 ? label : _ref4$skipLinkLabel,
    onExpand = _ref4.onExpand,
    onCollapse = _ref4.onCollapse,
    onPeekStart = _ref4.onPeekStart,
    onPeekEnd = _ref4.onPeekEnd,
    providedId = _ref4.id,
    canToggleWithShortcut = _ref4.canToggleWithShortcut;
  var isChatPanelLayoutEnabled = (0, _fg.fg)('platform-dst-chat-panel-layout');
  var id = (0, _useLayoutId.useLayoutId)({
    providedId: providedId
  });
  var expandAndFocusSideNav = (0, _useExpandSideNav.useExpandSideNav)({
    trigger: 'skip-link'
  });
  /**
   * Called after clicking on the side nav skip link, and ensures the side nav is expanded so that it is focusable.
   *
   * We need to update the DOM synchronously because `.focus()` is called synchronously after this state update.
   *
   * Only used when `platform_dst_nav4_skip_link_a11y_1` is OFF; can be removed on gate cleanup.
   */
  var synchronouslyExpandSideNav = (0, _react.useCallback)(function () {
    (0, _reactDom.flushSync)(function () {
      /**
       * Calling this unconditionally and relying on it to avoid no-op renders.
       *
       * We _could_ call it conditionally, but we'd be duplicating the screen size checks `expandAndFocusSideNav` makes.
       */
      expandAndFocusSideNav();
    });
  }, [expandAndFocusSideNav]);
  (0, _useSkipLinkInternal.useSkipLinkInternal)({
    id: id,
    label: skipLinkLabel,
    /**
     * `navigate` is the gate-on contract: it owns expanding the side nav AND moving
     * focus to the first nav item, atomically (via `useExpandSideNav`'s `flushSync`).
     *
     * `onBeforeNavigate` is the legacy contract used only when the gate is OFF.
     * On gate cleanup, drop `onBeforeNavigate` and `synchronouslyExpandSideNav` here.
     */
    navigate: (0, _fg.fg)('platform_dst_nav4_skip_link_a11y_1') ? expandAndFocusSideNav : undefined,
    onBeforeNavigate: (0, _fg.fg)('platform_dst_nav4_skip_link_a11y_1') ? undefined : synchronouslyExpandSideNav
  });
  var sideNavState = (0, _react.useContext)(_sideNavVisibilityState.SideNavVisibilityState);
  var setSideNavState = (0, _react.useContext)(_setSideNavVisibilityState.SetSideNavVisibilityState);
  var _useSideNavVisibility = (0, _useSideNavVisibility2.useSideNavVisibility)({
      defaultCollapsed: defaultCollapsed
    }),
    isExpandedOnDesktop = _useSideNavVisibility.isExpandedOnDesktop,
    isExpandedOnMobile = _useSideNavVisibility.isExpandedOnMobile;
  // We are placing `defaultCollapsed` into a state container so we can have a stable reference to the initial value.
  // This is so we can use it in an effect _that only runs once_, after the initial render on the client,
  // to sync the side nav context (provided in `<Root>`) with the `defaultCollapsed` prop provided to `<SideNav>`.
  var _useState = (0, _react.useState)(defaultCollapsed),
    _useState2 = (0, _slicedToArray2.default)(_useState, 1),
    initialDefaultCollapsed = _useState2[0];
  var _useAnalyticsEvents = (0, _useAnalyticsEvents2.useAnalyticsEvents)(),
    createAnalyticsEvent = _useAnalyticsEvents.createAnalyticsEvent;
  var _useState3 = (0, _react.useState)(isExpandedOnDesktop),
    _useState4 = (0, _slicedToArray2.default)(_useState3, 1),
    initialIsExpandedOnDesktop = _useState4[0];

  /**
   * Captures the initial collapsed/expanded state of the side nav.
   *
   * Only firing on desktop because the nav is never open by default on mobile.
   */
  (0, _react.useEffect)(function () {
    if (initialIsExpandedOnDesktop) {
      var isDesktop = window.matchMedia('(min-width: 64rem)').matches;
      if (isDesktop) {
        var navigationAnalyticsEvent = createAnalyticsEvent({
          source: 'topNav',
          actionSubject: 'sideNav',
          action: 'viewedOnLoad',
          actionSubjectId: 'sideNavMenu',
          attributes: {
            screen: 'desktop'
          }
        });
        navigationAnalyticsEvent.fire('navigation');
      }
    }
  }, [createAnalyticsEvent, initialIsExpandedOnDesktop]);
  var defaultWidth = (0, _useSafeDefaultWidth.useSafeDefaultWidth)({
    defaultWidthProp: defaultWidthProp,
    fallbackDefaultWidth: fallbackDefaultWidth,
    slotName: 'SideNav'
  });
  var _useState5 = (0, _react.useState)(defaultWidth),
    _useState6 = (0, _slicedToArray2.default)(_useState5, 2),
    inlineWidth = _useState6[0],
    setInlineWidth = _useState6[1];
  var _useState7 = (0, _react.useState)(defaultWidth),
    _useState8 = (0, _slicedToArray2.default)(_useState7, 2),
    overlayWidth = _useState8[0],
    setOverlayWidth = _useState8[1];
  var _useState9 = (0, _react.useState)(false),
    _useState0 = (0, _slicedToArray2.default)(_useState9, 2),
    isInline = _useState0[0],
    setIsInline = _useState0[1];
  (0, _react.useEffect)(function () {
    if (!isChatPanelLayoutEnabled) {
      return;
    }
    var mediaQuery = window.matchMedia('(min-width: 64rem)');
    setIsInline(mediaQuery.matches);
    var onChange = function onChange(event) {
      return setIsInline(event.matches);
    };
    return (0, _bindEventListener.bind)(mediaQuery, {
      type: 'change',
      listener: onChange
    });
  }, [isChatPanelLayoutEnabled]);
  var toggleVisibilityForChatPanel = (0, _useToggleSideNav.useToggleSideNav)({
    trigger: 'programmatic'
  });
  var closeOverlayForChatPanel = (0, _react.useCallback)(function () {
    // Allocation can overlay an expanded desktop nav when other slots consume
    // its space. Dismiss the visibility state selected by the viewport, not the mode.
    var isDesktop = window.matchMedia('(min-width: 64rem)').matches;
    if (isDesktop ? isExpandedOnDesktop : isExpandedOnMobile) {
      toggleVisibilityForChatPanel();
    }
  }, [isExpandedOnDesktop, isExpandedOnMobile, toggleVisibilityForChatPanel]);
  var _useLayoutAreaSizing = (0, _useLayoutAreaSizing2.useLayoutAreaSizing)({
      area: 'side-nav',
      config: {
        defaultWidth: defaultWidth,
        minWidth: minWidth,
        maxWidth: maxWidth,
        isOpen: isInline ? isExpandedOnDesktop : isExpandedOnMobile,
        onRequestClose: closeOverlayForChatPanel
      }
    }),
    managedSizing = _useLayoutAreaSizing.state,
    isManaged = _useLayoutAreaSizing.isManaged,
    prepareResize = _useLayoutAreaSizing.prepareResize,
    getManagedResizeBounds = _useLayoutAreaSizing.getResizeBounds,
    startResize = _useLayoutAreaSizing.startResize,
    resize = _useLayoutAreaSizing.resize,
    completeResize = _useLayoutAreaSizing.completeResize;
  var mode = (_managedSizing$mode = managedSizing === null || managedSizing === void 0 ? void 0 : managedSizing.mode) !== null && _managedSizing$mode !== void 0 ? _managedSizing$mode : isInline ? 'inline' : 'overlay';
  var renderedWidth = isChatPanelLayoutEnabled ? (_managedSizing$width = managedSizing === null || managedSizing === void 0 ? void 0 : managedSizing.width) !== null && _managedSizing$width !== void 0 ? _managedSizing$width : mode === 'inline' ? inlineWidth : overlayWidth : inlineWidth;
  var configuredMaxWidth = maxWidth !== null && maxWidth !== void 0 ? maxWidth : '100vw';
  var clampedWidth = !isChatPanelLayoutEnabled ? "clamp(240px, ".concat(inlineWidth, "px, 50vw)") : managedSizing ? "".concat(renderedWidth, "px") : "clamp(".concat(minWidth, ", ").concat(renderedWidth, "px, ").concat(configuredMaxWidth, ")");
  var dangerouslyHoistSlotSizes = (0, _react.useContext)(_hoistSlotSizesContext.DangerouslyHoistSlotSizes);
  var navRef = (0, _react.useRef)(null);
  var getResizeBounds = (0, _react.useCallback)(function () {
    if (!isChatPanelLayoutEnabled) {
      return {
        min: '240px',
        max: '50vw'
      };
    }
    var managedBounds = getManagedResizeBounds();
    if (managedBounds) {
      return managedBounds;
    }
    var sideNav = navRef.current;
    var layoutRoot = sideNav === null || sideNav === void 0 ? void 0 : sideNav.parentElement;
    var main = layoutRoot === null || layoutRoot === void 0 ? void 0 : layoutRoot.querySelector(':scope > [data-layout-slot][role="main"]');
    var fallbackMaxWidth = maxWidth !== null && maxWidth !== void 0 ? maxWidth : mode === 'inline' ? '100vw' : '90vw';
    if (!sideNav || mode === 'overlay') {
      var chatPanel = layoutRoot === null || layoutRoot === void 0 ? void 0 : layoutRoot.querySelector(':scope > [data-layout-chat-panel]');
      var inlineChatPanelWidth = chatPanel && getComputedStyle(chatPanel).gridArea === 'chat-panel' ? chatPanel.getBoundingClientRect().width : 0;
      var overlayMaxWidth = Math.floor((window.innerWidth - inlineChatPanelWidth) * 0.9);
      var _constrainedMaxWidth = maxWidth ? Math.min((0, _convertResizeBoundToPixels.convertResizeBoundToPixels)(maxWidth), overlayMaxWidth) : overlayMaxWidth;
      return {
        min: minWidth,
        max: "".concat(Math.max((0, _convertResizeBoundToPixels.convertResizeBoundToPixels)(minWidth), _constrainedMaxWidth), "px")
      };
    }
    if (!main) {
      return {
        min: minWidth,
        max: fallbackMaxWidth
      };
    }
    var sideNavWidth = sideNav.getBoundingClientRect().width;
    var mainWidth = main.getBoundingClientRect().width;

    // JSDOM does not perform layout, so retain the static fallback in unit tests and other
    // environments where used widths cannot be measured.
    if (sideNavWidth === 0 || mainWidth === 0) {
      return {
        min: minWidth,
        max: fallbackMaxWidth
      };
    }
    var localPanel = main.querySelector('[data-layout-with-panel-slot]');
    var isLocalPanelInline = localPanel && getComputedStyle(localPanel).gridArea === 'panel';
    var localPanelWidth = isLocalPanelInline ? localPanel.getBoundingClientRect().width : 0;
    var mainContentWidth = mainWidth - localPanelWidth;
    var mainMinimumWidth = getPixelCustomProperty(main, _constants.mainMinimumWidthVar, _constants.defaultMainMinWidth);
    var availableWidth = Math.max(0, mainContentWidth - mainMinimumWidth);
    var availableInlineWidth = Math.floor(sideNavWidth + availableWidth);
    var constrainedMaxWidth = maxWidth ? Math.min((0, _convertResizeBoundToPixels.convertResizeBoundToPixels)(maxWidth), availableInlineWidth) : availableInlineWidth;
    return {
      min: minWidth,
      max: "".concat(Math.max((0, _convertResizeBoundToPixels.convertResizeBoundToPixels)(minWidth), constrainedMaxWidth), "px")
    };
  }, [getManagedResizeBounds, isChatPanelLayoutEnabled, maxWidth, minWidth, mode]);
  /**
   * Used to share the side nav element with the `Panel`,
   * which observes the side nav to determine its maximum width.
   */
  var sharedRef = (0, _useSideNavRef.useSideNavRef)();
  var mergedRef = (0, _mergeRefs.default)([navRef, sharedRef]);
  var onCompleteResize = (0, _react.useCallback)(function (finalWidth) {
    if (!isChatPanelLayoutEnabled) {
      setInlineWidth(finalWidth);
      return;
    }
    if (mode === 'inline') {
      setInlineWidth(finalWidth);
    } else {
      setOverlayWidth(finalWidth);
    }
    completeResize(mode, finalWidth);
  }, [completeResize, isChatPanelLayoutEnabled, mode]);
  var onResizeStartInternal = (0, _react.useCallback)(function () {
    startResize(mode);
  }, [mode, startResize]);
  var onResizeInternal = (0, _react.useCallback)(function (width) {
    return resize(mode, width);
  }, [mode, resize]);
  var toggleButtonElement = (0, _react.useContext)(_sideNavToggleButtonElement.SideNavToggleButtonElement);
  var topNavStartElement = (0, _react.useContext)(_topNavStartElement.TopNavStartElement);
  var devTimeOnlyAttributes = {};
  var openLayerObserver = (0, _useOpenLayerObserver.useOpenLayerObserver)({
    isEnabled: !(0, _fg.fg)('platform-dst-top-layer')
  });
  var flyoutStateRef = (0, _react.useRef)({
    type: 'not-active'
  });
  var isFlyoutVisible = (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) === 'open';
  // Flyouts, including their close animation, already have overlay placement.
  // The CSS-first inline allocation must not override it with an ID selector.
  var shouldApplyUnmanagedSizing = !managedSizing && (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) !== 'open' && (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) !== 'triggered-animate-close';
  var isExpandedOnDesktopRef = (0, _useStableRef.default)(isExpandedOnDesktop);
  var hasPeekStartedRef = (0, _react.useRef)(false);
  var onPeekStartRef = (0, _useStableRef.default)(onPeekStart);
  var onPeekEndRef = (0, _useStableRef.default)(onPeekEnd);
  var onPeekStartTimeoutIdRef = (0, _react.useRef)(undefined);
  (0, _react.useEffect)(function () {
    return function () {
      clearTimeout(onPeekStartTimeoutIdRef.current);
    };
  }, []);
  var updateFlyoutState = (0, _react.useMemo)(function () {
    function tryAbortPendingClose() {
      if (flyoutStateRef.current.type === 'waiting-for-close') {
        flyoutStateRef.current.abort();
      }
    }
    function open() {
      var prevFlyoutState = flyoutStateRef.current;
      tryAbortPendingClose();
      flyoutStateRef.current = {
        type: 'open'
      };
      setSideNavState(function (currentState) {
        if ((currentState === null || currentState === void 0 ? void 0 : currentState.desktop) === 'collapsed' && (currentState === null || currentState === void 0 ? void 0 : currentState.flyout) !== 'open') {
          return _objectSpread(_objectSpread({}, currentState), {}, {
            flyout: 'open'
          });
        }
        return currentState;
      });

      // Avoid redundant calls to `onPeekStart()`
      if (prevFlyoutState.type === 'not-active') {
        clearTimeout(onPeekStartTimeoutIdRef.current);
        onPeekStartTimeoutIdRef.current = setTimeout(function () {
          var _onPeekStartRef$curre;
          // If the flyout isn't still open after ~500ms then we won't count the peek
          // As we want to track user intention rather than all hovers
          if (isExpandedOnDesktopRef.current || flyoutStateRef.current.type !== 'open') {
            return;
          }
          hasPeekStartedRef.current = true;
          (_onPeekStartRef$curre = onPeekStartRef.current) === null || _onPeekStartRef$curre === void 0 || _onPeekStartRef$curre.call(onPeekStartRef);
        }, onPeekStartDelayMs);
      }
    }
    function close() {
      var prevFlyoutState = flyoutStateRef.current;
      tryAbortPendingClose();
      flyoutStateRef.current = {
        type: 'not-active'
      };
      setSideNavState(function (currentState) {
        if ((currentState === null || currentState === void 0 ? void 0 : currentState.desktop) === 'collapsed' && (currentState === null || currentState === void 0 ? void 0 : currentState.flyout) === 'open') {
          return _objectSpread(_objectSpread({}, currentState), {}, {
            flyout: 'triggered-animate-close'
          });
        }
        return currentState;
      });

      // Avoid redundant calls to `onPeekEnd()`
      if (prevFlyoutState.type !== 'not-active' && hasPeekStartedRef.current) {
        var _onPeekEndRef$current;
        hasPeekStartedRef.current = false;
        (_onPeekEndRef$current = onPeekEndRef.current) === null || _onPeekEndRef$current === void 0 || _onPeekEndRef$current.call(onPeekEndRef, {
          trigger: isExpandedOnDesktopRef.current ? 'side-nav-expand' : 'mouse-leave'
        });
      }
    }
    function canClose() {
      if (!(0, _fg.fg)('platform-dst-top-layer')) {
        return (openLayerObserver === null || openLayerObserver === void 0 ? void 0 : openLayerObserver.getCount({
          namespace: _constants.openLayerObserverSideNavNamespace
        })) === 0;
      }
      var nav = navRef.current;
      return !(nav && isFlyoutHeldOpen({
        nav: nav
      }));
    }
    return function onAction(action) {
      if (action === 'drag-from-flyout-started') {
        open();
        flyoutStateRef.current = {
          type: 'is-dragging-from-flyout'
        };
        return;
      }
      if (action === 'drag-from-flyout-finished') {
        open();
        return;
      }

      // ignoring all actions until the drag is finished
      if (flyoutStateRef.current.type === 'is-dragging-from-flyout') {
        return;
      }
      if (action === 'open') {
        open();
        return;
      }
      if (action === 'waiting-for-close') {
        if (flyoutStateRef.current.type === 'waiting-for-close') {
          return;
        }

        // A timeout is used to close the flyout after a delay when the user mouses out of the flyout area, and to allow
        // us to cancel the close if the user mouses back in.
        var timeout = setTimeout(function () {
          updateFlyoutState('ready-to-close');
        }, _flyoutCloseDelayMs.sideNavFlyoutCloseDelayMs);
        flyoutStateRef.current = {
          type: 'waiting-for-close',
          abort: function abort() {
            clearTimeout(timeout);
          }
        };
        return;
      }
      if (action === 'ready-to-close') {
        // If there are no open layers, we can close the flyout.
        if (canClose()) {
          close();
          return;
        }
        flyoutStateRef.current = {
          type: 'ready-to-close'
        };
        return;
      }
      if (action === 'force-close') {
        close();
        return;
      }
    };
  }, [isExpandedOnDesktopRef, onPeekEndRef, onPeekStartRef, openLayerObserver, setSideNavState]);
  var toggleVisibilityByScreenResize = (0, _useToggleSideNav.useToggleSideNav)({
    trigger: 'screen-resize'
  });
  var toggleVisibilityByClickOutsideOnMobile = (0, _useToggleSideNav.useToggleSideNav)({
    trigger: 'click-outside-on-mobile'
  });

  // Using `useLayoutEffect` so that there's no visual shift in non-SSR environments when using legacy API
  // For SSR the new API is still necessary
  (0, _react.useLayoutEffect)(function () {
    if (sideNavState !== null) {
      // Only need to do an initial sync if it hasn't been initialized from Root
      return;
    }

    // Sync the visibility in context (provided in `<Root>`) with the local `defaultCollapsed` prop provided to `SideNav`
    // after SSR hydration. This should only run once, after the initial render on the client.
    (0, _react.startTransition)(function () {
      setSideNavState({
        desktop: initialDefaultCollapsed ? 'collapsed' : 'expanded',
        mobile: 'collapsed',
        flyout: 'closed',
        lastTrigger: null
      });
    });
  }, [initialDefaultCollapsed, setSideNavState, sideNavState]);
  var handleExpand = (0, _react.useCallback)(function (_ref5) {
    var screen = _ref5.screen,
      trigger = _ref5.trigger;
    onExpand === null || onExpand === void 0 || onExpand({
      screen: screen,
      trigger: trigger
    });
    var navigationAnalyticsEvent = createAnalyticsEvent({
      source: 'topNav',
      actionSubject: 'sideNav',
      action: 'expanded',
      actionSubjectId: 'sideNavMenu',
      attributes: {
        trigger: trigger
      }
    });
    navigationAnalyticsEvent.fire('navigation');

    // When the side nav gets expanded, we close the flyout to reset it.
    // This prevents the flyout from staying open and ensures we are respecting the user's intent to expand.
    updateFlyoutState('force-close');
  }, [onExpand, updateFlyoutState, createAnalyticsEvent]);
  var handleCollapse = (0, _react.useCallback)(function (_ref6) {
    var screen = _ref6.screen,
      trigger = _ref6.trigger;
    onCollapse === null || onCollapse === void 0 || onCollapse({
      screen: screen,
      trigger: trigger
    });
    var navigationAnalyticsEvent = createAnalyticsEvent({
      source: 'topNav',
      actionSubject: 'sideNav',
      action: 'collapsed',
      actionSubjectId: 'sideNavMenu',
      attributes: {
        trigger: trigger
      }
    });
    navigationAnalyticsEvent.fire('navigation');

    // When the side nav gets collapsed, we close the flyout to reset it.
    // This prevents the flyout from staying open and ensures we are respecting the user's intent to collapse.
    updateFlyoutState('force-close');
  }, [onCollapse, updateFlyoutState, createAnalyticsEvent]);
  (0, _useSideNavVisibilityCallbacks.useSideNavVisibilityCallbacks)({
    onExpand: handleExpand,
    onCollapse: handleCollapse,
    isExpandedOnDesktop: isExpandedOnDesktop,
    isExpandedOnMobile: isExpandedOnMobile,
    lastTrigger: (_sideNavState$lastTri = sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.lastTrigger) !== null && _sideNavState$lastTri !== void 0 ? _sideNavState$lastTri : null
  });
  (0, _react.useEffect)(function () {
    var mediaQueryList = window.matchMedia('(min-width: 64rem)');
    return (0, _bindEventListener.bind)(mediaQueryList, {
      type: 'change',
      listener: function listener() {
        if (mediaQueryList.matches) {
          // We're transitioning from tablet to desktop viewport size.
          // We forcibly show the side nav if it was shown on mobile.
          if (isExpandedOnMobile && !isExpandedOnDesktop) {
            toggleVisibilityByScreenResize();
          }
        }
      }
    });
  }, [toggleVisibilityByScreenResize, isExpandedOnDesktop, isExpandedOnMobile]);

  /**
   * Close the mobile side nav if there is a click outside.
   *
   * Binding/unbinding on changes to `isExpandedOnMobile` instead of window size changes for simplicity.
   * If we listened to window size changes we'd need nested `bind()` calls.
   */
  (0, _react.useEffect)(function () {
    if (!isExpandedOnMobile) {
      return;
    }

    /**
     * The expected URL fragment used by the side nav skip link.
     */
    var skipLinkUrlFragment = "#".concat(id);
    return (0, _bindEventListener.bind)(window, {
      type: 'click',
      listener: function listener(event) {
        if (window.matchMedia('(min-width: 64rem)').matches) {
          // Clicks on desktop should do nothing
          return;
        }
        var sideNav = navRef.current;
        if (!sideNav || !(event.target instanceof Node)) {
          // Ignore if our element references are invalid
          return;
        }
        if (!event.target.isConnected) {
          /**
           * If the element that was clicked is no longer in the document, we should not collapse the side nav.
           * This can happen when the user clicks on a dropdown menu item (such as one used in a `...` More menu),
           * as the dropdown menu will close after being clicked. By the time this event listener runs, the clicked
           * element will no longer be in the document, so the check below for `sideNav.contains(event.target)` will fail.
           */
          return;
        }
        if (sideNav.contains(event.target)) {
          // Clicks inside the side nav should not close it
          return;
        }
        if (toggleButtonElement !== null && toggleButtonElement !== void 0 && toggleButtonElement.contains(event.target)) {
          // Clicks on the toggle button will already toggle the side nav,
          // so we need to ignore it or we end up doing a double toggle
          return;
        }
        if (event.target instanceof HTMLAnchorElement &&
        /**
         * Intentionally using `.getAttribute()` for simplicity to match exactly what we expect
         * for skip links.
         *
         * Alternatives considered:
         *
         * - Using `.href` returns a full URL, which would then require extra parsing.
         * - Using `.hash` could incorrectly capture `<a href="/another-page#skip-link-id>` so we'd need extra checks.
         *
         * This approach has an edge case of `<a href="/same-page#skip-link-id>` not being captured,
         * but we are okay with that trade-off.
         */
        event.target.getAttribute('href') === skipLinkUrlFragment) {
          // This was a click on a link to the side nav, so we shouldn't try to collapse the SideNav.
          // It was most likely the skip link, although anyone can render a link with the ID.
          // In either case keeping the SideNav expanded makes sense.
          return;
        }
        toggleVisibilityByClickOutsideOnMobile();
      }
    });
  }, [id, isExpandedOnMobile, toggleButtonElement, toggleVisibilityByClickOutsideOnMobile]);
  (0, _react.useEffect)(function () {
    if (!toggleButtonElement) {
      return;
    }
    return (0, _bindEventListener.bind)(toggleButtonElement, {
      type: 'mouseenter',
      listener: function listener() {
        // Only flyout the side nav if the user hovered while the side nav was collapsed
        if (isExpandedOnDesktop) {
          return;
        }

        // Only flyout the side nav on desktop viewports
        var _window$matchMedia = window.matchMedia('(min-width: 64rem)'),
          matches = _window$matchMedia.matches;
        if (matches) {
          updateFlyoutState('open');
        }
      }
    });
  }, [updateFlyoutState, toggleButtonElement, isExpandedOnDesktop]);
  (0, _react.useEffect)(function () {
    if (!toggleButtonElement) {
      return;
    }
    return (0, _bindEventListener.bind)(toggleButtonElement, {
      type: 'mouseleave',
      listener: function listener() {
        // If the side nav is not in flyout mode, we don't need to do anything
        if (!isFlyoutVisible) {
          return;
        }
        updateFlyoutState('waiting-for-close');
      }
    });
  }, [isFlyoutVisible, toggleButtonElement, updateFlyoutState]);
  (0, _react.useEffect)(function () {
    if (!navRef.current) {
      return;
    }
    return (0, _bindEventListener.bind)(navRef.current, {
      type: 'mouseenter',
      listener: function listener() {
        // If the side nav is not in flyout mode, we don't need to do anything
        if (isExpandedOnDesktop || !isFlyoutVisible) {
          return;
        }

        // The user mouses has moused back over the side nav
        updateFlyoutState('open');
      }
    });
  }, [isFlyoutVisible, updateFlyoutState, isExpandedOnDesktop]);
  (0, _react.useEffect)(function () {
    if (!navRef.current) {
      return;
    }
    return (0, _bindEventListener.bind)(navRef.current, {
      type: 'mouseleave',
      listener: function listener() {
        // If the side nav is not in flyout mode, we don't need to do anything
        if (!isFlyoutVisible) {
          return;
        }
        updateFlyoutState('waiting-for-close');
      }
    });
  }, [isFlyoutVisible, updateFlyoutState]);
  (0, _react.useEffect)(function () {
    var nav = navRef.current;
    if (!nav) {
      return;
    }
    if (!isFlyoutVisible) {
      return;
    }

    // Using a monitor rather than a drop target. Rationale:
    // - We are not creating a drop target for the users to drop on,
    //   we are just interested in listening to events within an element
    // - We do not want to impact `location.{*}.dropTargets` in events
    return (0, _elementAdapter.monitorForElements)({
      canMonitor: function canMonitor(_ref7) {
        var source = _ref7.source;
        return nav.contains(source.element);
      },
      onGenerateDragPreview: function onGenerateDragPreview() {
        updateFlyoutState('drag-from-flyout-started');
      },
      onDrop: function onDrop(_ref8) {
        var location = _ref8.location;
        // Always marking the drag and done
        updateFlyoutState('drag-from-flyout-finished');

        // If the user dropped outside of the flyout, we will close the flyout
        var underUsersPointer = document.elementFromPoint(location.current.input.clientX, location.current.input.clientY);
        if (!nav.contains(underUsersPointer)) {
          updateFlyoutState('waiting-for-close');
        }
      }
    });
  }, [isFlyoutVisible, updateFlyoutState]);
  (0, _react.useEffect)(function () {
    if (!topNavStartElement || !toggleButtonElement) {
      return;
    }
    return (0, _bindEventListener.bind)(topNavStartElement, {
      type: 'mouseover',
      listener: function listener(event) {
        // If the side nav is not in flyout mode, we don't need to do anything
        if (isExpandedOnDesktop || !isFlyoutVisible) {
          return;
        }
        if (event.target === topNavStartElement) {
          // The mouse is directly over the TopNavStart element, so cancel any pending flyout closes.
          updateFlyoutState('open');
          return;
        }
        if (event.target instanceof Element && toggleButtonElement.contains(event.target)) {
          // The mouse is over the toggle button or any of its children, so we don't want to close the flyout.
          // We also don't need to cancel any pending closes, as we have separate event listeners for the toggle button mouse events.
          return;
        }

        // The user has moused over a child element of the TopNavStart element that isn't the toggle button, e.g. the app switcher or nav logo,
        // so we should close the flyout (with a delay).
        updateFlyoutState('waiting-for-close');
      }
    });
  }, [topNavStartElement, isFlyoutVisible, toggleButtonElement, isExpandedOnDesktop, updateFlyoutState]);
  (0, _react.useEffect)(function () {
    if (!topNavStartElement) {
      return;
    }
    return (0, _bindEventListener.bind)(topNavStartElement, {
      type: 'mouseleave',
      listener: function listener() {
        // If the side nav is not in flyout mode, we don't need to do anything
        if (!isFlyoutVisible) {
          return;
        }

        // The mouse has left the TopNavStart element, so we should close the flyout with a delay.
        updateFlyoutState('waiting-for-close');
      }
    });
  }, [topNavStartElement, isFlyoutVisible, updateFlyoutState]);
  (0, _react.useEffect)(function () {
    // Close the flyout if there are no more layers open and the user is not mousing over the
    // flyout areas (side nav, TopNavStart element)

    return openLayerObserver === null || openLayerObserver === void 0 ? void 0 : openLayerObserver.onChange(function (_ref9) {
      var count = _ref9.count;
      if (flyoutStateRef.current.type === 'ready-to-close' && count === 0) {
        updateFlyoutState('force-close');
      }
    }, {
      namespace: _constants.openLayerObserverSideNavNamespace
    });
  }, [openLayerObserver, updateFlyoutState]);
  var focusOutTimeoutIdRef = (0, _react.useRef)(undefined);
  (0, _react.useEffect)(function () {
    // The same as the open layer observer `onChange` above, for when the `platform-dst-top-layer`
    // gate is on. Top-layer surfaces opened from the side nav are DOM descendants of it.
    var nav = navRef.current;
    if (!nav || !(0, _fg.fg)('platform-dst-top-layer')) {
      return;
    }
    function closeIfReady() {
      if (flyoutStateRef.current.type !== 'ready-to-close' || !nav) {
        return;
      }
      if (isFlyoutHeldOpen({
        nav: nav
      })) {
        return;
      }
      updateFlyoutState('force-close');
    }
    var unbindLayerChange = (0, _bindOpenLayerChange.bindOpenLayerChange)({
      within: nav,
      onChange: closeIfReady
    });
    var unbindFocusOut = (0, _bindEventListener.bind)(nav, {
      type: 'focusout',
      listener: function listener() {
        // Wait for focus to move before checking where it went.
        clearTimeout(focusOutTimeoutIdRef.current);
        focusOutTimeoutIdRef.current = setTimeout(closeIfReady, 0);
      }
    });

    // Removing the focused text field (for example when an inline rename ends) fires no
    // `focusout` in some browsers, so also check again when content inside the side nav changes.
    var removalObserver = new MutationObserver(closeIfReady);
    removalObserver.observe(nav, {
      childList: true,
      subtree: true
    });
    return function cleanup() {
      unbindLayerChange();
      unbindFocusOut();
      removalObserver.disconnect();
      clearTimeout(focusOutTimeoutIdRef.current);
    };
  }, [updateFlyoutState]);
  (0, _react.useEffect)(function () {
    // Clear flyout close timer if being unmounted
    return function cleanupPendingFlyoutClose() {
      if (flyoutStateRef.current.type === 'waiting-for-close') {
        flyoutStateRef.current.abort();
      }
    };
  }, []);
  if (process.env.NODE_ENV !== 'production') {
    var visible = [];
    if (isExpandedOnMobile) {
      visible.push('small');
    }
    if (isExpandedOnDesktop) {
      visible.push('large');
    }
    if (isFlyoutVisible) {
      visible.push('flyout');
    }
    devTimeOnlyAttributes['data-visible'] = visible.length ? visible.join(',') : 'false';
  }
  (0, _useSideNavToggleKeyboardShortcut.useSideNavToggleKeyboardShortcut)({
    canToggleWithShortcut: canToggleWithShortcut
  });
  // Used to conditionally display the keyboard shortcut in the SideNavPanelSplitter tooltip.
  var isShortcutEnabled = (0, _useIsSideNavShortcutEnabled.useIsSideNavShortcutEnabled)();
  (0, _useResizingWidthCssVarOnRootElement.useResizingWidthCssVarOnRootElement)({
    isEnabled: !isChatPanelLayoutEnabled || !managedSizing,
    cssVar: panelSplitterResizingVar,
    panelId: _constants.sideNavPanelSplitterId
  });
  var isExpandedStateDifferentFromInitial = isExpandedOnMobile || isExpandedOnDesktop !== initialIsExpandedOnDesktop;

  /**
   * Used to track (between renders) if the expanded state of the side nav has ever changed since mount.
   *
   * Cannot rely solely on `isExpandedStateDifferentFromInitial` because the expanded state can go back to the initial state.
   */
  var hasExpandedStateChangedRef = (0, _react.useRef)(false);
  (0, _react.useEffect)(function () {
    if (hasExpandedStateChangedRef.current) {
      return;
    }
    if (isExpandedStateDifferentFromInitial) {
      hasExpandedStateChangedRef.current = true;
    }
  }, [isExpandedStateDifferentFromInitial]);

  /**
   * If the expanded state of the side nav has ever changed since mount.
   *
   * Used to prevent sidebar expand animations from running on the initial load.
   * Otherwise, the `@starting-style` rule will cause the sidebar to slide in initially.
   */
  var hasExpandedStateChanged = isExpandedStateDifferentFromInitial || hasExpandedStateChangedRef.current;
  var isMotionUpliftEnabled = (0, _fg.fg)('platform-dst-motion-uplift-sidenav');

  // This is only used for the regular expand and collapse animations, not the flyout animations.
  var shouldShowSidebarToggleAnimation = isMotionUpliftEnabled &&
  // We do not apply the animation styles on the initial render, as the `@starting-style` rule will cause the sidebar to
  // slide in initially.
  hasExpandedStateChanged &&
  // We also do not apply the animation styles if the side nav is in flyout mode to make sure we don't override flyout styles.
  // If we instead try to unset the `transform` property in the flyout styles using `transform: initial`, it results in the entire
  // flyout animation being disabled.
  !isFlyoutVisible &&
  /**
   * Disabling animations for Firefox, as it doesn't support animating the `display` property:
   * https://caniuse.com/mdn-css_properties_display_is_transitionable
   *
   * As of October 2025, Firefox supports the expand animation, but not the collapse animation (it instantly changes to `display: none`).
   * Because of this, we are disabling all sidebar animations for Firefox so it doesn't look like a bug.
   *
   * Unfortunately we cannot use `@supports` to target the support of `transition-behavior: allow-discrete` specifically
   * for the `display` property. And `@supports at-rule(@starting-style)` is also not ready for browser use yet.
   *
   * We are using JS to detect Firefox and disable animations, instead of using CSS, as Compiled currently does not merge duplicate
   * CSS at-rules when at-rules are nested: https://github.com/atlassian-labs/compiled/blob/e04a325915e1d13010205089e4915de0e53bc2d4/packages/css/src/plugins/merge-duplicate-at-rules.ts#L5
   * Avoiding nesting the `@supports` at-rule inside of `@media` means Compiled can remove duplicate styles from the generated CSS.
   */
  !isFirefox;
  return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("nav", (0, _extends2.default)({
    id: id
  }, devTimeOnlyAttributes, {
    "data-layout-slot": true,
    "aria-label": label,
    style: (0, _defineProperty2.default)({}, _constants.sideNavVar, clampedWidth),
    ref: mergedRef,
    "data-testid": testId,
    className: (0, _runtime.ax)([styles.root, isChatPanelLayoutEnabled && styles.chatPanelSizing, isChatPanelLayoutEnabled && (managedSizing === null || managedSizing === void 0 ? void 0 : managedSizing.mode) === 'overlay' && styles.managedOverlay, isExpandedOnDesktop && !isExpandedOnMobile && !isFlyoutVisible && styles.hiddenMobileOnly, !isExpandedOnDesktop && isExpandedOnMobile && !isFlyoutVisible && styles.hiddenDesktopOnly, !isExpandedOnDesktop && !isExpandedOnMobile && !isFlyoutVisible && styles.hiddenMobileAndDesktop, isMotionUpliftEnabled && motionUpliftStyles.animationRTLSupport, shouldShowSidebarToggleAnimation && isMotionUpliftEnabled && motionUpliftStyles.animationBaseStyles, isExpandedOnMobile && shouldShowSidebarToggleAnimation && isMotionUpliftEnabled && motionUpliftStyles.expandAnimationMobile, !isExpandedOnMobile && shouldShowSidebarToggleAnimation && isMotionUpliftEnabled && motionUpliftStyles.collapseAnimationMobile, isExpandedOnDesktop && shouldShowSidebarToggleAnimation && isMotionUpliftEnabled && motionUpliftStyles.expandAnimationDesktop, !isExpandedOnDesktop && shouldShowSidebarToggleAnimation && isMotionUpliftEnabled && motionUpliftStyles.collapseAnimationDesktop, (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) === 'open' && isMotionUpliftEnabled && motionUpliftStyles.flyoutOpen, (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) === 'open' && !isMotionUpliftEnabled && styles.flyoutOpen, (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) === 'triggered-animate-close' && isMotionUpliftEnabled && motionUpliftStyles.flyoutAnimateClosed, (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) === 'triggered-animate-close' && !isMotionUpliftEnabled && styles.flyoutAnimateClosed])
  }), isChatPanelLayoutEnabled &&
  /*#__PURE__*/
  // CSS reserves only the nav minimum for chat's fit decision, before effects or lazy loading.
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-global-styles
  _react.default.createElement("style", null, "\n#".concat(_root.gridRootChatFitId, " { --n_fitNav: 0px; }\n").concat(shouldApplyUnmanagedSizing ? "#".concat(_root.gridRootId, " nav[data-layout-slot] { grid-area: main / aside / aside / aside; width: min(90%, ").concat(clampedWidth, "); }") : '', "\n@media (min-width: 64rem) {\n  @container navigation-main-space (min-width: ").concat(minWidth, ") {\n    #").concat(_root.gridRootChatFitId, " { --n_fitNav: ").concat(isExpandedOnDesktop ? minWidth : '0px', "; }\n    ").concat(shouldApplyUnmanagedSizing ? "#".concat(_root.gridRootId, " nav[data-layout-slot] { grid-area: side-nav; width: min(").concat(clampedWidth, ", calc(100cqw + var(--n_fitNav) - var(--n_chatTrack, 0px))); }") : '', "\n  }\n}\n")), /*#__PURE__*/_react.default.createElement(_dangerouslyHoistCssVarToDocumentRoot.DangerouslyHoistCssVarToDocumentRoot, {
    variableName: _constants.sideNavLiveWidthVar,
    value: "0px",
    mediaQuery: '@media (min-width: 64rem)',
    responsiveValue: isExpandedOnDesktop ? "var(".concat(panelSplitterResizingVar, ", ").concat(clampedWidth, ")") : 0
  }), dangerouslyHoistSlotSizes &&
  /*#__PURE__*/
  // ------ START UNSAFE STYLES ------
  // These styles are only needed for the UNSAFE legacy use case for Jira + Confluence.
  // When they aren't needed anymore we can delete them wholesale.
  _react.default.createElement(_dangerouslyHoistCssVarToDocumentRoot.DangerouslyHoistCssVarToDocumentRoot, {
    variableName: _constants.UNSAFE_sideNavLayoutVar,
    value: "var(".concat(_constants.sideNavLiveWidthVar, ")")
  })
  // ------ END UNSAFE STYLES ------
  , /*#__PURE__*/_react.default.createElement(_provider.PanelSplitterProvider, {
    panelId: _constants.sideNavPanelSplitterId,
    panelRef: navRef,
    panelWidth: renderedWidth,
    onCompleteResize: onCompleteResize,
    onResizeStartInternal: isChatPanelLayoutEnabled && isManaged ? onResizeStartInternal : undefined,
    onResizeInternal: isChatPanelLayoutEnabled && isManaged ? onResizeInternal : undefined,
    prepareResize: isChatPanelLayoutEnabled ? prepareResize : undefined,
    getResizeBounds: getResizeBounds,
    resizingCssVar: panelSplitterResizingVar
    // Not resizable when in peek (flyout) mode.
    ,
    isEnabled: !isFlyoutVisible,
    shortcut: isShortcutEnabled ? _sideNavToggleTooltipKeyboardShortcut.sideNavToggleTooltipKeyboardShortcut : undefined
  }, /*#__PURE__*/_react.default.createElement("div", {
    className: (0, _runtime.ax)([styles.flexContainer])
  }, children))));
}

/**
 * The side navigation layout area. It will show on the left (inline start) of the screen.
 *
 * Use the side nav area components (`SideNavHeader`, `SideNavBody`, `SideNavFooter`) to position
 * content within areas of the side nav.
 *
 * You can optionally render a `PanelSplitter` as a child to make the side navigation slot resizable.
 */
function SideNav(_ref1) {
  var children = _ref1.children,
    defaultCollapsed = _ref1.defaultCollapsed,
    _ref1$defaultWidth = _ref1.defaultWidth,
    defaultWidth = _ref1$defaultWidth === void 0 ? 320 : _ref1$defaultWidth,
    minWidth = _ref1.minWidth,
    maxWidth = _ref1.maxWidth,
    testId = _ref1.testId,
    label = _ref1.label,
    _ref1$skipLinkLabel = _ref1.skipLinkLabel,
    skipLinkLabel = _ref1$skipLinkLabel === void 0 ? label : _ref1$skipLinkLabel,
    onExpand = _ref1.onExpand,
    onCollapse = _ref1.onCollapse,
    onPeekStart = _ref1.onPeekStart,
    onPeekEnd = _ref1.onPeekEnd,
    canToggleWithShortcut = _ref1.canToggleWithShortcut,
    id = _ref1.id;
  var sideNav = /*#__PURE__*/_react.default.createElement(SideNavInternal, {
    defaultCollapsed: defaultCollapsed,
    defaultWidth: defaultWidth,
    minWidth: minWidth,
    maxWidth: maxWidth,
    testId: testId,
    label: label,
    skipLinkLabel: skipLinkLabel,
    onExpand: onExpand,
    onCollapse: onCollapse,
    onPeekStart: onPeekStart,
    onPeekEnd: onPeekEnd,
    id: id,
    canToggleWithShortcut: canToggleWithShortcut
  }, children);

  // Top-layer surfaces are found through the DOM, so the namespace is only needed when the gate is off.
  if ((0, _fg.fg)('platform-dst-top-layer')) {
    return sideNav;
  }
  return /*#__PURE__*/_react.default.createElement(_openLayerObserverNamespaceProvider.OpenLayerObserverNamespaceProvider, {
    namespace: _constants.openLayerObserverSideNavNamespace
  }, sideNav);
}