UNPKG

@vtex/styleguide

Version:

> VTEX Styleguide React components ([Docs](https://vtex.github.io/styleguide))

94 lines (74 loc) 3.24 kB
"use strict"; 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;