├── .babelrc ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .prettierrc.json ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE-logo.md ├── LICENSE.md ├── README.md ├── dist ├── cjs.js ├── cjs.min.js ├── esm.js ├── esm.min.js ├── umd.js └── umd.min.js ├── examples ├── README.md └── counter │ ├── .gitignore │ ├── README.md │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json │ ├── src │ ├── App.js │ ├── components │ │ └── Counter.js │ ├── index.js │ └── store │ │ ├── constants.js │ │ ├── contexts.js │ │ └── reducers │ │ ├── counterReducer.js │ │ └── titleReducer.js │ └── yarn.lock ├── index.js ├── jest.config.js ├── logo ├── README.md ├── conflux-logo-atom.png ├── conflux-logo-dark.png └── conflux-logo-light.png ├── package-lock.json ├── package.json ├── rollup.config.js ├── src ├── hooks │ ├── index.js │ └── useStateValue.js ├── index.js └── store │ ├── StateProvider.jsx │ └── index.js └── test ├── StateProvider.test.js ├── helpers ├── components.js ├── constants.js ├── contexts.js └── reducers.js ├── useInitialState.test.js └── useStateValue.test.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env", "@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/** 2 | logo/** 3 | dist/** 4 | test/** 5 | .vscode/** 6 | rollup.config.js -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: 'babel-eslint', 3 | env: { 4 | browser: true, 5 | es6: true 6 | }, 7 | extends: [ 8 | 'airbnb', 9 | 'plugin:import/recommended', 10 | 'plugin:react/recommended', 11 | 'plugin:prettier/recommended' 12 | ], 13 | globals: { 14 | Atomics: 'readonly', 15 | SharedArrayBuffer: 'readonly' 16 | }, 17 | parserOptions: { 18 | ecmaFeatures: { 19 | jsx: true 20 | }, 21 | ecmaVersion: 2018, 22 | sourceType: 'module' 23 | }, 24 | plugins: ['import', 'react'], 25 | rules: { 26 | 'valid-jsdoc': 2, 27 | 'react/jsx-uses-react': 1, 28 | 'react/jsx-no-undef': 2, 29 | 'react/jsx-wrap-multilines': 2, 30 | 'react/no-string-refs': 0 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | node_modules/ 4 | build 5 | .DS_Store 6 | *.tgz 7 | template/src/__tests__/__snapshots__/ 8 | lerna-debug.log 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | /.changelog 13 | .npm/ 14 | /website 15 | .env 16 | notes.md -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "singleQuote": true, 4 | "tabWidth": 2 5 | } 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | All notable changes are described on the [Releases](https://github.com/dustinmyers/react-conflux/releases) page. 2 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | - Using welcoming and inclusive language 18 | - Being respectful of differing viewpoints and experiences 19 | - Gracefully accepting constructive criticism 20 | - Focusing on what is best for the community 21 | - Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | - The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | - Trolling, insulting/derogatory comments, and personal or political attacks 28 | - Public or private harassment 29 | - Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | - Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at githubfeedback@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Conflux 2 | 3 | When contributing to this repository, please first discuss the change you wish to make via issue, email, Slack, LinkedIn, or any other method with Dustin Myers or Nathan Thomas before making a change. 4 | 5 | Please note we have a [Code of Conduct](CODE_OF_CONDUCT.md). Please follow it in all your interactions with the project. 6 | 7 | ## Using the Issue Tracker 8 | 9 | The [issue tracker](https://github.com/dustinmyers/react-conflux/issues) is 10 | the preferred channel for spelling mistakes, errors or any general smaller feedback. Please respect the following restriction: 11 | 12 | - Please **do not** derail or troll issues. Keep the discussion on topic and respect the opinions of others. 13 | 14 | ## Pull Requests 15 | 16 | Please adhere to the coding conventions used throughout the project (spelling, indentation, punctuation etc.). 17 | 18 | Adhering to the following process is the best way to get your work included in the project: 19 | 20 | 1. [Fork](https://help.github.com/articles/fork-a-repo) the project, clone your fork, and configure the remotes: 21 | 22 | ```bash 23 | # Clone your fork of the repo into the current directory 24 | git clone git@github.com//react-conflux.git 25 | 26 | # Navigate to the newly cloned directory 27 | cd react-conflux/ 28 | 29 | # Assign the original repo to a remote called "upstream" 30 | git remote add upstream git@github.com:dustinmyers/react-conflux.git 31 | ``` 32 | 33 | 2. If you cloned a while ago, get the latest changes from upstream: 34 | 35 | ```bash 36 | git checkout master 37 | git pull upstream master 38 | ``` 39 | 40 | 3. Create a new topic branch (off the main project development branch) to 41 | contain your feature, change, or fix: 42 | 43 | ```bash 44 | git checkout -b 45 | ``` 46 | 47 | 4. Locally merge (or rebase) the upstream development branch into your topic branch: 48 | 49 | ```bash 50 | git pull [--rebase] upstream master 51 | ``` 52 | 53 | 5. Push your topic branch up to your fork: 54 | 55 | ```bash 56 | git push origin 57 | ``` 58 | 59 | 6. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) 60 | with a clear title and description. 61 | 62 | **IMPORTANT**: By submitting patches, you agree to allow the project owners to license your work under the terms of the [MIT License](LICENSE). 63 | -------------------------------------------------------------------------------- /LICENSE-logo.md: -------------------------------------------------------------------------------- 1 | The [Conflux logo](./logo) is available on the public domain under the license of CC0. 2 | 3 | You can copy, modify, and distribute it, even for commercial purposes, all without asking permission. 4 | 5 | [Read more about CC0.](http://creativecommons.org/publicdomain/zero/1.0/) 6 | You can find its legal text below. 7 | 8 | #### Creative Commons Zero v1.0 Universal 9 | 10 | CC0 1.0 Universal 11 | 12 | Statement of Purpose 13 | 14 | The laws of most jurisdictions throughout the world automatically confer 15 | exclusive Copyright and Related Rights (defined below) upon the creator and 16 | subsequent owner(s) (each and all, an "owner") of an original work of 17 | authorship and/or a database (each, a "Work"). 18 | 19 | Certain owners wish to permanently relinquish those rights to a Work for the 20 | purpose of contributing to a commons of creative, cultural and scientific 21 | works ("Commons") that the public can reliably and without fear of later 22 | claims of infringement build upon, modify, incorporate in other works, reuse 23 | and redistribute as freely as possible in any form whatsoever and for any 24 | purposes, including without limitation commercial purposes. These owners may 25 | contribute to the Commons to promote the ideal of a free culture and the 26 | further production of creative, cultural and scientific works, or to gain 27 | reputation or greater distribution for their Work in part through the use and 28 | efforts of others. 29 | 30 | For these and/or other purposes and motivations, and without any expectation 31 | of additional consideration or compensation, the person associating CC0 with a 32 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright 33 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work 34 | and publicly distribute the Work under its terms, with knowledge of his or her 35 | Copyright and Related Rights in the Work and the meaning and intended legal 36 | effect of CC0 on those rights. 37 | 38 | 1. Copyright and Related Rights. A Work made available under CC0 may be 39 | protected by copyright and related or neighboring rights ("Copyright and 40 | Related Rights"). Copyright and Related Rights include, but are not limited 41 | to, the following: 42 | 43 | i. the right to reproduce, adapt, distribute, perform, display, communicate, 44 | and translate a Work; 45 | 46 | ii. moral rights retained by the original author(s) and/or performer(s); 47 | 48 | iii. publicity and privacy rights pertaining to a person's image or likeness 49 | depicted in a Work; 50 | 51 | iv. rights protecting against unfair competition in regards to a Work, 52 | subject to the limitations in paragraph 4(a), below; 53 | 54 | v. rights protecting the extraction, dissemination, use and reuse of data in 55 | a Work; 56 | 57 | vi. database rights (such as those arising under Directive 96/9/EC of the 58 | European Parliament and of the Council of 11 March 1996 on the legal 59 | protection of databases, and under any national implementation thereof, 60 | including any amended or successor version of such directive); and 61 | 62 | vii. other similar, equivalent or corresponding rights throughout the world 63 | based on applicable law or treaty, and any national implementations thereof. 64 | 65 | 2. Waiver. To the greatest extent permitted by, but not in contravention of, 66 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and 67 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright 68 | and Related Rights and associated claims and causes of action, whether now 69 | known or unknown (including existing as well as future claims and causes of 70 | action), in the Work (i) in all territories worldwide, (ii) for the maximum 71 | duration provided by applicable law or treaty (including future time 72 | extensions), (iii) in any current or future medium and for any number of 73 | copies, and (iv) for any purpose whatsoever, including without limitation 74 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes 75 | the Waiver for the benefit of each member of the public at large and to the 76 | detriment of Affirmer's heirs and successors, fully intending that such Waiver 77 | shall not be subject to revocation, rescission, cancellation, termination, or 78 | any other legal or equitable action to disrupt the quiet enjoyment of the Work 79 | by the public as contemplated by Affirmer's express Statement of Purpose. 80 | 81 | 3. Public License Fallback. Should any part of the Waiver for any reason be 82 | judged legally invalid or ineffective under applicable law, then the Waiver 83 | shall be preserved to the maximum extent permitted taking into account 84 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver 85 | is so judged Affirmer hereby grants to each affected person a royalty-free, 86 | non transferable, non sublicensable, non exclusive, irrevocable and 87 | unconditional license to exercise Affirmer's Copyright and Related Rights in 88 | the Work (i) in all territories worldwide, (ii) for the maximum duration 89 | provided by applicable law or treaty (including future time extensions), (iii) 90 | in any current or future medium and for any number of copies, and (iv) for any 91 | purpose whatsoever, including without limitation commercial, advertising or 92 | promotional purposes (the "License"). The License shall be deemed effective as 93 | of the date CC0 was applied by Affirmer to the Work. Should any part of the 94 | License for any reason be judged legally invalid or ineffective under 95 | applicable law, such partial invalidity or ineffectiveness shall not 96 | invalidate the remainder of the License, and in such case Affirmer hereby 97 | affirms that he or she will not (i) exercise any of his or her remaining 98 | Copyright and Related Rights in the Work or (ii) assert any associated claims 99 | and causes of action with respect to the Work, in either case contrary to 100 | Affirmer's express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | 107 | b. Affirmer offers the Work as-is and makes no representations or warranties 108 | of any kind concerning the Work, express, implied, statutory or otherwise, 109 | including without limitation warranties of title, merchantability, fitness 110 | for a particular purpose, non infringement, or the absence of latent or 111 | other defects, accuracy, or the present or absence of errors, whether or not 112 | discoverable, all to the greatest extent permissible under applicable law. 113 | 114 | c. Affirmer disclaims responsibility for clearing rights of other persons 115 | that may apply to the Work or any use thereof, including without limitation 116 | any person's Copyright and Related Rights in the Work. Further, Affirmer 117 | disclaims responsibility for obtaining any necessary consents, permissions 118 | or other rights required for any use of the Work. 119 | 120 | d. Affirmer understands and acknowledges that Creative Commons is not a 121 | party to this document and has no duty or obligation with respect to this 122 | CC0 or use of the Work. 123 | 124 | For more information, please see 125 | 126 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Dustin Myers and Nathan Thomas 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 |

Conflux library logo

2 | 3 | Conflux is a modularized state management system utilizing the [Context API](https://reactjs.org/docs/context.html) and [React Hooks](https://reactjs.org/docs/hooks-intro.html) for the [React](https://reactjs.org/) ecosystem. It provides predictable and optionally-nested state containers for applications in an elegant, streamlined, and developer-friendly manner. 4 | 5 | ## Table of Contents 6 | 7 | - [Why Use Conflux?](#why-use-conflux) 8 | - [Origins](#origins) 9 | - [Learn Conflux](#learn-conflux) 10 | - [A Brief Overview](#a-brief-overview) 11 | - [Example Applications](#example-applications) 12 | - [Installation](#installation) 13 | - [Contributing and Getting Involved](#contributing-and-getting-involved) 14 | - [Logo](#logo) 15 | - [Authors](#authors) 16 | - [License](#license) 17 | - [Acknowledgements](#acknowledgements) 18 | 19 | ## Why Use Conflux? 20 | 21 | `Context` and `Hooks` are relatively cutting-edge at the moment, but the concept of global state management is most likely familiar to even the newest of developers. Most existing systems currently revolve around a single global store. While this pattern does come with huge benefits, modern applications are so large and complex that these stores can sometimes give you "the forest with the tree" when one only needs partial slices of state. 22 | 23 | While most people use `Context` in React to pass a single global state up-and-down the entire application, it also has the ability to be surgically scoped to a specific component tree within an application's component architecture. As most large chunks of state are sometimes only needed inside of their assigned section of the application, modularity, maintainability, and performance can all be improved by segmenting state to specific limbs of the component tree. 24 | 25 | Conflux upgrades state management by combining the best facets of `Redux`, `Context`, and `React Hooks`. Developers can define state to a specific component, state tree, or the entire application. In fact, all three of these are possible at the same time through the use of multiple StateProviders. It then becomes a trivial matter to destructure out state for use in your application's components. 26 | 27 | ## Origins 28 | 29 | Dustin Myers and Nathan Thomas wrote the Conflux patterns contained in this repository while searching for a better alternative to current state management libraries and frameworks. Too many of the current options are either boilerplate-heavy or unnecessarily complicated. The goal was to produce modularity in component tree branches' state in a really easy manner. This was achieved by using the `Context API` and `React Hooks`, providing modular state with minimal code patterns. 30 | 31 | ## Learn Conflux 32 | 33 | ### A Brief Overview 34 | 35 | You create as many instances of `StateProvider` as you would like for modularized state management, and the beauty of Conflux is that you can nest them in any manner you choose. 36 | 37 | ```js 38 | /** 39 | * While intimidating at first, the process of implementing Conflux is actually really straightforward. 40 | * In order to use Conflux in our application, we must first import StateProvider and the useStateValue hook. 41 | */ 42 | 43 | import { StateProvider, useStateValue } from 'react-conflux'; 44 | 45 | /** 46 | * The next step to using Conflux in our application is placing the StateProvider component in our 47 | * application. 48 | * 49 | * The following example demonstrates how you might go about wrapping the State Provider around 50 | * a part of your component tree. 51 | */ 52 | 53 | export const App = () => { 54 | return ( 55 | 56 | 57 | 58 | ); 59 | }; 60 | 61 | /** 62 | * The two parameters required by the StateProvider component are a reducer function and a 63 | * stateContext object. 64 | * 65 | * Reducers are pure functions that must take in some state and an action while returning state. 66 | * 67 | * Note that the first parameter of the reducer function, state, has a default value of initialState, 68 | * the beginning state of our reducer. The second parameter, the action, is an object sent into 69 | * our reducer from our dispatch function which we will see in just a minute. 70 | * 71 | * Here is an example of a reducer and its corresponding switch statement; in this 72 | * example, we're taking in a new to-do item and setting it to state. 73 | */ 74 | 75 | const toDoReducer = (state = initialState, action) => { 76 | switch (action.type) { 77 | case 'ADD_TODO': 78 | return { 79 | ...state, 80 | toDoItems: [...state.toDoItems, action.payload] 81 | }; 82 | default: 83 | return state; 84 | } 85 | }; 86 | 87 | /** 88 | * The initialState object contains the starting state necessary for the given StateProvider it's 89 | * being passed into. 90 | * 91 | * An example of this for demonstration purposes is below. 92 | */ 93 | 94 | const initialState = { 95 | inputText: '', 96 | listArray: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 97 | nameObject: { firstName: 'Marty', lastName: 'McFly' }, 98 | toDoItems: [ 99 | { id: 1, name: 'Meddle with the future' }, 100 | { id: 2, name: 'Check out the past' } 101 | ] 102 | }; 103 | 104 | /** 105 | * The stateContext object is created in your application by importing createContext from React and 106 | * defining your state like the example below. This context object is passed into the StateProvider 107 | * (and, later, your useStateValue hook). 108 | */ 109 | 110 | const exampleContext = createContext(); 111 | 112 | /** 113 | * Every action object must have a type and payload; the type allows us to navigate the cases 114 | * in our reducer switch statements, and the payload is the state which we will update in our 115 | * reducer. 116 | * 117 | * Here's an example of what an action object looks like. 118 | */ 119 | 120 | const action = { 121 | type: 'ADD_TODO', 122 | payload: { id: 3, name: 'Marty, we have to go back!' } 123 | }; 124 | 125 | /** 126 | * The last step to using Conflux is to rig it up in your components within the component tree 127 | * housed in the relevant StateProvider. 128 | * 129 | * You can destructure out your state and dispatch by passing the context object created above into 130 | * the useStateValue hook which is imported from Conflux You can then further destructure out your 131 | * individual state values to assign throughout your component. 132 | * 133 | * Additionally, the dispatch function can be invoked with an action object inside of it to send 134 | * state to our reducer (and ultimately to be placed into our StateProvider's state). 135 | */ 136 | 137 | const [state, dispatch] = useStateValue(ExampleContext); 138 | 139 | const { inputText } = state; 140 | 141 | dispatch({ 142 | type: 'ADD_TODO', 143 | payload: { id: 3, name: 'Marty, we have to go back!' } 144 | }); 145 | ``` 146 | 147 | ### Example Applications 148 | 149 | We try, whenever possible, to give you a corresponding CodeSandbox for every sample so that you can play with the code online. 150 | 151 | - **Counter** [Source Code](https://github.com/dustinmyers/react-conflux/tree/master/examples/counter) | [CodeSandbox](https://codesandbox.io/s/is5dx) 152 | - **To-Do App** [CodeSandbox](https://codesandbox.io/s/todo-app-conflux-example-2v6b7) 153 | - **With Data Fetch** 154 | - [TV Shows](https://codesandbox.io/s/reactconflux-data-fetch-example-r52e9) 155 | - [Random Animals](https://codesandbox.io/s/reactconflux-animals-example-58e3l) 156 | 157 | ## Installation 158 | 159 | To install the most recent stable version: 160 | 161 | ``` 162 | npm install react-conflux 163 | ``` 164 | 165 | or 166 | 167 | ``` 168 | yarn add react-conflux 169 | ``` 170 | 171 | At this time, no other dependencies are required for Conflux outside of running it within a React environment. 172 | 173 | ## Contributing and Getting Involved 174 | 175 | If you spot a bug or would like to request a feature, we welcome and are grateful for any contributions from the community. Please review the process for contributing to this project by reading the [contribution guidelines](CONTRIBUTING.md). 176 | 177 | ## Logo 178 | 179 | Please read the logo guidelines on use and copyright as well as find official PNG files on [GitHub](./logo/README.md). 180 | 181 | ## Authors 182 | 183 | - [Dustin Myers](https://github.com/dustinmyers) 184 | - [Nathan Thomas](https://github.com/nwthomas) 185 | 186 | ## License 187 | 188 | [MIT](LICENSE) 189 | 190 | ## Acknowledgements 191 | 192 | - [Redux](https://github.com/reduxjs/redux) - A phenomenal application of state management that paved the way for some of the patterns used in this library 193 | -------------------------------------------------------------------------------- /dist/cjs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { value: true }); 4 | 5 | function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } 6 | 7 | var React = require('react'); 8 | var React__default = _interopDefault(React); 9 | 10 | function _typeof(obj) { 11 | if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { 12 | _typeof = function (obj) { 13 | return typeof obj; 14 | }; 15 | } else { 16 | _typeof = function (obj) { 17 | return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; 18 | }; 19 | } 20 | 21 | return _typeof(obj); 22 | } 23 | 24 | function _slicedToArray(arr, i) { 25 | return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); 26 | } 27 | 28 | function _arrayWithHoles(arr) { 29 | if (Array.isArray(arr)) return arr; 30 | } 31 | 32 | function _iterableToArrayLimit(arr, i) { 33 | if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) { 34 | return; 35 | } 36 | 37 | var _arr = []; 38 | var _n = true; 39 | var _d = false; 40 | var _e = undefined; 41 | 42 | try { 43 | for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { 44 | _arr.push(_s.value); 45 | 46 | if (i && _arr.length === i) break; 47 | } 48 | } catch (err) { 49 | _d = true; 50 | _e = err; 51 | } finally { 52 | try { 53 | if (!_n && _i["return"] != null) _i["return"](); 54 | } finally { 55 | if (_d) throw _e; 56 | } 57 | } 58 | 59 | return _arr; 60 | } 61 | 62 | function _nonIterableRest() { 63 | throw new TypeError("Invalid attempt to destructure non-iterable instance"); 64 | } 65 | 66 | function unwrapExports (x) { 67 | return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; 68 | } 69 | 70 | function createCommonjsModule(fn, module) { 71 | return module = { exports: {} }, fn(module, module.exports), module.exports; 72 | } 73 | 74 | var reactIs_development = createCommonjsModule(function (module, exports) { 75 | 76 | 77 | 78 | { 79 | (function() { 80 | 81 | Object.defineProperty(exports, '__esModule', { value: true }); 82 | 83 | // The Symbol used to tag the ReactElement-like types. If there is no native Symbol 84 | // nor polyfill, then a plain number is used for performance. 85 | var hasSymbol = typeof Symbol === 'function' && Symbol.for; 86 | var REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for('react.element') : 0xeac7; 87 | var REACT_PORTAL_TYPE = hasSymbol ? Symbol.for('react.portal') : 0xeaca; 88 | var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for('react.fragment') : 0xeacb; 89 | var REACT_STRICT_MODE_TYPE = hasSymbol ? Symbol.for('react.strict_mode') : 0xeacc; 90 | var REACT_PROFILER_TYPE = hasSymbol ? Symbol.for('react.profiler') : 0xead2; 91 | var REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for('react.provider') : 0xeacd; 92 | var REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for('react.context') : 0xeace; // TODO: We don't use AsyncMode or ConcurrentMode anymore. They were temporary 93 | // (unstable) APIs that have been removed. Can we remove the symbols? 94 | 95 | var REACT_ASYNC_MODE_TYPE = hasSymbol ? Symbol.for('react.async_mode') : 0xeacf; 96 | var REACT_CONCURRENT_MODE_TYPE = hasSymbol ? Symbol.for('react.concurrent_mode') : 0xeacf; 97 | var REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0; 98 | var REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for('react.suspense') : 0xead1; 99 | var REACT_SUSPENSE_LIST_TYPE = hasSymbol ? Symbol.for('react.suspense_list') : 0xead8; 100 | var REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3; 101 | var REACT_LAZY_TYPE = hasSymbol ? Symbol.for('react.lazy') : 0xead4; 102 | var REACT_FUNDAMENTAL_TYPE = hasSymbol ? Symbol.for('react.fundamental') : 0xead5; 103 | var REACT_RESPONDER_TYPE = hasSymbol ? Symbol.for('react.responder') : 0xead6; 104 | var REACT_SCOPE_TYPE = hasSymbol ? Symbol.for('react.scope') : 0xead7; 105 | 106 | function isValidElementType(type) { 107 | return typeof type === 'string' || typeof type === 'function' || // Note: its typeof might be other than 'symbol' or 'number' if it's a polyfill. 108 | type === REACT_FRAGMENT_TYPE || type === REACT_CONCURRENT_MODE_TYPE || type === REACT_PROFILER_TYPE || type === REACT_STRICT_MODE_TYPE || type === REACT_SUSPENSE_TYPE || type === REACT_SUSPENSE_LIST_TYPE || typeof type === 'object' && type !== null && (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_PROVIDER_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE || type.$$typeof === REACT_FUNDAMENTAL_TYPE || type.$$typeof === REACT_RESPONDER_TYPE || type.$$typeof === REACT_SCOPE_TYPE); 109 | } 110 | 111 | /** 112 | * Forked from fbjs/warning: 113 | * https://github.com/facebook/fbjs/blob/e66ba20ad5be433eb54423f2b097d829324d9de6/packages/fbjs/src/__forks__/warning.js 114 | * 115 | * Only change is we use console.warn instead of console.error, 116 | * and do nothing when 'console' is not supported. 117 | * This really simplifies the code. 118 | * --- 119 | * Similar to invariant but only logs a warning if the condition is not met. 120 | * This can be used to log issues in development environments in critical 121 | * paths. Removing the logging code for production environments will keep the 122 | * same logic and follow the same code paths. 123 | */ 124 | var lowPriorityWarningWithoutStack = function () {}; 125 | 126 | { 127 | var printWarning = function (format) { 128 | for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 129 | args[_key - 1] = arguments[_key]; 130 | } 131 | 132 | var argIndex = 0; 133 | var message = 'Warning: ' + format.replace(/%s/g, function () { 134 | return args[argIndex++]; 135 | }); 136 | 137 | if (typeof console !== 'undefined') { 138 | console.warn(message); 139 | } 140 | 141 | try { 142 | // --- Welcome to debugging React --- 143 | // This error was thrown as a convenience so that you can use this stack 144 | // to find the callsite that caused this warning to fire. 145 | throw new Error(message); 146 | } catch (x) {} 147 | }; 148 | 149 | lowPriorityWarningWithoutStack = function (condition, format) { 150 | if (format === undefined) { 151 | throw new Error('`lowPriorityWarningWithoutStack(condition, format, ...args)` requires a warning ' + 'message argument'); 152 | } 153 | 154 | if (!condition) { 155 | for (var _len2 = arguments.length, args = new Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) { 156 | args[_key2 - 2] = arguments[_key2]; 157 | } 158 | 159 | printWarning.apply(void 0, [format].concat(args)); 160 | } 161 | }; 162 | } 163 | 164 | var lowPriorityWarningWithoutStack$1 = lowPriorityWarningWithoutStack; 165 | 166 | function typeOf(object) { 167 | if (typeof object === 'object' && object !== null) { 168 | var $$typeof = object.$$typeof; 169 | 170 | switch ($$typeof) { 171 | case REACT_ELEMENT_TYPE: 172 | var type = object.type; 173 | 174 | switch (type) { 175 | case REACT_ASYNC_MODE_TYPE: 176 | case REACT_CONCURRENT_MODE_TYPE: 177 | case REACT_FRAGMENT_TYPE: 178 | case REACT_PROFILER_TYPE: 179 | case REACT_STRICT_MODE_TYPE: 180 | case REACT_SUSPENSE_TYPE: 181 | return type; 182 | 183 | default: 184 | var $$typeofType = type && type.$$typeof; 185 | 186 | switch ($$typeofType) { 187 | case REACT_CONTEXT_TYPE: 188 | case REACT_FORWARD_REF_TYPE: 189 | case REACT_PROVIDER_TYPE: 190 | return $$typeofType; 191 | 192 | default: 193 | return $$typeof; 194 | } 195 | 196 | } 197 | 198 | case REACT_LAZY_TYPE: 199 | case REACT_MEMO_TYPE: 200 | case REACT_PORTAL_TYPE: 201 | return $$typeof; 202 | } 203 | } 204 | 205 | return undefined; 206 | } // AsyncMode is deprecated along with isAsyncMode 207 | 208 | var AsyncMode = REACT_ASYNC_MODE_TYPE; 209 | var ConcurrentMode = REACT_CONCURRENT_MODE_TYPE; 210 | var ContextConsumer = REACT_CONTEXT_TYPE; 211 | var ContextProvider = REACT_PROVIDER_TYPE; 212 | var Element = REACT_ELEMENT_TYPE; 213 | var ForwardRef = REACT_FORWARD_REF_TYPE; 214 | var Fragment = REACT_FRAGMENT_TYPE; 215 | var Lazy = REACT_LAZY_TYPE; 216 | var Memo = REACT_MEMO_TYPE; 217 | var Portal = REACT_PORTAL_TYPE; 218 | var Profiler = REACT_PROFILER_TYPE; 219 | var StrictMode = REACT_STRICT_MODE_TYPE; 220 | var Suspense = REACT_SUSPENSE_TYPE; 221 | var hasWarnedAboutDeprecatedIsAsyncMode = false; // AsyncMode should be deprecated 222 | 223 | function isAsyncMode(object) { 224 | { 225 | if (!hasWarnedAboutDeprecatedIsAsyncMode) { 226 | hasWarnedAboutDeprecatedIsAsyncMode = true; 227 | lowPriorityWarningWithoutStack$1(false, 'The ReactIs.isAsyncMode() alias has been deprecated, ' + 'and will be removed in React 17+. Update your code to use ' + 'ReactIs.isConcurrentMode() instead. It has the exact same API.'); 228 | } 229 | } 230 | 231 | return isConcurrentMode(object) || typeOf(object) === REACT_ASYNC_MODE_TYPE; 232 | } 233 | function isConcurrentMode(object) { 234 | return typeOf(object) === REACT_CONCURRENT_MODE_TYPE; 235 | } 236 | function isContextConsumer(object) { 237 | return typeOf(object) === REACT_CONTEXT_TYPE; 238 | } 239 | function isContextProvider(object) { 240 | return typeOf(object) === REACT_PROVIDER_TYPE; 241 | } 242 | function isElement(object) { 243 | return typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE; 244 | } 245 | function isForwardRef(object) { 246 | return typeOf(object) === REACT_FORWARD_REF_TYPE; 247 | } 248 | function isFragment(object) { 249 | return typeOf(object) === REACT_FRAGMENT_TYPE; 250 | } 251 | function isLazy(object) { 252 | return typeOf(object) === REACT_LAZY_TYPE; 253 | } 254 | function isMemo(object) { 255 | return typeOf(object) === REACT_MEMO_TYPE; 256 | } 257 | function isPortal(object) { 258 | return typeOf(object) === REACT_PORTAL_TYPE; 259 | } 260 | function isProfiler(object) { 261 | return typeOf(object) === REACT_PROFILER_TYPE; 262 | } 263 | function isStrictMode(object) { 264 | return typeOf(object) === REACT_STRICT_MODE_TYPE; 265 | } 266 | function isSuspense(object) { 267 | return typeOf(object) === REACT_SUSPENSE_TYPE; 268 | } 269 | 270 | exports.typeOf = typeOf; 271 | exports.AsyncMode = AsyncMode; 272 | exports.ConcurrentMode = ConcurrentMode; 273 | exports.ContextConsumer = ContextConsumer; 274 | exports.ContextProvider = ContextProvider; 275 | exports.Element = Element; 276 | exports.ForwardRef = ForwardRef; 277 | exports.Fragment = Fragment; 278 | exports.Lazy = Lazy; 279 | exports.Memo = Memo; 280 | exports.Portal = Portal; 281 | exports.Profiler = Profiler; 282 | exports.StrictMode = StrictMode; 283 | exports.Suspense = Suspense; 284 | exports.isValidElementType = isValidElementType; 285 | exports.isAsyncMode = isAsyncMode; 286 | exports.isConcurrentMode = isConcurrentMode; 287 | exports.isContextConsumer = isContextConsumer; 288 | exports.isContextProvider = isContextProvider; 289 | exports.isElement = isElement; 290 | exports.isForwardRef = isForwardRef; 291 | exports.isFragment = isFragment; 292 | exports.isLazy = isLazy; 293 | exports.isMemo = isMemo; 294 | exports.isPortal = isPortal; 295 | exports.isProfiler = isProfiler; 296 | exports.isStrictMode = isStrictMode; 297 | exports.isSuspense = isSuspense; 298 | })(); 299 | } 300 | }); 301 | 302 | unwrapExports(reactIs_development); 303 | var reactIs_development_1 = reactIs_development.typeOf; 304 | var reactIs_development_2 = reactIs_development.AsyncMode; 305 | var reactIs_development_3 = reactIs_development.ConcurrentMode; 306 | var reactIs_development_4 = reactIs_development.ContextConsumer; 307 | var reactIs_development_5 = reactIs_development.ContextProvider; 308 | var reactIs_development_6 = reactIs_development.Element; 309 | var reactIs_development_7 = reactIs_development.ForwardRef; 310 | var reactIs_development_8 = reactIs_development.Fragment; 311 | var reactIs_development_9 = reactIs_development.Lazy; 312 | var reactIs_development_10 = reactIs_development.Memo; 313 | var reactIs_development_11 = reactIs_development.Portal; 314 | var reactIs_development_12 = reactIs_development.Profiler; 315 | var reactIs_development_13 = reactIs_development.StrictMode; 316 | var reactIs_development_14 = reactIs_development.Suspense; 317 | var reactIs_development_15 = reactIs_development.isValidElementType; 318 | var reactIs_development_16 = reactIs_development.isAsyncMode; 319 | var reactIs_development_17 = reactIs_development.isConcurrentMode; 320 | var reactIs_development_18 = reactIs_development.isContextConsumer; 321 | var reactIs_development_19 = reactIs_development.isContextProvider; 322 | var reactIs_development_20 = reactIs_development.isElement; 323 | var reactIs_development_21 = reactIs_development.isForwardRef; 324 | var reactIs_development_22 = reactIs_development.isFragment; 325 | var reactIs_development_23 = reactIs_development.isLazy; 326 | var reactIs_development_24 = reactIs_development.isMemo; 327 | var reactIs_development_25 = reactIs_development.isPortal; 328 | var reactIs_development_26 = reactIs_development.isProfiler; 329 | var reactIs_development_27 = reactIs_development.isStrictMode; 330 | var reactIs_development_28 = reactIs_development.isSuspense; 331 | 332 | var reactIs = createCommonjsModule(function (module) { 333 | 334 | { 335 | module.exports = reactIs_development; 336 | } 337 | }); 338 | 339 | /* 340 | object-assign 341 | (c) Sindre Sorhus 342 | @license MIT 343 | */ 344 | /* eslint-disable no-unused-vars */ 345 | var getOwnPropertySymbols = Object.getOwnPropertySymbols; 346 | var hasOwnProperty = Object.prototype.hasOwnProperty; 347 | var propIsEnumerable = Object.prototype.propertyIsEnumerable; 348 | 349 | function toObject(val) { 350 | if (val === null || val === undefined) { 351 | throw new TypeError('Object.assign cannot be called with null or undefined'); 352 | } 353 | 354 | return Object(val); 355 | } 356 | 357 | function shouldUseNative() { 358 | try { 359 | if (!Object.assign) { 360 | return false; 361 | } 362 | 363 | // Detect buggy property enumeration order in older V8 versions. 364 | 365 | // https://bugs.chromium.org/p/v8/issues/detail?id=4118 366 | var test1 = new String('abc'); // eslint-disable-line no-new-wrappers 367 | test1[5] = 'de'; 368 | if (Object.getOwnPropertyNames(test1)[0] === '5') { 369 | return false; 370 | } 371 | 372 | // https://bugs.chromium.org/p/v8/issues/detail?id=3056 373 | var test2 = {}; 374 | for (var i = 0; i < 10; i++) { 375 | test2['_' + String.fromCharCode(i)] = i; 376 | } 377 | var order2 = Object.getOwnPropertyNames(test2).map(function (n) { 378 | return test2[n]; 379 | }); 380 | if (order2.join('') !== '0123456789') { 381 | return false; 382 | } 383 | 384 | // https://bugs.chromium.org/p/v8/issues/detail?id=3056 385 | var test3 = {}; 386 | 'abcdefghijklmnopqrst'.split('').forEach(function (letter) { 387 | test3[letter] = letter; 388 | }); 389 | if (Object.keys(Object.assign({}, test3)).join('') !== 390 | 'abcdefghijklmnopqrst') { 391 | return false; 392 | } 393 | 394 | return true; 395 | } catch (err) { 396 | // We don't expect any of the above to throw, but better to be safe. 397 | return false; 398 | } 399 | } 400 | 401 | var objectAssign = shouldUseNative() ? Object.assign : function (target, source) { 402 | var from; 403 | var to = toObject(target); 404 | var symbols; 405 | 406 | for (var s = 1; s < arguments.length; s++) { 407 | from = Object(arguments[s]); 408 | 409 | for (var key in from) { 410 | if (hasOwnProperty.call(from, key)) { 411 | to[key] = from[key]; 412 | } 413 | } 414 | 415 | if (getOwnPropertySymbols) { 416 | symbols = getOwnPropertySymbols(from); 417 | for (var i = 0; i < symbols.length; i++) { 418 | if (propIsEnumerable.call(from, symbols[i])) { 419 | to[symbols[i]] = from[symbols[i]]; 420 | } 421 | } 422 | } 423 | } 424 | 425 | return to; 426 | }; 427 | 428 | /** 429 | * Copyright (c) 2013-present, Facebook, Inc. 430 | * 431 | * This source code is licensed under the MIT license found in the 432 | * LICENSE file in the root directory of this source tree. 433 | */ 434 | 435 | var ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED'; 436 | 437 | var ReactPropTypesSecret_1 = ReactPropTypesSecret; 438 | 439 | var printWarning = function() {}; 440 | 441 | { 442 | var ReactPropTypesSecret$1 = ReactPropTypesSecret_1; 443 | var loggedTypeFailures = {}; 444 | var has = Function.call.bind(Object.prototype.hasOwnProperty); 445 | 446 | printWarning = function(text) { 447 | var message = 'Warning: ' + text; 448 | if (typeof console !== 'undefined') { 449 | console.error(message); 450 | } 451 | try { 452 | // --- Welcome to debugging React --- 453 | // This error was thrown as a convenience so that you can use this stack 454 | // to find the callsite that caused this warning to fire. 455 | throw new Error(message); 456 | } catch (x) {} 457 | }; 458 | } 459 | 460 | /** 461 | * Assert that the values match with the type specs. 462 | * Error messages are memorized and will only be shown once. 463 | * 464 | * @param {object} typeSpecs Map of name to a ReactPropType 465 | * @param {object} values Runtime values that need to be type-checked 466 | * @param {string} location e.g. "prop", "context", "child context" 467 | * @param {string} componentName Name of the component for error messages. 468 | * @param {?Function} getStack Returns the component stack. 469 | * @private 470 | */ 471 | function checkPropTypes(typeSpecs, values, location, componentName, getStack) { 472 | { 473 | for (var typeSpecName in typeSpecs) { 474 | if (has(typeSpecs, typeSpecName)) { 475 | var error; 476 | // Prop type validation may throw. In case they do, we don't want to 477 | // fail the render phase where it didn't fail before. So we log it. 478 | // After these have been cleaned up, we'll let them throw. 479 | try { 480 | // This is intentionally an invariant that gets caught. It's the same 481 | // behavior as without this statement except with a better message. 482 | if (typeof typeSpecs[typeSpecName] !== 'function') { 483 | var err = Error( 484 | (componentName || 'React class') + ': ' + location + ' type `' + typeSpecName + '` is invalid; ' + 485 | 'it must be a function, usually from the `prop-types` package, but received `' + typeof typeSpecs[typeSpecName] + '`.' 486 | ); 487 | err.name = 'Invariant Violation'; 488 | throw err; 489 | } 490 | error = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, ReactPropTypesSecret$1); 491 | } catch (ex) { 492 | error = ex; 493 | } 494 | if (error && !(error instanceof Error)) { 495 | printWarning( 496 | (componentName || 'React class') + ': type specification of ' + 497 | location + ' `' + typeSpecName + '` is invalid; the type checker ' + 498 | 'function must return `null` or an `Error` but returned a ' + typeof error + '. ' + 499 | 'You may have forgotten to pass an argument to the type checker ' + 500 | 'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' + 501 | 'shape all require an argument).' 502 | ); 503 | } 504 | if (error instanceof Error && !(error.message in loggedTypeFailures)) { 505 | // Only monitor this failure once because there tends to be a lot of the 506 | // same error. 507 | loggedTypeFailures[error.message] = true; 508 | 509 | var stack = getStack ? getStack() : ''; 510 | 511 | printWarning( 512 | 'Failed ' + location + ' type: ' + error.message + (stack != null ? stack : '') 513 | ); 514 | } 515 | } 516 | } 517 | } 518 | } 519 | 520 | /** 521 | * Resets warning cache when testing. 522 | * 523 | * @private 524 | */ 525 | checkPropTypes.resetWarningCache = function() { 526 | { 527 | loggedTypeFailures = {}; 528 | } 529 | }; 530 | 531 | var checkPropTypes_1 = checkPropTypes; 532 | 533 | var has$1 = Function.call.bind(Object.prototype.hasOwnProperty); 534 | var printWarning$1 = function() {}; 535 | 536 | { 537 | printWarning$1 = function(text) { 538 | var message = 'Warning: ' + text; 539 | if (typeof console !== 'undefined') { 540 | console.error(message); 541 | } 542 | try { 543 | // --- Welcome to debugging React --- 544 | // This error was thrown as a convenience so that you can use this stack 545 | // to find the callsite that caused this warning to fire. 546 | throw new Error(message); 547 | } catch (x) {} 548 | }; 549 | } 550 | 551 | function emptyFunctionThatReturnsNull() { 552 | return null; 553 | } 554 | 555 | var factoryWithTypeCheckers = function(isValidElement, throwOnDirectAccess) { 556 | /* global Symbol */ 557 | var ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator; 558 | var FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec. 559 | 560 | /** 561 | * Returns the iterator method function contained on the iterable object. 562 | * 563 | * Be sure to invoke the function with the iterable as context: 564 | * 565 | * var iteratorFn = getIteratorFn(myIterable); 566 | * if (iteratorFn) { 567 | * var iterator = iteratorFn.call(myIterable); 568 | * ... 569 | * } 570 | * 571 | * @param {?object} maybeIterable 572 | * @return {?function} 573 | */ 574 | function getIteratorFn(maybeIterable) { 575 | var iteratorFn = maybeIterable && (ITERATOR_SYMBOL && maybeIterable[ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]); 576 | if (typeof iteratorFn === 'function') { 577 | return iteratorFn; 578 | } 579 | } 580 | 581 | /** 582 | * Collection of methods that allow declaration and validation of props that are 583 | * supplied to React components. Example usage: 584 | * 585 | * var Props = require('ReactPropTypes'); 586 | * var MyArticle = React.createClass({ 587 | * propTypes: { 588 | * // An optional string prop named "description". 589 | * description: Props.string, 590 | * 591 | * // A required enum prop named "category". 592 | * category: Props.oneOf(['News','Photos']).isRequired, 593 | * 594 | * // A prop named "dialog" that requires an instance of Dialog. 595 | * dialog: Props.instanceOf(Dialog).isRequired 596 | * }, 597 | * render: function() { ... } 598 | * }); 599 | * 600 | * A more formal specification of how these methods are used: 601 | * 602 | * type := array|bool|func|object|number|string|oneOf([...])|instanceOf(...) 603 | * decl := ReactPropTypes.{type}(.isRequired)? 604 | * 605 | * Each and every declaration produces a function with the same signature. This 606 | * allows the creation of custom validation functions. For example: 607 | * 608 | * var MyLink = React.createClass({ 609 | * propTypes: { 610 | * // An optional string or URI prop named "href". 611 | * href: function(props, propName, componentName) { 612 | * var propValue = props[propName]; 613 | * if (propValue != null && typeof propValue !== 'string' && 614 | * !(propValue instanceof URI)) { 615 | * return new Error( 616 | * 'Expected a string or an URI for ' + propName + ' in ' + 617 | * componentName 618 | * ); 619 | * } 620 | * } 621 | * }, 622 | * render: function() {...} 623 | * }); 624 | * 625 | * @internal 626 | */ 627 | 628 | var ANONYMOUS = '<>'; 629 | 630 | // Important! 631 | // Keep this list in sync with production version in `./factoryWithThrowingShims.js`. 632 | var ReactPropTypes = { 633 | array: createPrimitiveTypeChecker('array'), 634 | bool: createPrimitiveTypeChecker('boolean'), 635 | func: createPrimitiveTypeChecker('function'), 636 | number: createPrimitiveTypeChecker('number'), 637 | object: createPrimitiveTypeChecker('object'), 638 | string: createPrimitiveTypeChecker('string'), 639 | symbol: createPrimitiveTypeChecker('symbol'), 640 | 641 | any: createAnyTypeChecker(), 642 | arrayOf: createArrayOfTypeChecker, 643 | element: createElementTypeChecker(), 644 | elementType: createElementTypeTypeChecker(), 645 | instanceOf: createInstanceTypeChecker, 646 | node: createNodeChecker(), 647 | objectOf: createObjectOfTypeChecker, 648 | oneOf: createEnumTypeChecker, 649 | oneOfType: createUnionTypeChecker, 650 | shape: createShapeTypeChecker, 651 | exact: createStrictShapeTypeChecker, 652 | }; 653 | 654 | /** 655 | * inlined Object.is polyfill to avoid requiring consumers ship their own 656 | * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is 657 | */ 658 | /*eslint-disable no-self-compare*/ 659 | function is(x, y) { 660 | // SameValue algorithm 661 | if (x === y) { 662 | // Steps 1-5, 7-10 663 | // Steps 6.b-6.e: +0 != -0 664 | return x !== 0 || 1 / x === 1 / y; 665 | } else { 666 | // Step 6.a: NaN == NaN 667 | return x !== x && y !== y; 668 | } 669 | } 670 | /*eslint-enable no-self-compare*/ 671 | 672 | /** 673 | * We use an Error-like object for backward compatibility as people may call 674 | * PropTypes directly and inspect their output. However, we don't use real 675 | * Errors anymore. We don't inspect their stack anyway, and creating them 676 | * is prohibitively expensive if they are created too often, such as what 677 | * happens in oneOfType() for any type before the one that matched. 678 | */ 679 | function PropTypeError(message) { 680 | this.message = message; 681 | this.stack = ''; 682 | } 683 | // Make `instanceof Error` still work for returned errors. 684 | PropTypeError.prototype = Error.prototype; 685 | 686 | function createChainableTypeChecker(validate) { 687 | { 688 | var manualPropTypeCallCache = {}; 689 | var manualPropTypeWarningCount = 0; 690 | } 691 | function checkType(isRequired, props, propName, componentName, location, propFullName, secret) { 692 | componentName = componentName || ANONYMOUS; 693 | propFullName = propFullName || propName; 694 | 695 | if (secret !== ReactPropTypesSecret_1) { 696 | if (throwOnDirectAccess) { 697 | // New behavior only for users of `prop-types` package 698 | var err = new Error( 699 | 'Calling PropTypes validators directly is not supported by the `prop-types` package. ' + 700 | 'Use `PropTypes.checkPropTypes()` to call them. ' + 701 | 'Read more at http://fb.me/use-check-prop-types' 702 | ); 703 | err.name = 'Invariant Violation'; 704 | throw err; 705 | } else if ( typeof console !== 'undefined') { 706 | // Old behavior for people using React.PropTypes 707 | var cacheKey = componentName + ':' + propName; 708 | if ( 709 | !manualPropTypeCallCache[cacheKey] && 710 | // Avoid spamming the console because they are often not actionable except for lib authors 711 | manualPropTypeWarningCount < 3 712 | ) { 713 | printWarning$1( 714 | 'You are manually calling a React.PropTypes validation ' + 715 | 'function for the `' + propFullName + '` prop on `' + componentName + '`. This is deprecated ' + 716 | 'and will throw in the standalone `prop-types` package. ' + 717 | 'You may be seeing this warning due to a third-party PropTypes ' + 718 | 'library. See https://fb.me/react-warning-dont-call-proptypes ' + 'for details.' 719 | ); 720 | manualPropTypeCallCache[cacheKey] = true; 721 | manualPropTypeWarningCount++; 722 | } 723 | } 724 | } 725 | if (props[propName] == null) { 726 | if (isRequired) { 727 | if (props[propName] === null) { 728 | return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required ' + ('in `' + componentName + '`, but its value is `null`.')); 729 | } 730 | return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required in ' + ('`' + componentName + '`, but its value is `undefined`.')); 731 | } 732 | return null; 733 | } else { 734 | return validate(props, propName, componentName, location, propFullName); 735 | } 736 | } 737 | 738 | var chainedCheckType = checkType.bind(null, false); 739 | chainedCheckType.isRequired = checkType.bind(null, true); 740 | 741 | return chainedCheckType; 742 | } 743 | 744 | function createPrimitiveTypeChecker(expectedType) { 745 | function validate(props, propName, componentName, location, propFullName, secret) { 746 | var propValue = props[propName]; 747 | var propType = getPropType(propValue); 748 | if (propType !== expectedType) { 749 | // `propValue` being instance of, say, date/regexp, pass the 'object' 750 | // check, but we can offer a more precise error message here rather than 751 | // 'of type `object`'. 752 | var preciseType = getPreciseType(propValue); 753 | 754 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + preciseType + '` supplied to `' + componentName + '`, expected ') + ('`' + expectedType + '`.')); 755 | } 756 | return null; 757 | } 758 | return createChainableTypeChecker(validate); 759 | } 760 | 761 | function createAnyTypeChecker() { 762 | return createChainableTypeChecker(emptyFunctionThatReturnsNull); 763 | } 764 | 765 | function createArrayOfTypeChecker(typeChecker) { 766 | function validate(props, propName, componentName, location, propFullName) { 767 | if (typeof typeChecker !== 'function') { 768 | return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside arrayOf.'); 769 | } 770 | var propValue = props[propName]; 771 | if (!Array.isArray(propValue)) { 772 | var propType = getPropType(propValue); 773 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an array.')); 774 | } 775 | for (var i = 0; i < propValue.length; i++) { 776 | var error = typeChecker(propValue, i, componentName, location, propFullName + '[' + i + ']', ReactPropTypesSecret_1); 777 | if (error instanceof Error) { 778 | return error; 779 | } 780 | } 781 | return null; 782 | } 783 | return createChainableTypeChecker(validate); 784 | } 785 | 786 | function createElementTypeChecker() { 787 | function validate(props, propName, componentName, location, propFullName) { 788 | var propValue = props[propName]; 789 | if (!isValidElement(propValue)) { 790 | var propType = getPropType(propValue); 791 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected a single ReactElement.')); 792 | } 793 | return null; 794 | } 795 | return createChainableTypeChecker(validate); 796 | } 797 | 798 | function createElementTypeTypeChecker() { 799 | function validate(props, propName, componentName, location, propFullName) { 800 | var propValue = props[propName]; 801 | if (!reactIs.isValidElementType(propValue)) { 802 | var propType = getPropType(propValue); 803 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected a single ReactElement type.')); 804 | } 805 | return null; 806 | } 807 | return createChainableTypeChecker(validate); 808 | } 809 | 810 | function createInstanceTypeChecker(expectedClass) { 811 | function validate(props, propName, componentName, location, propFullName) { 812 | if (!(props[propName] instanceof expectedClass)) { 813 | var expectedClassName = expectedClass.name || ANONYMOUS; 814 | var actualClassName = getClassName(props[propName]); 815 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + actualClassName + '` supplied to `' + componentName + '`, expected ') + ('instance of `' + expectedClassName + '`.')); 816 | } 817 | return null; 818 | } 819 | return createChainableTypeChecker(validate); 820 | } 821 | 822 | function createEnumTypeChecker(expectedValues) { 823 | if (!Array.isArray(expectedValues)) { 824 | { 825 | if (arguments.length > 1) { 826 | printWarning$1( 827 | 'Invalid arguments supplied to oneOf, expected an array, got ' + arguments.length + ' arguments. ' + 828 | 'A common mistake is to write oneOf(x, y, z) instead of oneOf([x, y, z]).' 829 | ); 830 | } else { 831 | printWarning$1('Invalid argument supplied to oneOf, expected an array.'); 832 | } 833 | } 834 | return emptyFunctionThatReturnsNull; 835 | } 836 | 837 | function validate(props, propName, componentName, location, propFullName) { 838 | var propValue = props[propName]; 839 | for (var i = 0; i < expectedValues.length; i++) { 840 | if (is(propValue, expectedValues[i])) { 841 | return null; 842 | } 843 | } 844 | 845 | var valuesString = JSON.stringify(expectedValues, function replacer(key, value) { 846 | var type = getPreciseType(value); 847 | if (type === 'symbol') { 848 | return String(value); 849 | } 850 | return value; 851 | }); 852 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of value `' + String(propValue) + '` ' + ('supplied to `' + componentName + '`, expected one of ' + valuesString + '.')); 853 | } 854 | return createChainableTypeChecker(validate); 855 | } 856 | 857 | function createObjectOfTypeChecker(typeChecker) { 858 | function validate(props, propName, componentName, location, propFullName) { 859 | if (typeof typeChecker !== 'function') { 860 | return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside objectOf.'); 861 | } 862 | var propValue = props[propName]; 863 | var propType = getPropType(propValue); 864 | if (propType !== 'object') { 865 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an object.')); 866 | } 867 | for (var key in propValue) { 868 | if (has$1(propValue, key)) { 869 | var error = typeChecker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret_1); 870 | if (error instanceof Error) { 871 | return error; 872 | } 873 | } 874 | } 875 | return null; 876 | } 877 | return createChainableTypeChecker(validate); 878 | } 879 | 880 | function createUnionTypeChecker(arrayOfTypeCheckers) { 881 | if (!Array.isArray(arrayOfTypeCheckers)) { 882 | printWarning$1('Invalid argument supplied to oneOfType, expected an instance of array.') ; 883 | return emptyFunctionThatReturnsNull; 884 | } 885 | 886 | for (var i = 0; i < arrayOfTypeCheckers.length; i++) { 887 | var checker = arrayOfTypeCheckers[i]; 888 | if (typeof checker !== 'function') { 889 | printWarning$1( 890 | 'Invalid argument supplied to oneOfType. Expected an array of check functions, but ' + 891 | 'received ' + getPostfixForTypeWarning(checker) + ' at index ' + i + '.' 892 | ); 893 | return emptyFunctionThatReturnsNull; 894 | } 895 | } 896 | 897 | function validate(props, propName, componentName, location, propFullName) { 898 | for (var i = 0; i < arrayOfTypeCheckers.length; i++) { 899 | var checker = arrayOfTypeCheckers[i]; 900 | if (checker(props, propName, componentName, location, propFullName, ReactPropTypesSecret_1) == null) { 901 | return null; 902 | } 903 | } 904 | 905 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`.')); 906 | } 907 | return createChainableTypeChecker(validate); 908 | } 909 | 910 | function createNodeChecker() { 911 | function validate(props, propName, componentName, location, propFullName) { 912 | if (!isNode(props[propName])) { 913 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`, expected a ReactNode.')); 914 | } 915 | return null; 916 | } 917 | return createChainableTypeChecker(validate); 918 | } 919 | 920 | function createShapeTypeChecker(shapeTypes) { 921 | function validate(props, propName, componentName, location, propFullName) { 922 | var propValue = props[propName]; 923 | var propType = getPropType(propValue); 924 | if (propType !== 'object') { 925 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.')); 926 | } 927 | for (var key in shapeTypes) { 928 | var checker = shapeTypes[key]; 929 | if (!checker) { 930 | continue; 931 | } 932 | var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret_1); 933 | if (error) { 934 | return error; 935 | } 936 | } 937 | return null; 938 | } 939 | return createChainableTypeChecker(validate); 940 | } 941 | 942 | function createStrictShapeTypeChecker(shapeTypes) { 943 | function validate(props, propName, componentName, location, propFullName) { 944 | var propValue = props[propName]; 945 | var propType = getPropType(propValue); 946 | if (propType !== 'object') { 947 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.')); 948 | } 949 | // We need to check all keys in case some are required but missing from 950 | // props. 951 | var allKeys = objectAssign({}, props[propName], shapeTypes); 952 | for (var key in allKeys) { 953 | var checker = shapeTypes[key]; 954 | if (!checker) { 955 | return new PropTypeError( 956 | 'Invalid ' + location + ' `' + propFullName + '` key `' + key + '` supplied to `' + componentName + '`.' + 957 | '\nBad object: ' + JSON.stringify(props[propName], null, ' ') + 958 | '\nValid keys: ' + JSON.stringify(Object.keys(shapeTypes), null, ' ') 959 | ); 960 | } 961 | var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret_1); 962 | if (error) { 963 | return error; 964 | } 965 | } 966 | return null; 967 | } 968 | 969 | return createChainableTypeChecker(validate); 970 | } 971 | 972 | function isNode(propValue) { 973 | switch (typeof propValue) { 974 | case 'number': 975 | case 'string': 976 | case 'undefined': 977 | return true; 978 | case 'boolean': 979 | return !propValue; 980 | case 'object': 981 | if (Array.isArray(propValue)) { 982 | return propValue.every(isNode); 983 | } 984 | if (propValue === null || isValidElement(propValue)) { 985 | return true; 986 | } 987 | 988 | var iteratorFn = getIteratorFn(propValue); 989 | if (iteratorFn) { 990 | var iterator = iteratorFn.call(propValue); 991 | var step; 992 | if (iteratorFn !== propValue.entries) { 993 | while (!(step = iterator.next()).done) { 994 | if (!isNode(step.value)) { 995 | return false; 996 | } 997 | } 998 | } else { 999 | // Iterator will provide entry [k,v] tuples rather than values. 1000 | while (!(step = iterator.next()).done) { 1001 | var entry = step.value; 1002 | if (entry) { 1003 | if (!isNode(entry[1])) { 1004 | return false; 1005 | } 1006 | } 1007 | } 1008 | } 1009 | } else { 1010 | return false; 1011 | } 1012 | 1013 | return true; 1014 | default: 1015 | return false; 1016 | } 1017 | } 1018 | 1019 | function isSymbol(propType, propValue) { 1020 | // Native Symbol. 1021 | if (propType === 'symbol') { 1022 | return true; 1023 | } 1024 | 1025 | // falsy value can't be a Symbol 1026 | if (!propValue) { 1027 | return false; 1028 | } 1029 | 1030 | // 19.4.3.5 Symbol.prototype[@@toStringTag] === 'Symbol' 1031 | if (propValue['@@toStringTag'] === 'Symbol') { 1032 | return true; 1033 | } 1034 | 1035 | // Fallback for non-spec compliant Symbols which are polyfilled. 1036 | if (typeof Symbol === 'function' && propValue instanceof Symbol) { 1037 | return true; 1038 | } 1039 | 1040 | return false; 1041 | } 1042 | 1043 | // Equivalent of `typeof` but with special handling for array and regexp. 1044 | function getPropType(propValue) { 1045 | var propType = typeof propValue; 1046 | if (Array.isArray(propValue)) { 1047 | return 'array'; 1048 | } 1049 | if (propValue instanceof RegExp) { 1050 | // Old webkits (at least until Android 4.0) return 'function' rather than 1051 | // 'object' for typeof a RegExp. We'll normalize this here so that /bla/ 1052 | // passes PropTypes.object. 1053 | return 'object'; 1054 | } 1055 | if (isSymbol(propType, propValue)) { 1056 | return 'symbol'; 1057 | } 1058 | return propType; 1059 | } 1060 | 1061 | // This handles more types than `getPropType`. Only used for error messages. 1062 | // See `createPrimitiveTypeChecker`. 1063 | function getPreciseType(propValue) { 1064 | if (typeof propValue === 'undefined' || propValue === null) { 1065 | return '' + propValue; 1066 | } 1067 | var propType = getPropType(propValue); 1068 | if (propType === 'object') { 1069 | if (propValue instanceof Date) { 1070 | return 'date'; 1071 | } else if (propValue instanceof RegExp) { 1072 | return 'regexp'; 1073 | } 1074 | } 1075 | return propType; 1076 | } 1077 | 1078 | // Returns a string that is postfixed to a warning about an invalid type. 1079 | // For example, "undefined" or "of type array" 1080 | function getPostfixForTypeWarning(value) { 1081 | var type = getPreciseType(value); 1082 | switch (type) { 1083 | case 'array': 1084 | case 'object': 1085 | return 'an ' + type; 1086 | case 'boolean': 1087 | case 'date': 1088 | case 'regexp': 1089 | return 'a ' + type; 1090 | default: 1091 | return type; 1092 | } 1093 | } 1094 | 1095 | // Returns class name of the object, if any. 1096 | function getClassName(propValue) { 1097 | if (!propValue.constructor || !propValue.constructor.name) { 1098 | return ANONYMOUS; 1099 | } 1100 | return propValue.constructor.name; 1101 | } 1102 | 1103 | ReactPropTypes.checkPropTypes = checkPropTypes_1; 1104 | ReactPropTypes.resetWarningCache = checkPropTypes_1.resetWarningCache; 1105 | ReactPropTypes.PropTypes = ReactPropTypes; 1106 | 1107 | return ReactPropTypes; 1108 | }; 1109 | 1110 | var propTypes = createCommonjsModule(function (module) { 1111 | /** 1112 | * Copyright (c) 2013-present, Facebook, Inc. 1113 | * 1114 | * This source code is licensed under the MIT license found in the 1115 | * LICENSE file in the root directory of this source tree. 1116 | */ 1117 | 1118 | { 1119 | var ReactIs = reactIs; 1120 | 1121 | // By explicitly using `prop-types` you are opting into new development behavior. 1122 | // http://fb.me/prop-types-in-prod 1123 | var throwOnDirectAccess = true; 1124 | module.exports = factoryWithTypeCheckers(ReactIs.isElement, throwOnDirectAccess); 1125 | } 1126 | }); 1127 | 1128 | /** 1129 | * The stateObjects provides persistent storage of state for as many initialState objects as 1130 | * needed throughout the application. 1131 | * 1132 | * Every instantiation of StateProvider will add a new initialState object to stateObjects with 1133 | * the key of the reducer name and the value of the state. 1134 | */ 1135 | 1136 | var stateObjects = {}; 1137 | /** 1138 | * Create a Context.Provider wrapper for children components wherever it is applied to the 1139 | * component tree. This component can be called multiple times throughout the application. 1140 | * 1141 | * @param {Function} reducer A reducer function that contains a switch statement and, ultimately, 1142 | * returns a state object. The reducer can never be undefined or anything other than a type of 1143 | * function. Reducers should return modified state if the action.type passed into them is defined 1144 | * or return the initialState if the action.type passed into them is undefined. 1145 | * 1146 | * @param {Object} stateContext A Context object created out of the createContext function 1147 | * from React. 1148 | * 1149 | * @param {JSX} children The descending component tree JSX is passed in and placed inside 1150 | * the Context.Provider. 1151 | * 1152 | * @returns {JSX} Returns a JSX component for a Context.Provider setup and passes in the memoized 1153 | * value as well as the children of the Context component. 1154 | */ 1155 | 1156 | var StateProvider = function StateProvider(_ref) { 1157 | var reducer = _ref.reducer, 1158 | stateContext = _ref.stateContext, 1159 | children = _ref.children; 1160 | 1161 | // Error messages for the reducer object 1162 | if (typeof reducer !== 'function') { 1163 | throw new Error('The reducer must be a function. You might have forgotten to pass your reducer into your StateProvider.'); 1164 | } // Error messages for the stateContext object 1165 | 1166 | 1167 | if (!stateContext) { 1168 | throw new Error('stateContext prop is undefined. Please check your createContext method and what you are passing into your StateProvider.'); 1169 | } 1170 | 1171 | if (children === undefined || _typeof(children) !== 'object' || !Object.keys(children).length) { 1172 | throw new Error('StateProvider must contain children components. You probably forgot to wrap it around your components in your JSX.'); 1173 | } 1174 | /** 1175 | * This initial reducer call sets returns the initial state object from the reducer that will 1176 | * then be passed into useReducer. 1177 | * 1178 | * 1179 | */ 1180 | 1181 | 1182 | if (stateObjects[reducer.name] === undefined) { 1183 | var getRandomString = Math.random().toString(36).substring(7); 1184 | /** 1185 | * The reducer function is invoked and passed no first parameter and an object for the second 1186 | * parameter. 1187 | * 1188 | * Parameter one is undefined as the reducer function should have a default parameter of 1189 | * initialState inside the application. 1190 | * 1191 | * Parameter two is an object with a key-value pair for an initialState retrieval using the 1192 | * getRandomString variable above appended to "@conflux" in a template literal string as 1193 | * shown below. 1194 | */ 1195 | 1196 | stateObjects[reducer.name] = reducer(undefined, { 1197 | type: "@conflux-".concat(getRandomString) 1198 | }); 1199 | } 1200 | /** 1201 | * Uses the useReducer hook to pass in a reducer and initialState. It returns 1202 | * an array that can be destructured into state and a dispatch function. 1203 | */ 1204 | 1205 | 1206 | var _useReducer = React.useReducer(reducer, stateObjects[reducer.name]), 1207 | _useReducer2 = _slicedToArray(_useReducer, 2), 1208 | state = _useReducer2[0], 1209 | dispatch = _useReducer2[1]; 1210 | /** 1211 | * The useMemo hook returns state and dispatch while guarding against unnecessary rerendering of the component 1212 | * tree contained within this stateContext.Provider. 1213 | * 1214 | * It will only update when the state object in value changes, rather than any other state/props outside of 1215 | * these values. 1216 | */ 1217 | 1218 | 1219 | var value = React.useMemo(function () { 1220 | return [state, dispatch]; 1221 | }, [state]); 1222 | var Provider = stateContext.Provider; 1223 | /** 1224 | * The newly instantiated copy of Provider is returned as a component from this function 1225 | * to be wrapped around JSX in the application. The value returned from the useMemo hook (an array containing 1226 | * state and dispatch) is passed into the Provider per the requirements for the Context API 1227 | * in the documentation at: https://reactjs.org/docs/context.html 1228 | * 1229 | * This array will be available for destructuring inside components contained in the state tree with 1230 | * react-conflux's custom hook "useStateValue". 1231 | */ 1232 | 1233 | return React__default.createElement(Provider, { 1234 | value: value 1235 | }, children); 1236 | }; 1237 | 1238 | StateProvider.propTypes = { 1239 | reducer: propTypes.func.isRequired, 1240 | stateContext: propTypes.object.isRequired, 1241 | // eslint-disable-line react/forbid-prop-types 1242 | children: propTypes.oneOfType([propTypes.element, propTypes.array]).isRequired 1243 | }; 1244 | 1245 | /** 1246 | * The useStateValue custom hook from Conflux provides a modular, predictable, and easy 1247 | * way to desctructure state and dispatch from the Context API's Consumer whenever needed. 1248 | * 1249 | * @param {Object} stateContext An object previously created using React's Context 1250 | * API that contains a Provider and Consumer. 1251 | * 1252 | * @returns {context} Returns a validated context array containing a state object and a 1253 | * dispatch function for use inside of a component. 1254 | */ 1255 | 1256 | var useStateValue = function useStateValue(stateContext) { 1257 | /** 1258 | * stateContext error messages for undefined and incorrect data types passed into 1259 | * useStateValue hook 1260 | */ 1261 | if (stateContext === undefined) { 1262 | throw new Error('The stateContext object is undefined in your useStateValue hook. You probably forgot to pass the stateContext object into your useStateValue hook.'); 1263 | } 1264 | 1265 | if (!stateContext.Provider && !stateContext.Consumer) { 1266 | throw new Error('Incorrect argument passed to the useStateValue hook. You probably passed a variable other than your context object into it.'); 1267 | } 1268 | /** 1269 | * The useContext React hook references the Context.Provider closest to it up the component 1270 | * tree. In Conflux, this will always return as an array which is [state, dispatch]. These 1271 | * are returned by the useStateValue hook for use inside the application. 1272 | */ 1273 | 1274 | 1275 | var context = React.useContext(stateContext); 1276 | /** 1277 | * context error message for if context returns undefined. This happens when the stateContext 1278 | * passed into the useStateValue hook is used in a component which is not a child of that 1279 | * context's Provider. 1280 | */ 1281 | 1282 | if (context === undefined) { 1283 | throw new Error('The useStateValue hook must be used within the Provider of the Context object you have passed to it. Check to make sure you have passed in the correct context object and that the useStateValue hook is within a child of the correct Provider.'); 1284 | } 1285 | /** 1286 | * Return the context of the Context.Provider closest to the useStateValue hook at the time 1287 | * it was called. 1288 | */ 1289 | 1290 | 1291 | return context; 1292 | }; 1293 | 1294 | exports.StateProvider = StateProvider; 1295 | exports.useStateValue = useStateValue; 1296 | -------------------------------------------------------------------------------- /dist/cjs.min.js: -------------------------------------------------------------------------------- 1 | "use strict";function _interopDefault(e){return e&&"object"==typeof e&&"default"in e?e.default:e}Object.defineProperty(exports,"__esModule",{value:!0});var React=require("react"),React__default=_interopDefault(React);function _typeof(e){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function _slicedToArray(e,t){return _arrayWithHoles(e)||_iterableToArrayLimit(e,t)||_nonIterableRest()}function _arrayWithHoles(e){if(Array.isArray(e))return e}function _iterableToArrayLimit(e,t){if(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e)){var r=[],o=!0,n=!1,a=void 0;try{for(var i,u=e[Symbol.iterator]();!(o=(i=u.next()).done)&&(r.push(i.value),!t||r.length!==t);o=!0);}catch(e){n=!0,a=e}finally{try{o||null==u.return||u.return()}finally{if(n)throw a}}return r}}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}function createCommonjsModule(e,t){return e(t={exports:{}},t.exports),t.exports}var ReactPropTypesSecret="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED",ReactPropTypesSecret_1=ReactPropTypesSecret;function emptyFunction(){}function emptyFunctionWithReset(){}emptyFunctionWithReset.resetWarningCache=emptyFunction;var factoryWithThrowingShims=function(){function e(e,t,r,o,n,a){if(a!==ReactPropTypesSecret_1){var i=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw i.name="Invariant Violation",i}}function t(){return e}var r={array:e.isRequired=e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:emptyFunctionWithReset,resetWarningCache:emptyFunction};return r.PropTypes=r},propTypes=createCommonjsModule(function(e){e.exports=factoryWithThrowingShims()}),stateObjects={},StateProvider=function(e){var t=e.reducer,r=e.stateContext,o=e.children;if("function"!=typeof t)throw new Error("The reducer must be a function. You might have forgotten to pass your reducer into your StateProvider.");if(!r)throw new Error("stateContext prop is undefined. Please check your createContext method and what you are passing into your StateProvider.");if(void 0===o||"object"!==_typeof(o)||!Object.keys(o).length)throw new Error("StateProvider must contain children components. You probably forgot to wrap it around your components in your JSX.");if(void 0===stateObjects[t.name]){var n=Math.random().toString(36).substring(7);stateObjects[t.name]=t(void 0,{type:"@conflux-".concat(n)})}var a=_slicedToArray(React.useReducer(t,stateObjects[t.name]),2),i=a[0],u=a[1],c=React.useMemo(function(){return[i,u]},[i]),s=r.Provider;return React__default.createElement(s,{value:c},o)};StateProvider.propTypes={reducer:propTypes.func.isRequired,stateContext:propTypes.object.isRequired,children:propTypes.oneOfType([propTypes.element,propTypes.array]).isRequired};var useStateValue=function(e){if(void 0===e)throw new Error("The stateContext object is undefined in your useStateValue hook. You probably forgot to pass the stateContext object into your useStateValue hook.");if(!e.Provider&&!e.Consumer)throw new Error("Incorrect argument passed to the useStateValue hook. You probably passed a variable other than your context object into it.");var t=React.useContext(e);if(void 0===t)throw new Error("The useStateValue hook must be used within the Provider of the Context object you have passed to it. Check to make sure you have passed in the correct context object and that the useStateValue hook is within a child of the correct Provider.");return t};exports.StateProvider=StateProvider,exports.useStateValue=useStateValue; 2 | -------------------------------------------------------------------------------- /dist/esm.js: -------------------------------------------------------------------------------- 1 | import React, { useReducer, useMemo, useContext } from 'react'; 2 | 3 | function _arrayWithHoles(arr) { 4 | if (Array.isArray(arr)) return arr; 5 | } 6 | 7 | function _iterableToArrayLimit(arr, i) { 8 | if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) { 9 | return; 10 | } 11 | 12 | var _arr = []; 13 | var _n = true; 14 | var _d = false; 15 | var _e = undefined; 16 | 17 | try { 18 | for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { 19 | _arr.push(_s.value); 20 | 21 | if (i && _arr.length === i) break; 22 | } 23 | } catch (err) { 24 | _d = true; 25 | _e = err; 26 | } finally { 27 | try { 28 | if (!_n && _i["return"] != null) _i["return"](); 29 | } finally { 30 | if (_d) throw _e; 31 | } 32 | } 33 | 34 | return _arr; 35 | } 36 | 37 | function _nonIterableRest() { 38 | throw new TypeError("Invalid attempt to destructure non-iterable instance"); 39 | } 40 | 41 | function _slicedToArray(arr, i) { 42 | return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); 43 | } 44 | 45 | function _typeof2(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof2 = function _typeof2(obj) { return typeof obj; }; } else { _typeof2 = function _typeof2(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof2(obj); } 46 | 47 | function _typeof(obj) { 48 | if (typeof Symbol === "function" && _typeof2(Symbol.iterator) === "symbol") { 49 | _typeof = function _typeof(obj) { 50 | return _typeof2(obj); 51 | }; 52 | } else { 53 | _typeof = function _typeof(obj) { 54 | return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : _typeof2(obj); 55 | }; 56 | } 57 | 58 | return _typeof(obj); 59 | } 60 | 61 | function unwrapExports (x) { 62 | return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; 63 | } 64 | 65 | function createCommonjsModule(fn, module) { 66 | return module = { exports: {} }, fn(module, module.exports), module.exports; 67 | } 68 | 69 | var reactIs_development = createCommonjsModule(function (module, exports) { 70 | 71 | 72 | 73 | { 74 | (function() { 75 | 76 | Object.defineProperty(exports, '__esModule', { value: true }); 77 | 78 | // The Symbol used to tag the ReactElement-like types. If there is no native Symbol 79 | // nor polyfill, then a plain number is used for performance. 80 | var hasSymbol = typeof Symbol === 'function' && Symbol.for; 81 | var REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for('react.element') : 0xeac7; 82 | var REACT_PORTAL_TYPE = hasSymbol ? Symbol.for('react.portal') : 0xeaca; 83 | var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for('react.fragment') : 0xeacb; 84 | var REACT_STRICT_MODE_TYPE = hasSymbol ? Symbol.for('react.strict_mode') : 0xeacc; 85 | var REACT_PROFILER_TYPE = hasSymbol ? Symbol.for('react.profiler') : 0xead2; 86 | var REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for('react.provider') : 0xeacd; 87 | var REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for('react.context') : 0xeace; // TODO: We don't use AsyncMode or ConcurrentMode anymore. They were temporary 88 | // (unstable) APIs that have been removed. Can we remove the symbols? 89 | 90 | var REACT_ASYNC_MODE_TYPE = hasSymbol ? Symbol.for('react.async_mode') : 0xeacf; 91 | var REACT_CONCURRENT_MODE_TYPE = hasSymbol ? Symbol.for('react.concurrent_mode') : 0xeacf; 92 | var REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0; 93 | var REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for('react.suspense') : 0xead1; 94 | var REACT_SUSPENSE_LIST_TYPE = hasSymbol ? Symbol.for('react.suspense_list') : 0xead8; 95 | var REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3; 96 | var REACT_LAZY_TYPE = hasSymbol ? Symbol.for('react.lazy') : 0xead4; 97 | var REACT_FUNDAMENTAL_TYPE = hasSymbol ? Symbol.for('react.fundamental') : 0xead5; 98 | var REACT_RESPONDER_TYPE = hasSymbol ? Symbol.for('react.responder') : 0xead6; 99 | var REACT_SCOPE_TYPE = hasSymbol ? Symbol.for('react.scope') : 0xead7; 100 | 101 | function isValidElementType(type) { 102 | return typeof type === 'string' || typeof type === 'function' || // Note: its typeof might be other than 'symbol' or 'number' if it's a polyfill. 103 | type === REACT_FRAGMENT_TYPE || type === REACT_CONCURRENT_MODE_TYPE || type === REACT_PROFILER_TYPE || type === REACT_STRICT_MODE_TYPE || type === REACT_SUSPENSE_TYPE || type === REACT_SUSPENSE_LIST_TYPE || typeof type === 'object' && type !== null && (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_PROVIDER_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE || type.$$typeof === REACT_FUNDAMENTAL_TYPE || type.$$typeof === REACT_RESPONDER_TYPE || type.$$typeof === REACT_SCOPE_TYPE); 104 | } 105 | 106 | /** 107 | * Forked from fbjs/warning: 108 | * https://github.com/facebook/fbjs/blob/e66ba20ad5be433eb54423f2b097d829324d9de6/packages/fbjs/src/__forks__/warning.js 109 | * 110 | * Only change is we use console.warn instead of console.error, 111 | * and do nothing when 'console' is not supported. 112 | * This really simplifies the code. 113 | * --- 114 | * Similar to invariant but only logs a warning if the condition is not met. 115 | * This can be used to log issues in development environments in critical 116 | * paths. Removing the logging code for production environments will keep the 117 | * same logic and follow the same code paths. 118 | */ 119 | var lowPriorityWarningWithoutStack = function () {}; 120 | 121 | { 122 | var printWarning = function (format) { 123 | for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 124 | args[_key - 1] = arguments[_key]; 125 | } 126 | 127 | var argIndex = 0; 128 | var message = 'Warning: ' + format.replace(/%s/g, function () { 129 | return args[argIndex++]; 130 | }); 131 | 132 | if (typeof console !== 'undefined') { 133 | console.warn(message); 134 | } 135 | 136 | try { 137 | // --- Welcome to debugging React --- 138 | // This error was thrown as a convenience so that you can use this stack 139 | // to find the callsite that caused this warning to fire. 140 | throw new Error(message); 141 | } catch (x) {} 142 | }; 143 | 144 | lowPriorityWarningWithoutStack = function (condition, format) { 145 | if (format === undefined) { 146 | throw new Error('`lowPriorityWarningWithoutStack(condition, format, ...args)` requires a warning ' + 'message argument'); 147 | } 148 | 149 | if (!condition) { 150 | for (var _len2 = arguments.length, args = new Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) { 151 | args[_key2 - 2] = arguments[_key2]; 152 | } 153 | 154 | printWarning.apply(void 0, [format].concat(args)); 155 | } 156 | }; 157 | } 158 | 159 | var lowPriorityWarningWithoutStack$1 = lowPriorityWarningWithoutStack; 160 | 161 | function typeOf(object) { 162 | if (typeof object === 'object' && object !== null) { 163 | var $$typeof = object.$$typeof; 164 | 165 | switch ($$typeof) { 166 | case REACT_ELEMENT_TYPE: 167 | var type = object.type; 168 | 169 | switch (type) { 170 | case REACT_ASYNC_MODE_TYPE: 171 | case REACT_CONCURRENT_MODE_TYPE: 172 | case REACT_FRAGMENT_TYPE: 173 | case REACT_PROFILER_TYPE: 174 | case REACT_STRICT_MODE_TYPE: 175 | case REACT_SUSPENSE_TYPE: 176 | return type; 177 | 178 | default: 179 | var $$typeofType = type && type.$$typeof; 180 | 181 | switch ($$typeofType) { 182 | case REACT_CONTEXT_TYPE: 183 | case REACT_FORWARD_REF_TYPE: 184 | case REACT_PROVIDER_TYPE: 185 | return $$typeofType; 186 | 187 | default: 188 | return $$typeof; 189 | } 190 | 191 | } 192 | 193 | case REACT_LAZY_TYPE: 194 | case REACT_MEMO_TYPE: 195 | case REACT_PORTAL_TYPE: 196 | return $$typeof; 197 | } 198 | } 199 | 200 | return undefined; 201 | } // AsyncMode is deprecated along with isAsyncMode 202 | 203 | var AsyncMode = REACT_ASYNC_MODE_TYPE; 204 | var ConcurrentMode = REACT_CONCURRENT_MODE_TYPE; 205 | var ContextConsumer = REACT_CONTEXT_TYPE; 206 | var ContextProvider = REACT_PROVIDER_TYPE; 207 | var Element = REACT_ELEMENT_TYPE; 208 | var ForwardRef = REACT_FORWARD_REF_TYPE; 209 | var Fragment = REACT_FRAGMENT_TYPE; 210 | var Lazy = REACT_LAZY_TYPE; 211 | var Memo = REACT_MEMO_TYPE; 212 | var Portal = REACT_PORTAL_TYPE; 213 | var Profiler = REACT_PROFILER_TYPE; 214 | var StrictMode = REACT_STRICT_MODE_TYPE; 215 | var Suspense = REACT_SUSPENSE_TYPE; 216 | var hasWarnedAboutDeprecatedIsAsyncMode = false; // AsyncMode should be deprecated 217 | 218 | function isAsyncMode(object) { 219 | { 220 | if (!hasWarnedAboutDeprecatedIsAsyncMode) { 221 | hasWarnedAboutDeprecatedIsAsyncMode = true; 222 | lowPriorityWarningWithoutStack$1(false, 'The ReactIs.isAsyncMode() alias has been deprecated, ' + 'and will be removed in React 17+. Update your code to use ' + 'ReactIs.isConcurrentMode() instead. It has the exact same API.'); 223 | } 224 | } 225 | 226 | return isConcurrentMode(object) || typeOf(object) === REACT_ASYNC_MODE_TYPE; 227 | } 228 | function isConcurrentMode(object) { 229 | return typeOf(object) === REACT_CONCURRENT_MODE_TYPE; 230 | } 231 | function isContextConsumer(object) { 232 | return typeOf(object) === REACT_CONTEXT_TYPE; 233 | } 234 | function isContextProvider(object) { 235 | return typeOf(object) === REACT_PROVIDER_TYPE; 236 | } 237 | function isElement(object) { 238 | return typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE; 239 | } 240 | function isForwardRef(object) { 241 | return typeOf(object) === REACT_FORWARD_REF_TYPE; 242 | } 243 | function isFragment(object) { 244 | return typeOf(object) === REACT_FRAGMENT_TYPE; 245 | } 246 | function isLazy(object) { 247 | return typeOf(object) === REACT_LAZY_TYPE; 248 | } 249 | function isMemo(object) { 250 | return typeOf(object) === REACT_MEMO_TYPE; 251 | } 252 | function isPortal(object) { 253 | return typeOf(object) === REACT_PORTAL_TYPE; 254 | } 255 | function isProfiler(object) { 256 | return typeOf(object) === REACT_PROFILER_TYPE; 257 | } 258 | function isStrictMode(object) { 259 | return typeOf(object) === REACT_STRICT_MODE_TYPE; 260 | } 261 | function isSuspense(object) { 262 | return typeOf(object) === REACT_SUSPENSE_TYPE; 263 | } 264 | 265 | exports.typeOf = typeOf; 266 | exports.AsyncMode = AsyncMode; 267 | exports.ConcurrentMode = ConcurrentMode; 268 | exports.ContextConsumer = ContextConsumer; 269 | exports.ContextProvider = ContextProvider; 270 | exports.Element = Element; 271 | exports.ForwardRef = ForwardRef; 272 | exports.Fragment = Fragment; 273 | exports.Lazy = Lazy; 274 | exports.Memo = Memo; 275 | exports.Portal = Portal; 276 | exports.Profiler = Profiler; 277 | exports.StrictMode = StrictMode; 278 | exports.Suspense = Suspense; 279 | exports.isValidElementType = isValidElementType; 280 | exports.isAsyncMode = isAsyncMode; 281 | exports.isConcurrentMode = isConcurrentMode; 282 | exports.isContextConsumer = isContextConsumer; 283 | exports.isContextProvider = isContextProvider; 284 | exports.isElement = isElement; 285 | exports.isForwardRef = isForwardRef; 286 | exports.isFragment = isFragment; 287 | exports.isLazy = isLazy; 288 | exports.isMemo = isMemo; 289 | exports.isPortal = isPortal; 290 | exports.isProfiler = isProfiler; 291 | exports.isStrictMode = isStrictMode; 292 | exports.isSuspense = isSuspense; 293 | })(); 294 | } 295 | }); 296 | 297 | unwrapExports(reactIs_development); 298 | var reactIs_development_1 = reactIs_development.typeOf; 299 | var reactIs_development_2 = reactIs_development.AsyncMode; 300 | var reactIs_development_3 = reactIs_development.ConcurrentMode; 301 | var reactIs_development_4 = reactIs_development.ContextConsumer; 302 | var reactIs_development_5 = reactIs_development.ContextProvider; 303 | var reactIs_development_6 = reactIs_development.Element; 304 | var reactIs_development_7 = reactIs_development.ForwardRef; 305 | var reactIs_development_8 = reactIs_development.Fragment; 306 | var reactIs_development_9 = reactIs_development.Lazy; 307 | var reactIs_development_10 = reactIs_development.Memo; 308 | var reactIs_development_11 = reactIs_development.Portal; 309 | var reactIs_development_12 = reactIs_development.Profiler; 310 | var reactIs_development_13 = reactIs_development.StrictMode; 311 | var reactIs_development_14 = reactIs_development.Suspense; 312 | var reactIs_development_15 = reactIs_development.isValidElementType; 313 | var reactIs_development_16 = reactIs_development.isAsyncMode; 314 | var reactIs_development_17 = reactIs_development.isConcurrentMode; 315 | var reactIs_development_18 = reactIs_development.isContextConsumer; 316 | var reactIs_development_19 = reactIs_development.isContextProvider; 317 | var reactIs_development_20 = reactIs_development.isElement; 318 | var reactIs_development_21 = reactIs_development.isForwardRef; 319 | var reactIs_development_22 = reactIs_development.isFragment; 320 | var reactIs_development_23 = reactIs_development.isLazy; 321 | var reactIs_development_24 = reactIs_development.isMemo; 322 | var reactIs_development_25 = reactIs_development.isPortal; 323 | var reactIs_development_26 = reactIs_development.isProfiler; 324 | var reactIs_development_27 = reactIs_development.isStrictMode; 325 | var reactIs_development_28 = reactIs_development.isSuspense; 326 | 327 | var reactIs = createCommonjsModule(function (module) { 328 | 329 | { 330 | module.exports = reactIs_development; 331 | } 332 | }); 333 | 334 | /* 335 | object-assign 336 | (c) Sindre Sorhus 337 | @license MIT 338 | */ 339 | /* eslint-disable no-unused-vars */ 340 | var getOwnPropertySymbols = Object.getOwnPropertySymbols; 341 | var hasOwnProperty = Object.prototype.hasOwnProperty; 342 | var propIsEnumerable = Object.prototype.propertyIsEnumerable; 343 | 344 | function toObject(val) { 345 | if (val === null || val === undefined) { 346 | throw new TypeError('Object.assign cannot be called with null or undefined'); 347 | } 348 | 349 | return Object(val); 350 | } 351 | 352 | function shouldUseNative() { 353 | try { 354 | if (!Object.assign) { 355 | return false; 356 | } 357 | 358 | // Detect buggy property enumeration order in older V8 versions. 359 | 360 | // https://bugs.chromium.org/p/v8/issues/detail?id=4118 361 | var test1 = new String('abc'); // eslint-disable-line no-new-wrappers 362 | test1[5] = 'de'; 363 | if (Object.getOwnPropertyNames(test1)[0] === '5') { 364 | return false; 365 | } 366 | 367 | // https://bugs.chromium.org/p/v8/issues/detail?id=3056 368 | var test2 = {}; 369 | for (var i = 0; i < 10; i++) { 370 | test2['_' + String.fromCharCode(i)] = i; 371 | } 372 | var order2 = Object.getOwnPropertyNames(test2).map(function (n) { 373 | return test2[n]; 374 | }); 375 | if (order2.join('') !== '0123456789') { 376 | return false; 377 | } 378 | 379 | // https://bugs.chromium.org/p/v8/issues/detail?id=3056 380 | var test3 = {}; 381 | 'abcdefghijklmnopqrst'.split('').forEach(function (letter) { 382 | test3[letter] = letter; 383 | }); 384 | if (Object.keys(Object.assign({}, test3)).join('') !== 385 | 'abcdefghijklmnopqrst') { 386 | return false; 387 | } 388 | 389 | return true; 390 | } catch (err) { 391 | // We don't expect any of the above to throw, but better to be safe. 392 | return false; 393 | } 394 | } 395 | 396 | var objectAssign = shouldUseNative() ? Object.assign : function (target, source) { 397 | var from; 398 | var to = toObject(target); 399 | var symbols; 400 | 401 | for (var s = 1; s < arguments.length; s++) { 402 | from = Object(arguments[s]); 403 | 404 | for (var key in from) { 405 | if (hasOwnProperty.call(from, key)) { 406 | to[key] = from[key]; 407 | } 408 | } 409 | 410 | if (getOwnPropertySymbols) { 411 | symbols = getOwnPropertySymbols(from); 412 | for (var i = 0; i < symbols.length; i++) { 413 | if (propIsEnumerable.call(from, symbols[i])) { 414 | to[symbols[i]] = from[symbols[i]]; 415 | } 416 | } 417 | } 418 | } 419 | 420 | return to; 421 | }; 422 | 423 | /** 424 | * Copyright (c) 2013-present, Facebook, Inc. 425 | * 426 | * This source code is licensed under the MIT license found in the 427 | * LICENSE file in the root directory of this source tree. 428 | */ 429 | 430 | var ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED'; 431 | 432 | var ReactPropTypesSecret_1 = ReactPropTypesSecret; 433 | 434 | var printWarning = function() {}; 435 | 436 | { 437 | var ReactPropTypesSecret$1 = ReactPropTypesSecret_1; 438 | var loggedTypeFailures = {}; 439 | var has = Function.call.bind(Object.prototype.hasOwnProperty); 440 | 441 | printWarning = function(text) { 442 | var message = 'Warning: ' + text; 443 | if (typeof console !== 'undefined') { 444 | console.error(message); 445 | } 446 | try { 447 | // --- Welcome to debugging React --- 448 | // This error was thrown as a convenience so that you can use this stack 449 | // to find the callsite that caused this warning to fire. 450 | throw new Error(message); 451 | } catch (x) {} 452 | }; 453 | } 454 | 455 | /** 456 | * Assert that the values match with the type specs. 457 | * Error messages are memorized and will only be shown once. 458 | * 459 | * @param {object} typeSpecs Map of name to a ReactPropType 460 | * @param {object} values Runtime values that need to be type-checked 461 | * @param {string} location e.g. "prop", "context", "child context" 462 | * @param {string} componentName Name of the component for error messages. 463 | * @param {?Function} getStack Returns the component stack. 464 | * @private 465 | */ 466 | function checkPropTypes(typeSpecs, values, location, componentName, getStack) { 467 | { 468 | for (var typeSpecName in typeSpecs) { 469 | if (has(typeSpecs, typeSpecName)) { 470 | var error; 471 | // Prop type validation may throw. In case they do, we don't want to 472 | // fail the render phase where it didn't fail before. So we log it. 473 | // After these have been cleaned up, we'll let them throw. 474 | try { 475 | // This is intentionally an invariant that gets caught. It's the same 476 | // behavior as without this statement except with a better message. 477 | if (typeof typeSpecs[typeSpecName] !== 'function') { 478 | var err = Error( 479 | (componentName || 'React class') + ': ' + location + ' type `' + typeSpecName + '` is invalid; ' + 480 | 'it must be a function, usually from the `prop-types` package, but received `' + typeof typeSpecs[typeSpecName] + '`.' 481 | ); 482 | err.name = 'Invariant Violation'; 483 | throw err; 484 | } 485 | error = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, ReactPropTypesSecret$1); 486 | } catch (ex) { 487 | error = ex; 488 | } 489 | if (error && !(error instanceof Error)) { 490 | printWarning( 491 | (componentName || 'React class') + ': type specification of ' + 492 | location + ' `' + typeSpecName + '` is invalid; the type checker ' + 493 | 'function must return `null` or an `Error` but returned a ' + typeof error + '. ' + 494 | 'You may have forgotten to pass an argument to the type checker ' + 495 | 'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' + 496 | 'shape all require an argument).' 497 | ); 498 | } 499 | if (error instanceof Error && !(error.message in loggedTypeFailures)) { 500 | // Only monitor this failure once because there tends to be a lot of the 501 | // same error. 502 | loggedTypeFailures[error.message] = true; 503 | 504 | var stack = getStack ? getStack() : ''; 505 | 506 | printWarning( 507 | 'Failed ' + location + ' type: ' + error.message + (stack != null ? stack : '') 508 | ); 509 | } 510 | } 511 | } 512 | } 513 | } 514 | 515 | /** 516 | * Resets warning cache when testing. 517 | * 518 | * @private 519 | */ 520 | checkPropTypes.resetWarningCache = function() { 521 | { 522 | loggedTypeFailures = {}; 523 | } 524 | }; 525 | 526 | var checkPropTypes_1 = checkPropTypes; 527 | 528 | var has$1 = Function.call.bind(Object.prototype.hasOwnProperty); 529 | var printWarning$1 = function() {}; 530 | 531 | { 532 | printWarning$1 = function(text) { 533 | var message = 'Warning: ' + text; 534 | if (typeof console !== 'undefined') { 535 | console.error(message); 536 | } 537 | try { 538 | // --- Welcome to debugging React --- 539 | // This error was thrown as a convenience so that you can use this stack 540 | // to find the callsite that caused this warning to fire. 541 | throw new Error(message); 542 | } catch (x) {} 543 | }; 544 | } 545 | 546 | function emptyFunctionThatReturnsNull() { 547 | return null; 548 | } 549 | 550 | var factoryWithTypeCheckers = function(isValidElement, throwOnDirectAccess) { 551 | /* global Symbol */ 552 | var ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator; 553 | var FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec. 554 | 555 | /** 556 | * Returns the iterator method function contained on the iterable object. 557 | * 558 | * Be sure to invoke the function with the iterable as context: 559 | * 560 | * var iteratorFn = getIteratorFn(myIterable); 561 | * if (iteratorFn) { 562 | * var iterator = iteratorFn.call(myIterable); 563 | * ... 564 | * } 565 | * 566 | * @param {?object} maybeIterable 567 | * @return {?function} 568 | */ 569 | function getIteratorFn(maybeIterable) { 570 | var iteratorFn = maybeIterable && (ITERATOR_SYMBOL && maybeIterable[ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]); 571 | if (typeof iteratorFn === 'function') { 572 | return iteratorFn; 573 | } 574 | } 575 | 576 | /** 577 | * Collection of methods that allow declaration and validation of props that are 578 | * supplied to React components. Example usage: 579 | * 580 | * var Props = require('ReactPropTypes'); 581 | * var MyArticle = React.createClass({ 582 | * propTypes: { 583 | * // An optional string prop named "description". 584 | * description: Props.string, 585 | * 586 | * // A required enum prop named "category". 587 | * category: Props.oneOf(['News','Photos']).isRequired, 588 | * 589 | * // A prop named "dialog" that requires an instance of Dialog. 590 | * dialog: Props.instanceOf(Dialog).isRequired 591 | * }, 592 | * render: function() { ... } 593 | * }); 594 | * 595 | * A more formal specification of how these methods are used: 596 | * 597 | * type := array|bool|func|object|number|string|oneOf([...])|instanceOf(...) 598 | * decl := ReactPropTypes.{type}(.isRequired)? 599 | * 600 | * Each and every declaration produces a function with the same signature. This 601 | * allows the creation of custom validation functions. For example: 602 | * 603 | * var MyLink = React.createClass({ 604 | * propTypes: { 605 | * // An optional string or URI prop named "href". 606 | * href: function(props, propName, componentName) { 607 | * var propValue = props[propName]; 608 | * if (propValue != null && typeof propValue !== 'string' && 609 | * !(propValue instanceof URI)) { 610 | * return new Error( 611 | * 'Expected a string or an URI for ' + propName + ' in ' + 612 | * componentName 613 | * ); 614 | * } 615 | * } 616 | * }, 617 | * render: function() {...} 618 | * }); 619 | * 620 | * @internal 621 | */ 622 | 623 | var ANONYMOUS = '<>'; 624 | 625 | // Important! 626 | // Keep this list in sync with production version in `./factoryWithThrowingShims.js`. 627 | var ReactPropTypes = { 628 | array: createPrimitiveTypeChecker('array'), 629 | bool: createPrimitiveTypeChecker('boolean'), 630 | func: createPrimitiveTypeChecker('function'), 631 | number: createPrimitiveTypeChecker('number'), 632 | object: createPrimitiveTypeChecker('object'), 633 | string: createPrimitiveTypeChecker('string'), 634 | symbol: createPrimitiveTypeChecker('symbol'), 635 | 636 | any: createAnyTypeChecker(), 637 | arrayOf: createArrayOfTypeChecker, 638 | element: createElementTypeChecker(), 639 | elementType: createElementTypeTypeChecker(), 640 | instanceOf: createInstanceTypeChecker, 641 | node: createNodeChecker(), 642 | objectOf: createObjectOfTypeChecker, 643 | oneOf: createEnumTypeChecker, 644 | oneOfType: createUnionTypeChecker, 645 | shape: createShapeTypeChecker, 646 | exact: createStrictShapeTypeChecker, 647 | }; 648 | 649 | /** 650 | * inlined Object.is polyfill to avoid requiring consumers ship their own 651 | * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is 652 | */ 653 | /*eslint-disable no-self-compare*/ 654 | function is(x, y) { 655 | // SameValue algorithm 656 | if (x === y) { 657 | // Steps 1-5, 7-10 658 | // Steps 6.b-6.e: +0 != -0 659 | return x !== 0 || 1 / x === 1 / y; 660 | } else { 661 | // Step 6.a: NaN == NaN 662 | return x !== x && y !== y; 663 | } 664 | } 665 | /*eslint-enable no-self-compare*/ 666 | 667 | /** 668 | * We use an Error-like object for backward compatibility as people may call 669 | * PropTypes directly and inspect their output. However, we don't use real 670 | * Errors anymore. We don't inspect their stack anyway, and creating them 671 | * is prohibitively expensive if they are created too often, such as what 672 | * happens in oneOfType() for any type before the one that matched. 673 | */ 674 | function PropTypeError(message) { 675 | this.message = message; 676 | this.stack = ''; 677 | } 678 | // Make `instanceof Error` still work for returned errors. 679 | PropTypeError.prototype = Error.prototype; 680 | 681 | function createChainableTypeChecker(validate) { 682 | { 683 | var manualPropTypeCallCache = {}; 684 | var manualPropTypeWarningCount = 0; 685 | } 686 | function checkType(isRequired, props, propName, componentName, location, propFullName, secret) { 687 | componentName = componentName || ANONYMOUS; 688 | propFullName = propFullName || propName; 689 | 690 | if (secret !== ReactPropTypesSecret_1) { 691 | if (throwOnDirectAccess) { 692 | // New behavior only for users of `prop-types` package 693 | var err = new Error( 694 | 'Calling PropTypes validators directly is not supported by the `prop-types` package. ' + 695 | 'Use `PropTypes.checkPropTypes()` to call them. ' + 696 | 'Read more at http://fb.me/use-check-prop-types' 697 | ); 698 | err.name = 'Invariant Violation'; 699 | throw err; 700 | } else if ( typeof console !== 'undefined') { 701 | // Old behavior for people using React.PropTypes 702 | var cacheKey = componentName + ':' + propName; 703 | if ( 704 | !manualPropTypeCallCache[cacheKey] && 705 | // Avoid spamming the console because they are often not actionable except for lib authors 706 | manualPropTypeWarningCount < 3 707 | ) { 708 | printWarning$1( 709 | 'You are manually calling a React.PropTypes validation ' + 710 | 'function for the `' + propFullName + '` prop on `' + componentName + '`. This is deprecated ' + 711 | 'and will throw in the standalone `prop-types` package. ' + 712 | 'You may be seeing this warning due to a third-party PropTypes ' + 713 | 'library. See https://fb.me/react-warning-dont-call-proptypes ' + 'for details.' 714 | ); 715 | manualPropTypeCallCache[cacheKey] = true; 716 | manualPropTypeWarningCount++; 717 | } 718 | } 719 | } 720 | if (props[propName] == null) { 721 | if (isRequired) { 722 | if (props[propName] === null) { 723 | return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required ' + ('in `' + componentName + '`, but its value is `null`.')); 724 | } 725 | return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required in ' + ('`' + componentName + '`, but its value is `undefined`.')); 726 | } 727 | return null; 728 | } else { 729 | return validate(props, propName, componentName, location, propFullName); 730 | } 731 | } 732 | 733 | var chainedCheckType = checkType.bind(null, false); 734 | chainedCheckType.isRequired = checkType.bind(null, true); 735 | 736 | return chainedCheckType; 737 | } 738 | 739 | function createPrimitiveTypeChecker(expectedType) { 740 | function validate(props, propName, componentName, location, propFullName, secret) { 741 | var propValue = props[propName]; 742 | var propType = getPropType(propValue); 743 | if (propType !== expectedType) { 744 | // `propValue` being instance of, say, date/regexp, pass the 'object' 745 | // check, but we can offer a more precise error message here rather than 746 | // 'of type `object`'. 747 | var preciseType = getPreciseType(propValue); 748 | 749 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + preciseType + '` supplied to `' + componentName + '`, expected ') + ('`' + expectedType + '`.')); 750 | } 751 | return null; 752 | } 753 | return createChainableTypeChecker(validate); 754 | } 755 | 756 | function createAnyTypeChecker() { 757 | return createChainableTypeChecker(emptyFunctionThatReturnsNull); 758 | } 759 | 760 | function createArrayOfTypeChecker(typeChecker) { 761 | function validate(props, propName, componentName, location, propFullName) { 762 | if (typeof typeChecker !== 'function') { 763 | return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside arrayOf.'); 764 | } 765 | var propValue = props[propName]; 766 | if (!Array.isArray(propValue)) { 767 | var propType = getPropType(propValue); 768 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an array.')); 769 | } 770 | for (var i = 0; i < propValue.length; i++) { 771 | var error = typeChecker(propValue, i, componentName, location, propFullName + '[' + i + ']', ReactPropTypesSecret_1); 772 | if (error instanceof Error) { 773 | return error; 774 | } 775 | } 776 | return null; 777 | } 778 | return createChainableTypeChecker(validate); 779 | } 780 | 781 | function createElementTypeChecker() { 782 | function validate(props, propName, componentName, location, propFullName) { 783 | var propValue = props[propName]; 784 | if (!isValidElement(propValue)) { 785 | var propType = getPropType(propValue); 786 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected a single ReactElement.')); 787 | } 788 | return null; 789 | } 790 | return createChainableTypeChecker(validate); 791 | } 792 | 793 | function createElementTypeTypeChecker() { 794 | function validate(props, propName, componentName, location, propFullName) { 795 | var propValue = props[propName]; 796 | if (!reactIs.isValidElementType(propValue)) { 797 | var propType = getPropType(propValue); 798 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected a single ReactElement type.')); 799 | } 800 | return null; 801 | } 802 | return createChainableTypeChecker(validate); 803 | } 804 | 805 | function createInstanceTypeChecker(expectedClass) { 806 | function validate(props, propName, componentName, location, propFullName) { 807 | if (!(props[propName] instanceof expectedClass)) { 808 | var expectedClassName = expectedClass.name || ANONYMOUS; 809 | var actualClassName = getClassName(props[propName]); 810 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + actualClassName + '` supplied to `' + componentName + '`, expected ') + ('instance of `' + expectedClassName + '`.')); 811 | } 812 | return null; 813 | } 814 | return createChainableTypeChecker(validate); 815 | } 816 | 817 | function createEnumTypeChecker(expectedValues) { 818 | if (!Array.isArray(expectedValues)) { 819 | { 820 | if (arguments.length > 1) { 821 | printWarning$1( 822 | 'Invalid arguments supplied to oneOf, expected an array, got ' + arguments.length + ' arguments. ' + 823 | 'A common mistake is to write oneOf(x, y, z) instead of oneOf([x, y, z]).' 824 | ); 825 | } else { 826 | printWarning$1('Invalid argument supplied to oneOf, expected an array.'); 827 | } 828 | } 829 | return emptyFunctionThatReturnsNull; 830 | } 831 | 832 | function validate(props, propName, componentName, location, propFullName) { 833 | var propValue = props[propName]; 834 | for (var i = 0; i < expectedValues.length; i++) { 835 | if (is(propValue, expectedValues[i])) { 836 | return null; 837 | } 838 | } 839 | 840 | var valuesString = JSON.stringify(expectedValues, function replacer(key, value) { 841 | var type = getPreciseType(value); 842 | if (type === 'symbol') { 843 | return String(value); 844 | } 845 | return value; 846 | }); 847 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of value `' + String(propValue) + '` ' + ('supplied to `' + componentName + '`, expected one of ' + valuesString + '.')); 848 | } 849 | return createChainableTypeChecker(validate); 850 | } 851 | 852 | function createObjectOfTypeChecker(typeChecker) { 853 | function validate(props, propName, componentName, location, propFullName) { 854 | if (typeof typeChecker !== 'function') { 855 | return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside objectOf.'); 856 | } 857 | var propValue = props[propName]; 858 | var propType = getPropType(propValue); 859 | if (propType !== 'object') { 860 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an object.')); 861 | } 862 | for (var key in propValue) { 863 | if (has$1(propValue, key)) { 864 | var error = typeChecker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret_1); 865 | if (error instanceof Error) { 866 | return error; 867 | } 868 | } 869 | } 870 | return null; 871 | } 872 | return createChainableTypeChecker(validate); 873 | } 874 | 875 | function createUnionTypeChecker(arrayOfTypeCheckers) { 876 | if (!Array.isArray(arrayOfTypeCheckers)) { 877 | printWarning$1('Invalid argument supplied to oneOfType, expected an instance of array.') ; 878 | return emptyFunctionThatReturnsNull; 879 | } 880 | 881 | for (var i = 0; i < arrayOfTypeCheckers.length; i++) { 882 | var checker = arrayOfTypeCheckers[i]; 883 | if (typeof checker !== 'function') { 884 | printWarning$1( 885 | 'Invalid argument supplied to oneOfType. Expected an array of check functions, but ' + 886 | 'received ' + getPostfixForTypeWarning(checker) + ' at index ' + i + '.' 887 | ); 888 | return emptyFunctionThatReturnsNull; 889 | } 890 | } 891 | 892 | function validate(props, propName, componentName, location, propFullName) { 893 | for (var i = 0; i < arrayOfTypeCheckers.length; i++) { 894 | var checker = arrayOfTypeCheckers[i]; 895 | if (checker(props, propName, componentName, location, propFullName, ReactPropTypesSecret_1) == null) { 896 | return null; 897 | } 898 | } 899 | 900 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`.')); 901 | } 902 | return createChainableTypeChecker(validate); 903 | } 904 | 905 | function createNodeChecker() { 906 | function validate(props, propName, componentName, location, propFullName) { 907 | if (!isNode(props[propName])) { 908 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`, expected a ReactNode.')); 909 | } 910 | return null; 911 | } 912 | return createChainableTypeChecker(validate); 913 | } 914 | 915 | function createShapeTypeChecker(shapeTypes) { 916 | function validate(props, propName, componentName, location, propFullName) { 917 | var propValue = props[propName]; 918 | var propType = getPropType(propValue); 919 | if (propType !== 'object') { 920 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.')); 921 | } 922 | for (var key in shapeTypes) { 923 | var checker = shapeTypes[key]; 924 | if (!checker) { 925 | continue; 926 | } 927 | var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret_1); 928 | if (error) { 929 | return error; 930 | } 931 | } 932 | return null; 933 | } 934 | return createChainableTypeChecker(validate); 935 | } 936 | 937 | function createStrictShapeTypeChecker(shapeTypes) { 938 | function validate(props, propName, componentName, location, propFullName) { 939 | var propValue = props[propName]; 940 | var propType = getPropType(propValue); 941 | if (propType !== 'object') { 942 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.')); 943 | } 944 | // We need to check all keys in case some are required but missing from 945 | // props. 946 | var allKeys = objectAssign({}, props[propName], shapeTypes); 947 | for (var key in allKeys) { 948 | var checker = shapeTypes[key]; 949 | if (!checker) { 950 | return new PropTypeError( 951 | 'Invalid ' + location + ' `' + propFullName + '` key `' + key + '` supplied to `' + componentName + '`.' + 952 | '\nBad object: ' + JSON.stringify(props[propName], null, ' ') + 953 | '\nValid keys: ' + JSON.stringify(Object.keys(shapeTypes), null, ' ') 954 | ); 955 | } 956 | var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret_1); 957 | if (error) { 958 | return error; 959 | } 960 | } 961 | return null; 962 | } 963 | 964 | return createChainableTypeChecker(validate); 965 | } 966 | 967 | function isNode(propValue) { 968 | switch (typeof propValue) { 969 | case 'number': 970 | case 'string': 971 | case 'undefined': 972 | return true; 973 | case 'boolean': 974 | return !propValue; 975 | case 'object': 976 | if (Array.isArray(propValue)) { 977 | return propValue.every(isNode); 978 | } 979 | if (propValue === null || isValidElement(propValue)) { 980 | return true; 981 | } 982 | 983 | var iteratorFn = getIteratorFn(propValue); 984 | if (iteratorFn) { 985 | var iterator = iteratorFn.call(propValue); 986 | var step; 987 | if (iteratorFn !== propValue.entries) { 988 | while (!(step = iterator.next()).done) { 989 | if (!isNode(step.value)) { 990 | return false; 991 | } 992 | } 993 | } else { 994 | // Iterator will provide entry [k,v] tuples rather than values. 995 | while (!(step = iterator.next()).done) { 996 | var entry = step.value; 997 | if (entry) { 998 | if (!isNode(entry[1])) { 999 | return false; 1000 | } 1001 | } 1002 | } 1003 | } 1004 | } else { 1005 | return false; 1006 | } 1007 | 1008 | return true; 1009 | default: 1010 | return false; 1011 | } 1012 | } 1013 | 1014 | function isSymbol(propType, propValue) { 1015 | // Native Symbol. 1016 | if (propType === 'symbol') { 1017 | return true; 1018 | } 1019 | 1020 | // falsy value can't be a Symbol 1021 | if (!propValue) { 1022 | return false; 1023 | } 1024 | 1025 | // 19.4.3.5 Symbol.prototype[@@toStringTag] === 'Symbol' 1026 | if (propValue['@@toStringTag'] === 'Symbol') { 1027 | return true; 1028 | } 1029 | 1030 | // Fallback for non-spec compliant Symbols which are polyfilled. 1031 | if (typeof Symbol === 'function' && propValue instanceof Symbol) { 1032 | return true; 1033 | } 1034 | 1035 | return false; 1036 | } 1037 | 1038 | // Equivalent of `typeof` but with special handling for array and regexp. 1039 | function getPropType(propValue) { 1040 | var propType = typeof propValue; 1041 | if (Array.isArray(propValue)) { 1042 | return 'array'; 1043 | } 1044 | if (propValue instanceof RegExp) { 1045 | // Old webkits (at least until Android 4.0) return 'function' rather than 1046 | // 'object' for typeof a RegExp. We'll normalize this here so that /bla/ 1047 | // passes PropTypes.object. 1048 | return 'object'; 1049 | } 1050 | if (isSymbol(propType, propValue)) { 1051 | return 'symbol'; 1052 | } 1053 | return propType; 1054 | } 1055 | 1056 | // This handles more types than `getPropType`. Only used for error messages. 1057 | // See `createPrimitiveTypeChecker`. 1058 | function getPreciseType(propValue) { 1059 | if (typeof propValue === 'undefined' || propValue === null) { 1060 | return '' + propValue; 1061 | } 1062 | var propType = getPropType(propValue); 1063 | if (propType === 'object') { 1064 | if (propValue instanceof Date) { 1065 | return 'date'; 1066 | } else if (propValue instanceof RegExp) { 1067 | return 'regexp'; 1068 | } 1069 | } 1070 | return propType; 1071 | } 1072 | 1073 | // Returns a string that is postfixed to a warning about an invalid type. 1074 | // For example, "undefined" or "of type array" 1075 | function getPostfixForTypeWarning(value) { 1076 | var type = getPreciseType(value); 1077 | switch (type) { 1078 | case 'array': 1079 | case 'object': 1080 | return 'an ' + type; 1081 | case 'boolean': 1082 | case 'date': 1083 | case 'regexp': 1084 | return 'a ' + type; 1085 | default: 1086 | return type; 1087 | } 1088 | } 1089 | 1090 | // Returns class name of the object, if any. 1091 | function getClassName(propValue) { 1092 | if (!propValue.constructor || !propValue.constructor.name) { 1093 | return ANONYMOUS; 1094 | } 1095 | return propValue.constructor.name; 1096 | } 1097 | 1098 | ReactPropTypes.checkPropTypes = checkPropTypes_1; 1099 | ReactPropTypes.resetWarningCache = checkPropTypes_1.resetWarningCache; 1100 | ReactPropTypes.PropTypes = ReactPropTypes; 1101 | 1102 | return ReactPropTypes; 1103 | }; 1104 | 1105 | var propTypes = createCommonjsModule(function (module) { 1106 | /** 1107 | * Copyright (c) 2013-present, Facebook, Inc. 1108 | * 1109 | * This source code is licensed under the MIT license found in the 1110 | * LICENSE file in the root directory of this source tree. 1111 | */ 1112 | 1113 | { 1114 | var ReactIs = reactIs; 1115 | 1116 | // By explicitly using `prop-types` you are opting into new development behavior. 1117 | // http://fb.me/prop-types-in-prod 1118 | var throwOnDirectAccess = true; 1119 | module.exports = factoryWithTypeCheckers(ReactIs.isElement, throwOnDirectAccess); 1120 | } 1121 | }); 1122 | 1123 | /** 1124 | * The stateObjects provides persistent storage of state for as many initialState objects as 1125 | * needed throughout the application. 1126 | * 1127 | * Every instantiation of StateProvider will add a new initialState object to stateObjects with 1128 | * the key of the reducer name and the value of the state. 1129 | */ 1130 | 1131 | var stateObjects = {}; 1132 | /** 1133 | * Create a Context.Provider wrapper for children components wherever it is applied to the 1134 | * component tree. This component can be called multiple times throughout the application. 1135 | * 1136 | * @param {Function} reducer A reducer function that contains a switch statement and, ultimately, 1137 | * returns a state object. The reducer can never be undefined or anything other than a type of 1138 | * function. Reducers should return modified state if the action.type passed into them is defined 1139 | * or return the initialState if the action.type passed into them is undefined. 1140 | * 1141 | * @param {Object} stateContext A Context object created out of the createContext function 1142 | * from React. 1143 | * 1144 | * @param {JSX} children The descending component tree JSX is passed in and placed inside 1145 | * the Context.Provider. 1146 | * 1147 | * @returns {JSX} Returns a JSX component for a Context.Provider setup and passes in the memoized 1148 | * value as well as the children of the Context component. 1149 | */ 1150 | 1151 | var StateProvider = function StateProvider(_ref) { 1152 | var reducer = _ref.reducer, 1153 | stateContext = _ref.stateContext, 1154 | children = _ref.children; 1155 | 1156 | // Error messages for the reducer object 1157 | if (typeof reducer !== 'function') { 1158 | throw new Error('The reducer must be a function. You might have forgotten to pass your reducer into your StateProvider.'); 1159 | } // Error messages for the stateContext object 1160 | 1161 | 1162 | if (!stateContext) { 1163 | throw new Error('stateContext prop is undefined. Please check your createContext method and what you are passing into your StateProvider.'); 1164 | } 1165 | 1166 | if (children === undefined || _typeof(children) !== 'object' || !Object.keys(children).length) { 1167 | throw new Error('StateProvider must contain children components. You probably forgot to wrap it around your components in your JSX.'); 1168 | } 1169 | /** 1170 | * This initial reducer call sets returns the initial state object from the reducer that will 1171 | * then be passed into useReducer. 1172 | * 1173 | * 1174 | */ 1175 | 1176 | 1177 | if (stateObjects[reducer.name] === undefined) { 1178 | var getRandomString = Math.random().toString(36).substring(7); 1179 | /** 1180 | * The reducer function is invoked and passed no first parameter and an object for the second 1181 | * parameter. 1182 | * 1183 | * Parameter one is undefined as the reducer function should have a default parameter of 1184 | * initialState inside the application. 1185 | * 1186 | * Parameter two is an object with a key-value pair for an initialState retrieval using the 1187 | * getRandomString variable above appended to "@conflux" in a template literal string as 1188 | * shown below. 1189 | */ 1190 | 1191 | stateObjects[reducer.name] = reducer(undefined, { 1192 | type: "@conflux-".concat(getRandomString) 1193 | }); 1194 | } 1195 | /** 1196 | * Uses the useReducer hook to pass in a reducer and initialState. It returns 1197 | * an array that can be destructured into state and a dispatch function. 1198 | */ 1199 | 1200 | 1201 | var _useReducer = useReducer(reducer, stateObjects[reducer.name]), 1202 | _useReducer2 = _slicedToArray(_useReducer, 2), 1203 | state = _useReducer2[0], 1204 | dispatch = _useReducer2[1]; 1205 | /** 1206 | * The useMemo hook returns state and dispatch while guarding against unnecessary rerendering of the component 1207 | * tree contained within this stateContext.Provider. 1208 | * 1209 | * It will only update when the state object in value changes, rather than any other state/props outside of 1210 | * these values. 1211 | */ 1212 | 1213 | 1214 | var value = useMemo(function () { 1215 | return [state, dispatch]; 1216 | }, [state]); 1217 | var Provider = stateContext.Provider; 1218 | /** 1219 | * The newly instantiated copy of Provider is returned as a component from this function 1220 | * to be wrapped around JSX in the application. The value returned from the useMemo hook (an array containing 1221 | * state and dispatch) is passed into the Provider per the requirements for the Context API 1222 | * in the documentation at: https://reactjs.org/docs/context.html 1223 | * 1224 | * This array will be available for destructuring inside components contained in the state tree with 1225 | * react-conflux's custom hook "useStateValue". 1226 | */ 1227 | 1228 | return React.createElement(Provider, { 1229 | value: value 1230 | }, children); 1231 | }; 1232 | 1233 | StateProvider.propTypes = { 1234 | reducer: propTypes.func.isRequired, 1235 | stateContext: propTypes.object.isRequired, 1236 | // eslint-disable-line react/forbid-prop-types 1237 | children: propTypes.oneOfType([propTypes.element, propTypes.array]).isRequired 1238 | }; 1239 | 1240 | /** 1241 | * The useStateValue custom hook from Conflux provides a modular, predictable, and easy 1242 | * way to desctructure state and dispatch from the Context API's Consumer whenever needed. 1243 | * 1244 | * @param {Object} stateContext An object previously created using React's Context 1245 | * API that contains a Provider and Consumer. 1246 | * 1247 | * @returns {context} Returns a validated context array containing a state object and a 1248 | * dispatch function for use inside of a component. 1249 | */ 1250 | 1251 | var useStateValue = function useStateValue(stateContext) { 1252 | /** 1253 | * stateContext error messages for undefined and incorrect data types passed into 1254 | * useStateValue hook 1255 | */ 1256 | if (stateContext === undefined) { 1257 | throw new Error('The stateContext object is undefined in your useStateValue hook. You probably forgot to pass the stateContext object into your useStateValue hook.'); 1258 | } 1259 | 1260 | if (!stateContext.Provider && !stateContext.Consumer) { 1261 | throw new Error('Incorrect argument passed to the useStateValue hook. You probably passed a variable other than your context object into it.'); 1262 | } 1263 | /** 1264 | * The useContext React hook references the Context.Provider closest to it up the component 1265 | * tree. In Conflux, this will always return as an array which is [state, dispatch]. These 1266 | * are returned by the useStateValue hook for use inside the application. 1267 | */ 1268 | 1269 | 1270 | var context = useContext(stateContext); 1271 | /** 1272 | * context error message for if context returns undefined. This happens when the stateContext 1273 | * passed into the useStateValue hook is used in a component which is not a child of that 1274 | * context's Provider. 1275 | */ 1276 | 1277 | if (context === undefined) { 1278 | throw new Error('The useStateValue hook must be used within the Provider of the Context object you have passed to it. Check to make sure you have passed in the correct context object and that the useStateValue hook is within a child of the correct Provider.'); 1279 | } 1280 | /** 1281 | * Return the context of the Context.Provider closest to the useStateValue hook at the time 1282 | * it was called. 1283 | */ 1284 | 1285 | 1286 | return context; 1287 | }; 1288 | 1289 | export { StateProvider, useStateValue }; 1290 | -------------------------------------------------------------------------------- /dist/umd.min.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],t):t(((e=e||self).umd=e.umd||{},e.umd.min={}),e.React)}(this,function(e,f){"use strict";var y="default"in f?f.default:f;function l(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){if(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e)){var r=[],o=!0,n=!1,i=void 0;try{for(var a,u=e[Symbol.iterator]();!(o=(a=u.next()).done)&&(r.push(a.value),!t||r.length!==t);o=!0);}catch(e){n=!0,i=e}finally{try{o||null==u.return||u.return()}finally{if(n)throw i}}return r}}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function p(e){return(p="function"==typeof Symbol&&"symbol"===t(Symbol.iterator)?function(e){return t(e)}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":t(e)})(e)}function r(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}function o(e,t){return e(t={exports:{}},t.exports),t.exports}var n=o(function(e,t){Object.defineProperty(t,"__esModule",{value:!0});var r="function"==typeof Symbol&&Symbol.for,o=r?Symbol.for("react.element"):60103,n=r?Symbol.for("react.portal"):60106,i=r?Symbol.for("react.fragment"):60107,a=r?Symbol.for("react.strict_mode"):60108,u=r?Symbol.for("react.profiler"):60114,c=r?Symbol.for("react.provider"):60109,s=r?Symbol.for("react.context"):60110,f=r?Symbol.for("react.async_mode"):60111,y=r?Symbol.for("react.concurrent_mode"):60111,l=r?Symbol.for("react.forward_ref"):60112,p=r?Symbol.for("react.suspense"):60113,d=r?Symbol.for("react.suspense_list"):60120,m=r?Symbol.for("react.memo"):60115,b=r?Symbol.for("react.lazy"):60116,h=r?Symbol.for("react.fundamental"):60117,S=r?Symbol.for("react.responder"):60118,v=r?Symbol.for("react.scope"):60119;function P(e){if("object"==typeof e&&null!==e){var t=e.$$typeof;switch(t){case o:switch(e=e.type){case f:case y:case i:case u:case a:case p:return e;default:switch(e=e&&e.$$typeof){case s:case l:case c:return e;default:return t}}case b:case m:case n:return t}}}function C(e){return P(e)===y}t.typeOf=P,t.AsyncMode=f,t.ConcurrentMode=y,t.ContextConsumer=s,t.ContextProvider=c,t.Element=o,t.ForwardRef=l,t.Fragment=i,t.Lazy=b,t.Memo=m,t.Portal=n,t.Profiler=u,t.StrictMode=a,t.Suspense=p,t.isValidElementType=function(e){return"string"==typeof e||"function"==typeof e||e===i||e===y||e===u||e===a||e===p||e===d||"object"==typeof e&&null!==e&&(e.$$typeof===b||e.$$typeof===m||e.$$typeof===c||e.$$typeof===s||e.$$typeof===l||e.$$typeof===h||e.$$typeof===S||e.$$typeof===v)},t.isAsyncMode=function(e){return C(e)||P(e)===f},t.isConcurrentMode=C,t.isContextConsumer=function(e){return P(e)===s},t.isContextProvider=function(e){return P(e)===c},t.isElement=function(e){return"object"==typeof e&&null!==e&&e.$$typeof===o},t.isForwardRef=function(e){return P(e)===l},t.isFragment=function(e){return P(e)===i},t.isLazy=function(e){return P(e)===b},t.isMemo=function(e){return P(e)===m},t.isPortal=function(e){return P(e)===n},t.isProfiler=function(e){return P(e)===u},t.isStrictMode=function(e){return P(e)===a},t.isSuspense=function(e){return P(e)===p}});r(n);n.typeOf,n.AsyncMode,n.ConcurrentMode,n.ContextConsumer,n.ContextProvider,n.Element,n.ForwardRef,n.Fragment,n.Lazy,n.Memo,n.Portal,n.Profiler,n.StrictMode,n.Suspense,n.isValidElementType,n.isAsyncMode,n.isConcurrentMode,n.isContextConsumer,n.isContextProvider,n.isElement,n.isForwardRef,n.isFragment,n.isLazy,n.isMemo,n.isPortal,n.isProfiler,n.isStrictMode,n.isSuspense;var i=o(function(e,t){});r(i);i.typeOf,i.AsyncMode,i.ConcurrentMode,i.ContextConsumer,i.ContextProvider,i.Element,i.ForwardRef,i.Fragment,i.Lazy,i.Memo,i.Portal,i.Profiler,i.StrictMode,i.Suspense,i.isValidElementType,i.isAsyncMode,i.isConcurrentMode,i.isContextConsumer,i.isContextProvider,i.isElement,i.isForwardRef,i.isFragment,i.isLazy,i.isMemo,i.isPortal,i.isProfiler,i.isStrictMode,i.isSuspense,o(function(e){e.exports=n});var a=Object.getOwnPropertySymbols,u=Object.prototype.hasOwnProperty,c=Object.prototype.propertyIsEnumerable;!function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},r=0;r<10;r++)t["_"+String.fromCharCode(r)]=r;if("0123456789"!==Object.getOwnPropertyNames(t).map(function(e){return t[e]}).join(""))return!1;var o={};return"abcdefghijklmnopqrst".split("").forEach(function(e){o[e]=e}),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},o)).join("")}catch(e){return!1}}()||Object.assign,Function.call.bind(Object.prototype.hasOwnProperty);function s(){}function d(){}d.resetWarningCache=s;function m(e){var t=e.reducer,r=e.stateContext,o=e.children;if("function"!=typeof t)throw new Error("The reducer must be a function. You might have forgotten to pass your reducer into your StateProvider.");if(!r)throw new Error("stateContext prop is undefined. Please check your createContext method and what you are passing into your StateProvider.");if(void 0===o||"object"!==p(o)||!Object.keys(o).length)throw new Error("StateProvider must contain children components. You probably forgot to wrap it around your components in your JSX.");if(void 0===h[t.name]){var n=Math.random().toString(36).substring(7);h[t.name]=t(void 0,{type:"@conflux-".concat(n)})}var i=l(f.useReducer(t,h[t.name]),2),a=i[0],u=i[1],c=f.useMemo(function(){return[a,u]},[a]),s=r.Provider;return y.createElement(s,{value:c},o)}var b=o(function(e){e.exports=function(){function e(e,t,r,o,n,i){if("SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"!==i){var a=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw a.name="Invariant Violation",a}}function t(){return e}var r={array:e.isRequired=e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:d,resetWarningCache:s};return r.PropTypes=r}()}),h={};m.propTypes={reducer:b.func.isRequired,stateContext:b.object.isRequired,children:b.oneOfType([b.element,b.array]).isRequired};e.StateProvider=m,e.useStateValue=function(e){if(void 0===e)throw new Error("The stateContext object is undefined in your useStateValue hook. You probably forgot to pass the stateContext object into your useStateValue hook.");if(!e.Provider&&!e.Consumer)throw new Error("Incorrect argument passed to the useStateValue hook. You probably passed a variable other than your context object into it.");var t=f.useContext(e);if(void 0===t)throw new Error("The useStateValue hook must be used within the Provider of the Context object you have passed to it. Check to make sure you have passed in the correct context object and that the useStateValue hook is within a child of the correct Provider.");return t},Object.defineProperty(e,"__esModule",{value:!0})}); 2 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | Please enjoy this collection of examples that demonstrates the abilities of the Conflux library. 4 | -------------------------------------------------------------------------------- /examples/counter/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 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 | -------------------------------------------------------------------------------- /examples/counter/README.md: -------------------------------------------------------------------------------- 1 | # Conflux Counter Example 2 | 3 | This project template was built with [Create React App](https://github.com/facebookincubator/create-react-app), which provides a simple way to start React projects with no build configuration needed. 4 | 5 | Projects built with Create-React-App include support for ES6 syntax, as well as several unofficial / not-yet-final forms of Javascript syntax such as Class Properties and JSX. See the list of [language features and polyfills supported by Create-React-App](https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md#supported-language-features-and-polyfills) for more information. 6 | 7 | ## Available Scripts 8 | 9 | In the project directory, you can run: 10 | 11 | ### `npm start` 12 | 13 | Runs the app in the development mode.
14 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 15 | 16 | The page will reload if you make edits.
17 | You will also see any lint errors in the console. 18 | 19 | ### `npm test` 20 | 21 | Launches the test runner in the interactive watch mode.
22 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 23 | 24 | ### `npm run build` 25 | 26 | Builds the app for production to the `build` folder.
27 | It correctly bundles React in production mode and optimizes the build for the best performance. 28 | 29 | The build is minified and the filenames include the hashes.
30 | Your app is ready to be deployed! 31 | 32 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 33 | 34 | ### `npm run eject` 35 | 36 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 37 | 38 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 39 | 40 | Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 41 | 42 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 43 | -------------------------------------------------------------------------------- /examples/counter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "counter", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "react": "^16.8.6", 7 | "react-conflux": "^0.0.2-beta.6", 8 | "react-dom": "^16.8.6", 9 | "react-scripts": "3.0.1" 10 | }, 11 | "scripts": { 12 | "start": "react-scripts start", 13 | "build": "react-scripts build", 14 | "test": "react-scripts test", 15 | "eject": "react-scripts eject" 16 | }, 17 | "eslintConfig": { 18 | "extends": "react-app" 19 | }, 20 | "browserslist": { 21 | "production": [ 22 | ">0.2%", 23 | "not dead", 24 | "not op_mini all" 25 | ], 26 | "development": [ 27 | "last 1 chrome version", 28 | "last 1 firefox version", 29 | "last 1 safari version" 30 | ] 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/counter/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinmyers/react-conflux/16b27d423613ef53acf596a7420ee8459d9396e2/examples/counter/public/favicon.ico -------------------------------------------------------------------------------- /examples/counter/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 22 | React App 23 | 24 | 25 | 26 |
27 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /examples/counter/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /examples/counter/src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StateProvider } from 'react-conflux'; 3 | import { counterReducer } from './store/reducers/counterReducer'; 4 | import { titleReducer } from './store/reducers/titleReducer'; 5 | import { counterContext, titleContext } from './store/contexts'; 6 | 7 | import Counter from './components/Counter'; 8 | 9 | const App = () => { 10 | return ( 11 | 12 | 13 | 14 | 15 | 16 | ); 17 | }; 18 | 19 | export default App; 20 | -------------------------------------------------------------------------------- /examples/counter/src/components/Counter.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useStateValue } from 'react-conflux'; 3 | import { counterContext, titleContext } from '../store/contexts'; 4 | import { INCREMENT, DECREMENT } from '../store/constants'; 5 | 6 | const Counter = () => { 7 | const [counterState, counterDispatch] = useStateValue(counterContext); 8 | const [titleState] = useStateValue(titleContext); 9 | const increment = e => { 10 | e.preventDefault(); 11 | counterDispatch({ type: INCREMENT, payload: counterState.count + 1 }); 12 | }; 13 | const decrement = e => { 14 | e.preventDefault(); 15 | counterDispatch({ type: DECREMENT, payload: counterState.count - 1 }); 16 | }; 17 | return ( 18 |
19 |

{titleState.title}

20 |

This is the count from the counterReducer: {counterState.count}

21 | 24 | 27 |
28 | ); 29 | }; 30 | 31 | export default Counter; 32 | -------------------------------------------------------------------------------- /examples/counter/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | ReactDOM.render(, document.getElementById('root')); -------------------------------------------------------------------------------- /examples/counter/src/store/constants.js: -------------------------------------------------------------------------------- 1 | export const INCREMENT = 'INCREMENT'; 2 | export const DECREMENT = 'DECREMENT'; 3 | -------------------------------------------------------------------------------- /examples/counter/src/store/contexts.js: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | export const counterContext = createContext(); 4 | export const titleContext = createContext(); 5 | -------------------------------------------------------------------------------- /examples/counter/src/store/reducers/counterReducer.js: -------------------------------------------------------------------------------- 1 | import { INCREMENT, DECREMENT } from '../constants'; 2 | 3 | const initialState = { 4 | count: 0 5 | }; 6 | 7 | export const counterReducer = (state = initialState, action) => { 8 | switch (action.type) { 9 | case INCREMENT: 10 | return { 11 | ...state, 12 | count: action.payload 13 | }; 14 | case DECREMENT: 15 | return { 16 | ...state, 17 | count: action.payload 18 | }; 19 | default: 20 | return state; 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /examples/counter/src/store/reducers/titleReducer.js: -------------------------------------------------------------------------------- 1 | const initialState = { 2 | title: 'This is the title from the titleReducer' 3 | }; 4 | 5 | export const titleReducer = (state = initialState, action) => { 6 | switch (action.type) { 7 | default: 8 | return state; 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // import { StateProvider, useStateValue } from "./src"; 2 | 3 | if (process.env.NODE_ENV === 'production') { 4 | module.exports = require('./dist/cjs.min.js'); // eslint-disable-line 5 | } else { 6 | module.exports = require('./dist/cjs.js'); // eslint-disable-line 7 | } 8 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | // For a detailed explanation regarding each configuration property, visit: 2 | // https://jestjs.io/docs/en/configuration.html 3 | 4 | module.exports = { 5 | // All imported modules in your tests should be mocked automatically 6 | // automock: false, 7 | 8 | // Stop running tests after `n` failures 9 | // bail: 0, 10 | 11 | // Respect "browser" field in package.json when resolving modules 12 | // browser: false, 13 | 14 | // The directory where Jest should store its cached dependency information 15 | // cacheDirectory: "/private/var/folders/f4/9wxm_rqx12ng9bh67dc_vhwc0000gn/T/jest_dx", 16 | 17 | // Automatically clear mock calls and instances between every test 18 | clearMocks: true, 19 | 20 | // Indicates whether the coverage information should be collected while executing the test 21 | // collectCoverage: false, 22 | 23 | // An array of glob patterns indicating a set of files for which coverage information should be collected 24 | // collectCoverageFrom: null, 25 | 26 | // The directory where Jest should output its coverage files 27 | // coverageDirectory: null, 28 | 29 | // An array of regexp pattern strings used to skip coverage collection 30 | // coveragePathIgnorePatterns: [ 31 | // "/node_modules/" 32 | // ], 33 | 34 | // A list of reporter names that Jest uses when writing coverage reports 35 | // coverageReporters: [ 36 | // "json", 37 | // "text", 38 | // "lcov", 39 | // "clover" 40 | // ], 41 | 42 | // An object that configures minimum threshold enforcement for coverage results 43 | // coverageThreshold: null, 44 | 45 | // A path to a custom dependency extractor 46 | // dependencyExtractor: null, 47 | 48 | // Allows for a lable to be printed alongside a test while it is running 49 | displayName: 'React-Conflux', 50 | 51 | // Make calling deprecated APIs throw helpful error messages 52 | // errorOnDeprecated: false, 53 | 54 | // Force coverage collection from ignored files using an array of glob patterns 55 | // forceCoverageMatch: [], 56 | 57 | // A path to a module which exports an async function that is triggered once before all test suites 58 | // globalSetup: null, 59 | 60 | // A path to a module which exports an async function that is triggered once after all test suites 61 | // globalTeardown: null, 62 | 63 | // A set of global variables that need to be available in all test environments 64 | // globals: {}, 65 | 66 | // An array of directory names to be searched recursively up from the requiring module's location 67 | // moduleDirectories: [ 68 | // "node_modules" 69 | // ], 70 | 71 | // An array of file extensions your modules use 72 | // moduleFileExtensions: [ 73 | // "js", 74 | // "json", 75 | // "jsx", 76 | // "ts", 77 | // "tsx", 78 | // "node" 79 | // ], 80 | 81 | // A map from regular expressions to module names that allow to stub out resources with a single module 82 | // moduleNameMapper: {}, 83 | 84 | // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader 85 | // modulePathIgnorePatterns: [], 86 | 87 | // Activates notifications for test results 88 | // notify: false, 89 | 90 | // An enum that specifies notification mode. Requires { notify: true } 91 | // notifyMode: "failure-change", 92 | 93 | // A preset that is used as a base for Jest's configuration 94 | // preset: null, 95 | 96 | // Run tests from one or more projects 97 | // projects: null, 98 | 99 | // Use this configuration option to add custom reporters to Jest 100 | // reporters: undefined, 101 | 102 | // Automatically reset mock state between every test 103 | // resetMocks: false, 104 | 105 | // Reset the module registry before running each individual test 106 | // resetModules: false, 107 | 108 | // A path to a custom resolver 109 | // resolver: null, 110 | 111 | // Automatically restore mock state between every test 112 | // restoreMocks: false, 113 | 114 | // The root directory that Jest should scan for tests and modules within 115 | // rootDir: null, 116 | 117 | // A list of paths to directories that Jest should use to search for files in 118 | // roots: [ 119 | // "" 120 | // ], 121 | 122 | // Allows you to use a custom runner instead of Jest's default test runner 123 | // runner: "jest-runner", 124 | 125 | // The paths to modules that run some code to configure or set up the testing environment before each test 126 | // setupFiles: [], 127 | 128 | // A list of paths to modules that run some code to configure or set up the testing framework before each test 129 | // setupFilesAfterEnv: [], 130 | 131 | // A list of paths to snapshot serializer modules Jest should use for snapshot testing 132 | // snapshotSerializers: [], 133 | 134 | // The test environment that will be used for testing 135 | testEnvironment: 'node', 136 | 137 | // Options that will be passed to the testEnvironment 138 | // testEnvironmentOptions: {}, 139 | 140 | // Adds a location field to test results 141 | // testLocationInResults: false, 142 | 143 | // The glob patterns Jest uses to detect test files 144 | // testMatch: [ 145 | // "**/__tests__/**/*.[jt]s?(x)", 146 | // "**/?(*.)+(spec|test).[tj]s?(x)" 147 | // ], 148 | 149 | // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped 150 | testPathIgnorePatterns: [ 151 | "/node_modules/", 152 | "/website/" 153 | ], 154 | 155 | // The regexp pattern or array of patterns that Jest uses to detect test files 156 | // testRegex: [], 157 | 158 | // This option allows the use of a custom results processor 159 | // testResultsProcessor: null, 160 | 161 | // This option allows use of a custom test runner 162 | // testRunner: "jasmine2", 163 | 164 | // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href 165 | // testURL: "http://localhost", 166 | 167 | // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" 168 | // timers: "real", 169 | 170 | // A map from regular expressions to paths to transformers 171 | // transform: null, 172 | 173 | // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation 174 | // transformIgnorePatterns: [ 175 | // "/node_modules/" 176 | // ], 177 | 178 | // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them 179 | // unmockedModulePathPatterns: undefined, 180 | 181 | // Indicates whether each individual test should be reported during the run 182 | verbose: true 183 | 184 | // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode 185 | // watchPathIgnorePatterns: [], 186 | 187 | // Whether to use watchman for file crawling 188 | // watchman: true, 189 | }; 190 | -------------------------------------------------------------------------------- /logo/README.md: -------------------------------------------------------------------------------- 1 | # The Conflux Logo 2 | 3 | The following logos are the only valid Conflux logos. Don't use any other logos to represent Conflux. 4 | 5 | ## Conflux Atomic Pattern 6 | 7 | Conflux logo 8 | 9 | Download this logo as a [PNG](https://raw.githubusercontent.com/dustinmyers/react-conflux/master/logo/conflux-logo-atom.png) 10 | 11 | ## Conflux Logo Dark Pattern 12 | 13 | Conflux dark logo 14 | 15 | Download this logo as a [PNG](https://raw.githubusercontent.com/dustinmyers/react-conflux/master/logo/conflux-logo-dark.png) 16 | 17 | ## Conflux Logo Light Pattern 18 | 19 | Conflux light logo 20 | 21 | _(You can't see the text because it's white, but it's there.)_ 22 | 23 | Download this logo as a [PNG](https://raw.githubusercontent.com/dustinmyers/react-conflux/master/logo/conflux-logo-light.png) 24 | 25 | ## Logo Modifications 26 | 27 | We ask that you would only use the original logos provided to you on this page. If you really want to change the logo up, please use the [Ubuntu Bold](https://fonts.google.com/specimen/Ubuntu) font coupled with the Conflux logo. 28 | 29 | ## License 30 | 31 | The Conflux logo is licensed under CCO, waiving all copyright, available [here](../LICENSE). 32 | -------------------------------------------------------------------------------- /logo/conflux-logo-atom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinmyers/react-conflux/16b27d423613ef53acf596a7420ee8459d9396e2/logo/conflux-logo-atom.png -------------------------------------------------------------------------------- /logo/conflux-logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinmyers/react-conflux/16b27d423613ef53acf596a7420ee8459d9396e2/logo/conflux-logo-dark.png -------------------------------------------------------------------------------- /logo/conflux-logo-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinmyers/react-conflux/16b27d423613ef53acf596a7420ee8459d9396e2/logo/conflux-logo-light.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-conflux", 3 | "version": "0.0.2-beta.6", 4 | "description": "React Context + Hooks implementation of the Flux pattern", 5 | "keywords": [ 6 | "conflux", 7 | "react-conflux", 8 | "react", 9 | "redux", 10 | "flux", 11 | "context", 12 | "context api", 13 | "hooks", 14 | "react hooks", 15 | "immutable", 16 | "elm", 17 | "functional", 18 | "hot", 19 | "reducer" 20 | ], 21 | "main": "./index.js", 22 | "peerDependencies": { 23 | "react": "^16.8.6" 24 | }, 25 | "dependencies": { 26 | "prop-types": "^15.7.2" 27 | }, 28 | "devDependencies": { 29 | "@babel/core": "^7.4.5", 30 | "@babel/plugin-transform-runtime": "^7.4.4", 31 | "@babel/preset-env": "^7.4.5", 32 | "@babel/preset-react": "^7.0.0", 33 | "@babel/runtime": "^7.4.5", 34 | "babel-eslint": "^10.0.1", 35 | "babel-loader": "^7.1.5", 36 | "eslint": "^5.16.0", 37 | "eslint-config-airbnb": "^17.1.0", 38 | "eslint-config-prettier": "^4.3.0", 39 | "eslint-plugin-import": "^2.17.2", 40 | "eslint-plugin-jsx-a11y": "^6.2.1", 41 | "eslint-plugin-prettier": "^3.1.0", 42 | "eslint-plugin-react": "^7.13.0", 43 | "jest": "^24.8.0", 44 | "prettier": "^1.17.1", 45 | "react": "^16.8.6", 46 | "react-test-renderer": "^16.8.6", 47 | "rollup": "^1.12.3", 48 | "rollup-plugin-babel": "^4.3.2", 49 | "rollup-plugin-commonjs": "^10.0.0", 50 | "rollup-plugin-node-resolve": "^5.0.0", 51 | "rollup-plugin-replace": "^2.2.0", 52 | "rollup-plugin-uglify": "^6.0.2" 53 | }, 54 | "scripts": { 55 | "build": "rollup -c", 56 | "test": "jest --watch --verbose", 57 | "lint": "npx eslint --fix ./src/*" 58 | }, 59 | "repository": { 60 | "type": "git", 61 | "url": "git+https://github.com/dustinmyers/react-conflux.git" 62 | }, 63 | "author": "Dustin Myers, Nathan Thomas", 64 | "license": "MIT", 65 | "bugs": { 66 | "url": "https://github.com/dustinmyers/react-conflux/issues" 67 | }, 68 | "homepage": "https://github.com/dustinmyers/react-conflux#readme" 69 | } 70 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import { uglify } from 'rollup-plugin-uglify'; 2 | import babel from 'rollup-plugin-babel'; 3 | import resolve from 'rollup-plugin-node-resolve'; 4 | import commonjs from 'rollup-plugin-commonjs'; 5 | import replace from 'rollup-plugin-replace'; 6 | 7 | const input = 'src/index.js'; 8 | const external = ['react']; 9 | const globals = { 10 | react: 'React', 11 | 'react-dom': 'ReactDOM' 12 | }; 13 | 14 | // CommonJS Modules 15 | const cjs = [ 16 | { 17 | input, 18 | external, 19 | output: { 20 | file: 'dist/cjs.js', 21 | format: 'cjs', 22 | globals 23 | }, 24 | plugins: [ 25 | babel({ 26 | exclude: /node_modules/ 27 | }), 28 | replace({ 'process.env.NODE_ENV': JSON.stringify('development') }), 29 | resolve({ 30 | extensions: ['.js', '.jsx'] 31 | }), 32 | commonjs() 33 | ] 34 | }, 35 | { 36 | input, 37 | external, 38 | output: { 39 | file: 'dist/cjs.min.js', 40 | format: 'cjs', 41 | globals 42 | }, 43 | plugins: [ 44 | babel({ 45 | exclude: /node_modules/ 46 | }), 47 | replace({ 'process.env.NODE_ENV': JSON.stringify('production') }), 48 | resolve({ 49 | extensions: ['.js', '.jsx'] 50 | }), 51 | commonjs(), 52 | uglify() 53 | ] 54 | } 55 | ]; 56 | 57 | // ECMAScript Modules 58 | const esm = [ 59 | { 60 | input, 61 | external, 62 | output: { 63 | file: 'dist/esm.js', 64 | format: 'esm', 65 | globals 66 | }, 67 | plugins: [ 68 | babel({ 69 | exclude: /node_modules/, 70 | runtimeHelpers: true, 71 | plugins: [['@babel/transform-runtime', { useESModules: true }]] 72 | }), 73 | replace({ 'process.env.NODE_ENV': JSON.stringify('development') }), 74 | resolve({ 75 | extensions: ['.js', '.jsx'] 76 | }), 77 | commonjs() 78 | ] 79 | }, 80 | { 81 | input, 82 | external, 83 | output: { 84 | file: 'dist/esm.min.js', 85 | format: 'esm', 86 | globals 87 | }, 88 | plugins: [ 89 | babel({ 90 | exclude: /node_modules/, 91 | runtimeHelpers: true, 92 | plugins: [['@babel/transform-runtime', { useESModules: true }]] 93 | }), 94 | replace({ 'process.env.NODE_ENV': JSON.stringify('development') }), 95 | resolve({ 96 | extensions: ['.js', '.jsx'] 97 | }), 98 | commonjs() 99 | ] 100 | } 101 | ]; 102 | 103 | // Universal Module Definition 104 | const umd = [ 105 | { 106 | input, 107 | external, 108 | output: { 109 | file: 'dist/umd.js', 110 | format: 'umd', 111 | name: 'umd', 112 | globals 113 | }, 114 | plugins: [ 115 | babel({ 116 | exclude: /node_modules/, 117 | runtimeHelpers: true, 118 | plugins: [['@babel/transform-runtime', { useESModules: true }]] 119 | }), 120 | replace({ 'process.env.NODE_ENV': JSON.stringify('development') }), 121 | resolve({ 122 | extensions: ['.js', '.jsx'] 123 | }), 124 | commonjs({ include: /node_modules/ }) 125 | ] 126 | }, 127 | { 128 | input, 129 | external, 130 | output: { 131 | file: 'dist/umd.min.js', 132 | format: 'umd', 133 | name: 'umd.min', 134 | globals 135 | }, 136 | plugins: [ 137 | babel({ 138 | exclude: /node_modules/, 139 | runtimeHelpers: true, 140 | plugins: [['@babel/transform-runtime', { useESModules: true }]] 141 | }), 142 | resolve({ 143 | extensions: ['.js', '.jsx'] 144 | }), 145 | commonjs({ include: /node_modules/ }), 146 | replace({ 'process.env.NODE_ENV': JSON.stringify('production') }), 147 | uglify() 148 | ] 149 | } 150 | ]; 151 | 152 | let config; 153 | switch (process.env.BUILD_ENV) { 154 | case 'cjs': 155 | config = cjs; 156 | break; 157 | case 'esm': 158 | config = esm; 159 | break; 160 | case 'umd': 161 | config = umd; 162 | break; 163 | default: 164 | config = cjs.concat(esm).concat(umd); 165 | } 166 | 167 | export default config; 168 | -------------------------------------------------------------------------------- /src/hooks/index.js: -------------------------------------------------------------------------------- 1 | import useStateValue from './useStateValue'; 2 | 3 | export { useStateValue }; // eslint-disable-line import/prefer-default-export 4 | -------------------------------------------------------------------------------- /src/hooks/useStateValue.js: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | 3 | /** 4 | * The useStateValue custom hook from Conflux provides a modular, predictable, and easy 5 | * way to desctructure state and dispatch from the Context API's Consumer whenever needed. 6 | * 7 | * @param {Object} stateContext An object previously created using React's Context 8 | * API that contains a Provider and Consumer. 9 | * 10 | * @returns {context} Returns a validated context array containing a state object and a 11 | * dispatch function for use inside of a component. 12 | */ 13 | 14 | const useStateValue = stateContext => { 15 | /** 16 | * stateContext error messages for undefined and incorrect data types passed into 17 | * useStateValue hook 18 | */ 19 | 20 | if (stateContext === undefined) { 21 | throw new Error( 22 | 'The stateContext object is undefined in your useStateValue hook. You probably forgot to pass the stateContext object into your useStateValue hook.' 23 | ); 24 | } 25 | 26 | if (!stateContext.Provider && !stateContext.Consumer) { 27 | throw new Error( 28 | 'Incorrect argument passed to the useStateValue hook. You probably passed a variable other than your context object into it.' 29 | ); 30 | } 31 | 32 | /** 33 | * The useContext React hook references the Context.Provider closest to it up the component 34 | * tree. In Conflux, this will always return as an array which is [state, dispatch]. These 35 | * are returned by the useStateValue hook for use inside the application. 36 | */ 37 | 38 | const context = useContext(stateContext); 39 | 40 | /** 41 | * context error message for if context returns undefined. This happens when the stateContext 42 | * passed into the useStateValue hook is used in a component which is not a child of that 43 | * context's Provider. 44 | */ 45 | 46 | if (context === undefined) { 47 | throw new Error( 48 | 'The useStateValue hook must be used within the Provider of the Context object you have passed to it. Check to make sure you have passed in the correct context object and that the useStateValue hook is within a child of the correct Provider.' 49 | ); 50 | } 51 | 52 | /** 53 | * Return the context of the Context.Provider closest to the useStateValue hook at the time 54 | * it was called. 55 | */ 56 | 57 | return context; 58 | }; 59 | 60 | export default useStateValue; 61 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import StateProvider from './store'; 2 | import { useStateValue } from './hooks'; 3 | 4 | export { StateProvider, useStateValue }; 5 | -------------------------------------------------------------------------------- /src/store/StateProvider.jsx: -------------------------------------------------------------------------------- 1 | import React, { useReducer, useMemo } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | /** 5 | * The stateObjects provides persistent storage of state for as many initialState objects as 6 | * needed throughout the application. 7 | * 8 | * Every instantiation of StateProvider will add a new initialState object to stateObjects with 9 | * the key of the reducer name and the value of the state. 10 | */ 11 | 12 | const stateObjects = {}; 13 | 14 | /** 15 | * Create a Context.Provider wrapper for children components wherever it is applied to the 16 | * component tree. This component can be called multiple times throughout the application. 17 | * 18 | * @param {Function} reducer A reducer function that contains a switch statement and, ultimately, 19 | * returns a state object. The reducer can never be undefined or anything other than a type of 20 | * function. Reducers should return modified state if the action.type passed into them is defined 21 | * or return the initialState if the action.type passed into them is undefined. 22 | * 23 | * @param {Object} stateContext A Context object created out of the createContext function 24 | * from React. 25 | * 26 | * @param {JSX} children The descending component tree JSX is passed in and placed inside 27 | * the Context.Provider. 28 | * 29 | * @returns {JSX} Returns a JSX component for a Context.Provider setup and passes in the memoized 30 | * value as well as the children of the Context component. 31 | */ 32 | 33 | const StateProvider = ({ reducer, stateContext, children }) => { 34 | // Error messages for the reducer object 35 | if (typeof reducer !== 'function') { 36 | throw new Error( 37 | 'The reducer must be a function. You might have forgotten to pass your reducer into your StateProvider.' 38 | ); 39 | } 40 | 41 | // Error messages for the stateContext object 42 | if (!stateContext) { 43 | throw new Error( 44 | 'stateContext prop is undefined. Please check your createContext method and what you are passing into your StateProvider.' 45 | ); 46 | } 47 | 48 | if ( 49 | children === undefined || 50 | typeof children !== 'object' || 51 | !Object.keys(children).length 52 | ) { 53 | throw new Error( 54 | 'StateProvider must contain children components. You probably forgot to wrap it around your components in your JSX.' 55 | ); 56 | } 57 | 58 | /** 59 | * This initial reducer call sets returns the initial state object from the reducer that will 60 | * then be passed into useReducer. 61 | * 62 | * 63 | */ 64 | 65 | if (stateObjects[reducer.name] === undefined) { 66 | const getRandomString = Math.random() 67 | .toString(36) 68 | .substring(7); 69 | 70 | /** 71 | * The reducer function is invoked and passed no first parameter and an object for the second 72 | * parameter. 73 | * 74 | * Parameter one is undefined as the reducer function should have a default parameter of 75 | * initialState inside the application. 76 | * 77 | * Parameter two is an object with a key-value pair for an initialState retrieval using the 78 | * getRandomString variable above appended to "@conflux" in a template literal string as 79 | * shown below. 80 | */ 81 | 82 | stateObjects[reducer.name] = reducer(undefined, { 83 | type: `@conflux-${getRandomString}` 84 | }); 85 | } 86 | 87 | /** 88 | * Uses the useReducer hook to pass in a reducer and initialState. It returns 89 | * an array that can be destructured into state and a dispatch function. 90 | */ 91 | 92 | const [state, dispatch] = useReducer(reducer, stateObjects[reducer.name]); 93 | 94 | /** 95 | * The useMemo hook returns state and dispatch while guarding against unnecessary rerendering of the component 96 | * tree contained within this stateContext.Provider. 97 | * 98 | * It will only update when the state object in value changes, rather than any other state/props outside of 99 | * these values. 100 | */ 101 | 102 | const value = useMemo(() => { 103 | return [state, dispatch]; 104 | }, [state]); 105 | 106 | const { Provider } = stateContext; 107 | 108 | /** 109 | * The newly instantiated copy of Provider is returned as a component from this function 110 | * to be wrapped around JSX in the application. The value returned from the useMemo hook (an array containing 111 | * state and dispatch) is passed into the Provider per the requirements for the Context API 112 | * in the documentation at: https://reactjs.org/docs/context.html 113 | * 114 | * This array will be available for destructuring inside components contained in the state tree with 115 | * react-conflux's custom hook "useStateValue". 116 | */ 117 | 118 | return {children}; 119 | }; 120 | 121 | StateProvider.propTypes = { 122 | reducer: PropTypes.func.isRequired, 123 | stateContext: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types 124 | children: PropTypes.oneOfType([PropTypes.element, PropTypes.array]).isRequired 125 | }; 126 | 127 | export default StateProvider; 128 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import StateProvider from './StateProvider'; 2 | 3 | export default StateProvider; 4 | -------------------------------------------------------------------------------- /test/StateProvider.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TestRenderer from 'react-test-renderer'; 3 | import ShallowRenderer from 'react-test-renderer/shallow'; 4 | import { StateProvider } from '../src'; 5 | import { testContext } from './helpers/contexts'; 6 | import { testReducer } from './helpers/reducers'; 7 | 8 | /** 9 | * In order for this test suite to run, you must npm link this repository to a React dependency 10 | * elsewhere. 11 | * 12 | * EX: npm link ../test-app/node_modules/react 13 | */ 14 | 15 | describe('', () => { 16 | describe('tests that the component will mount successfully with all arguments', () => { 17 | it('should mount successfully without crashing', () => { 18 | const tree = TestRenderer.create( 19 | 20 |

Testing

21 |
22 | ); 23 | expect(tree).toBeTruthy(); 24 | }); 25 | }); 26 | 27 | describe('tests the reducer argument passed into the component', () => { 28 | /** 29 | * Rids console.error in tests from PropTypes where we're specifically trying to test if 30 | * custom error messages occur when passing certain props. 31 | * */ 32 | 33 | beforeEach(() => { 34 | console.error = jest.fn(); 35 | }); 36 | 37 | const errorMessage = 38 | 'The reducer must be a function. You might have forgotten to pass your reducer into your StateProvider.'; 39 | 40 | it('should throw an error when no reducer is passed into it', () => { 41 | const renderer = new ShallowRenderer(); 42 | expect(() => { 43 | return renderer.render( 44 | 45 |

Testing

46 |
47 | ); 48 | }).toThrow(errorMessage); 49 | }); 50 | 51 | it('should throw an error when an object is passed in as a reducer', () => { 52 | const renderer = new ShallowRenderer(); 53 | expect(() => { 54 | return renderer.render( 55 | 56 |

Testing

57 |
58 | ); 59 | }).toThrow(errorMessage); 60 | }); 61 | 62 | it('should throw an error when an array is passed in as a reducer', () => { 63 | const renderer = new ShallowRenderer(); 64 | expect(() => { 65 | return renderer.render( 66 | 67 |

Testing

68 |
69 | ); 70 | }).toThrow(errorMessage); 71 | }); 72 | 73 | it('should throw an error when a string is passed in as a reducer', () => { 74 | const renderer = new ShallowRenderer(); 75 | expect(() => { 76 | return renderer.render( 77 | 78 |

Testing

79 |
80 | ); 81 | }).toThrow(errorMessage); 82 | }); 83 | }); 84 | 85 | describe('tests the children argument passed into the component', () => { 86 | beforeEach(() => { 87 | console.error = jest.fn(); 88 | }); 89 | 90 | const errorMessage = 91 | 'StateProvider must contain children components. You probably forgot to wrap it around your components in your JSX.'; 92 | 93 | it('should throw an error when no children are passed into it', () => { 94 | const renderer = new ShallowRenderer(); 95 | expect(() => { 96 | return renderer.render( 97 | 98 | ); 99 | }).toThrow(errorMessage); 100 | }); 101 | 102 | it('should throw an error when children are not of type "object"', () => { 103 | const renderer = new ShallowRenderer(); 104 | expect(() => { 105 | return renderer.render( 106 | 107 | {'Marty, we have to go back!'} 108 | 109 | ); 110 | }).toThrow(errorMessage); 111 | }); 112 | 113 | it('should throw an error when children are an empty object', () => { 114 | const renderer = new ShallowRenderer(); 115 | expect(() => { 116 | return renderer.render( 117 | 118 | {} 119 | 120 | ); 121 | }).toThrow(errorMessage); 122 | }); 123 | }); 124 | }); 125 | -------------------------------------------------------------------------------- /test/helpers/components.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StateProvider } from '../../src'; 3 | import { testReducer } from './reducers'; 4 | import { testContext } from './contexts'; 5 | 6 | export const TestApp = ({ children }) => { 7 | return ( 8 | 9 |
{children}
10 |
11 | ); 12 | }; 13 | -------------------------------------------------------------------------------- /test/helpers/constants.js: -------------------------------------------------------------------------------- 1 | export const UPDATE_TEXT = 'UPDATE_TEXT'; 2 | -------------------------------------------------------------------------------- /test/helpers/contexts.js: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | export const testContext = createContext(); 4 | export const wrongContext = createContext(); 5 | -------------------------------------------------------------------------------- /test/helpers/reducers.js: -------------------------------------------------------------------------------- 1 | import { UPDATE_TEXT } from './constants'; 2 | 3 | const initialState = { text: 'Testing' }; 4 | 5 | export const testReducer = (state = initialState, action) => { 6 | switch (action.type) { 7 | case UPDATE_TEXT: 8 | console.log(action); 9 | return { 10 | ...state, 11 | text: action.payload 12 | }; 13 | default: 14 | return state; 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /test/useInitialState.test.js: -------------------------------------------------------------------------------- 1 | import { testReducer } from './helpers/reducers'; 2 | import useInitialState from '../src/hooks/useInitialState'; 3 | 4 | describe('.useInitialState()', () => { 5 | describe('tests that a function passed into .useInitialState() as an argument will be invoked', () => { 6 | it('should invoke the function that is passed into it successfully', () => { 7 | const spy = jest.fn(str => { 8 | return 'Testing'; 9 | }); 10 | expect(useInitialState(spy)).toBe('Testing'); 11 | }); 12 | }); 13 | 14 | describe('tests that a reducer passed as an argument into .useInitialState() successfully return initialState', () => { 15 | it('should return an object successfully when the reducer is invoked', () => { 16 | const initialState = useInitialState(testReducer); 17 | expect(typeof initialState).toBe('object'); 18 | }); 19 | 20 | it('should return state successfully from a reducer', () => { 21 | const initialState = useInitialState(testReducer); 22 | expect(initialState.text).toBe('Testing'); 23 | }); 24 | }); 25 | 26 | describe('tests that an error that primitive data types, arrays, and objects passed as argument throws an error', () => { 27 | it('should throw an error when a string literal is passed into it', () => { 28 | expect(() => { 29 | return useInitialState('testing'); 30 | }).toThrowError(/reducer is not a function/i); 31 | }); 32 | 33 | it('should throw an error when a number literal is passed into it', () => { 34 | expect(() => { 35 | return useInitialState(5); 36 | }).toThrowError(/reducer is not a function/i); 37 | }); 38 | 39 | it('should throw an error when an object literal is passed into it', () => { 40 | expect(() => { 41 | return useInitialState({ object: 'object' }); 42 | }).toThrowError(/reducer is not a function/i); 43 | }); 44 | 45 | it('should throw an error when an array literal is passed into it', () => { 46 | expect(() => { 47 | return useInitialState(['array']); 48 | }).toThrowError(/reducer is not a function/i); 49 | }); 50 | }); 51 | 52 | describe('tests that .useInitialState() generates a random string to invoke the reducer for initialState', () => { 53 | it('should return a string prepended by @conflux when passed a mock function', () => { 54 | const spy = jest.fn((state, action) => { 55 | return action; 56 | }); 57 | expect(useInitialState(spy).type.includes('@conflux')).toBeTruthy(); 58 | }); 59 | }); 60 | }); 61 | -------------------------------------------------------------------------------- /test/useStateValue.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TestRenderer from 'react-test-renderer'; 3 | import { useStateValue } from '../src'; 4 | import { TestApp } from './helpers/components'; 5 | import { testContext, wrongContext } from './helpers/contexts'; 6 | 7 | /** 8 | * In order for this test suite to run, you must npm link this repository to a React dependency 9 | * elsewhere. 10 | * 11 | * EX: npm link ../test-app/node_modules/react 12 | */ 13 | 14 | describe('.useStateValue()', () => { 15 | describe('tests that .useStateValue() will destructure state and dispatch', () => { 16 | it('should mount successfully and destructure state and dispatch without crashing', () => { 17 | const ChildComponent = () => { 18 | const [{ text }, dispatch] = useStateValue(testContext); 19 | return

{text}

; 20 | }; 21 | 22 | const tree = TestRenderer.create( 23 | 24 | 25 | 26 | ).toJSON(); 27 | 28 | expect(tree.children[0].children[0]).toBe('Testing'); 29 | }); 30 | }); 31 | 32 | describe('tests that not passing context to .useStateValue() throws an error', () => { 33 | beforeEach(() => { 34 | console.error = jest.fn(); 35 | }); 36 | 37 | it('should throw an error when no context is passed into it', () => { 38 | const ChildComponent = () => { 39 | const [{ text }] = useStateValue(); 40 | return

{text}

; 41 | }; 42 | 43 | expect(() => { 44 | return TestRenderer.create( 45 | 46 | 47 | 48 | ); 49 | }).toThrow( 50 | 'The stateContext object is undefined in your useStateValue hook. You probably forgot to pass the stateContext object into your useStateValue hook.' 51 | ); 52 | }); 53 | }); 54 | 55 | describe('tests that primitive data types, arrays, and objects passed as argument throws an error', () => { 56 | beforeEach(() => { 57 | console.error = jest.fn(); 58 | }); 59 | 60 | const errorMessage = 61 | 'Incorrect argument passed to the useStateValue hook. You probably passed a variable other than your context object into it.'; 62 | 63 | it('should throw an error when an object literal is passed into it', () => { 64 | const ChildComponent = () => { 65 | const [{ text }, dispatch] = useStateValue({ text: 'Testing' }); 66 | return

{text}

; 67 | }; 68 | 69 | expect(() => { 70 | return TestRenderer.create( 71 | 72 | 73 | 74 | ); 75 | }).toThrow(errorMessage); 76 | }); 77 | 78 | it('should throw an error when an array literal is passed into it', () => { 79 | const ChildComponent = () => { 80 | const [{ text }, dispatch] = useStateValue(['Testing']); 81 | return

{text}

; 82 | }; 83 | 84 | expect(() => { 85 | return TestRenderer.create( 86 | 87 | 88 | 89 | ); 90 | }).toThrow(errorMessage); 91 | }); 92 | 93 | it('should thrown an error when a string literal is passed into it', () => { 94 | const ChildComponent = () => { 95 | const [{ text }, dispatch] = useStateValue('Testing'); 96 | return

{text}

; 97 | }; 98 | 99 | expect(() => { 100 | return TestRenderer.create( 101 | 102 | 103 | 104 | ); 105 | }).toThrow(errorMessage); 106 | }); 107 | }); 108 | 109 | describe('tests that the wrong context passed into .useStateValue() throws an error', () => { 110 | beforeEach(() => { 111 | console.error = jest.fn(); 112 | }); 113 | 114 | it('should throw an error when the wrong context object is passed into it', () => { 115 | const ChildComponent = () => { 116 | const [{ text }, dispatch] = useStateValue(wrongContext); 117 | return

{text}

; 118 | }; 119 | 120 | expect(() => { 121 | return TestRenderer.create( 122 | 123 | 124 | 125 | ); 126 | }).toThrow( 127 | 'The useStateValue hook must be used within the Provider of the Context object you have passed to it. Check to make sure you have passed in the correct context object and that the useStateValue hook is within a child of the correct Provider.' 128 | ); 129 | }); 130 | }); 131 | }); 132 | --------------------------------------------------------------------------------