@atlaskit/side-navigation
Version:
A highly composable side navigation component that supports nested views.
186 lines (180 loc) • 7.8 kB
JavaScript
/* index.tsx generated by @compiled/babel-plugin v3.0.2 */
import _extends from "@babel/runtime/helpers/extends";
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
import "./index.compiled.css";
import { ax, ix } from "@compiled/react/runtime";
import React, { Fragment, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import ExitingPersistence from '@atlaskit/motion/exiting-persistence';
import { fg } from '@atlaskit/platform-feature-flags/fg';
import useChildIds from '../../common/use-child-ids';
import { GoBackItem as GoBackButton } from '../Item/go-back-item';
import { NestingItem } from '../NestingItem';
import { NestedContext } from './nested-context';
import { NestingMotion } from './nesting-motion';
// Named so ERT doesn't pick up the override name as a type.
export var ROOT_ID = 'ATLASKIT_NESTED_ROOT';
/**
* @deprecated `@atlaskit/side-navigation` is deprecated. Use `@atlaskit/navigation-system` instead.
*/
var nestableNavigationContentStyles = null;
var nestingRootStyles = null;
/**
* __Nestable navigation content__
*
* The container for navigation items with nested views
*
* - [Examples](https://atlassian.design/components/side-navigation/examples#nested-navigation)
* - [Code](https://atlassian.design/components/side-navigation/code)
*
* @deprecated `@atlaskit/side-navigation` is deprecated. Use `@atlaskit/navigation-system` instead.
*/
export var NestableNavigationContent = function NestableNavigationContent(props) {
var containerRef = useRef(null);
var children = props.children,
testId = props.testId,
overrides = props.overrides,
initialStack = props.initialStack,
onChange = props.onChange,
onUnknownNest = props.onUnknownNest,
stack = props.stack,
showTopScrollIndicator = props.showTopScrollIndicator,
_props$isDefaultFocus = props.isDefaultFocusControl,
isDefaultFocusControl = _props$isDefaultFocus === void 0 ? true : _props$isDefaultFocus;
var goBackButtonRef = useRef(null);
var _useState = useState(stack || initialStack || []),
_useState2 = _slicedToArray(_useState, 2),
committedStack = _useState2[0],
setCommittedStack = _useState2[1];
var controlledStack = stack || undefined;
var currentStackId = committedStack[committedStack.length - 1] || ROOT_ID;
var _useState3 = useState('nesting'),
_useState4 = _slicedToArray(_useState3, 2),
transition = _useState4[0],
setTransition = _useState4[1];
var backTestId = testId && "".concat(testId, "--go-back-item");
var _useState5 = useState(''),
_useState6 = _slicedToArray(_useState5, 2),
activeParentId = _useState6[0],
setActiveParentId = _useState6[1];
var _useState7 = useState(false),
_useState8 = _slicedToArray(_useState7, 2),
focusGoBackButton = _useState8[0],
setFocusGoBackButton = _useState8[1];
var shouldFocus = isDefaultFocusControl && fg('platform-side-navigation-keyboard-focus');
var renderGoBackItem = overrides && overrides.GoBackItem && overrides.GoBackItem.render ? overrides.GoBackItem.render : function (props) {
return /*#__PURE__*/React.createElement(GoBackButton, props, "Go back");
};
var _useChildIds = useChildIds(currentStackId, committedStack, onUnknownNest),
childIdsRef = _useChildIds.childIdsRef;
var onNestHandler = useCallback(function (layerId) {
onChange && onChange(committedStack.concat(layerId));
setFocusGoBackButton(true);
if (controlledStack) {
// We are in controlled mode - ignore the steps.
return;
}
// We need to split the state update into to parts.
// First: Updating the direction of the motions.
// Second: Actually updating the stack (which will cause elements to enter & leave).
setTransition('nesting');
requestAnimationFrame(function () {
setCommittedStack(function (prev) {
var newStack = prev.concat(layerId);
return newStack;
});
});
}, [controlledStack, onChange, committedStack]);
var onUnNestHandler = useCallback(function () {
onChange && onChange(committedStack.slice(0, committedStack.length - 1));
setActiveParentId(currentStackId);
setFocusGoBackButton(false);
if (controlledStack) {
// We are in controlled mode - ignore the steps.
return;
}
// We need to split the state update into to parts.
// First: Updating the direction of the motions.
// Second: Actually updating the stack (which will cause elements to enter & leave).
setTransition('unnesting');
requestAnimationFrame(function () {
setCommittedStack(function (prev) {
var newStack = prev.slice(0, prev.length - 1);
return newStack;
});
});
}, [controlledStack, onChange, committedStack, setActiveParentId, currentStackId]);
useEffect(function () {
if (!controlledStack) {
// We aren't in controlled mode - bail out.
return;
}
if (JSON.stringify(committedStack) === JSON.stringify(controlledStack)) {
// stacks are equal - do nothing!
return;
}
// Controlled prop updated, let's figure out if we're nesting or unnesting.
if (controlledStack.length < committedStack.length) {
// We are unnesting (removing from the stack)
setTransition('unnesting');
} else {
// We are nesting (adding to the stack)
setTransition('nesting');
}
requestAnimationFrame(function () {
setCommittedStack(controlledStack);
});
}, [committedStack, controlledStack]);
var backButton = renderGoBackItem({
onClick: onUnNestHandler,
testId: backTestId,
ref: shouldFocus ? goBackButtonRef : null
});
var context = useMemo(function () {
return {
currentStackId: currentStackId,
backButton: backButton,
stack: committedStack,
onNest: onNestHandler,
onUnNest: onUnNestHandler,
parentId: ROOT_ID,
childIds: childIdsRef,
forceShowTopScrollIndicator: showTopScrollIndicator,
activeParentId: activeParentId,
goBackButtonRef: goBackButtonRef,
isDefaultFocusControl: isDefaultFocusControl,
focusGoBackButton: focusGoBackButton
};
}, [currentStackId, backButton, committedStack, onNestHandler, onUnNestHandler, childIdsRef, showTopScrollIndicator, activeParentId, goBackButtonRef, isDefaultFocusControl, focusGoBackButton]);
var manageFocus = function manageFocus(event) {
var triggeredByKeyboard = event.nativeEvent.detail === 0;
if (triggeredByKeyboard) {
containerRef.current && containerRef.current.focus();
}
};
return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement("div", {
"data-testid": testId,
ref: containerRef,
tabIndex: -1,
onClick: manageFocus,
className: ax(["_12ji1r31 _1qu2glyw _12y31o36 _4t3i1osq _kqswh2mm"])
}, /*#__PURE__*/React.createElement(ExitingPersistence, null, /*#__PURE__*/React.createElement(NestingMotion
// Key is needed to have a unique react instance per stack name.
// This enables us to easily animate it in & out with exiting persistence.
, {
key: currentStackId,
enterFrom: transition === 'nesting' ? 'right' : 'left',
exitTo: transition === 'nesting' ? 'left' : 'right',
testId: testId && "".concat(testId, "-anim")
}, function (motion) {
return /*#__PURE__*/React.createElement("div", _extends({}, motion, {
className: ax(["_1e0c1txw _1bsb1osq _4t3i1osq _kqswstnw _2lx21bp4", motion.className])
}), /*#__PURE__*/React.createElement(NestedContext.Provider, {
// This provider is inside the NestingMotion to ensure it keeps a stale
// reference to the previous value.
value: context
}, /*#__PURE__*/React.createElement(NestingItem, {
title: "",
id: ROOT_ID
}, children)));
}))));
};