design-react-kit
Version:
Componenti React per Bootstrap 5
100 lines • 4.65 kB
JavaScript
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