UNPKG

@clayui/modal

Version:
168 lines (166 loc) 4.38 kB
import { ClayPortal, stack } from "@clayui/shared"; import { suppressOthers } from "aria-hidden"; import classNames from "classnames"; import React, { useEffect, useMemo, useRef } from "react"; import warning from "warning"; import Body from "./Body"; import Context from "./Context"; import Footer from "./Footer"; import Header, { Item, ItemGroup, Subtitle, SubtitleSection, Title, TitleIndicator, TitleSection } from "./Header"; import { useUserInteractions } from "./Hook"; import { ObserverType } from "./types"; const warningMessage = `You need to pass the 'observer' prop to ClayModal for everything to work fine, use the 'useModal' hook that exposes the observer. > const {observer} = useModal({...}); > > return ( > <ClayModal observer={observer}> > ... > </ClayModal> > ); `; let counter = 0; function Modal({ center, children, className, containerElementRef, containerProps = {}, disableAutoClose = false, observer, role = "dialog", size, spritemap, status, zIndex, ...otherProps }) { const modalElementRef = useRef(null); const modalBodyElementRef = useRef(null); const [show, content] = observer && observer.mutation ? observer.mutation : [false, false]; warning(observer !== void 0, warningMessage); useUserInteractions( modalElementRef, modalBodyElementRef, () => !disableAutoClose && observer.dispatch(ObserverType.Close), show, content ); useEffect(() => { observer.dispatch(ObserverType.RestoreFocus, document.activeElement); observer.dispatch(ObserverType.Open); }, []); useEffect(() => { if (modalBodyElementRef.current && show && content) { const focusedElement = modalBodyElementRef.current.querySelector("h1"); if (focusedElement) { focusedElement.focus(); } else { modalBodyElementRef.current.focus(); } } }, [show, content]); const ariaLabelledby = useMemo(() => { counter++; return `clay-modal-label-${counter}`; }, []); useEffect(() => { if (show && content) { stack.push(modalElementRef); } return () => { const index = stack.indexOf(modalElementRef); if (index >= 0) { stack.splice(index, 1); } }; }, [show, modalElementRef, content]); useEffect(() => { if (modalElementRef.current && show && stack[stack.length - 1] === modalElementRef) { return suppressOthers(modalElementRef.current); } }, [show]); return /* @__PURE__ */ React.createElement( ClayPortal, { ...containerProps, containerRef: containerElementRef, subPortalRef: modalElementRef }, /* @__PURE__ */ React.createElement( "div", { "aria-hidden": "true", className: classNames("modal-backdrop fade", { show }), style: { zIndex } } ), /* @__PURE__ */ React.createElement( "div", { ...otherProps, className: classNames("fade modal d-block", className, { show }), ref: modalElementRef, style: { zIndex: zIndex && zIndex + 10 } }, /* @__PURE__ */ React.createElement( "div", { className: classNames("modal-dialog", { [`modal-${size}`]: size, [`modal-${status}`]: status, "modal-dialog-centered": center }) }, /* @__PURE__ */ React.createElement( "div", { "aria-labelledby": ariaLabelledby, "aria-modal": "true", className: "modal-content", ref: modalBodyElementRef, role, tabIndex: -1 }, /* @__PURE__ */ React.createElement( Context.Provider, { value: { ariaLabelledby, onClose: () => observer.dispatch(ObserverType.Close), spritemap, status } }, content && children ) ) ) ) ); } Modal.Body = Body; Modal.Footer = Footer; Modal.Header = Header; Modal.Item = Item; Modal.ItemGroup = ItemGroup; Modal.Subtitle = Subtitle; Modal.SubtitleSection = SubtitleSection; Modal.Title = Title; Modal.TitleIndicator = TitleIndicator; Modal.TitleSection = TitleSection; var Modal_default = Modal; export { Modal_default as default };