Skip to content

Commit

Permalink
✨ feat: awareness com
Browse files Browse the repository at this point in the history
  • Loading branch information
jiangchu committed May 7, 2024
1 parent e712842 commit 1fcb4c1
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 16 deletions.
16 changes: 8 additions & 8 deletions src/Awareness/Cursors/index.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import isEqual from 'fast-deep-equal';
import { memo } from 'react';
import { memo, useContext } from 'react';

import { StoreContext } from '../store';
import Cursor from './Cursor';

import type { AwarenessState } from '../store';
import { useStore } from '../store';
// import { useStore } from '../store';

const Cursors = memo(() => {
const awarenessStates = useStore<AwarenessState[]>(
(s) => s.awarenessStates?.filter((a) => a.active && a.user.id !== s.currentUser.id),
isEqual,
);
// const awarenessStates = useStore<AwarenessState[]>(
// (s) => s.awarenessStates?.filter((a) => a.active && a.user.id !== s.currentUser.id),
// isEqual,
// );

const { awarenessStates } = useContext(StoreContext)!;
return (
<>
{awarenessStates?.map((a) => {
Expand Down
Empty file added src/Awareness/demos/demo.tsx
Empty file.
34 changes: 34 additions & 0 deletions src/Awareness/event.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useEffect } from 'react';
import { distinctUntilChanged, fromEvent, merge, startWith } from 'rxjs';

Check failure on line 2 in src/Awareness/event.ts

View workflow job for this annotation

GitHub Actions / test

Cannot find module 'rxjs' or its corresponding type declarations.
import { map } from 'rxjs/operators';

Check failure on line 3 in src/Awareness/event.ts

View workflow job for this annotation

GitHub Actions / test

Cannot find module 'rxjs/operators' or its corresponding type declarations.

interface AwarenessEventParams {
onMouseMove: (p: { x: number; y: number }) => void;
onBlur: (e: DocumentVisibilityState) => void;
}

// 鼠标移动事件
const mouse$ = fromEvent<MouseEvent>(document, 'mousemove').pipe(
distinctUntilChanged(),
map((e) => ({ x: e.clientX, y: e.clientY })),
startWith({ x: -100, y: -100 }),
);

const visibility$ = merge(
fromEvent(document, 'visibilitychange').pipe(map(() => document.visibilityState)),
fromEvent(window, 'focus').pipe(map(() => document.visibilityState)),
fromEvent(window, 'blur').pipe(map(() => 'hidden')),
);

export const useAwarenessEvent = ({ onMouseMove, onBlur }: AwarenessEventParams) => {
useEffect(() => {
const x = mouse$.subscribe(onMouseMove);
const y = visibility$.subscribe(onBlur);

return () => {
x.unsubscribe();
y.unsubscribe();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
};
44 changes: 36 additions & 8 deletions src/Awareness/store.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { nanoid } from 'nanoid';
import { createContext, useState } from 'react';
import { createContext, useEffect, useState } from 'react';
import type { Awareness } from 'y-protocols/awareness';
import { WebrtcProvider } from 'y-webrtc';
import { useAwarenessEvent } from './event';

export interface User {
id: string;
Expand Down Expand Up @@ -32,16 +33,43 @@ interface ProviderStore {

export const useCreateStore = (provider: WebrtcProvider, user: Pick<User, 'color' | 'name'>) => {
const [followUser, setFollowUser] = useState<string | undefined>(undefined);
const [awarenessStates, setAwarenessStates] = useState<AwarenessState[]>([]);
const [currentUser] = useState<User>({
id: nanoid(),
name: user?.name ?? 'Anonymous',
color: user?.color ?? 'black',
});
const [awareness] = useState<ProviderStore['awareness']>(provider.awareness);

useAwarenessEvent({
onMouseMove: (p) => {
awareness!.setLocalStateField('cursor', p);
},
onBlur: (e) => {
awareness!.setLocalStateField('active', e === 'visible');
},
});

useEffect(() => {
// 先创建一下监听事件
awareness!.on('change', () => {
const awarenessStates = Array.from(awareness!.getStates().values()) as AwarenessState[];

setAwarenessStates(awarenessStates);
});

// 再初始化一轮用户
awareness!.setLocalStateField('user', currentUser);

awareness!.setLocalStateField('active', true);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

return {
provider,
awareness: provider.awareness,
currentUser: {
id: nanoid(),
name: user?.name ?? 'Anonymous',
color: user?.color ?? 'black',
},
awarenessStates: [],
awareness,
currentUser,
awarenessStates,
followUser,
setFollowUser,
};
Expand Down

0 comments on commit 1fcb4c1

Please sign in to comment.