UNPKG

@kubit-ui-web/react-components

Version:

Kubit React Components is a customizable, accessible library of React web components, designed to enhance your application's user experience

72 lines 3.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.useTrapFocus = void 0; const react_1 = __importDefault(require("react")); const focusHandlers_1 = require("../../utils/focusHandlers/focusHandlers"); const useTrapFocus = ({ ref, // Default false in order to only active the window listener when needed trapFocus = false, }) => { react_1.default.useEffect(() => { const handleKeyDown = (e) => { // Do nothing is ref is not defined // Do nothing if tab is not pressed if (!ref.current || e.key !== 'Tab') { return; } const focusableElements = (0, focusHandlers_1.getFocusableDescendantsV2)({ element: ref.current }); // When the ref does not contain focusable elements if (!focusableElements.length) { // Do not change the current focus if the current focus is inside the ref // This happens in some element like in actionBottomSheet dropdown // When the focus is trap, but the options are not focusabled if (ref.current.contains(document.activeElement)) { e.preventDefault(); } return; } const firstFocusableElement = focusableElements[0]; const lastFocusableElement = focusableElements[focusableElements.length - 1]; // If we are at the last focusable element and we press tab (without shift), change the focus to the first focusable element if (!e.shiftKey && document.activeElement === lastFocusableElement) { firstFocusableElement?.focus(); e.preventDefault(); return; } // If we are at the first focusable element and we press shift + tab, change the focus to the last focusable element if (e.shiftKey && document.activeElement === firstFocusableElement) { lastFocusableElement?.focus(); e.preventDefault(); return; } // If we have preceded or passed the focusable elements, then: // When tab -> focus first element // When shift + tab -> focus last element // preceded or passed how ? -> Imagine no focusable elements inside the element container with tabIndex="-1", but they are focused manually with focus() if (firstFocusableElement?.compareDocumentPosition(e.target) & Node.DOCUMENT_POSITION_PRECEDING || lastFocusableElement?.compareDocumentPosition(e.target) & Node.DOCUMENT_POSITION_FOLLOWING) { if (e.shiftKey) { lastFocusableElement?.focus(); e.preventDefault(); return; } firstFocusableElement?.focus(); e.preventDefault(); } }; // It is being used window event listener instead of ref.eventListener because the focus is redirected to the body when a focused element disappears or is marked as disabled // In these cases, the handleKeyDown would not be triggered if the event listener is attached to the ref if (trapFocus) { window.addEventListener('keydown', handleKeyDown); } return () => { window.removeEventListener('keydown', handleKeyDown); }; }, [trapFocus]); }; exports.useTrapFocus = useTrapFocus; //# sourceMappingURL=useTrapFocus.js.map