UNPKG

@atlaskit/navigation-system

Version:

The latest navigation system for Atlassian apps.

176 lines (169 loc) • 9.84 kB
/* toggle-button.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.SideNavToggleButton = void 0; require("./toggle-button.compiled.css"); var _runtime = require("@compiled/react/runtime"); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var _react = _interopRequireWildcard(require("react")); var _bindEventListener = require("bind-event-listener"); var _useAnalyticsEvents2 = require("@atlaskit/analytics-next/useAnalyticsEvents"); var _sidebarCollapse = _interopRequireDefault(require("@atlaskit/icon/core/sidebar-collapse")); var _sidebarExpand = _interopRequireDefault(require("@atlaskit/icon/core/sidebar-expand")); var _useOpenLayerObserver = require("@atlaskit/layering/use-open-layer-observer"); var _fg = require("@atlaskit/platform-feature-flags/fg"); var _requestClosePopovers = require("@atlaskit/top-layer/page-surface/request-close-popovers"); var _iconButton = require("../../top-nav-items/themed/icon-button"); var _sideNavToggleButtonAttachRef = require("./side-nav-toggle-button-attach-ref"); var _sideNavToggleTooltipKeyboardShortcut = require("./side-nav-toggle-tooltip-keyboard-shortcut"); var _sideNavVisibilityState = require("./side-nav-visibility-state"); var _useIsSideNavShortcutEnabled = require("./use-is-side-nav-shortcut-enabled"); var _useSideNavVisibility2 = require("./use-side-nav-visibility"); 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; } var toggleButtonTooltipOptions = { // We're disabling pointer events on the tooltip to prevent it from blocking mouse events, so that the side nav flyout stays open // when moving the mouse from the top bar to the side nav. ignoreTooltipPointerEvents: true, // A press swaps the label between `collapseLabel` and `expandLabel`, so keep the // tooltip open to show the new label. hasNewContentOnTriggerClick: true }; // For duplicate "mouseenter" issue when changing icons (see below) var silentIconStyles = null; /** * __SideNavToggleButton__ * * Button for toggling the side nav. It should be used in the top bar. */ var SideNavToggleButton = exports.SideNavToggleButton = function SideNavToggleButton(_ref) { var _ref$defaultCollapsed = _ref.defaultCollapsed, defaultCollapsed = _ref$defaultCollapsed === void 0 ? false : _ref$defaultCollapsed, expandLabel = _ref.expandLabel, collapseLabel = _ref.collapseLabel, testId = _ref.testId, interactionName = _ref.interactionName, onClick = _ref.onClick; var _useSideNavVisibility = (0, _useSideNavVisibility2.useSideNavVisibility)({ defaultCollapsed: defaultCollapsed }), isSideNavExpandedOnDesktop = _useSideNavVisibility.isExpandedOnDesktop, isSideNavExpandedOnMobile = _useSideNavVisibility.isExpandedOnMobile; var sideNavState = (0, _react.useContext)(_sideNavVisibilityState.SideNavVisibilityState); // When default state is provided to `Root` the state in context will already be // initialized in SSR var _useState = (0, _react.useState)(sideNavState === null ? !defaultCollapsed : isSideNavExpandedOnDesktop), _useState2 = (0, _slicedToArray2.default)(_useState, 2), isSideNavExpanded = _useState2[0], setIsSideNavExpanded = _useState2[1]; var ref = (0, _react.useContext)(_sideNavToggleButtonAttachRef.SideNavToggleButtonAttachRef); /** * Addresses HOT-121458 by ensuring that the toggle button element in context is always up to date. * * My theory is that something to do with SSR, hydration and suspense was causing the * underlying HTML element to change but without causing the toggle button to remount. * * This meant the effect calling `ref()` did not re-run, and the value in context became stale. */ var _useState3 = (0, _react.useState)(null), _useState4 = (0, _slicedToArray2.default)(_useState3, 2), element = _useState4[0], setElement = _useState4[1]; (0, _react.useEffect)(function () { ref(element); }, [element, ref]); (0, _react.useEffect)(function () { var _window$matchMedia = window.matchMedia('(min-width: 64rem)'), matches = _window$matchMedia.matches; setIsSideNavExpanded(matches ? isSideNavExpandedOnDesktop : isSideNavExpandedOnMobile); }, [isSideNavExpandedOnDesktop, isSideNavExpandedOnMobile]); (0, _react.useEffect)(function () { // When screen size changes, ensure we use the correct visibility state var mediaQueryList = window.matchMedia('(min-width: 64rem)'); return (0, _bindEventListener.bind)(mediaQueryList, { type: 'change', listener: function listener() { setIsSideNavExpanded(mediaQueryList.matches ? isSideNavExpandedOnDesktop : isSideNavExpandedOnMobile); } }); }, [isSideNavExpandedOnDesktop, isSideNavExpandedOnMobile]); var toggleVisibility = (0, _useToggleSideNav.useToggleSideNav)({ trigger: 'toggle-button' }); var _useAnalyticsEvents = (0, _useAnalyticsEvents2.useAnalyticsEvents)(), createAnalyticsEvent = _useAnalyticsEvents.createAnalyticsEvent; var openLayerObserver = (0, _useOpenLayerObserver.useOpenLayerObserver)({ isEnabled: !(0, _fg.fg)('platform-dst-top-layer') }); var handleClick = (0, _react.useCallback)(function (event, analyticsEvent) { onClick === null || onClick === void 0 || onClick(event, analyticsEvent, { isSideNavVisible: isSideNavExpanded }); toggleVisibility(); // Not gated. Top-layer tooltips (`platform-dst-top-layer-tooltip`) are not known to the observer. (0, _requestClosePopovers.requestClosePopovers)(); openLayerObserver === null || openLayerObserver === void 0 || openLayerObserver.closeLayers(); }, [isSideNavExpanded, onClick, openLayerObserver, toggleVisibility]); var handlePointerEnter = (0, _react.useCallback)(function () { // Hovers don't do anything on mobile, so not capturing var isDesktop = window.matchMedia('(min-width: 64rem)').matches; if (!isDesktop) { return; } var navigationAnalyticsEvent = createAnalyticsEvent({ source: 'topNav', actionSubject: 'sideNav', action: 'hovered', actionSubjectId: 'sideNavButton', attributes: { itemState: isSideNavExpanded ? 'expanded' : 'collapsed', screen: 'desktop' } }); navigationAnalyticsEvent.fire('navigation'); }, [createAnalyticsEvent, isSideNavExpanded]); /** * ## Behaviour * It is intentional that collapse icon will be used while the flyout is open. * The icon is tied to the expanded / collapse state, and not the flyout state. * * ## Why a function? * Unfortunately, changing the icon inside an <IconButton> when the user is over * the button will cause the svg element to be replaced, which can trigger a * "mouseenter" event. This is problematic when the user is already over the button, * as it can result in a "mouseenter" event after the user manually entered the button. * * `icon` accepts a function for the `icon` prop (ie a render prop), so we don't need to * memoize it, or pull it out into a new function */ var icon = function icon(props) { return /*#__PURE__*/_react.default.createElement("span", { className: (0, _runtime.ax)(["_1e0c1bgi _lcxvglyw"]) }, isSideNavExpanded ? /*#__PURE__*/_react.default.createElement(_sidebarCollapse.default, props) : /*#__PURE__*/_react.default.createElement(_sidebarExpand.default, props)); }; var isShortcutEnabled = (0, _useIsSideNavShortcutEnabled.useIsSideNavShortcutEnabled)(); var tooltipProps = (0, _react.useMemo)(function () { return _objectSpread(_objectSpread({}, toggleButtonTooltipOptions), {}, { shortcut: isShortcutEnabled ? _sideNavToggleTooltipKeyboardShortcut.sideNavToggleTooltipKeyboardShortcut : undefined }); }, [isShortcutEnabled]); return /*#__PURE__*/_react.default.createElement(_iconButton.IconButton, { appearance: "subtle", label: isSideNavExpanded ? collapseLabel : expandLabel, icon: icon, onClick: handleClick, onPointerEnter: handlePointerEnter, testId: testId, isTooltipDisabled: false, interactionName: interactionName, ref: setElement, tooltip: tooltipProps }); };