react-peer-chat 0.3.3 → 0.3.5

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.
package/README.md CHANGED
@@ -1,2 +1,140 @@
1
1
  # react-peer-chat
2
- An easy to use react component for impleting peer-to-peer chatting.
2
+ An easy to use react component for impleting peer-to-peer chatting using [peerjs](https://peerjs.com/) under the hood.
3
+
4
+ It is as easy as to import a React component!
5
+ ## Features
6
+ - Peer-to-peer chat without need to have any knowledge about WebRTC
7
+ - Easy to use
8
+ - Supports text chat that persists on page reload
9
+ - Supports voice chat
10
+ - Fully Customizable. See [usage with FoC](#Full-Customization)
11
+ ## Installation
12
+ To install react-peer-chat
13
+ ```bash
14
+ # with npm:
15
+ npm install react-peer-chat --save
16
+
17
+ # with yarn:
18
+ yarn add react-peer-chat
19
+
20
+ # with pnpm:
21
+ pnpm add react-peer-chat
22
+
23
+ # with bun:
24
+ bun add react-peer-chat
25
+ ```
26
+ ## Usage
27
+ When you use the `<Chat>` component of `react-peer-chat`, initially the user will see 2 buttons(svg icons), one for text chat and other for voice chat.
28
+ #### Basic Usage
29
+ ```jsx
30
+ import React, { useEffect } from 'react';
31
+ import Chat, { clearChat } from 'react-peer-chat';
32
+ import 'react-peer-chat/build/styles.css';
33
+
34
+ function App() {
35
+ useEffect(() => {
36
+ return clearChat // clear the chat when app is unmounted
37
+ }, [])
38
+
39
+ return <Chat
40
+ name='John Doe'
41
+ peerId='some-unique-id'
42
+ remotePeerId='another-unique-id'
43
+ />
44
+ }
45
+ ```
46
+ #### Partial Customization
47
+ Use props provided by `<Chat>` component to customize it.
48
+ ```jsx
49
+ import React from 'react';
50
+ import Chat from 'react-peer-chat';
51
+ import 'react-peer-chat/build/styles.css';
52
+
53
+ function App() {
54
+ return <Chat
55
+ name='John Doe'
56
+ peerId='some-unique-id'
57
+ remotePeerId='another-unique-id'
58
+ dialogOptions={{
59
+ position: 'left',
60
+ style: { padding: '4px' }
61
+ }}
62
+ props={{ title: 'React Peer Chat Component' }}
63
+ onError={() => {
64
+ console.error('Microphone not accessible!');
65
+ }}
66
+ />
67
+ }
68
+ ```
69
+ #### Full Customization
70
+ Use Function as Children(FoC) to fully customize the `<Chat>` component.
71
+ ```jsx
72
+ import React from 'react'
73
+ import Chat from 'react-peer-chat'
74
+ // import 'react-peer-chat/build/styles.css' (No need to import CSS when using custom component)
75
+
76
+ function App() {
77
+ return <Chat
78
+ name='John Doe'
79
+ peerId='some-unique-id'
80
+ remotePeerId='another-unique-id'
81
+ onError={() => {
82
+ console.error('Microphone not accessible!');
83
+ }}
84
+ >
85
+ {({ remotePeerName, messages, addMessage, audio, setAudio }) => (
86
+ <YourCustomComponent>
87
+ {...}
88
+ </YourCustomComponent>
89
+ )}
90
+ </Chat>
91
+ }
92
+ ```
93
+ ## Chat Component API Reference
94
+ Here is the full API for the `<Chat>` component, these properties can be set on an instance of Chat:
95
+ | Parameter | Type | Required | Default | Description |
96
+ | - | - | - | - | - |
97
+ | `name` | `String` | No | Anonymous User | Name of the peer which will be shown to the remote peer. |
98
+ | `peerId` | `String` | Yes | - | It is the unique id that is alloted to a peer. It uniquely identifies a peer from other peers. |
99
+ | `remotePeerId` | `String` | No | - | It is the unique id of the remote peer. If provided, the peer will try to connect to the remote peer. |
100
+ | `text` | `Boolean` | No | `true` | Text chat will be enabled if this property is set to true. |
101
+ | `voice` | `Boolean` | No | `true` | Voice chat will be enabled if this property is set to true. |
102
+ | `peerOptions` | [`PeerOptions`](#PeerOptions) | No | - | Options to customize peerjs Peer instance. |
103
+ | `dialogOptions` | [`DialogOptions`](#DialogOptions) | No | { position: 'center' } | Options to customize text dialog box styling. |
104
+ | `onError` | `Function` | No | `() => alert('Microphone not accessible!')` | Function to be executed when microphone is not accessible. |
105
+ | `props` | `React.DetailedHTMLProps` | No | - | Props to customize the `<Chat>` component. |
106
+ | `children` | [`Children`](#Children) | No | - | Props to customize the `<Chat>` component. |
107
+ ### Types
108
+ #### PeerOptions
109
+ ```typescript
110
+ import { PeerOptions } from 'peerjs'
111
+ ```
112
+ #### DialogOptions
113
+ ```typescript
114
+ import { CSSProperties } from 'react';
115
+ type DialogPosition = 'left' | 'center' | 'right';
116
+ type DialogOptions = {
117
+ position: DialogPosition;
118
+ style: CSSProperties;
119
+ };
120
+ ```
121
+ #### Children
122
+ ```typescript
123
+ import { ReactNode } from 'react';
124
+ type Message = {
125
+ id: string;
126
+ text: string;
127
+ };
128
+ type ChildrenOptions = {
129
+ remotePeerName?: string;
130
+ messages?: Message[];
131
+ addMessage?: (message: Message, sendToRemotePeer?: boolean) => void;
132
+ audio?: boolean;
133
+ setAudio?: (audio: boolean) => void;
134
+ };
135
+ type Children = (childrenOptions: ChildrenOptions) => ReactNode;
136
+ ```
137
+ ## Used By
138
+ - [StarWars](https://starwarsgame.vercel.app/)
139
+ ## Author
140
+ [Sahil Aggarwal](https://www.github.com/SahilAggarwal2004)
package/build/index.d.ts CHANGED
@@ -5,7 +5,7 @@ type Message = {
5
5
  text: string;
6
6
  };
7
7
  type ChildrenOptions = {
8
- remotePeer?: string;
8
+ remotePeerName?: string;
9
9
  messages?: Message[];
10
10
  addMessage?: (message: Message, sendToRemotePeer?: boolean) => void;
11
11
  audio?: boolean;
@@ -24,7 +24,7 @@ type Props = {
24
24
  voice?: boolean;
25
25
  peerOptions?: PeerOptions;
26
26
  dialogOptions?: DialogOptions;
27
- onError?: () => void;
27
+ onError?: Function;
28
28
  children?: (childrenOptions: ChildrenOptions) => ReactNode;
29
29
  props?: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
30
30
  };
package/build/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import React, { useEffect, useRef, useState } from 'react';
2
2
  import useStorage, { removeStorage } from './storage.js';
3
3
  import { BiSolidMessageDetail, BiSolidMessageX, BsFillMicFill, BsFillMicMuteFill, GrSend } from './icons.js';
4
- export default function Chat({ name, peerId, remotePeerId, peerOptions, text = true, voice = true, dialogOptions, onError = () => console.error("Can not access microphone!"), children, props = {} }) {
4
+ export default function Chat({ name, peerId, remotePeerId, peerOptions, text = true, voice = true, dialogOptions, onError = () => alert("Microphone not accessible!"), children, props = {} }) {
5
5
  const [peer, setPeer] = useState();
6
6
  const [notification, setNotification] = useState(false);
7
- const [remotePeer, setRemotePeer] = useStorage('rpc-remote-peer', '', { save: true });
7
+ const [remotePeerName, setRemotePeer] = useStorage('rpc-remote-peer', '', { save: true });
8
8
  const [messages, setMessages] = useStorage('rpc-messages', [], { save: true });
9
9
  const connRef = useRef();
10
10
  const [dialog, setDialog] = useState(false);
@@ -26,11 +26,11 @@ export default function Chat({ name, peerId, remotePeerId, peerOptions, text = t
26
26
  function handleConnection(conn) {
27
27
  connRef.current = conn;
28
28
  conn.on('open', () => {
29
- conn.on('data', ({ type, message, remotePeer, messages }) => {
29
+ conn.on('data', ({ type, message, remotePeerName, messages }) => {
30
30
  if (type === 'message')
31
31
  addMessage(message);
32
32
  else if (type === 'init') {
33
- setRemotePeer(remotePeer || 'Anonymous User');
33
+ setRemotePeer(remotePeerName || 'Anonymous User');
34
34
  setMessages(old => {
35
35
  if (messages.length > old.length)
36
36
  return messages;
@@ -38,7 +38,7 @@ export default function Chat({ name, peerId, remotePeerId, peerOptions, text = t
38
38
  });
39
39
  }
40
40
  });
41
- conn.send({ type: 'init', remotePeer: name, messages });
41
+ conn.send({ type: 'init', remotePeerName: name, messages });
42
42
  });
43
43
  }
44
44
  useEffect(() => {
@@ -64,27 +64,32 @@ export default function Chat({ name, peerId, remotePeerId, peerOptions, text = t
64
64
  }
65
65
  if (audio) {
66
66
  const getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
67
- getUserMedia({
68
- video: false,
69
- audio: {
70
- autoGainControl: false,
71
- noiseSuppression: true,
72
- echoCancellation: true
73
- }
74
- }, (stream) => {
75
- localStream.current = stream;
76
- if (remotePeerId) {
77
- call = peer.call(remotePeerId, stream);
78
- call.on('stream', handleRemoteStream);
79
- call.on('close', call.removeAllListeners);
80
- }
81
- peer.on('call', e => {
82
- call = e;
83
- call.answer(stream);
84
- call.on('stream', handleRemoteStream);
85
- call.on('close', call.removeAllListeners);
86
- });
87
- }, onError);
67
+ try {
68
+ getUserMedia({
69
+ video: false,
70
+ audio: {
71
+ autoGainControl: false,
72
+ noiseSuppression: true,
73
+ echoCancellation: true
74
+ }
75
+ }, (stream) => {
76
+ localStream.current = stream;
77
+ if (remotePeerId) {
78
+ call = peer.call(remotePeerId, stream);
79
+ call.on('stream', handleRemoteStream);
80
+ call.on('close', call.removeAllListeners);
81
+ }
82
+ peer.on('call', e => {
83
+ call = e;
84
+ call.answer(stream);
85
+ call.on('stream', handleRemoteStream);
86
+ call.on('close', call.removeAllListeners);
87
+ });
88
+ }, onError);
89
+ }
90
+ catch (_a) {
91
+ onError();
92
+ }
88
93
  }
89
94
  });
90
95
  peer.on('connection', handleConnection);
@@ -110,9 +115,9 @@ export default function Chat({ name, peerId, remotePeerId, peerOptions, text = t
110
115
  const container = containerRef.current;
111
116
  if (container)
112
117
  container.scrollTop = container.scrollHeight;
113
- }, [dialog, remotePeer, messages]);
118
+ }, [dialog, remotePeerName, messages]);
114
119
  return React.createElement("div", { className: 'rpc-main', ...props },
115
- typeof children === 'function' ? children({ remotePeer, messages, addMessage, audio, setAudio }) : React.createElement(React.Fragment, null,
120
+ typeof children === 'function' ? children({ remotePeerName, messages, addMessage, audio, setAudio }) : React.createElement(React.Fragment, null,
116
121
  text && React.createElement("div", null,
117
122
  dialog ? React.createElement(BiSolidMessageX, { onClick: () => setDialog(false) }) : React.createElement("div", { className: 'rpc-notification' },
118
123
  React.createElement(BiSolidMessageDetail, { onClick: () => {
@@ -126,7 +131,7 @@ export default function Chat({ name, peerId, remotePeerId, peerOptions, text = t
126
131
  React.createElement("div", null,
127
132
  React.createElement("div", { ref: containerRef, className: 'rpc-message-container' }, messages.map(({ id, text }, i) => React.createElement("div", { key: i },
128
133
  React.createElement("strong", null,
129
- id === peerId ? 'You' : remotePeer,
134
+ id === peerId ? 'You' : remotePeerName,
130
135
  ": "),
131
136
  React.createElement("span", null, text)))),
132
137
  React.createElement("hr", null),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-peer-chat",
3
- "version": "0.3.3",
3
+ "version": "0.3.5",
4
4
  "description": "An easy to use react component for impleting peer-to-peer chatting.",
5
5
  "main": "./build/index.js",
6
6
  "type": "module",