├── .babelrc ├── .browserslistrc ├── .github ├── dependabot.yml └── workflows │ ├── TestOnPushPR.yml │ └── codeql-analysis.yml ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── config └── setup.js ├── dist └── index.js ├── lib ├── __tests__ │ └── index.test.js └── index.js ├── package.json └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env", "@babel/preset-react", "minify"] 3 | } -------------------------------------------------------------------------------- /.browserslistrc: -------------------------------------------------------------------------------- 1 | defaults 2 | not ie 11 3 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "npm" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | versioning-strategy: increase 8 | -------------------------------------------------------------------------------- /.github/workflows/TestOnPushPR.yml: -------------------------------------------------------------------------------- 1 | name: Test commit on push and pr 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Checkout branch 10 | uses: actions/checkout@v2 11 | 12 | - name: Install 13 | run: yarn 14 | 15 | - name: Test 16 | run: yarn test 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | schedule: 21 | - cron: '21 11 * * 3' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'javascript' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://git.io/codeql-language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v2 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v1 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 52 | 53 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 54 | # If this step fails, then you should remove it and run the build manually (see below) 55 | - name: Autobuild 56 | uses: github/codeql-action/autobuild@v1 57 | 58 | # ℹ️ Command-line programs to run using the OS shell. 59 | # 📚 https://git.io/JvXDl 60 | 61 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 62 | # and modify them (or add more) to build your code if your project 63 | # uses a compiled language 64 | 65 | #- run: | 66 | # make bootstrap 67 | # make release 68 | 69 | - name: Perform CodeQL Analysis 70 | uses: github/codeql-action/analyze@v1 71 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | .DS_Store 39 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .babelrc 2 | .npmignore 3 | /config/ 4 | yarn.lock -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Li Jie 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 | # ActionCable Provider for React 2 | 3 | This package provides an ActionCable context provider and consumer to allow you to subscribe to ActionCable channels in your React components. 4 | 5 | ## Requirements 6 | 7 | As this package uses React's new Context API, **React 16.3+ is required**. 8 | 9 | Run `npx browserslist` to see `default, not ie 11` option in `.browserslistrc` [compatibility](https://browserl.ist/?q=defaults). There is no IE 11 support starting in version 4.0.0. 10 | 11 | ## Install 12 | 13 | ```shell 14 | npm install --save @thrash-industries/react-actioncable-provider 15 | # OR 16 | yarn add @thrash-industries/react-actioncable-provider 17 | ``` 18 | 19 | ## Usage 20 | 21 | The public API exports two components that you'll use: `` and ``. 22 | 23 | ### `` 24 | 25 | The provider is used in an outer container and wraps all of the components that may or may not consume the context. It accepts one of two props: `url` and `cable`. Passing `url` will result in the provider instantiating its own `ActionCable.Consumer` with that URL. Passing `cable` allows you to manually instantiate an `ActionCable.Consumer` on your own and pass it to the provider to be used by all descendent consumers. 26 | 27 | #### With `url` 28 | 29 | ```jsx 30 | ... 31 | ``` 32 | 33 | #### With `cable` 34 | 35 | ```jsx 36 | import ActionCable from "actioncable"; 37 | 38 | const cable = ActionCable.createConsumer("ws://test.example.com/cable"); 39 | 40 | ...; 41 | ``` 42 | 43 | ### `` 44 | 45 | The consumer will wrap an individual component. It accepts several props: 46 | 47 | - `channel` [String] Name of the channel to which you want to subscribe. 48 | - `channel` [Object] An object with a `channel` key which denotes the channel to which you want to subscribe. All other keys are passed to the channel as params. 49 | - `onConnected` [Function] A handler function that is called when the channel connects. 50 | - `onDisconnected` [Function] A handler function that is called when the channel disconnects. 51 | - `onInitialized` [Function] A handler function that is called when the `ActionCable`.`Consumer` is initialized. 52 | - `onRejected` [Function] A handler function that is called when the requested subscription is rejected. 53 | - `onReceived` [Function] A handler function that is called when the channel transmits a message to the client. 54 | 55 | ```jsx 56 | import React from "react"; 57 | import PropTypes from "prop-types"; 58 | import { ActionCableConsumer } from "@thrash-industries/react-actioncable-provider"; 59 | 60 | export default class Widget extends React.Component { 61 | static propTypes = { 62 | message: PropTypes.string 63 | }; 64 | 65 | constructor(...props) { 66 | super(...props); 67 | 68 | this.handleReceived = this.handleReceived.bind(this); 69 | 70 | this.state = { 71 | message: "" 72 | }; 73 | } 74 | 75 | handleReceived(message) { 76 | this.setState(state => { 77 | return { 78 | message 79 | }; 80 | }); 81 | } 82 | 83 | render() { 84 | return ( 85 | 89 |

