UNPKG

design-react-kit

Version:

Componenti React per Bootstrap 5

100 lines 4.65 kB
import classNames from 'classnames'; import React, { useEffect, useRef, useState } from 'react'; import { Collapse as CollapseBase } from 'reactstrap'; import { Icon } from '../Icon/Icon'; export const Collapse = ({ header = false, className, navbar, megamenu, children, isOpen = false, onOverlayClick, cssModule, testId, closeSrText = 'Nascondi la navigazione', ...attributes }) => { const newCssModule = { 'navbar-collapse': 'navbar-collapsable', ...cssModule }; // Two-phase state to allow CSS transitions to play. // isVisible controls display:block/none; isExpanded controls the animation class. const [isVisible, setIsVisible] = useState(isOpen); const [isExpanded, setIsExpanded] = useState(isOpen); const panelRef = useRef(null); const triggerRef = useRef(null); useEffect(() => { if (!(megamenu || navbar)) return; if (isOpen) { triggerRef.current = document.activeElement; setIsVisible(true); // Double rAF ensures the browser has painted display:block before adding // the expanded class, so the CSS transform transition can fire. requestAnimationFrame(() => { requestAnimationFrame(() => { setIsExpanded(true); panelRef.current?.focus(); }); }); return; } setIsExpanded(false); // Wait for the CSS transition to complete before hiding. const timer = setTimeout(() => { setIsVisible(false); triggerRef.current?.focus(); }, PANEL_TRANSITION_MS); return () => clearTimeout(timer); }, [isOpen, megamenu, navbar]); useEffect(() => { if (!(megamenu || navbar)) return; if (isOpen) { document.body.style.overflow = 'hidden'; } else { document.body.style.overflow = ''; } return () => { document.body.style.overflow = ''; }; }, [isOpen, megamenu, navbar]); useEffect(() => { if (!(megamenu || navbar)) return; const main = document.querySelector('main'); if (!main) return; if (isOpen) { main.setAttribute('inert', ''); } else { main.removeAttribute('inert'); } return () => main.removeAttribute('inert'); }, [isOpen, megamenu, navbar]); useEffect(() => { if (!(megamenu || navbar)) return; const handleKeyDown = (e) => { if (e.key === 'Escape' && isOpen) { onOverlayClick?.(); } }; document.addEventListener('keydown', handleKeyDown); return () => document.removeEventListener('keydown', handleKeyDown); }, [isOpen, megamenu, navbar, onOverlayClick]); // Must match the longest CSS transition on .navbar-collapsable (currently 0.3s + buffer). const PANEL_TRANSITION_MS = 350; if (megamenu || navbar) { const classes = classNames(className, 'navbar-collapse', { expanded: isExpanded }); const overlayClasses = classNames('overlay', { fade: isVisible, show: isExpanded }); const displayStyle = { display: isVisible ? 'block' : 'none' }; return (React.createElement(CollapseBase, { className: classes, cssModule: newCssModule, navbar: navbar, style: displayStyle, tabIndex: -1, innerRef: panelRef, role: isOpen ? 'dialog' : undefined, "aria-modal": isOpen ? true : undefined, "aria-label": isOpen ? 'Menu di navigazione' : undefined, "data-testid": testId, ...attributes }, React.createElement("div", { className: overlayClasses, style: displayStyle, onClick: onOverlayClick }), React.createElement("div", { className: 'close-div' }, React.createElement("button", { className: 'btn close-menu', type: 'button', onClick: onOverlayClick }, React.createElement("span", { className: 'visually-hidden' }, closeSrText), React.createElement(Icon, { color: 'white', icon: 'it-close-big' }))), megamenu ? React.createElement("div", { className: 'menu-wrapper ' }, children) : React.createElement(React.Fragment, null, children))); } const classes = classNames(className, { 'link-list-wrapper': header }); return (React.createElement(CollapseBase, { className: classes, cssModule: newCssModule, ...attributes, navbar: navbar, isOpen: isOpen, "data-testid": testId }, children)); }; //# sourceMappingURL=Collapse.js.map