[2/4] Rename sync hooks, add bookmarks to demo (#4094)
Adds a new `onEditorMount` callback to the store, allowing store creators to do things like registering bookmark handlers. We use this in the new demo hook. This also renames `useRemoteSyncClient` to `useMultiplayerSync`, and `useRemoteSyncDemo` to `useMultiplayerDemo`. Closes TLD-2601 ### Change type - [x] `api`
This commit is contained in:
parent
965bc10997
commit
627c84c2af
13 changed files with 127 additions and 39 deletions
|
@ -1,2 +1,6 @@
|
|||
export { useDemoRemoteSyncClient, type UseDemoSyncClientConfig } from './useDemoSyncClient'
|
||||
export { useRemoteSyncClient, type RemoteTLStoreWithStatus } from './useRemoteSyncClient'
|
||||
export {
|
||||
useMultiplayerSync,
|
||||
type RemoteTLStoreWithStatus,
|
||||
type UseMultiplayerSyncOptions,
|
||||
} from './useMultiplayerSync'
|
||||
export { useMultiplayerDemo, type UseMultiplayerDemoOptions } from './useMutliplayerDemo'
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
} from '@tldraw/sync'
|
||||
import { useEffect, useState } from 'react'
|
||||
import {
|
||||
Editor,
|
||||
Signal,
|
||||
TAB_ID,
|
||||
TLAssetStore,
|
||||
|
@ -33,14 +34,14 @@ export type RemoteTLStoreWithStatus = Exclude<
|
|||
>
|
||||
|
||||
/** @public */
|
||||
export function useRemoteSyncClient(opts: UseSyncClientConfig): RemoteTLStoreWithStatus {
|
||||
export function useMultiplayerSync(opts: UseMultiplayerSyncOptions): RemoteTLStoreWithStatus {
|
||||
const [state, setState] = useState<{
|
||||
readyClient?: TLSyncClient<TLRecord, TLStore>
|
||||
error?: Error
|
||||
} | null>(null)
|
||||
const { uri, roomId = 'default', userPreferences: prefs, assets } = opts
|
||||
const { uri, roomId = 'default', userPreferences: prefs, assets, onEditorMount } = opts
|
||||
|
||||
const store = useTLStore({ schema, assets })
|
||||
const store = useTLStore({ schema, assets, onEditorMount })
|
||||
|
||||
const error: NonNullable<typeof state>['error'] = state?.error ?? undefined
|
||||
const track = opts.trackAnalyticsEvent
|
||||
|
@ -134,11 +135,12 @@ export function useRemoteSyncClient(opts: UseSyncClientConfig): RemoteTLStoreWit
|
|||
}
|
||||
|
||||
/** @public */
|
||||
export interface UseSyncClientConfig {
|
||||
export interface UseMultiplayerSyncOptions {
|
||||
uri: string
|
||||
roomId?: string
|
||||
userPreferences?: Signal<TLUserPreferences>
|
||||
/* @internal */
|
||||
trackAnalyticsEvent?(name: string, data: { [key: string]: any }): void
|
||||
assets?: Partial<TLAssetStore>
|
||||
onEditorMount?: (editor: Editor) => void
|
||||
}
|
|
@ -1,9 +1,19 @@
|
|||
import { useMemo } from 'react'
|
||||
import { MediaHelpers, Signal, TLAssetStore, TLUserPreferences, uniqueId } from 'tldraw'
|
||||
import { RemoteTLStoreWithStatus, useRemoteSyncClient } from './useRemoteSyncClient'
|
||||
import { useCallback, useMemo } from 'react'
|
||||
import {
|
||||
AssetRecordType,
|
||||
Editor,
|
||||
MediaHelpers,
|
||||
Signal,
|
||||
TLAsset,
|
||||
TLAssetStore,
|
||||
TLUserPreferences,
|
||||
getHashForString,
|
||||
uniqueId,
|
||||
} from 'tldraw'
|
||||
import { RemoteTLStoreWithStatus, useMultiplayerSync } from './useMultiplayerSync'
|
||||
|
||||
/** @public */
|
||||
export interface UseDemoSyncClientConfig {
|
||||
export interface UseMultiplayerDemoOptions {
|
||||
roomId: string
|
||||
userPreferences?: Signal<TLUserPreferences>
|
||||
/** @internal */
|
||||
|
@ -29,18 +39,26 @@ function getEnv(cb: () => string | undefined): string | undefined {
|
|||
const DEMO_WORKER = getEnv(() => process.env.DEMO_WORKER) ?? 'https://demo.tldraw.xyz'
|
||||
const IMAGE_WORKER = getEnv(() => process.env.IMAGE_WORKER) ?? 'https://images.tldraw.xyz'
|
||||
|
||||
export function useDemoRemoteSyncClient({
|
||||
export function useMultiplayerDemo({
|
||||
roomId,
|
||||
userPreferences,
|
||||
host = DEMO_WORKER,
|
||||
}: UseDemoSyncClientConfig): RemoteTLStoreWithStatus {
|
||||
}: UseMultiplayerDemoOptions): RemoteTLStoreWithStatus {
|
||||
const assets = useMemo(() => createDemoAssetStore(host), [host])
|
||||
|
||||
return useRemoteSyncClient({
|
||||
return useMultiplayerSync({
|
||||
uri: `${host}/connect/${roomId}`,
|
||||
roomId,
|
||||
userPreferences,
|
||||
assets,
|
||||
onEditorMount: useCallback(
|
||||
(editor: Editor) => {
|
||||
editor.registerExternalAssetHandler('url', async ({ url }) => {
|
||||
return await createAssetFromUrlUsingDemoServer(host, url)
|
||||
})
|
||||
},
|
||||
[host]
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -116,3 +134,49 @@ function createDemoAssetStore(host: string): TLAssetStore {
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
async function createAssetFromUrlUsingDemoServer(host: string, url: string): Promise<TLAsset> {
|
||||
const urlHash = getHashForString(url)
|
||||
try {
|
||||
// First, try to get the meta data from our endpoint
|
||||
const fetchUrl = new URL(`${host}/bookmarks/unfurl`)
|
||||
fetchUrl.searchParams.set('url', url)
|
||||
|
||||
const meta = (await (await fetch(fetchUrl)).json()) as {
|
||||
description?: string
|
||||
image?: string
|
||||
favicon?: string
|
||||
title?: string
|
||||
} | null
|
||||
|
||||
return {
|
||||
id: AssetRecordType.createId(urlHash),
|
||||
typeName: 'asset',
|
||||
type: 'bookmark',
|
||||
props: {
|
||||
src: url,
|
||||
description: meta?.description ?? '',
|
||||
image: meta?.image ?? '',
|
||||
favicon: meta?.favicon ?? '',
|
||||
title: meta?.title ?? '',
|
||||
},
|
||||
meta: {},
|
||||
}
|
||||
} catch (error) {
|
||||
// Otherwise, fallback to a blank bookmark
|
||||
console.error(error)
|
||||
return {
|
||||
id: AssetRecordType.createId(urlHash),
|
||||
typeName: 'asset',
|
||||
type: 'bookmark',
|
||||
props: {
|
||||
src: url,
|
||||
description: '',
|
||||
image: '',
|
||||
favicon: '',
|
||||
title: '',
|
||||
},
|
||||
meta: {},
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue