Solid Adapter (`@roomful/solid`)
Audience: users.
Provider
Section titled “Provider”import { RoomfulProvider } from '@roomful/solid';
function App() { return ( <RoomfulProvider roomId="my-room" transport="auto" presence={{ name: 'Alice', color: '#4F46E5' }} onConnect={() => console.log('connected')} onError={(error) => console.error(error)} > <Workspace /> </RoomfulProvider> );}| Hook | Returns | Purpose |
|---|---|---|
useRoom() | Room | access low-level room instance |
usePresence() | { self, others, all, update, replace } | reactive participant data |
useCursors(opts?) | { ref, cursors, mount, unmount } | cursor tracking/rendering |
useSharedState(key, opts) | [value, setValue] | synchronized state |
useAwareness() | { others, set, setFocus, setSelection, setTyping } | ephemeral peer context |
useEvent(name, handler) | emit function | subscribe and emit |
usePeers() | Accessor<Peer[]> | connected peers |
useConnectionStatus() | Accessor<RoomStatus> | current room status |
Collaboration primitives (v1.5)
Section titled “Collaboration primitives (v1.5)”| Hook | Returns | Purpose |
|---|---|---|
useViewport(opts?) | { ref, states, broadcast, stopBroadcast, present, stopPresenting, follow, unfollow } | follow a peer’s scroll/zoom (viewport) |
useLocks() | { locks, acquire, release, releaseAll, isLocked, getHolder } | advisory locks over UI keys (locks) |
useLockState(key) | Accessor<LockState | null> | one key’s holder, for lock-on-focus (locks) |
usePointer(opts?) | { ref, beams, activate, deactivate, render } | laser pointer beams (pointer) |
useComments(opts?) | { threads, add, reply, resolve, reopen, getByElement, getOpen } | anchored comment threads (comments) |
useActivity(opts?) | { entries, record } | room activity feed, newest first (activity) |
useFieldPresence() | { fields, setActiveField, getFieldPeers } | who’s on which field (field presence) |
useAgentApprovals(opts?) | { proposals, pending, approve, reject, propose } | human-in-the-loop agent approvals (agent approvals) |
useHistory(opts?) | { timeline, canUndo, canRedo, capture, transaction, undo, redo } | undo/redo plus shared timeline (history) |
The reactive members (states, beams, locks, threads, timeline, canUndo, canRedo, and useLockState) are Solid accessors — call them to read.
Reactive values are returned as Solid accessors — call them to read (others(), cursors(), status()). usePresence() exposes self, others, and all as accessors alongside the update/replace presence mutators. useAwareness() exposes the remote others accessor plus the set/setFocus/setSelection/setTyping mutators.
useSharedState(key, opts) intentionally mirrors React useState: it returns a [value, setValue] tuple where value is an accessor, and setValue accepts either the next value or an updater function. opts is required and forwards directly to room.useState(...).
Example
Section titled “Example”import { useCursors, useSharedState } from '@roomful/solid';
function PollWidget() { const { ref, cursors } = useCursors<{ tool: 'pen' | 'eraser' }>(); const [votes, setVotes] = useSharedState('poll-votes', { initialValue: { yes: 0, no: 0 }, strategy: 'crdt', });
return ( <div ref={ref}> <p> Yes: {votes().yes} | No: {votes().no} </p> <p>Remote cursors: {cursors().length}</p> <button onClick={() => setVotes((v) => ({ ...v, yes: v.yes + 1 }))}>Vote Yes</button> </div> );}Shared State Notes
Section titled “Shared State Notes”useSharedState()currently binds one shared-state engine per room. Every component in that room must use the samekeyand compatibleopts.optsforwards directly toroom.useState(...), includinginitialValue,strategy, andpersist.- The setter reference is stable and returns the resolved value; it is a no-op when the next value is structurally equal to the current one.
Integration Notes
Section titled “Integration Notes”RoomfulProvidercreates the room, connects on mount, and disconnects automatically on cleanup. It acceptsonConnect,onDisconnect, andonErrorlifecycle callbacks in addition to the standardRoomOptions.useRoom()throws aRoomfulErrorwhen called outside aRoomfulProvider.useCursors()returns a callbackrefyou attach to an element (<div ref={ref} />); it mounts cursor tracking on attach and unmounts on detach.mount(element)/unmount()are also available for explicit control.useEvent(name, handler)subscribes to a channel and returns a stableemit(payload)function for the same channel.