@atlaskit/drawer
Version:
A drawer is a panel that slides in from the left side of the screen.
88 lines (86 loc) • 3.78 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = useDrawerStack;
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _react = require("react");
var _useLazyCallback = _interopRequireDefault(require("@atlaskit/ds-lib/use-lazy-callback"));
var _usePreviousValue = _interopRequireDefault(require("@atlaskit/ds-lib/use-previous-value"));
var _useStateRef3 = _interopRequireDefault(require("@atlaskit/ds-lib/use-state-ref"));
/**
* **Major versions will not know about each other**
*
* An array holding references to all currently open drawers. This only works
* for drawers of the same major version, because the reference differs between
* majors (for example V13 will not know about any from V14).
*
* Adapted from `useModalStack` in `@atlaskit/modal-dialog`. The top-layer drawer
* path uses this to know its position in the stack so that only the foreground
* drawer renders a visible `::backdrop` (this avoids cumulative darkening for
* nested or stacked drawers). Unlike the modal version, the register is timed
* off `isOpen` rather than `@atlaskit/motion`'s `useExitingPersistence`: the
* `Dialog` primitive owns its own exit lifecycle, so the top-layer drawer needs
* no `ExitingPersistence` wrapper.
*/
var drawerStackRegister = [];
/**
* Returns the position of the calling drawer in the drawer stack. A stack index
* of `0` is the foreground (top of the stack); higher numbers are further back.
*/
function useDrawerStack(_ref) {
var isOpen = _ref.isOpen,
onStackChange = _ref.onStackChange;
var _useStateRef = (0, _useStateRef3.default)(0),
_useStateRef2 = (0, _slicedToArray2.default)(_useStateRef, 2),
stackIndexRef = _useStateRef2[0],
setStackIndex = _useStateRef2[1];
var currentStackIndex = stackIndexRef.current;
var previousStackIndex = (0, _usePreviousValue.default)(stackIndexRef.current);
// Kept stable for the lifetime of the component so it can be the identity in
// the shared register. This is why it is a lazy callback and not a
// useMemo/useCallback value.
var updateStack = (0, _useLazyCallback.default)(function () {
var newStackIndex = drawerStackRegister.indexOf(updateStack);
// Read from the ref rather than state: this closure only ever sees the
// initial state value.
if (stackIndexRef.current !== newStackIndex) {
setStackIndex(newStackIndex);
stackIndexRef.current = newStackIndex;
}
});
(0, _react.useEffect)(function () {
if (!isOpen) {
return;
}
// Opening: join the front of the register (the newest open drawer is the
// foreground at index 0), then notify every open drawer to recompute.
if (drawerStackRegister.indexOf(updateStack) === -1) {
drawerStackRegister.unshift(updateStack);
}
drawerStackRegister.forEach(function (callback) {
return callback();
});
return function () {
// Closing or unmounting: leave the register and notify the rest.
var index = drawerStackRegister.indexOf(updateStack);
if (index !== -1) {
drawerStackRegister.splice(index, 1);
}
drawerStackRegister.forEach(function (callback) {
return callback();
});
};
}, [isOpen, updateStack]);
(0, _react.useEffect)(function () {
if (previousStackIndex === undefined) {
// Initial render: nothing to notify about.
return;
}
if (previousStackIndex !== currentStackIndex) {
onStackChange === null || onStackChange === void 0 || onStackChange(currentStackIndex);
}
}, [onStackChange, previousStackIndex, currentStackIndex]);
return currentStackIndex;
}