import DOMPurify from 'dompurify'; import type { ReactNode } from 'react'; import { useCallback, useMemo, useSyncExternalStore } from 'react'; import { createPortal } from 'react-dom'; import { OmnichannelRoomIconContext } from '../context/OmnichannelRoomIconContext'; import OmnichannelRoomIconManager from '../lib/OmnichannelRoomIconManager'; let icons = Array.from(OmnichannelRoomIconManager.icons.values()); export type OmnichannelRoomIconProviderProps = { children?: ReactNode; }; export const OmnichannelRoomIconProvider = ({ children }: OmnichannelRoomIconProviderProps) => { const svgIcons = useSyncExternalStore( useCallback( (callback): (() => void) => OmnichannelRoomIconManager.on('change', () => { icons = Array.from(OmnichannelRoomIconManager.icons.values()); callback(); }), [], ), (): string[] => icons, ); return ( { const extractSnapshot = (app: string, iconName: string) => OmnichannelRoomIconManager.get(app, iconName); // We cache all the icons here, so that we can use them in the OmnichannelRoomIcon component const snapshots = new Map(); return { queryIcon: ( app: string, iconName: string, ): [subscribe: (onStoreChange: () => void) => () => void, getSnapshot: () => string | undefined] => [ (callback): (() => void) => OmnichannelRoomIconManager.on(`${app}-${iconName}`, () => { snapshots.set(`${app}-${iconName}`, extractSnapshot(app, iconName)); // Then we call the callback (onStoreChange), signaling React to re-render callback(); }), // No problem here, because it's return value is a cached in the snapshots map on subsequent calls () => { let snapshot = snapshots.get(`${app}-${iconName}`); if (!snapshot) { snapshot = extractSnapshot(app, iconName); snapshots.set(`${app}-${iconName}`, snapshot); } return snapshot; }, ], }; }, [])} > {createPortal( ${svgIcons.join('')}`, { USE_PROFILES: { svg: true, svgFilters: true }, }).slice(5, -6), }} />, document.body, 'custom-icons', )} {children} ); };