@atlaskit/popup
Version:
A popup displays brief content in an overlay.
62 lines (61 loc) • 2.23 kB
JavaScript
import { useEffect } from 'react';
import createFocusTrap from 'focus-trap';
import noop from '@atlaskit/ds-lib/noop';
import { useLayering } from '@atlaskit/layering';
import { fg } from '@atlaskit/platform-feature-flags';
import { useAnimationFrame } from './utils/use-animation-frame';
export const useFocusManager = ({
initialFocusRef,
popupRef,
triggerRef,
autoFocus,
shouldCloseOnTab,
shouldDisableFocusTrap,
shouldReturnFocus,
shouldRenderToParent
}) => {
const {
requestFrame,
cancelAllFrames
} = useAnimationFrame();
const {
currentLevel
} = useLayering();
useEffect(() => {
if (!popupRef || shouldCloseOnTab) {
return noop;
}
if (shouldDisableFocusTrap && fg('platform_dst_popup-disable-focuslock')) {
const isDropdown = popupRef.matches('[id^=ds--dropdown--]');
const popups = document.querySelectorAll(`[data-ds--level="${currentLevel - 1}"]`);
if (!(popups[popups.length - 1] && !shouldRenderToParent && isDropdown)) {
// Plucking trigger & popup content container from the tab order so that
// when we Shift+Tab, the focus moves to the element before trigger
requestFrame(() => {
triggerRef === null || triggerRef === void 0 ? void 0 : triggerRef.setAttribute('tabindex', '-1');
if (popupRef && autoFocus) {
popupRef.setAttribute('tabindex', '-1');
}
(initialFocusRef || popupRef).focus();
});
return noop;
}
}
const trapConfig = {
clickOutsideDeactivates: true,
escapeDeactivates: fg('platform_dst_nested_escape') ? false : true,
initialFocus: initialFocusRef || popupRef,
fallbackFocus: popupRef,
returnFocusOnDeactivate: shouldReturnFocus
};
const focusTrap = createFocusTrap(popupRef, trapConfig);
// Wait for the popup to reposition itself before we focus
requestFrame(() => {
focusTrap.activate();
});
return () => {
cancelAllFrames();
focusTrap.deactivate();
};
}, [popupRef, triggerRef, autoFocus, initialFocusRef, shouldCloseOnTab, shouldDisableFocusTrap, requestFrame, cancelAllFrames, shouldReturnFocus, shouldRenderToParent, currentLevel]);
};