Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add presence hook and barebones demo to test it #15

Merged
merged 10 commits into from Jul 27, 2023
8 changes: 6 additions & 2 deletions examples/src/app/debugger/Console.tsx
Expand Up @@ -213,7 +213,9 @@ function PrettyString(props: { value: string }) {
valueEscaped = valueEscaped.slice(1, valueEscaped.length - 1)
return (
<span className="text-blue-300">
&ldquot;<span className="text-blue-600">{valueEscaped}</span>&rdquot;
{'"'}
<span className="text-blue-600">{valueEscaped}</span>
{'"'}
</span>
)
}
Expand All @@ -222,7 +224,9 @@ function PrettyKeyString(props: { value: string }) {
const valueEscaped = JSON.stringify(props.value).slice(1, props.value.length + 1)
return (
<span className="text-red-300">
&ldquot;<span className="text-red-600">{valueEscaped}</span>&rdquot;
{'"'}
<span className="text-red-600">{valueEscaped}</span>
{'"'}
</span>
)
}
34 changes: 34 additions & 0 deletions examples/src/app/presence/Presence.tsx
@@ -0,0 +1,34 @@
'use client'

import { usePresence } from '@/lib/provider'
import { useCallback, useRef } from 'react'

const COLORS = ['bg-red-500', 'bg-blue-500', 'bg-green-500', 'bg-purple-500', 'bg-pink-500']

export function Presence() {
const myColor = useRef(COLORS[Math.floor(Math.random() * COLORS.length)])
const [presence, setPresence] = usePresence<{ x: number; y: number; color: string }>()

const updatePresence = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
setPresence({
x: e.clientX - e.currentTarget.offsetLeft,
y: e.clientY - e.currentTarget.offsetTop,
color: myColor.current,
})
}, [])

return (
<div
className="border-blue-400 border relative overflow-hidden w-[500px] h-[500px]"
onMouseMove={updatePresence}
>
{Array.from(presence.entries()).map(([key, value]) => (
<div
key={key}
className={`absolute rounded-full ${value.color}`}
style={{ left: value.x - 6, top: value.y - 8, width: 10, height: 10 }}
/>
))}
</div>
)
}
18 changes: 18 additions & 0 deletions examples/src/app/presence/page.tsx
@@ -0,0 +1,18 @@
import { ENV_CONFIG } from '@/lib/config'
import { Presence } from './Presence'
import { YDocProvider } from '@/lib/provider'
import { getOrCreateDoc } from '@/lib/yserv'

type HomeProps = {
searchParams: Record<string, string>
}

export default async function Home({ searchParams }: HomeProps) {
const connectionKey = await getOrCreateDoc(searchParams.doc, ENV_CONFIG)

return (
<YDocProvider connectionKey={connectionKey} setQueryParam="doc">
<Presence />
</YDocProvider>
)
}
38 changes: 38 additions & 0 deletions examples/src/lib/provider.tsx
Expand Up @@ -22,6 +22,44 @@ export function useAwareness(): Awareness | null {
return useContext(YjsContext)?.provider?.awareness ?? null
}

export function usePresence<T extends Record<string, any>>(): [
Map<number, T>,
paulgb marked this conversation as resolved.
Show resolved Hide resolved
(presence: T) => void,
] {
const awareness = useAwareness()
const [presence, setPresence] = useState<Map<number, T>>(new Map())

useEffect(() => {
if (awareness) {
const callback = () => {
const map = new Map()
awareness.getStates().forEach((state, clientID) => {
if (Object.keys(state).length > 0) {
map.set(clientID, state)
}
})

setPresence(map)
}
awareness.on('change', callback)
return () => {
awareness.off('change', callback)
}
}
}, [awareness])

const setLocalPresence = useCallback(
(localState: any) => {
if (awareness) {
awareness.setLocalState(localState)
}
},
[awareness],
)

return [presence, setLocalPresence]
}

type YDocProviderProps = {
children: React.ReactNode

Expand Down