UNPKG

@utahdts/utah-design-system

Version:
101 lines (96 loc) 3.28 kB
import { useCallback, useEffect, useMemo, } from 'react'; import { useImmer } from 'use-immer'; import { Banner } from '../../../components/popups/Banner/Banner'; import { BannerIcon } from '../../../components/popups/Banner/BannerIcon'; import { BannerMessage } from '../../../components/popups/Banner/BannerMessage'; import { joinClassNames } from '../../../util/joinClassNames'; import { useBanner } from '../hooks/useBanner'; /** @typedef {import('@utahdts/utah-design-system').UtahDesignSystemContextBannerWithId} UtahDesignSystemContextBannerWithId */ /** * @param {object} props * @param {UtahDesignSystemContextBannerWithId[]} props.banners * @param {number} [props.bannerDuration] * @param {string} [props.defaultClassName] * @returns {import('react').JSX.Element} */ export function BannersGlobal({ banners, bannerDuration, defaultClassName }) { const { removeBanner } = useBanner(); const timers = useMemo(() => /** @type {Record<string, number>} */({}), []); const [zones, setZones] = useImmer(/** @type {Record<string, UtahDesignSystemContextBannerWithId[]>} */({})); const currentOnClose = useCallback( /** * @param {import('react').MouseEvent | undefined} e * @param {UtahDesignSystemContextBannerWithId} banner */ (e, banner) => { if (banner.onClose) { banner.onClose(e); } else { removeBanner(banner); } if (banner.id) { clearTimeout(timers[banner.id]); } }, [removeBanner, timers] ); useEffect(() => { const draftZones = /** @type {Record<string, UtahDesignSystemContextBannerWithId[]>} */ ({}); const uniqueZones = [...new Set(banners.map((banner) => banner.position))]; uniqueZones.forEach((zone) => { if (zone) { draftZones[zone] = []; } }); banners.forEach((banner) => { const duration = banner.duration || bannerDuration; if (duration && !timers[banner.id]) { timers[banner.id] = window.setTimeout(() => { currentOnClose(undefined, banner); }, duration); } // @ts-expect-error draftZones[banner.position].push(banner); }); setZones(draftZones); }, [bannerDuration, banners, currentOnClose, removeBanner, setZones, timers]); useEffect( () => { // Cleaning timers Object.keys(timers).forEach((key) => clearTimeout(timers[key])); }, [] ); return ( <div className="utah-design-system banner-global__wrapper" aria-live="polite" > {Object.keys(zones).map((zone) => ( <div className={joinClassNames(`banner-global__${zone}`, 'banner-global__zone')} key={`banner-global__${zone}`} > {zones[zone]?.map((banner) => ( <Banner key={`banner__${banner.id}`} id={`banner__${banner.id}`} className={banner.className || defaultClassName} position={banner.position} onClose={(e) => currentOnClose(e, banner)} > {banner.icon ? <BannerIcon>{banner.icon}</BannerIcon> : ''} <BannerMessage> {banner.message} </BannerMessage> </Banner> ))} </div> ))} </div> ); }