├── .editorconfig ├── .github └── FUNDING.yml ├── .gitignore ├── .prettierrc ├── .travis.yml ├── LICENSE ├── README.md ├── package.json ├── rollup.config.js ├── src ├── PeerDataContext.tsx ├── PeerDataProvider.tsx ├── index.test.tsx ├── index.ts ├── react-app-env.d.ts ├── usePeerData.tsx ├── useSignaling.tsx └── withPeerData.tsx ├── tsconfig.json ├── tsconfig.prod.json ├── tsconfig.test.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [vardius] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with a single custom sponsorship URL 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | /dist 12 | /.rpt2_cache 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": false, 3 | "printWidth": 80, 4 | "tabWidth": 2, 5 | "singleQuote": true, 6 | "trailingComma": "all", 7 | "bracketSpacing": false, 8 | "jsxBracketSameLine": true 9 | } 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "node" 4 | - 8 5 | - 9 6 | script: 7 | - yarn test && codecov 8 | before_install: 9 | - npm install -g yarn 10 | - npm i -g codecov 11 | after_success: 12 | - bash <(curl -s https://codecov.io/bash) -e TRAVIS_NODE_VERSION 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Rafał Lorenz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | React WebRTC - PeerData 2 | ================ 3 | [![Build Status](https://travis-ci.org/vardius/react-peer-data.svg?branch=master)](https://travis-ci.org/vardius/react-peer-data) 4 | [![npm version](https://img.shields.io/npm/v/react-peer-data.svg)](https://www.npmjs.com/package/react-peer-data) 5 | [![npm downloads](https://img.shields.io/npm/dm/react-peer-data.svg)](https://www.npmjs.com/package/react-peer-data) 6 | [![license](https://img.shields.io/github/license/vardius/react-peer-data.svg)](LICENSE) 7 | [![codecov](https://codecov.io/gh/vardius/react-peer-data/branch/master/graph/badge.svg)](https://codecov.io/gh/vardius/react-peer-data) 8 | 9 |
10 | Table of Content 11 | 12 | 13 | - [About](#about) 14 | - [How to use](#how-to-use) 15 | - [Installation](#installation) 16 | - [Examples](#examples) 17 | - [Hook](#hook) 18 | - [HOC](#hoc) 19 | - [License](#license) 20 | 21 | 22 |
23 | 24 | ABOUT 25 | ================================================== 26 | React wrapper for PeerData library for files, media streaming/sharing using WebRTC. 27 | 28 | Contributors: 29 | 30 | * [Rafał Lorenz](http://rafallorenz.com) 31 | 32 | Want to contribute ? Feel free to send pull requests! 33 | 34 | Have problems, bugs, feature ideas? 35 | We are using the github [issue tracker](https://github.com/vardius/react-peer-data/issues) to manage them. 36 | 37 | 39 | 40 | HOW TO USE 41 | ================================================== 42 | 43 | 1. [Chat Example](https://github.com/vardius/react-webrtc-chat) 44 | 45 | ## Getting started 46 | ### Installation 47 | ```bash 48 | npm install react-peer-data 49 | ``` 50 | ### Examples 51 | Use `PeerDataProvider` to instantiate and pass peerData object down the component tree 52 | ```javascript 53 | import React from 'react'; 54 | import ReactDOM from 'react-dom'; 55 | import { EventDispatcher } from "peer-data"; 56 | import { PeerDataProvider } from 'react-peer-data'; 57 | 58 | import App from './App'; 59 | 60 | ReactDOM.render( 61 | 66 | 67 | , 68 | document.getElementById("root") 69 | ); 70 | ``` 71 | You can access peerData context value in two ways: 72 | #### Hook 73 | ```javascript 74 | import React, { useEffect } from 'react'; 75 | import { usePeerData } from 'react-peer-data'; 76 | 77 | function App() { 78 | const peerData = usePeerData(); 79 | 80 | useEffect(() => { 81 | const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true }); 82 | const room = peerData.connect('my-room', stream); 83 | room 84 | .on("participant", participant => { 85 | participant 86 | .on("disconnected", () => { console.log('disconnected', participant.id); }) 87 | .on("track", event => { console.log('stream', participant.id, event.streams[0]); }) 88 | .on("message", payload => { console.log(participant.id, payload); }) 89 | .on("error", event => { 90 | console.error('peer', participant.id, event); 91 | participant.renegotiate(); 92 | }); 93 | }) 94 | .on("error", event => { console.error('room', name, event); }); 95 | 96 | return () => room.disconnect() 97 | }, [peerData]); 98 | 99 | return null; // @TODO: render participants 100 | } 101 | 102 | export default App; 103 | ``` 104 | #### HOC 105 | ```javascript 106 | import React from 'react'; 107 | import { withPeerData } from 'react-peer-data'; 108 | 109 | function App({ peerData }) { 110 | // follow example from above 111 | 112 | return null; // @TODO: render participants 113 | } 114 | 115 | export default withPeerData(App); 116 | ``` 117 | 118 | License 119 | ------- 120 | 121 | This package is released under the MIT license. See the complete license in the package: 122 | 123 | [LICENSE](LICENSE.md) 124 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-peer-data", 3 | "version": "1.1.4", 4 | "description": "React wrapper for PeerData library for files, media streaming/sharing using WebRTC", 5 | "author": { 6 | "name": "Rafał Lorenz", 7 | "email": "vardius@gmail.com" 8 | }, 9 | "license": "MIT", 10 | "bugs": { 11 | "url": "https://github.com/vardius/react-peer-data/issues" 12 | }, 13 | "homepage": "https://github.com/vardius/react-peer-data#readme", 14 | "main": "dist/index.js", 15 | "module": "dist/index.es.js", 16 | "jsnext:main": "dist/index.es.js", 17 | "types": "dist/index.d.ts", 18 | "peerDependencies": { 19 | "react": "^16.8.6", 20 | "react-dom": "^16.8.6" 21 | }, 22 | "dependencies": { 23 | "peer-data": "^3.2.4" 24 | }, 25 | "devDependencies": { 26 | "@types/jest": "^24.0.13", 27 | "@types/node": "^12.0.2", 28 | "@types/react": "^16.8.17", 29 | "@types/react-dom": "^16.8.4", 30 | "react": "^16.8.6", 31 | "react-dom": "^16.8.6", 32 | "react-scripts": "2.1.5", 33 | "rimraf": "^2.6.1", 34 | "rollup": "^1.11.3", 35 | "rollup-plugin-commonjs": "^9.3.4", 36 | "rollup-plugin-node-resolve": "^4.2.3", 37 | "rollup-plugin-sourcemaps": "^0.4.2", 38 | "rollup-plugin-typescript2": "^0.21.0", 39 | "typescript": "^3.4.5" 40 | }, 41 | "scripts": { 42 | "test": "cp -f ./tsconfig.test.json ./tsconfig.json && react-scripts test --env=jsdom --coverage", 43 | "test:watch": "cp -f ./tsconfig.test.json ./tsconfig.json && CI=true react-scripts test --env=jsdom", 44 | "build": "cp -f ./tsconfig.prod.json ./tsconfig.json && rollup -c", 45 | "clean": "rimraf dist es lib coverage", 46 | "prepare": "yarn build", 47 | "prebuild": "yarn clean", 48 | "postbuild": "rimraf {lib,es}/**/__tests__", 49 | "preversion": "yarn test", 50 | "postversion": "git push && git push --tags" 51 | }, 52 | "jest": { 53 | "collectCoverageFrom": [ 54 | "src/**/*.{ts,tsx}", 55 | "!src/index.ts" 56 | ] 57 | }, 58 | "files": [ 59 | "dist" 60 | ], 61 | "keywords": [ 62 | "react hook", 63 | "react-hook", 64 | "use", 65 | "webrtc", 66 | "web", 67 | "rtc", 68 | "peer", 69 | "peer2peer", 70 | "react", 71 | "usePeerData", 72 | "useWebRtc", 73 | "react-use-peer", 74 | "react-use-webrtc", 75 | "react-use-peerdata", 76 | "react-peer-hook", 77 | "react-peerdata-hook", 78 | "react-webrtc-hook", 79 | "use-peer", 80 | "peer data", 81 | "peerdata", 82 | "usepeerdata hook", 83 | "usewebrtc hook", 84 | "react-hooks-peer-data", 85 | "react-hooks-web-rtc", 86 | "react usepeerdata", 87 | "react usewebrtc", 88 | "react hooks tutorial", 89 | "react custom hooks", 90 | "react-usepeerdata", 91 | "react-usewebrtc", 92 | "use hooks", 93 | "react usepeerdata hook", 94 | "react usewebrtc hook", 95 | "react-hooks-peerdata", 96 | "react-hooks-webrtc", 97 | "react hooks usepeerdata", 98 | "react hooks webrtc", 99 | "use peer data hook", 100 | "react peer data hook", 101 | "react webrtc hook" 102 | ] 103 | } 104 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import sourcemaps from "rollup-plugin-sourcemaps"; 2 | import resolve from "rollup-plugin-node-resolve"; 3 | import commonjs from "rollup-plugin-commonjs"; 4 | import typescript from "rollup-plugin-typescript2"; 5 | 6 | const env = process.env.NODE_ENV; 7 | const pkg = require("./package"); 8 | const external = [ 9 | ...Object.keys(pkg.dependencies || {}), 10 | ...Object.keys(pkg.peerDependencies || {}), 11 | ]; 12 | let override = { compilerOptions: { jsx: 'react' } }; 13 | 14 | const plugins = [ 15 | sourcemaps(), 16 | resolve({ 17 | mainFields: ['module', 'main', 'browser', 'jsnext'] 18 | }), 19 | typescript({ 20 | clean: true, 21 | rollupCommonJSResolveHack: true, 22 | exclude: ['*.d.ts', '**/*.d.ts'], 23 | tsconfigOverride: override, 24 | }), 25 | commonjs(), 26 | ]; 27 | 28 | const config = { 29 | input: "src/index.ts", 30 | external: external, 31 | plugins: plugins, 32 | output: [ 33 | { 34 | name: pkg.name, 35 | exports: 'named', 36 | file: pkg.module, 37 | format: "es", 38 | sourcemap: true 39 | }, 40 | { 41 | name: pkg.name, 42 | exports: 'named', 43 | file: pkg.main, 44 | format: "cjs", 45 | sourcemap: true 46 | }, 47 | ] 48 | }; 49 | 50 | export default config; 51 | -------------------------------------------------------------------------------- /src/PeerDataContext.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PeerData from 'peer-data'; 3 | 4 | const PeerDataContext = React.createContext(null); 5 | 6 | export default PeerDataContext; 7 | -------------------------------------------------------------------------------- /src/PeerDataProvider.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactNode } from 'react'; 2 | import PeerData, { EventDispatcher } from 'peer-data'; 3 | import PeerDataContext from './PeerDataContext'; 4 | import useSignaling, {Options} from './useSignaling'; 5 | 6 | export interface Props { 7 | children: ReactNode; 8 | servers?: RTCConfiguration, 9 | constraints?: RTCDataChannelInit, 10 | signaling?: Options, 11 | } 12 | 13 | function PeerDataProvider({ children, servers, constraints, signaling = {dispatcher: new EventDispatcher()} }: Props) { 14 | useSignaling(signaling); 15 | 16 | return ( 17 | 18 | {React.Children.only(children)} 19 | 20 | ); 21 | } 22 | 23 | export default PeerDataProvider; 24 | -------------------------------------------------------------------------------- /src/index.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | 4 | it('renders without crashing', () => { 5 | const div = document.createElement('div'); 6 | ReactDOM.render(
, div); 7 | ReactDOM.unmountComponentAtNode(div); 8 | }); 9 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { default as PeerDataContext } from './PeerDataContext'; 2 | export { default as PeerDataProvider } from './PeerDataProvider'; 3 | export { default as usePeerData } from './usePeerData'; 4 | export { default as useSignaling } from './useSignaling'; 5 | export { default as withPeerData } from './withPeerData'; 6 | -------------------------------------------------------------------------------- /src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /src/usePeerData.tsx: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import PeerData from 'peer-data'; 3 | import PeerDataContext from './PeerDataContext'; 4 | 5 | const usePeerData = (): PeerData | null => useContext(PeerDataContext); 6 | 7 | export default usePeerData; 8 | -------------------------------------------------------------------------------- /src/useSignaling.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | import { SocketChannel, EventDispatcher } from "peer-data"; 3 | 4 | export interface Options { 5 | dispatcher: EventDispatcher 6 | url?: string | null, 7 | customChannel?: Object | null, 8 | } 9 | 10 | const useSignaling = ({ dispatcher, url = null, customChannel = null }: Options) => useState(customChannel ? customChannel : new SocketChannel(dispatcher, url)); 11 | 12 | export default useSignaling; 13 | -------------------------------------------------------------------------------- /src/withPeerData.tsx: -------------------------------------------------------------------------------- 1 | import React, { ComponentType, Ref } from 'react'; 2 | import PeerData from 'peer-data'; 3 | import usePeerData from './usePeerData'; 4 | 5 | type Omit = Pick>; 6 | type Diff = Omit; 7 | 8 | interface InjectedProps { 9 | peerData: PeerData; 10 | } 11 | 12 | export default function withPeerData(WrappedComponent: ComponentType) { 13 | type HocProps = Diff & { 14 | forwardedRef?: Ref; 15 | }; 16 | 17 | function Hoc(props: HocProps) { 18 | const peerData = usePeerData(); 19 | const { forwardedRef, ...rest } = props; 20 | 21 | return ; 22 | } 23 | 24 | Hoc.displayName = `withPeerData(${WrappedComponent.displayName || WrappedComponent.name || 'Component'})`; 25 | 26 | return React.forwardRef((props: HocProps, ref) => { 27 | return ; 28 | }); 29 | }; 30 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "build", 4 | "target": "es5", 5 | "sourceMap": true, 6 | "declaration": true, 7 | "lib": [ 8 | "dom", 9 | "dom.iterable", 10 | "esnext" 11 | ], 12 | "allowJs": false, 13 | "skipLibCheck": true, 14 | "esModuleInterop": true, 15 | "allowSyntheticDefaultImports": true, 16 | "strict": true, 17 | "forceConsistentCasingInFileNames": true, 18 | "module": "esnext", 19 | "moduleResolution": "node", 20 | "resolveJsonModule": true, 21 | "noEmit": true, 22 | "jsx": "preserve", 23 | "noImplicitReturns": true, 24 | "noImplicitThis": true, 25 | "noImplicitAny": true, 26 | "strictNullChecks": true, 27 | "suppressImplicitAnyIndexErrors": true, 28 | "noUnusedLocals": true, 29 | "noUnusedParameters": true, 30 | }, 31 | "include": [ 32 | "src" 33 | ], 34 | "exclude": [ 35 | "node_modules", 36 | "build", 37 | "dist", 38 | "example", 39 | "rollup.config.js" 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /tsconfig.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "build", 4 | "target": "es5", 5 | "sourceMap": true, 6 | "declaration": true, 7 | "lib": [ 8 | "dom", 9 | "dom.iterable", 10 | "esnext" 11 | ], 12 | "allowJs": false, 13 | "skipLibCheck": true, 14 | "esModuleInterop": true, 15 | "allowSyntheticDefaultImports": true, 16 | "strict": true, 17 | "forceConsistentCasingInFileNames": true, 18 | "module": "esnext", 19 | "moduleResolution": "node", 20 | "resolveJsonModule": true, 21 | "noEmit": true, 22 | "jsx": "preserve", 23 | "noImplicitReturns": true, 24 | "noImplicitThis": true, 25 | "noImplicitAny": true, 26 | "strictNullChecks": true, 27 | "suppressImplicitAnyIndexErrors": true, 28 | "noUnusedLocals": true, 29 | "noUnusedParameters": true, 30 | }, 31 | "include": [ 32 | "src" 33 | ], 34 | "exclude": [ 35 | "node_modules", 36 | "build", 37 | "dist", 38 | "example", 39 | "rollup.config.js" 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.prod.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "jsx": "preserve", 6 | "declaration": false, 7 | "isolatedModules": true, 8 | } 9 | } 10 | --------------------------------------------------------------------------------