@cloudflare/realtimekit-react 1.2.0-staging.9 → 1.2.1-staging.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,34 @@
1
+ import React, { useEffect } from 'react';
2
+
3
+ import { RealtimeKitProvider, useRealtimeKitClient } from '../src';
4
+ import Meeting from './components/Meeting';
5
+ import Participants from './components/Participants';
6
+ import Chat from './components/Chat';
7
+
8
+ function App() {
9
+ const [client, loadClient] = useRealtimeKitClient();
10
+
11
+ useEffect(() => {
12
+ fetch('https://api.cluster.dyte.in/auth/anonymous')
13
+ .then((res) => res.json())
14
+ .then((data) => {
15
+ const { authToken } = data;
16
+ loadClient({
17
+ authToken,
18
+ defaults: { video: false, audio: false },
19
+ });
20
+ });
21
+ }, []);
22
+
23
+ Object.assign(window, { client });
24
+
25
+ return (
26
+ <RealtimeKitProvider value={client}>
27
+ <Meeting />
28
+ <Participants />
29
+ <Chat />
30
+ </RealtimeKitProvider>
31
+ );
32
+ }
33
+
34
+ export default App;
@@ -0,0 +1,51 @@
1
+ import React from 'react';
2
+ import { useRealtimeKitSelector } from '../../src';
3
+
4
+ function Chat() {
5
+ const roomJoined = useRealtimeKitSelector(
6
+ (meeting) => meeting.self.roomJoined,
7
+ );
8
+ const chat = useRealtimeKitSelector((meeting) => meeting.chat);
9
+ if (!roomJoined) {
10
+ return null;
11
+ }
12
+
13
+ return (
14
+ <fieldset className="section">
15
+ <legend>Chat</legend>
16
+ <div>
17
+ <ul>
18
+ {chat?.messages.map(
19
+ (message: any) => (
20
+ <li key={message.id}>
21
+ {message.type}
22
+ -
23
+ {message.type === 'text' && message.message}
24
+ </li>
25
+ ),
26
+ )}
27
+ </ul>
28
+ <form
29
+ onSubmit={(e) => {
30
+ e.preventDefault();
31
+ const messageInput = (e.target as any).elements
32
+ .message as HTMLInputElement;
33
+ const message = messageInput.value.trim();
34
+
35
+ if (message !== '') {
36
+ if (chat) {
37
+ chat.sendTextMessage(message);
38
+ }
39
+ messageInput.value = '';
40
+ }
41
+ }}
42
+ >
43
+ <input type="text" name="message" />
44
+ <button type="submit">Send</button>
45
+ </form>
46
+ </div>
47
+ </fieldset>
48
+ );
49
+ }
50
+
51
+ export default Chat;
@@ -0,0 +1,83 @@
1
+ import React from 'react';
2
+ import { useRealtimeKitMeeting, useRealtimeKitSelector } from '../../src';
3
+
4
+ function Meeting() {
5
+ const { meeting } = useRealtimeKitMeeting();
6
+ const roomJoined = useRealtimeKitSelector((m) => m.self.roomJoined);
7
+ const participantCount = useRealtimeKitSelector((m) => m.participants.count);
8
+ const self = useRealtimeKitSelector((m) => m.self);
9
+
10
+ return (
11
+ <fieldset>
12
+ <legend>Meeting details</legend>
13
+ <div>
14
+ {!roomJoined && (
15
+ <div>
16
+ <div>
17
+ Status:
18
+ {' '}
19
+ {roomJoined === undefined ? 'Connecting...' : 'Connected'}
20
+ </div>
21
+ {meeting && (
22
+ <div>
23
+ <button type="button" onClick={() => meeting.joinRoom()}>
24
+ Join
25
+ </button>
26
+ </div>
27
+ )}
28
+ </div>
29
+ )}
30
+ {roomJoined && (
31
+ <div>
32
+ <div>
33
+ Name:
34
+ {self?.name}
35
+ </div>
36
+ <div>
37
+ audio:
38
+ {' '}
39
+ <span className="token">
40
+ {JSON.stringify(self?.audioEnabled)}
41
+ </span>
42
+ , video:
43
+ {' '}
44
+ <span className="token">
45
+ {JSON.stringify(self?.videoEnabled)}
46
+ </span>
47
+ </div>
48
+ <div>
49
+ Participant Count:
50
+ {participantCount}
51
+ </div>
52
+ <button
53
+ type="button"
54
+ onClick={() => {
55
+ if (self?.audioEnabled) {
56
+ self?.disableAudio();
57
+ } else {
58
+ self?.enableAudio();
59
+ }
60
+ }}
61
+ >
62
+ {self?.audioEnabled ? 'Disable Audio' : 'Enable Audio'}
63
+ </button>
64
+ <button
65
+ type="button"
66
+ onClick={() => {
67
+ if (self?.videoEnabled) {
68
+ self?.disableVideo();
69
+ } else {
70
+ self?.enableVideo();
71
+ }
72
+ }}
73
+ >
74
+ {self?.videoEnabled ? 'Disable Video' : 'Enable Video'}
75
+ </button>
76
+ </div>
77
+ )}
78
+ </div>
79
+ </fieldset>
80
+ );
81
+ }
82
+
83
+ export default Meeting;
@@ -0,0 +1,122 @@
1
+ import React, { FC, useEffect, useRef } from 'react';
2
+ import { useRealtimeKitSelector } from '../../src';
3
+
4
+ const PeerView: FC<{
5
+ peerId: string;
6
+ }> = ({ peerId }) => {
7
+ const {
8
+ audioEnabled, audioTrack, videoEnabled, videoTrack,
9
+ } = useRealtimeKitSelector((meeting) => meeting.participants.active.get(peerId))!;
10
+ const videoRef = useRef<HTMLVideoElement>(null);
11
+ const audioRef = useRef<HTMLAudioElement>(null);
12
+
13
+ useEffect(() => {
14
+ if (!audioRef.current) return;
15
+
16
+ if (audioEnabled && audioTrack) {
17
+ const stream = new MediaStream();
18
+ stream.addTrack(audioTrack);
19
+ audioRef.current.srcObject = stream;
20
+ } else {
21
+ audioRef.current.srcObject = null;
22
+ }
23
+ }, [audioEnabled, audioTrack]);
24
+
25
+ useEffect(() => {
26
+ if (!videoRef.current) return;
27
+
28
+ if (videoEnabled && videoTrack) {
29
+ const stream = new MediaStream();
30
+ stream.addTrack(videoTrack);
31
+ videoRef.current.srcObject = stream;
32
+ } else {
33
+ videoRef.current.srcObject = null;
34
+ }
35
+ }, [videoEnabled, videoTrack]);
36
+
37
+ return (
38
+ <div>
39
+ <video
40
+ width={100}
41
+ height={100}
42
+ ref={videoRef}
43
+ autoPlay
44
+ playsInline
45
+ style={{
46
+ display: videoEnabled ? 'block' : 'none',
47
+ background: 'wheat',
48
+ }}
49
+ />
50
+ <audio ref={audioRef} autoPlay />
51
+ </div>
52
+ );
53
+ };
54
+
55
+ function ActiveParticipants() {
56
+ const activeParticipants = useRealtimeKitSelector(
57
+ (meeting) => meeting.participants.active,
58
+ );
59
+
60
+ return (
61
+ <div>
62
+ {activeParticipants?.toArray().map((peer: { id: string }) => (
63
+ <PeerView key={peer.id} peerId={peer.id} />
64
+ ))}
65
+ </div>
66
+ );
67
+ }
68
+
69
+ function Participants() {
70
+ const roomJoined = useRealtimeKitSelector(
71
+ (meeting) => meeting.self.roomJoined,
72
+ );
73
+ const joinedParticipants = useRealtimeKitSelector(
74
+ (meeting) => meeting.participants.joined,
75
+ );
76
+
77
+ if (!joinedParticipants || !roomJoined) {
78
+ return null;
79
+ }
80
+
81
+ return (
82
+ <fieldset className="section">
83
+ <legend>Participants</legend>
84
+ <div>
85
+ <h2>Active Participants</h2>
86
+ <ActiveParticipants />
87
+ </div>
88
+ <div>
89
+ <h2>Joined Participants</h2>
90
+ <ul style={{ paddingLeft: '1.25rem' }}>
91
+ {joinedParticipants
92
+ ?.toArray()
93
+ .map(
94
+ (peer: {
95
+ id: string;
96
+ audioEnabled: boolean;
97
+ name: string;
98
+ videoEnabled: boolean;
99
+ }) => (
100
+ <li key={peer.id}>
101
+ {peer.name}
102
+ {' '}
103
+ - audio:
104
+ {' '}
105
+ <span className="token">
106
+ {JSON.stringify(peer.audioEnabled)}
107
+ </span>
108
+ , video:
109
+ {' '}
110
+ <span className="token">
111
+ {JSON.stringify(peer.videoEnabled)}
112
+ </span>
113
+ </li>
114
+ ),
115
+ )}
116
+ </ul>
117
+ </div>
118
+ </fieldset>
119
+ );
120
+ }
121
+
122
+ export default Participants;
@@ -0,0 +1,24 @@
1
+ body {
2
+ font-family: sans-serif;
3
+ margin: 1rem;
4
+ }
5
+
6
+ span.token {
7
+ color: #2160fd;
8
+ }
9
+
10
+ .section {
11
+ margin-top: 1rem;
12
+ }
13
+
14
+ fieldset {
15
+ border: 2px solid #c7c7c7;
16
+ border-radius: 6px;
17
+ }
18
+
19
+ #root {
20
+ display: block;
21
+ width: 100%;
22
+ max-width: 768px;
23
+ margin: 0 auto;
24
+ }
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom';
3
+ import './index.css';
4
+ import App from './App';
5
+
6
+ ReactDOM.render(
7
+ <React.StrictMode>
8
+ <App />
9
+ </React.StrictMode>,
10
+ document.getElementById('root'),
11
+ );
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudflare/realtimekit-react",
3
- "version": "1.2.0-staging.9",
3
+ "version": "1.2.1-staging.1",
4
4
  "description": "A real-time video and audio SDK for building custom, collaborative communication experiences.",
