import { Client , Others , Presence , LiveObject , LiveMap , Room , User , LiveList , } from "@liveblocks/client" ; import * as React from "react" ; type LiveblocksProviderProps = { children : React . ReactNode ; client : Client ; } ; const ClientContext = React . createContext < Client | null > ( null ) ; const RoomContext = React . createContext < Room | null > ( null ) ; /**
 * Makes the Liveblocks client available in the component hierarchy below.
 */ export function LiveblocksProvider ( props ) { return ( < ClientContext . Provider value = { props . client } > { props . children } < /ClientContext.Provider>); } /**
 * Returns the client of the nearest LiveblocksProvider above in the react component tree
 */ function useClient ( ) { const client = React . useContext ( ClientContext ) ; if ( client == null ) { throw new Error ( "LiveblocksProvider is missing from the react tree" ) ; } return client ; } type RoomProviderProps < TStorageRoot > = { /**
     * The id of the room you want to connect to
     */ id : string ; /**
     * A callback that let you initialize the default presence when entering the room.
     * If ommited, the default presence will be an empty object
     */ defaultPresence ? : ( ) => Presence ; defaultStorageRoot ? : TStorageRoot ; children : React . ReactNode ; } ; /**
 * Makes a Room available in the component hierarchy below.
 * When this component is unmounted, the current user leave the room.
 * That means that you can't have 2 RoomProvider with the same room id in your react tree.
 */ export function RoomProvider < TStorageRoot > ( { id , children , defaultPresence , defaultStorageRoot , } ) { const client = useClient ( ) ; React . useEffect ( ( ) => { return ( ) => { client . leave ( id ) ; } ; } , [ client , id ] ) ; const room = client . getRoom ( id ) || client . enter ( id , { defaultPresence : defaultPresence ? defaultPresence ( ) : undefined , defaultStorageRoot , } ) ; return < RoomContext . Provider value = { room } > { children } < /RoomContext.Provider>; } /**
 * Returns the room of the nearest RoomProvider above in the react component tree
 */ export function useRoom ( ) { const room = React . useContext ( RoomContext ) ; if ( room == null ) { throw new Error ( "RoomProvider is missing from the react tree" ) ; } return room ; } example export function useMyPresence < T extends Presence > ( ) { const room = useRoom ( ) ; const presence = room . getPresence < T > ( ) ; const [ , update ] = React . useState ( 0 ) ; React . useEffect ( ( ) => { function onMyPresenceChange ( ) { update ( ( x ) => x + 1 ) ; } const unsubscribe = room . subscribe ( "my-presence" , onMyPresenceChange ) ; return ( ) => { unsubscribe ( ) ; } ; } , [ room ] ) ; const setPresence = React . useCallback ( ( overrides , options ? ) => room . updatePresence ( overrides , options ) , [ room ] ) ; return [ presence , setPresence ] ; } example export function useUpdateMyPresence < T extends Presence > ( ) { const room = useRoom ( ) ; return React . useCallback ( ( overrides , options ? ) => { room . updatePresence ( overrides , options ) ; } , [ room ] ) ; } example export function useOthers < T extends Presence > ( ) { const room = useRoom ( ) ; const [ , update ] = React . useState ( 0 ) ; React . useEffect ( ( ) => { function onOthersChange ( ) { update ( ( x ) => x + 1 ) ; } const unsubscribe = room . subscribe ( "others" , onOthersChange ) ; return ( ) => { unsubscribe ( ) ; } ; } , [ room ] ) ; return room . getOthers ( ) ; } example export function useBroadcastEvent ( ) { const room = useRoom ( ) ; return React . useCallback ( ( event ) => { room . broadcastEvent ( event ) ; } , [ room ] ) ; } example export function useErrorListener ( callback ) { const room = useRoom ( ) ; const savedCallback = React . useRef ( callback ) ; React . useEffect ( ( ) => { savedCallback . current = callback ; } ) ; React . useEffect ( ( ) => { const listener = ( e ) => savedCallback . current ( e ) ; const unsubscribe = room . subscribe ( "error" , listener ) ; return ( ) => { unsubscribe ( ) ; } ; } , [ room ] ) ; } example export function useEventListener < TEvent > ( callback ) { const room = useRoom ( ) ; const savedCallback = React . useRef ( callback ) ; React . useEffect ( ( ) => { savedCallback . current = callback ; } ) ; React . useEffect ( ( ) => { const listener = ( e ) => savedCallback . current ( e ) ; const unsubscribe = room . subscribe ( "event" , listener ) ; return ( ) => { unsubscribe ( ) ; } ; } , [ room ] ) ; } example export function useSelf < TPresence extends Presence = Presence > ( ) { const room = useRoom ( ) ; const [ , update ] = React . useState ( 0 ) ; React . useEffect ( ( ) => { function onChange ( ) { update ( ( x ) => x + 1 ) ; } const unsubscribePresence = room . subscribe ( "my-presence" , onChange ) ; const unsubscribeConnection = room . subscribe ( "connection" , onChange ) ; return ( ) => { unsubscribePresence ( ) ; unsubscribeConnection ( ) ; } ; } , [ room ] ) ; return room . getSelf < TPresence > ( ) ; } export function useStorage < TRoot extends Record < string , any > > ( ) { const room = useRoom ( ) ; const [ root , setState ] = React . useState < LiveObject < TRoot > | null > ( null ) ; React . useEffect ( ( ) => { let didCancel = false ; async function fetchStorage ( ) { const storage = await room . getStorage < TRoot > ( ) ; if ( ! didCancel ) { setState ( storage . root ) ; } } fetchStorage ( ) ; return ( ) => { didCancel = true ; } ; } , [ room ] ) ; return [ root ] ; } param key param entries returns example export function useMap < TKey extends string , TValue > ( key , entries ? ) { return useCrdt ( key , new LiveMap ( entries ) ) ; } param key param items returns example export function useList < TValue > ( key , items ? ) { return useCrdt < LiveList < TValue > > ( key , new LiveList ( items ) ) ; } param key param initialData returns example export function useObject < TData > ( key , initialData ? ) { return useCrdt ( key , new LiveObject ( initialData ) ) ; } /**
 * Returns a function that undoes the last operation executed by the current client.
 * It does not impact operations made by other clients.
 */ export function useUndo ( ) { return useRoom ( ) . history . undo ; } /**
 * Returns a function that redoes the last operation executed by the current client.
 * It does not impact operations made by other clients.
 */ export function useRedo ( ) { return useRoom ( ) . history . redo ; } /**
 * Returns a function that batches modifications made during the given function.
 * All the modifications are sent to other clients in a single message.
 * All the modifications are merged in a single history item (undo/redo).
 * All the subscribers are called only after the batch is over.
 */ export function useBatch ( ) { return useRoom ( ) . batch ; } /**
 * Returns the room.history
 */ export function useHistory ( ) { return useRoom ( ) . history ; } function useCrdt < T > ( key , initialCrdt ) { const room = useRoom ( ) ; const [ root ] = useStorage ( ) ; const [ , setCount ] = React . useState ( 0 ) ; React . useEffect ( ( ) => { if ( root == null ) { return ; } let crdt = root . get ( key ) ; if ( crdt == null ) { crdt = initialCrdt ; root . set ( key , crdt ) ; } function onChange ( ) { setCount ( ( x ) => x + 1 ) ; } function onRootChange ( ) { const newCrdt = root ! . get ( key ) ; if ( newCrdt !== crdt ) { unsubscribeCrdt ( ) ; crdt = newCrdt ; unsubscribeCrdt = room . subscribe ( crdt as any , onChange ) ; setCount ( ( x ) => x + 1 ) ; } } let unsubscribeCrdt = room . subscribe ( crdt as any , onChange ) ; const unsubscribeRoot = room . subscribe ( root as any , onRootChange ) ; setCount ( ( x ) => x + 1 ) ; return ( ) => { unsubscribeRoot ( ) ; unsubscribeCrdt ( ) ; } ; } , [ root , room ] ) ; return root ?. get ( key ) ?? null ; }