{this.state.message}

90 |
91 | ); 92 | } 93 | } 94 | ``` 95 | 96 | ## Publishing 97 | 98 | - `yarn` Install dependencies 99 | - `yarn test` Run tests 100 | - `yarn build` Build for production 101 | - `npm version [patch|minor|major]` Increment version 102 | - `npm publish` Publish to npm 103 | ## Other Uses 104 | 105 | ### React Native 106 | 107 | See https://github.com/cpunion/react-native-actioncable 108 | 109 | ### Server Side Rendering 110 | 111 | See https://github.com/cpunion/react-actioncable-provider/issues/8 112 | 113 | Example: https://github.com/cpunion/react-actioncable-ssr-example 114 | -------------------------------------------------------------------------------- /config/setup.js: -------------------------------------------------------------------------------- 1 | import Enzyme from 'enzyme'; 2 | import Adapter from 'enzyme-adapter-react-16'; 3 | 4 | Enzyme.configure({ adapter: new Adapter() }); 5 | 6 | const { JSDOM } = require('jsdom'); 7 | 8 | const jsdom = new JSDOM(''); 9 | const { window } = jsdom; 10 | 11 | function copyProps(src, target) { 12 | const props = Object.getOwnPropertyNames(src) 13 | .filter(prop => typeof target[prop] === 'undefined') 14 | .reduce( 15 | (result, prop) => ({ 16 | ...result, 17 | [prop]: Object.getOwnPropertyDescriptor(src, prop) 18 | }), 19 | {} 20 | ); 21 | Object.defineProperties(target, props); 22 | } 23 | 24 | global.window = window; 25 | global.document = window.document; 26 | global.navigator = { 27 | userAgent: 'node.js' 28 | }; 29 | copyProps(window, global); 30 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var React=require("react"),PropTypes=require("prop-types"),actioncable=require("actioncable"),{Provider,Consumer}=React.createContext();class ActionCableProvider extends React.Component{UNSAFE_componentWillMount=function(){this.cable=this.props.cable?this.props.cable:actioncable.createConsumer(this.props.url)};componentWillUnmount=function(){!this.props.cable&&this.cable&&this.cable.disconnect()};UNSAFE_componentWillReceiveProps=function(a){// Props not changed 2 | this.props.cable===a.cable&&this.props.url===a.url||(// cable is created by self, disconnect it 3 | // create or assign cable 4 | this.componentWillUnmount(),this.UNSAFE_componentWillMount())};render=function(){return React.createElement(Provider,{value:{cable:this.cable}},this.props.children||null)}}ActionCableProvider.displayName="ActionCableProvider",ActionCableProvider.propTypes={cable:PropTypes.object,url:PropTypes.string,children:PropTypes.any};class ActionCableController extends React.Component{componentDidMount=function(){this.connectToChannel()};connectToChannel=function(){var a=this.props,b=a.onReceived,c=a.onInitialized,d=a.onConnected,e=a.onDisconnected,f=a.onRejected;this.cable=this.props.cable.subscriptions.create(this.props.channel,{received:function(a){b&&b(a)},initialized:function(){c&&c()},connected:function(){d&&d()},disconnected:function(){e&&e()},rejected:function(){f&&f()}})};disconnectFromChannel=function(){this.cable&&(this.props.cable.subscriptions.remove(this.cable),this.cable=null)};componentDidUpdate=function(a){JSON.stringify(a.channel)!==JSON.stringify(this.props.channel)&&(this.disconnectFromChannel(),this.connectToChannel())};componentWillUnmount=function(){this.disconnectFromChannel()};send=function(a){if(!this.cable)throw new Error("ActionCable component unloaded");this.cable.send(a)};perform=function(a,b){if(!this.cable)throw new Error("ActionCable component unloaded");this.cable.perform(a,b)};render=function(){return this.props.children||null}}ActionCableController.displayName="ActionCableController",ActionCableController.propTypes={cable:PropTypes.object,onReceived:PropTypes.func,onInitialized:PropTypes.func,onConnected:PropTypes.func,onDisconnected:PropTypes.func,onRejected:PropTypes.func,children:PropTypes.any};class Component extends React.Component{render=function(){return React.createElement(Consumer,null,a=>{let{cable:b}=a;return React.createElement(ActionCableController,{cable:b,...this.props,ref:this.props.forwardedRef},this.props.children||null)})}}Component.displayName="ActionCableConsumer",Component.propTypes={onReceived:PropTypes.func,onInitialized:PropTypes.func,onConnected:PropTypes.func,onDisconnected:PropTypes.func,onRejected:PropTypes.func,children:PropTypes.any};var ActionCableConsumer=React.forwardRef(function(a,b){return React.createElement(Component,{...a,forwardedRef:b},a.children||null)});class ActionCable extends React.Component{componentDidMount=function(){console.warn("DEPRECATION WARNING: The component has been deprecated and will be removed in a future release. Use instead.")};render=function(){return React.createElement(ActionCableConsumer,{...this.props},this.props.children||null)}}// Compatible old usage 5 | ActionCable.displayName="ActionCable",ActionCable.propTypes={onReceived:PropTypes.func,onInitialized:PropTypes.func,onConnected:PropTypes.func,onDisconnected:PropTypes.func,onRejected:PropTypes.func,children:PropTypes.any},exports.ActionCable=ActionCable,exports.ActionCableConsumer=ActionCableConsumer,exports.ActionCableController=ActionCableController,exports.ActionCableProvider=ActionCableProvider,exports.default=ActionCableProvider; -------------------------------------------------------------------------------- /lib/__tests__/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow, mount } from 'enzyme'; 3 | import actioncable from 'actioncable'; 4 | import { 5 | ActionCableProvider, 6 | ActionCableConsumer, 7 | ActionCableController 8 | } from '../index'; 9 | 10 | describe(ActionCableProvider, () => { 11 | describe('with children', () => { 12 | it('renders children', () => { 13 | const node = shallow( 14 | 15 | Child 16 | 17 | ); 18 | 19 | expect(node.children()).toHaveLength(1); 20 | }); 21 | }); 22 | 23 | describe('with no children', () => { 24 | it('renders null', () => { 25 | const node = shallow(); 26 | 27 | expect(node.children()).toHaveLength(0); 28 | }); 29 | }); 30 | }); 31 | 32 | describe('ActionCableConsumer', () => { 33 | describe('wrapped with ForwardRef', () => { 34 | it('renders the ForwardRef', () => { 35 | const node = shallow( 36 | 37 | 38 | 39 | ); 40 | 41 | expect(node.find('ForwardRef')).toHaveLength(1); 42 | }); 43 | 44 | it('renders the consumer', () => { 45 | const node = mount( 46 | 47 | 48 | 49 | ); 50 | 51 | const consumer = node.find('ActionCableConsumer'); 52 | 53 | expect(consumer).toHaveLength(1); 54 | }); 55 | 56 | it('renders the controller', () => { 57 | const node = mount( 58 | 59 | 60 | 61 | ); 62 | 63 | const controller = node.find('ActionCableController'); 64 | 65 | expect(controller).toHaveLength(1); 66 | }); 67 | }); 68 | }); 69 | 70 | describe('ActionCableController', () => { 71 | describe('with cable passed to provider', () => { 72 | it('passes cable to the controller as a prop', () => { 73 | const cable = actioncable.createConsumer('ws://test.example.com/cable'); 74 | 75 | const node = mount( 76 | 77 | 78 | 79 | ); 80 | 81 | const controller = node.find('ActionCableController'); 82 | 83 | expect(controller.prop('cable')).toStrictEqual(cable); 84 | }); 85 | 86 | describe('with children', () => { 87 | it('renders children', () => { 88 | const cable = actioncable.createConsumer('ws://test.example.com/cable'); 89 | 90 | const node = mount( 91 | 92 | 93 | Child 94 | 95 | 96 | ); 97 | 98 | const controller = node.find('ActionCableController'); 99 | 100 | expect(controller.children()).toHaveLength(1); 101 | }); 102 | }); 103 | 104 | describe('without children', () => { 105 | it('renders null', () => { 106 | const cable = actioncable.createConsumer('ws://test.example.com/cable'); 107 | 108 | const node = mount( 109 | 110 | > 111 | 112 | ); 113 | 114 | const controller = node.find('ActionCableController'); 115 | 116 | expect(controller.children()).toHaveLength(0); 117 | }); 118 | }); 119 | }); 120 | }); 121 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }) 6 | 7 | var React = require("react") 8 | var PropTypes = require("prop-types") 9 | var actioncable = require("actioncable") 10 | var { Provider, Consumer } = React.createContext() 11 | 12 | class ActionCableProvider extends React.Component { 13 | UNSAFE_componentWillMount = function () { 14 | if (this.props.cable) { 15 | this.cable = this.props.cable 16 | } else { 17 | this.cable = actioncable.createConsumer(this.props.url) 18 | } 19 | } 20 | 21 | componentWillUnmount = function () { 22 | if (!this.props.cable && this.cable) { 23 | this.cable.disconnect() 24 | } 25 | } 26 | 27 | UNSAFE_componentWillReceiveProps = function (nextProps) { 28 | // Props not changed 29 | if ( 30 | this.props.cable === nextProps.cable && 31 | this.props.url === nextProps.url 32 | ) { 33 | return 34 | } 35 | 36 | // cable is created by self, disconnect it 37 | this.componentWillUnmount() 38 | 39 | // create or assign cable 40 | this.UNSAFE_componentWillMount() 41 | } 42 | 43 | render = function () { 44 | return React.createElement( 45 | Provider, 46 | { 47 | value: { 48 | cable: this.cable 49 | } 50 | }, 51 | this.props.children || null 52 | ) 53 | } 54 | } 55 | 56 | ActionCableProvider.displayName = "ActionCableProvider" 57 | 58 | ActionCableProvider.propTypes = { 59 | cable: PropTypes.object, 60 | url: PropTypes.string, 61 | children: PropTypes.any 62 | } 63 | 64 | class ActionCableController extends React.Component { 65 | componentDidMount = function () { 66 | this.connectToChannel() 67 | } 68 | connectToChannel = function () { 69 | var self = this 70 | var _props = this.props 71 | 72 | var onReceived = _props.onReceived 73 | 74 | var onInitialized = _props.onInitialized 75 | 76 | var onConnected = _props.onConnected 77 | 78 | var onDisconnected = _props.onDisconnected 79 | 80 | var onRejected = _props.onRejected 81 | 82 | this.cable = this.props.cable.subscriptions.create(this.props.channel, { 83 | received: function (data) { 84 | onReceived && onReceived(data) 85 | }, 86 | initialized: function () { 87 | onInitialized && onInitialized() 88 | }, 89 | connected: function () { 90 | onConnected && onConnected() 91 | }, 92 | disconnected: function () { 93 | onDisconnected && onDisconnected() 94 | }, 95 | rejected: function () { 96 | onRejected && onRejected() 97 | } 98 | }) 99 | } 100 | disconnectFromChannel = function() { 101 | if (this.cable) { 102 | this.props.cable.subscriptions.remove(this.cable) 103 | this.cable = null 104 | } 105 | } 106 | componentDidUpdate = function(prevProps) { 107 | if ( 108 | JSON.stringify(prevProps.channel) !== JSON.stringify(this.props.channel) 109 | ) { 110 | this.disconnectFromChannel() 111 | this.connectToChannel() 112 | } 113 | } 114 | componentWillUnmount = function () { 115 | this.disconnectFromChannel() 116 | } 117 | 118 | send = function (data) { 119 | if (!this.cable) { 120 | throw new Error("ActionCable component unloaded") 121 | } 122 | 123 | this.cable.send(data) 124 | } 125 | 126 | perform = function (action, data) { 127 | if (!this.cable) { 128 | throw new Error("ActionCable component unloaded") 129 | } 130 | 131 | this.cable.perform(action, data) 132 | } 133 | 134 | render = function () { 135 | return this.props.children || null 136 | } 137 | } 138 | 139 | ActionCableController.displayName = "ActionCableController" 140 | 141 | ActionCableController.propTypes = { 142 | cable: PropTypes.object, 143 | onReceived: PropTypes.func, 144 | onInitialized: PropTypes.func, 145 | onConnected: PropTypes.func, 146 | onDisconnected: PropTypes.func, 147 | onRejected: PropTypes.func, 148 | children: PropTypes.any 149 | } 150 | 151 | class Component extends React.Component { 152 | render = function () { 153 | return React.createElement(Consumer, null, ({ cable }) => { 154 | return React.createElement( 155 | ActionCableController, 156 | { 157 | cable, 158 | ...this.props, 159 | ref: this.props.forwardedRef 160 | }, 161 | this.props.children || null 162 | ) 163 | }) 164 | } 165 | } 166 | 167 | Component.displayName = "ActionCableConsumer" 168 | 169 | Component.propTypes = { 170 | onReceived: PropTypes.func, 171 | onInitialized: PropTypes.func, 172 | onConnected: PropTypes.func, 173 | onDisconnected: PropTypes.func, 174 | onRejected: PropTypes.func, 175 | children: PropTypes.any 176 | } 177 | 178 | var ActionCableConsumer = React.forwardRef(function (props, ref) { 179 | return React.createElement( 180 | Component, 181 | { 182 | ...props, 183 | forwardedRef: ref 184 | }, 185 | props.children || null 186 | ) 187 | }) 188 | 189 | class ActionCable extends React.Component { 190 | componentDidMount = function () { 191 | console.warn( 192 | "DEPRECATION WARNING: The component has been deprecated and will be removed in a future release. Use instead." 193 | ) 194 | } 195 | render = function () { 196 | return React.createElement( 197 | ActionCableConsumer, 198 | { ...this.props }, 199 | this.props.children || null 200 | ) 201 | } 202 | } 203 | 204 | ActionCable.displayName = "ActionCable" 205 | 206 | ActionCable.propTypes = { 207 | onReceived: PropTypes.func, 208 | onInitialized: PropTypes.func, 209 | onConnected: PropTypes.func, 210 | onDisconnected: PropTypes.func, 211 | onRejected: PropTypes.func, 212 | children: PropTypes.any 213 | } 214 | 215 | exports.ActionCable = ActionCable 216 | exports.ActionCableConsumer = ActionCableConsumer 217 | exports.ActionCableController = ActionCableController 218 | exports.ActionCableProvider = ActionCableProvider 219 | 220 | // Compatible old usage 221 | exports.default = ActionCableProvider 222 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@thrash-industries/react-actioncable-provider", 3 | "version": "4.0.3", 4 | "description": "ActionCable Provider for React", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "test": "jest --coverage", 8 | "test:watch": "jest --watch", 9 | "build": "babel lib/index.js --out-dir dist" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/JackHowa/react-actioncable-provider" 14 | }, 15 | "keywords": [ 16 | "ActionCable", 17 | "react", 18 | "Rails", 19 | "WebSockets" 20 | ], 21 | "files": [ 22 | "dist/index.js" 23 | ], 24 | "author": "Li Jie ", 25 | "contributors": [ 26 | "jackhowa ", 27 | "hashwin" 28 | ], 29 | "license": "MIT", 30 | "bugs": { 31 | "url": "https://github.com/JackHowa/react-actioncable-provider/issues" 32 | }, 33 | "homepage": "https://github.com/JackHowa/react-actioncable-provider", 34 | "dependencies": { 35 | "actioncable": "^5.2.8", 36 | "prop-types": "^15.8.1", 37 | "react": "^16.9.0" 38 | }, 39 | "devDependencies": { 40 | "@babel/cli": "^7.24.8", 41 | "@babel/core": "^7.25.2", 42 | "@babel/preset-env": "^7.25.3", 43 | "@babel/preset-react": "^7.24.7", 44 | "babel-jest": "^29.7.0", 45 | "babel-preset-minify": "^0.5.2", 46 | "chai": "^5.1.1", 47 | "enzyme": "^3.7.0", 48 | "enzyme-adapter-react-16": "^1.15.8", 49 | "jest": "^26.6.3", 50 | "react-dom": "^16.9.0", 51 | "react-test-renderer": "^16.9.0" 52 | }, 53 | "jest": { 54 | "verbose": true, 55 | "collectCoverageFrom": [ 56 | "lib/**/*.{js,jsx}" 57 | ], 58 | "coverageDirectory": "coverage", 59 | "setupFiles": [ 60 | "/config/setup.js" 61 | ], 62 | "testPathIgnorePatterns": [ 63 | "/(build|docs|node_modules)/" 64 | ] 65 | }, 66 | "directories": { 67 | "lib": "lib" 68 | } 69 | } 70 | --------------------------------------------------------------------------------