5
5
  "main": "./dist/index.cjs.js",
6
6
  "module": "./dist/index.es.js",
@@ -12,15 +12,12 @@
12
12
  }
13
13
  },
14
14
  "types": "./dist/index.d.ts",
15
- "files": [
16
- "dist"
17
- ],
18
15
  "bugs": {
19
- "url": "https://realtime.cloudflare.com/issues"
16
+ "url": "https://community.cloudflare.com"
20
17
  },
21
18
  "private": false,
22
19
  "dependencies": {
23
- "@cloudflare/realtimekit": "1.2.0-staging.9"
20
+ "@cloudflare/realtimekit": "1.2.1-staging.1"
24
21
  },
25
22
  "peerDependencies": {
26
23
  "react": ">=16.8.6"
@@ -0,0 +1,8 @@
1
+ {
2
+ "compilerOptions": {
3
+ "composite": true,
4
+ "module": "esnext",
5
+ "moduleResolution": "node"
6
+ },
7
+ "include": ["vite.config.ts"]
8
+ }
@@ -0,0 +1,36 @@
1
+ import React, { ReactNode } from 'react';
2
+ import RTKClient from '@cloudflare/realtimekit';
3
+ type Listener = () => void;
4
+ declare class RTKUpdates {
5
+ private meeting;
6
+ private l;
7
+ constructor(meeting: RTKClient);
8
+ clean(): void;
9
+ addListener(listener: Listener): void;
10
+ removeListener(listener: Listener): void;
11
+ private onUpdate;
12
+ }
13
+ export declare const RealtimeKitContext: React.Context<{
14
+ meeting: RTKClient | undefined;
15
+ updates: RTKUpdates | undefined;
16
+ }>;
17
+ /**
18
+ * Provider component which makes the RealtimeKitClient object
19
+ * available to nested components
20
+ * @component
21
+ * @param value The RealtimeKitClient instance from `useRealtimeKitClient()`
22
+ * @param fallback Any fallback UI you want to render until the instance initialises.
23
+ */
24
+ export declare function RealtimeKitProvider({ value, children, fallback, }: {
25
+ value: RTKClient | undefined;
26
+ children: ReactNode;
27
+ fallback?: ReactNode;
28
+ }): import("react/jsx-runtime").JSX.Element;
29
+ /**
30
+ * Hook which returns the reference to the RealtimeKitClient object
31
+ * @returns meeting instance from `useRealtimeKitClient()`
32
+ */
33
+ export declare const useRealtimeKitClient: () => {
34
+ meeting: RTKClient;
35
+ };
36
+ export {};
@@ -0,0 +1,14 @@
1
+ import RTKClient, { RTKConfigOptions } from '@cloudflare/realtimekit';
2
+ interface RealtimeKitClientParams {
3
+ resetOnLeave?: boolean;
4
+ }
5
+ /**
6
+ * Hook which manages a RealtimeKitClient instance
7
+ */
8
+ export declare const useRealtimeKitClient: (clientParams?: RealtimeKitClientParams) => readonly [RTKClient | undefined, (options: RTKConfigOptions) => Promise<RTKClient | undefined>];
9
+ type StateSelector<T extends object, U> = (state: T) => U;
10
+ /**
11
+ * Hook which extracts data from the RealtimeKitClient object
12
+ */
13
+ export declare const useRealtimeKitSelector: <StateSlice>(selector: StateSelector<RTKClient, StateSlice>) => StateSlice;
14
+ export * from './context';