@vtex/styleguide
Version:
> VTEX Styleguide React components ([Docs](https://vtex.github.io/styleguide))
94 lines (74 loc) • 3.24 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _react = require("react");
var _react2 = _interopRequireDefault(_react);
var _utils = require("./utils");
var _useMergeRefs = require("../../utilities/useMergeRefs");
var _useMergeRefs2 = _interopRequireDefault(_useMergeRefs);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var FOCUSABLE_SELECTOR = 'a,frame,iframe,input:not([type=hidden]):not(:disabled),select:not(:disabled),textarea:not(:disabled),button:not(:disabled),*[tabindex]:not([tabindex="-1"])';
var findFirstFocusable = function findFirstFocusable(element) {
if (element.matches && element.matches(FOCUSABLE_SELECTOR)) {
return element;
}
return element.querySelector(FOCUSABLE_SELECTOR);
};
var findLastFocusable = function findLastFocusable(element) {
if (element.matches && element.matches(FOCUSABLE_SELECTOR)) {
return element;
}
var focusableElements = element.querySelectorAll(FOCUSABLE_SELECTOR);
return focusableElements[focusableElements.length - 1];
};
var focusFirstElement = function focusFirstElement(element) {
var firstElement = findFirstFocusable(element);
firstElement == null ? void 0 : firstElement.focus();
};
var FocusTrap = function FocusTrap(_ref) {
var children = _ref.children;
var child = _react.Children.only(children);
var focusContainer = (0, _react.useRef)(null);
var handleTab = (0, _react.useCallback)(function (event) {
if (!focusContainer.current) {
return;
}
var firstFocusableElement = findFirstFocusable(focusContainer.current);
var lastFocusableElement = findLastFocusable(focusContainer.current);
if (event.target === firstFocusableElement && event.shiftKey) {
event.preventDefault();
lastFocusableElement == null ? void 0 : lastFocusableElement.focus();
} else if (event.target === lastFocusableElement && !event.shiftKey) {
event.preventDefault();
firstFocusableElement == null ? void 0 : firstFocusableElement.focus();
}
}, []);
var handleKeyEvent = (0, _react.useCallback)(function (event) {
if (event.key === _utils.Key.TAB) {
handleTab(event);
}
}, [handleTab]);
(0, _react.useEffect)(function () {
if (_utils.canUseDOM) document.addEventListener('keydown', handleKeyEvent);
return function () {
if (_utils.canUseDOM) document.removeEventListener('keydown', handleKeyEvent);
};
}, [handleKeyEvent]);
(0, _react.useEffect)(function () {
if (!focusContainer.current) {
return;
}
var alreadyHasFocus = _utils.canUseDOM && focusContainer.current && focusContainer.current.contains(document.activeElement);
if (!alreadyHasFocus) focusFirstElement(focusContainer.current);
}, [focusContainer]);
var mergedRefs = (0, _useMergeRefs2.default)(typeof child === 'object' ? // The ref property doesn't exist on ReactElement types, but
// it exist in practice and is the only way to get the child
// element's ref
// eslint-disable-next-line @typescript-eslint/no-explicit-any
child.ref : function () {}, focusContainer);
return _react2.default.cloneElement(child, {
ref: mergedRefs
});
};
exports.default = FocusTrap;