import { createContext, useContext, useMemo } from "react"; export interface CodeBlockRendererProps { code: string; language?: string; } export class CodeBlockRendererRegistry { components: Record> = {}; registerComponent(language: string, component: React.FunctionComponent) { this.components[language] = component; } getComponent(language: string): React.FunctionComponent | undefined { return this.components[language]; } } const Context = createContext(null); interface CodeBlockRendererProviderProps { components: Record>; children: React.ReactNode; } /** * the compoennts must be memoized to avoid rerendering the provider unnecessarily * @param param0 * @returns */ export function CodeBlockRendererProvider({ components, children }: CodeBlockRendererProviderProps) { const registry = useMemo(() => { const registry = new CodeBlockRendererRegistry(); for (const [language, component] of Object.entries(components)) { registry.registerComponent(language, component); } return registry; }, [components]); return ( <> {children} ) } export function useCodeBlockRendererRegistry() { return useContext(Context); } export function useCodeBlockComponent(language: string) { const registry = useContext(Context); if (registry) { return registry.getComponent(language); } return undefined; }