@intility/bifrost-react
Version:
React library for Intility's design system, Bifrost.
115 lines (114 loc) • 4.69 kB
JavaScript
"use client";
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import classNames from "classnames";
import { FocusTrap } from "focus-trap-react";
import { forwardRef, useEffect } from "react";
import useBreakpoint from "../../hooks/useBreakpoint.js";
import isInert from "../../utils/isInert.js";
import CloseButton from "../common/CloseButton.internal.js";
const Drawer = /*#__PURE__*/ forwardRef(({ children, className, position = "right", header, footer, isOpen = false, overlay = undefined, disableFocusTrap = false, noPadding = false, onRequestClose, ...props }, ref)=>{
const isLarge = useBreakpoint("large");
// if overlay prop is undefined, an overlay will be displayed (with css) for
// screens under 1280px ('large'), unless it's a bottom drawer
const overlayEnabled = overlay ?? (position !== "bottom" && !isLarge);
const drawerContent = /*#__PURE__*/ _jsxs(_Fragment, {
children: [
onRequestClose && /*#__PURE__*/ _jsx(CloseButton, {
onClick: onRequestClose
}),
header && /*#__PURE__*/ _jsx("header", {
className: "bf-drawer-header",
"data-testid": "bf-drawer-header",
children: header
}),
children
]
});
return /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsx(FocusTrap, {
active: isOpen && overlayEnabled && !disableFocusTrap,
focusTrapOptions: {
allowOutsideClick: true,
fallbackFocus: ".bf-drawer-focus-trap-fallback",
initialFocus: false
},
children: /*#__PURE__*/ _jsx("div", {
className: classNames("bf-drawer", "bf-scrollbar-small", "bf-drawer-focus-trap-fallback", "bf-container", "bf-open-sans", className, {
"bf-drawer-open": isOpen,
"bf-drawer-with-footer": footer,
"bf-drawer-with-close": onRequestClose,
"bf-drawer-bottom": position === "bottom",
"bf-drawer-nopadding": noPadding
}),
"data-testid": "bf-drawer",
ref: ref,
tabIndex: -1,
// inert is an attribute to disable interactivity (like clicks and
// focus) and AT (Assistive Technologies, like screen reader).
inert: isInert(!isOpen),
...props,
children: /*#__PURE__*/ _jsx("div", {
children: footer ? /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsx("div", {
className: "bf-drawer-content bf-scrollbar-small",
children: drawerContent
}),
/*#__PURE__*/ _jsx("div", {
className: "bf-drawer-footer",
children: footer
})
]
}) : drawerContent
})
})
}),
overlayEnabled && /*#__PURE__*/ _jsx(Overlay, {
onRequestClose: onRequestClose,
open: isOpen
})
]
});
});
Drawer.displayName = "Drawer";
// INTERNAL Overlay
const Overlay = ({ onRequestClose, open })=>{
// close drawer on ESC
useEffect(()=>{
if (!open || !onRequestClose) return;
const closeDrawerOnEsc = (e)=>{
if (e.key === "Escape") {
e.stopPropagation();
onRequestClose(e);
}
};
document.addEventListener("keydown", closeDrawerOnEsc);
return ()=>{
document.removeEventListener("keydown", closeDrawerOnEsc);
};
}, [
onRequestClose,
open
]);
// disable body scrollbar
useEffect(()=>{
if (!open) return;
document.documentElement.classList.add("bf-drawer-overlay-active");
return ()=>{
document.documentElement.classList.remove("bf-drawer-overlay-active");
};
}, [
open
]);
return /*#__PURE__*/ _jsx("div", {
className: classNames("bf-drawer-overlay", {
"bf-drawer-overlay-open": open
}),
onClick: (e)=>{
e.stopPropagation();
onRequestClose?.(e);
}
});
};
export default Drawer;