import { ROOM_OPEN_MODE, RoomOpenModeToPath, type RoomOpenMode } from '@tldraw/dotcom-shared' import { useMultiplayerSync } from '@tldraw/sync' import { useCallback } from 'react' import { DefaultHelpMenu, DefaultHelpMenuContent, DefaultKeyboardShortcutsDialog, DefaultKeyboardShortcutsDialogContent, DefaultMainMenu, EditSubmenu, Editor, ExportFileContentSubMenu, ExtrasGroup, PeopleMenu, PreferencesGroup, TLComponents, Tldraw, TldrawUiButton, TldrawUiButtonIcon, TldrawUiButtonLabel, TldrawUiMenuGroup, TldrawUiMenuItem, ViewSubmenu, assertExists, useActions, useEditor, useTranslation, useValue, } from 'tldraw' import { UrlStateParams, useUrlState } from '../hooks/useUrlState' import { assetUrls } from '../utils/assetUrls' import { MULTIPLAYER_SERVER } from '../utils/config' import { createAssetFromUrl } from '../utils/createAssetFromUrl' import { multiplayerAssetStore } from '../utils/multiplayerAssetStore' import { useSharing } from '../utils/sharing' import { OPEN_FILE_ACTION, SAVE_FILE_COPY_ACTION, useFileSystem } from '../utils/useFileSystem' import { useHandleUiEvents } from '../utils/useHandleUiEvent' import { DocumentTopZone } from './DocumentName/DocumentName' import { MultiplayerFileMenu } from './FileMenu' import { Links } from './Links' import { ShareMenu } from './ShareMenu' import { SneakyOnDropOverride } from './SneakyOnDropOverride' import { StoreErrorScreen } from './StoreErrorScreen' import { ThemeUpdater } from './ThemeUpdater/ThemeUpdater' const components: TLComponents = { ErrorFallback: ({ error }) => { throw error }, HelpMenu: () => ( ), MainMenu: () => ( ), KeyboardShortcutsDialog: (props) => { const actions = useActions() return ( ) }, TopPanel: () => { const editor = useEditor() const isOffline = useValue( 'offline', () => { const status = assertExists( editor.store.props.multiplayerStatus, 'should be used with multiplayer store' ) return status.get() === 'offline' }, [] ) return }, SharePanel: () => { const editor = useEditor() const msg = useTranslation() return (
editor.addOpenMenu('share menu')} > {msg('people-menu.invite')}
) }, } export function MultiplayerEditor({ roomOpenMode, roomSlug, }: { roomOpenMode: RoomOpenMode roomSlug: string }) { const handleUiEvent = useHandleUiEvents() const storeWithStatus = useMultiplayerSync({ uri: `${MULTIPLAYER_SERVER}/${RoomOpenModeToPath[roomOpenMode]}/${roomSlug}`, roomId: roomSlug, assets: multiplayerAssetStore, }) const sharingUiOverrides = useSharing() const fileSystemUiOverrides = useFileSystem({ isMultiplayer: true }) const isReadonly = roomOpenMode === ROOM_OPEN_MODE.READ_ONLY || roomOpenMode === ROOM_OPEN_MODE.READ_ONLY_LEGACY const handleMount = useCallback( (editor: Editor) => { if (!isReadonly) { ;(window as any).app = editor ;(window as any).editor = editor } editor.updateInstanceState({ isReadonly, }) editor.registerExternalAssetHandler('url', createAssetFromUrl) }, [isReadonly] ) if (storeWithStatus.error) { return } return (
) } export function UrlStateSync() { const syncViewport = useCallback((params: UrlStateParams) => { window.history.replaceState( {}, document.title, window.location.pathname + `?v=${params.v}&p=${params.p}` ) }, []) useUrlState(syncViewport) return null }