import { App, uniqueId, useApp } from '@tldraw/editor' import { createContext, useCallback, useContext, useState } from 'react' import { useEvents } from './useEventsProvider' /** @public */ export interface DialogProps { onClose: () => void } /** @public */ export interface TLDialog { id: string onClose?: () => void component: (props: DialogProps) => any } /** @public */ export type DialogsContextType = { addDialog: (dialog: Omit & { id?: string }) => string removeDialog: (id: string) => string updateDialog: (id: string, newDialogData: Partial) => string clearDialogs: () => void dialogs: TLDialog[] } /** @public */ export const DialogsContext = createContext({} as DialogsContextType) /** @public */ export type DialogsProviderProps = { overrides?: (app: App) => DialogsContextType children: any } /** @public */ export function DialogsProvider({ children }: DialogsProviderProps) { const app = useApp() const trackEvent = useEvents() const [dialogs, setDialogs] = useState([]) const addDialog = useCallback( (dialog: Omit & { id?: string }) => { const id = dialog.id ?? uniqueId() setDialogs((d) => { return [...d.filter((m) => m.id !== dialog.id), { ...dialog, id }] }) trackEvent('dialog', 'open-menu', { id }) app.addOpenMenu(id) return id }, [app, trackEvent] ) const updateDialog = useCallback( (id: string, newDialogData: Partial) => { setDialogs((d) => d.map((m) => { if (m.id === id) { return { ...m, ...newDialogData, } } return m }) ) trackEvent('dialog', 'open-menu', { id }) app.addOpenMenu(id) return id }, [app, trackEvent] ) const removeDialog = useCallback( (id: string) => { setDialogs((d) => d.filter((m) => { if (m.id === id) { m.onClose?.() return false } return true }) ) trackEvent('dialog', 'close-menu', { id }) app.deleteOpenMenu(id) return id }, [app, trackEvent] ) const clearDialogs = useCallback(() => { setDialogs((d) => { d.forEach((m) => { m.onClose?.() trackEvent('dialog', 'close-menu', { id: m.id }) app.deleteOpenMenu(m.id) }) return [] }) }, [app, trackEvent]) return ( {children} ) } /** @public */ export function useDialogs() { const ctx = useContext(DialogsContext) if (!ctx) { throw new Error('useDialogs must be used within a DialogsProvider') } return ctx }