├── .prettierrc
├── .gitignore
├── logo.png
├── .flowconfig
├── .travis.yml
├── .babelrc
├── tsconfig.json
├── rollup.config.js
├── example
├── index.html
├── simple.js
├── shared.js
├── complex.js
└── single.js
├── LICENSE
├── src
├── unstated.d.ts
└── unstated.js
├── logo.svg
├── README.md
├── package.json
├── __tests__
├── unstated.js
└── unstated.tsx
└── flow-typed
└── npm
└── jest_v22.x.x.js
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | *.log
3 | lib
4 | .cache
5 | dist
6 |
--------------------------------------------------------------------------------
/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paul-phan/unstated-x/HEAD/logo.png
--------------------------------------------------------------------------------
/.flowconfig:
--------------------------------------------------------------------------------
1 | [ignore]
2 |
3 | [include]
4 |
5 | [libs]
6 |
7 | [lints]
8 |
9 | [options]
10 |
11 | [strict]
12 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | git:
2 | depth: 1
3 | sudo: false
4 | language: node_js
5 | node_js:
6 | - '8'
7 | cache:
8 | yarn: true
9 | directories:
10 | - node_modules
11 | script:
12 | - yarn test && yarn flow
13 | - yarn typescript
14 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "@babel/preset-env",
5 | {
6 | "modules": false,
7 | "loose": true
8 | }
9 | ],
10 | "@babel/preset-react",
11 | "@babel/preset-flow"
12 | ],
13 | "plugins": [
14 | "@babel/plugin-proposal-class-properties"
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "es5",
5 | "lib": ["es6", "dom"],
6 | "sourceMap": true,
7 | "jsx": "react",
8 | "moduleResolution": "node",
9 | "forceConsistentCasingInFileNames": true,
10 | "strict": true,
11 | "noEmit": true
12 | },
13 | "include": ["src/**/*", "__test__/*.tsx"]
14 | }
15 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import babel from 'rollup-plugin-babel';
2 | import pkg from './package.json';
3 |
4 | export default {
5 | input: 'src/unstated.js',
6 | output: [
7 | {
8 | file: pkg.main,
9 | format: 'cjs'
10 | },
11 | {
12 | file: pkg.module,
13 | format: 'es'
14 | }
15 | ],
16 | external: [
17 | ...Object.keys(pkg.dependencies || {}),
18 | ...Object.keys(pkg.peerDependencies || {})
19 | ],
20 | plugins: [babel()]
21 | };
22 |
--------------------------------------------------------------------------------
/example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Unstated - Examples
6 |
7 |
8 | Simple
9 |
10 |
11 |
12 | Complex
13 |
14 |
15 |
16 | Shared
17 |
18 |
19 |
20 | Single Subscribe
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/example/simple.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React from 'react';
3 | import { render } from 'react-dom';
4 | import { Provider, Subscribe, Container } from '../src/unstated';
5 |
6 | type CounterState = {
7 | count: number
8 | };
9 |
10 | class CounterContainer extends Container {
11 | state = { count: 0 };
12 |
13 | increment() {
14 | this.setState({ count: this.state.count + 1 });
15 | }
16 |
17 | decrement() {
18 | this.setState({ count: this.state.count - 1 });
19 | }
20 | }
21 |
22 | function Counter() {
23 | return (
24 |
25 | {counter => (
26 |
27 | counter.decrement()}>-
28 | {counter.state.count}
29 | counter.increment()}>+
30 |
31 | )}
32 |
33 | );
34 | }
35 |
36 | render(
37 |
38 |
39 | ,
40 | window.simple
41 | );
42 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Permission is hereby granted, free of charge, to any person obtaining a copy
2 | of this software and associated documentation files (the "Software"), to deal
3 | in the Software without restriction, including without limitation the rights
4 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
5 | copies of the Software, and to permit persons to whom the Software is
6 | furnished to do so, subject to the following conditions:
7 |
8 | The above copyright notice and this permission notice shall be included in all
9 | copies or substantial portions of the Software.
10 |
11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17 | SOFTWARE.
18 |
--------------------------------------------------------------------------------
/example/shared.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React from 'react';
3 | import { render } from 'react-dom';
4 | import { Provider, Subscribe, Container } from '../src/unstated';
5 |
6 | type CounterState = {
7 | count: number
8 | };
9 |
10 | class CounterContainer extends Container {
11 | state = { count: 0 };
12 |
13 | increment() {
14 | this.setState({ count: this.state.count + 1 });
15 | }
16 |
17 | decrement() {
18 | this.setState({ count: this.state.count - 1 });
19 | }
20 | }
21 |
22 | const sharedCounterContainer = new CounterContainer();
23 |
24 | function Counter() {
25 | return (
26 |
27 | {counter => (
28 |
29 | counter.decrement()}>-
30 | {counter.state.count}
31 | sharedCounterContainer.increment()}>+
32 |
33 | )}
34 |
35 | );
36 | }
37 |
38 | render(
39 |
40 |
41 | ,
42 | window.shared
43 | );
44 |
--------------------------------------------------------------------------------
/src/unstated.d.ts:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | export class Container {
4 | constructor(state?: object);
5 | state: State;
6 | _listeners: [Function];
7 | setStateSync(
8 | state:
9 | | ((prevState: Readonly) => Partial | State | null)
10 | | (Partial | State | null),
11 | callback?: () => void
12 | ): void;
13 | setState(
14 | state:
15 | | ((prevState: Readonly) => Partial | State | null)
16 | | (Partial | State | null),
17 | callback?: () => void
18 | ): Promise;
19 | subscribe(fn: (changes: {}) => any): void;
20 | unsubscribe(fn: (changes: {}) => any): void;
21 | }
22 |
23 | export interface ContainerType {
24 | new (...args: any[]): Container;
25 | }
26 |
27 | interface SubscribeProps {
28 | to: (ContainerType | Container)[];
29 | children(...instances: any[]): React.ReactNode;
30 | }
31 | interface SubscribeOneProps {
32 | to: (ContainerType | Container);
33 | bind: string[];
34 | children(...instances: any[]): React.ReactNode;
35 | }
36 |
37 | export class Subscribe extends React.Component {}
38 | export class SubscribeOne extends React.Component {}
39 |
40 | export interface ProviderProps {
41 | inject?: Container[];
42 | children: React.ReactNode;
43 | }
44 |
45 | export const Provider: React.SFC;
46 |
--------------------------------------------------------------------------------
/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # This project will not be maintained anymore in favor of Hooks: https://github.com/paul-phan/global-state-hook
2 |
3 |
4 | # Unstated-x
5 |
6 | > State so simple, it goes without saying
7 |
8 | ## Installation
9 |
10 | ```sh
11 | yarn add unstated-x
12 | ```
13 |
14 | ## About Unstated
15 |
16 | The original documentation can be found in: https://github.com/jamiebuilds/unstated
17 |
18 | ## Additional Functions
19 |
20 | > Fix broken Controlled Component when using Asynchronous Unstated `setState` by using `setStateSync`
21 |
22 | ```js
23 | function App() {
24 | return (
25 |
26 | {app => (
27 | app.setStateSync({ value: e.target.value })}
29 | value={app.state.value}
30 | />
31 | )}
32 |
33 | );
34 | }
35 | ```
36 |
37 | > Add Subscribe to only one Container and only state you want to:
38 |
39 | ```js
40 | function App() {
41 | return (
42 |
43 | {app => (
44 |
45 | This will update only if the "value" state is updated, others will not
46 | app.setStateSync({ value: e.target.value })}
48 | value={app.state.value}
49 | />
50 |
51 | )}
52 |
53 | );
54 | }
55 | ```
56 |
57 | You can checkout the example to see more.
58 |
59 | > In this version, if you use React version 16.3 or higher, it will use the native React.createContext rather than the `create-react-context` library. I also removed support for multiple ` ` it clearly unnecessary.
60 |
61 | ## Contribution
62 |
63 | Feel free to create issues/pull request, I will eager to apply it to unstated-x if it good enough :)
64 |
--------------------------------------------------------------------------------
/example/complex.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React from 'react';
3 | import { render } from 'react-dom';
4 | import { Provider, Subscribe, Container } from '../src/unstated';
5 |
6 | type AppState = {
7 | amount: number
8 | };
9 |
10 | class AppContainer extends Container {
11 | state = {
12 | amount: 1
13 | };
14 |
15 | setAmount(amount: number) {
16 | this.setState({ amount });
17 | }
18 | }
19 |
20 | type CounterState = {
21 | count: number
22 | };
23 |
24 | class CounterContainer extends Container {
25 | state = {
26 | count: 0
27 | };
28 |
29 | increment(amount: number) {
30 | this.setState({ count: this.state.count + amount });
31 | }
32 |
33 | decrement(amount: number) {
34 | this.setState({ count: this.state.count - amount });
35 | }
36 | }
37 |
38 | function Counter() {
39 | return (
40 |
41 | {(app, counter) => (
42 |
43 | Count: {counter.state.count}
44 | counter.decrement(app.state.amount)}>-
45 | counter.increment(app.state.amount)}>+
46 |
47 | )}
48 |
49 | );
50 | }
51 |
52 | function App() {
53 | return (
54 |
55 | {app => (
56 |
57 |
58 | Amount:
59 | {
63 | app.setAmount(parseInt(event.currentTarget.value, 10));
64 | }}
65 | />
66 |
67 | )}
68 |
69 | );
70 | }
71 |
72 | render(
73 |
74 |
75 | ,
76 | window.complex
77 | );
78 |
--------------------------------------------------------------------------------
/example/single.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React from 'react';
3 | import { render } from 'react-dom';
4 | import { Container, Provider, SubscribeOne } from '../src/unstated';
5 |
6 | type CounterState = {
7 | count: number
8 | };
9 |
10 | class AppContainer extends Container {
11 | state = {};
12 | }
13 |
14 | function App() {
15 | return (
16 |
17 | Open React DevTools => Highlight updates to check result
18 |
19 | {app => (
20 |
21 | Subscribe to only one state property:: {app.state.test}
22 |
23 | app.setStateSync({ test: e.target.value })}
25 | value={app.state.test || ''}
26 | />
27 |
28 |
29 | )}
30 |
31 |
32 | {app => (
33 |
34 | Subscribe to only one state property:: {app.state.test1}
35 |
36 | app.setStateSync({ test1: e.target.value })}
38 | value={app.state.test1 || ''}
39 | />
40 |
41 |
42 | )}
43 |
44 |
45 | {app => (
46 |
47 | Subscribe to only one state property:: {app.state.test2}
48 |
49 | app.setStateSync({ test2: e.target.value })}
51 | value={app.state.test2 || ''}
52 | />
53 |
54 |
55 | )}
56 |
57 |
58 | );
59 | }
60 |
61 | render(
62 |
63 |
64 | ,
65 | window.single
66 | );
67 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "unstated-x",
3 | "version": "1.0.1",
4 | "description": "Add more powers to unstated",
5 | "main": "lib/unstated.js",
6 | "module": "lib/unstated.es.js",
7 | "types": "lib/unstated.d.ts",
8 | "repository": "https://github.com/paul-phan/unstated-x.git",
9 | "license": "MIT",
10 | "files": [
11 | "lib"
12 | ],
13 | "scripts": {
14 | "clean": "rm -rf lib",
15 | "build": "rollup -c && flow-copy-source src lib && cp src/unstated.d.ts lib/unstated.d.ts",
16 | "typecheck": "flow",
17 | "test": "jest",
18 | "format": "prettier --write **/*.{js,json,md}",
19 | "prepublish": "yarn clean && yarn build",
20 | "precommit": "lint-staged",
21 | "example": "parcel example/index.html",
22 | "typescript": "tsc -p tsconfig.json"
23 | },
24 | "dependencies": {},
25 | "peerDependencies": {
26 | "react": "^16.14.0"
27 | },
28 | "resolutions": {
29 | "babel-core": "7.0.0-bridge.0"
30 | },
31 | "devDependencies": {
32 | "@babel/core": "^7.15.0",
33 | "@babel/plugin-proposal-class-properties": "^7.14.5",
34 | "@babel/preset-env": "^7.15.0",
35 | "@babel/preset-flow": "^7.14.5",
36 | "@babel/preset-react": "^7.14.5",
37 | "@babel/register": "^7.15.3",
38 | "@types/react": "^17.0.17",
39 | "babel-core": "^7.0.0-bridge.0",
40 | "babel-loader": "^8.2.2",
41 | "flow-bin": "^0.157.0",
42 | "flow-copy-source": "^2.0.9",
43 | "husky": "^7.0.1",
44 | "jest": "^27.0.6",
45 | "jsdom": "^16.7.0",
46 | "lint-staged": "^11.1.2",
47 | "parcel-bundler": "^1.12.5",
48 | "prettier": "^2.3.2",
49 | "prop-types": "^15.7.2",
50 | "react": "^17.0.2",
51 | "react-dom": "^17.0.2",
52 | "react-test-renderer": "^17.0.2",
53 | "rollup": "^2.56.2",
54 | "rollup-plugin-babel": "^4.4.0",
55 | "typescript": "^4.3.5"
56 | },
57 | "lint-staged": {
58 | "*.{js,json,md}": [
59 | "prettier --write",
60 | "git add"
61 | ]
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/__tests__/unstated.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React from 'react';
3 | import renderer from 'react-test-renderer';
4 | import { Provider, Subscribe, Container } from '../src/unstated';
5 |
6 | function render(element) {
7 | return renderer.create(element).toJSON();
8 | }
9 |
10 | class CounterContainer extends Container<{ count: number }> {
11 | state = { count: 0 };
12 | increment(amount = 1) {
13 | this.setState({ count: this.state.count + amount });
14 | }
15 | decrement(amount = 1) {
16 | this.setState({ count: this.state.count - amount });
17 | }
18 | }
19 |
20 | class AmounterContainer extends Container<{ amount: number }> {
21 | state = { amount: 1 };
22 | setAmount(amount) {
23 | this.setState({ amount });
24 | }
25 | }
26 |
27 | function Counter() {
28 | return (
29 |
30 | {counter => (
31 |
32 | {counter.state.count}
33 | counter.decrement()}>-
34 | counter.increment()}>+
35 |
36 | )}
37 |
38 | );
39 | }
40 |
41 | function CounterWithAmount() {
42 | return (
43 |
44 | {(counter, amounter) => (
45 |
46 | {counter.state.count}
47 | counter.decrement(amounter.state.amount)}>
48 | -
49 |
50 | counter.increment(amounter.state.amount)}>
51 | +
52 |
53 |
54 | )}
55 |
56 | );
57 | }
58 |
59 | function CounterWithAmountApp() {
60 | return (
61 |
62 | {amounter => (
63 |
64 |
65 | {
69 | amounter.setAmount(parseInt(event.currentTarget.value, 10));
70 | }}
71 | />
72 |
73 | )}
74 |
75 | );
76 | }
77 |
78 | test('basic', () => {
79 | // still too lazy
80 | });
81 |
--------------------------------------------------------------------------------
/__tests__/unstated.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Provider, Subscribe, Container } from '../src/unstated';
3 |
4 | class CounterContainer extends Container<{ count: number }> {
5 | state = { count: 0 };
6 | increment(amount = 1) {
7 | this.setState({ count: this.state.count + amount });
8 | }
9 | decrement(amount = 1) {
10 | this.setState({ count: this.state.count - amount });
11 | }
12 | }
13 |
14 | class AmounterContainer extends Container<{ amount: number }> {
15 | state = { amount: 1 };
16 | setAmount(amount: number) {
17 | this.setState({ amount });
18 | }
19 | }
20 |
21 | function Counter() {
22 | return (
23 |
24 | {(counter: CounterContainer) => (
25 |
26 | {counter.state.count}
27 | counter.decrement()}>-
28 | counter.increment()}>+
29 |
30 | )}
31 |
32 | );
33 | }
34 |
35 | function CounterWithAmount() {
36 | return (
37 |
38 | {(counter: CounterContainer, amounter: AmounterContainer) => (
39 |
40 | {counter.state.count}
41 | counter.decrement(amounter.state.amount)}>
42 | -
43 |
44 | counter.increment(amounter.state.amount)}>
45 | +
46 |
47 |
48 | )}
49 |
50 | );
51 | }
52 |
53 | function CounterWithAmountApp() {
54 | return (
55 |
56 | {(amounter: AmounterContainer) => (
57 |
58 |
59 | {
63 | amounter.setAmount(parseInt(event.currentTarget.value, 10));
64 | }}
65 | />
66 |
67 | )}
68 |
69 | );
70 | }
71 |
72 | const sharedAmountContainer = new AmounterContainer();
73 |
74 | function CounterWithSharedAmountApp() {
75 | return (
76 |
77 | {(amounter: AmounterContainer) => (
78 |
79 |
80 | {
84 | amounter.setAmount(parseInt(event.currentTarget.value, 10));
85 | }}
86 | />
87 |
88 | )}
89 |
90 | );
91 | }
92 |
93 | let counter = new CounterContainer();
94 | let render = () => (
95 |
96 |
97 |
98 | );
99 |
--------------------------------------------------------------------------------
/src/unstated.js:
--------------------------------------------------------------------------------
1 | import React, { createContext } from 'react';
2 |
3 | export const StateContext = createContext(null);
4 |
5 | export class Container {
6 | state = {};
7 | _listeners = [];
8 |
9 | constructor(state = {}) {
10 | this.state = state;
11 | }
12 |
13 | _setState(updater, callback) {
14 | let nextState;
15 |
16 | if (typeof updater === 'function') {
17 | nextState = updater(this.state);
18 | } else {
19 | nextState = updater;
20 | }
21 |
22 | if (nextState == null) {
23 | if (callback) callback();
24 | }
25 | return nextState;
26 | }
27 |
28 | setStateSync(updater, callback) {
29 | const nextState = this._setState(updater, callback);
30 |
31 | this.state = Object.assign({}, this.state, nextState);
32 |
33 | this._listeners.forEach(fn => fn(nextState));
34 | }
35 |
36 | setState(updater, callback) {
37 | return Promise.resolve().then(() => {
38 | const nextState = this._setState(updater, callback);
39 |
40 | this.state = Object.assign({}, this.state, nextState);
41 |
42 | let promises = this._listeners.map(listener => listener(nextState));
43 |
44 | return Promise.all(promises).then(() => {
45 | if (callback) {
46 | return callback();
47 | }
48 | });
49 | });
50 | }
51 |
52 | subscribe(fn) {
53 | this._listeners.push(fn);
54 | }
55 |
56 | unsubscribe(fn) {
57 | this._listeners = this._listeners.filter(f => f !== fn);
58 | }
59 | }
60 |
61 | export class Subscribe extends React.Component {
62 | state = {};
63 | instances = [];
64 | unmounted = false;
65 |
66 | componentWillUnmount() {
67 | this.unmounted = true;
68 | this._unsubscribe();
69 | }
70 |
71 | _unsubscribe() {
72 | this.instances.forEach(container => {
73 | container.unsubscribe(this.onUpdate);
74 | });
75 | }
76 |
77 | onUpdate = () => {
78 | return new Promise(resolve => {
79 | if (!this.unmounted) {
80 | this.setState({}, resolve);
81 | } else {
82 | resolve();
83 | }
84 | });
85 | };
86 |
87 | _createInstances(map, containers) {
88 | this._unsubscribe();
89 |
90 | if (map === null) {
91 | throw new Error(
92 | 'You must wrap your components with a '
93 | );
94 | }
95 |
96 | let safeMap = map;
97 | let instances = containers.map(ContainerItem => {
98 | let instance;
99 |
100 | if (
101 | typeof ContainerItem === 'object' &&
102 | ContainerItem instanceof Container
103 | ) {
104 | instance = ContainerItem;
105 | } else {
106 | instance = safeMap.get(ContainerItem);
107 |
108 | if (!instance) {
109 | instance = new ContainerItem();
110 | safeMap.set(ContainerItem, instance);
111 | }
112 | }
113 |
114 | instance.unsubscribe(this.onUpdate);
115 | instance.subscribe(this.onUpdate);
116 |
117 | return instance;
118 | });
119 |
120 | this.instances = instances;
121 | return instances;
122 | }
123 |
124 | render() {
125 | return (
126 |
127 | {map =>
128 | Reflect.apply(
129 | this.props.children,
130 | null,
131 | this._createInstances(map, this.props.to)
132 | )
133 | }
134 |
135 | );
136 | }
137 | }
138 |
139 | export class SubscribeOne extends React.Component {
140 | state = {};
141 | instance = null;
142 | unmounted = false;
143 |
144 | componentWillUnmount() {
145 | this.unmounted = true;
146 | this._unsubscribe();
147 | }
148 |
149 | _unsubscribe() {
150 | this.instance && this.instance.unsubscribe(this.onUpdate);
151 | }
152 |
153 | onUpdate = changedState => {
154 | return new Promise(resolve => {
155 | if (
156 | !this.unmounted &&
157 | Array.isArray(this.props.bind) &&
158 | Object.keys(changedState).filter(key => this.props.bind.includes(key))
159 | .length > 0
160 | ) {
161 | this.setState({}, resolve);
162 | } else {
163 | resolve();
164 | }
165 | });
166 | };
167 |
168 | _createInstance(map, container) {
169 | this._unsubscribe();
170 | if (map === null) {
171 | throw new Error(
172 | 'You must wrap your components with a '
173 | );
174 | }
175 | let safeMap = map;
176 | if (typeof container === 'object' && container instanceof Container) {
177 | this.instance = container;
178 | } else {
179 | this.instance = safeMap.get(container);
180 |
181 | if (!this.instance) {
182 | this.instance = new container();
183 | safeMap.set(container, this.instance);
184 | }
185 | }
186 |
187 | this.instance.unsubscribe(this.onUpdate);
188 | this.instance.subscribe(this.onUpdate);
189 |
190 | return this.instance;
191 | }
192 |
193 | render() {
194 | return (
195 |
196 | {map => this.props.children(this._createInstance(map, this.props.to))}
197 |
198 | );
199 | }
200 | }
201 |
202 | export function Provider(props) {
203 | return (
204 |
205 | {props.children}
206 |
207 | );
208 | }
209 |
--------------------------------------------------------------------------------
/flow-typed/npm/jest_v22.x.x.js:
--------------------------------------------------------------------------------
1 | // flow-typed signature: 6e1fc0a644aa956f79029fec0709e597
2 | // flow-typed version: 07ebad4796/jest_v22.x.x/flow_>=v0.39.x
3 |
4 | type JestMockFn, TReturn> = {
5 | (...args: TArguments): TReturn,
6 | /**
7 | * An object for introspecting mock calls
8 | */
9 | mock: {
10 | /**
11 | * An array that represents all calls that have been made into this mock
12 | * function. Each call is represented by an array of arguments that were
13 | * passed during the call.
14 | */
15 | calls: Array,
16 | /**
17 | * An array that contains all the object instances that have been
18 | * instantiated from this mock function.
19 | */
20 | instances: Array
21 | },
22 | /**
23 | * Resets all information stored in the mockFn.mock.calls and
24 | * mockFn.mock.instances arrays. Often this is useful when you want to clean
25 | * up a mock's usage data between two assertions.
26 | */
27 | mockClear(): void,
28 | /**
29 | * Resets all information stored in the mock. This is useful when you want to
30 | * completely restore a mock back to its initial state.
31 | */
32 | mockReset(): void,
33 | /**
34 | * Removes the mock and restores the initial implementation. This is useful
35 | * when you want to mock functions in certain test cases and restore the
36 | * original implementation in others. Beware that mockFn.mockRestore only
37 | * works when mock was created with jest.spyOn. Thus you have to take care of
38 | * restoration yourself when manually assigning jest.fn().
39 | */
40 | mockRestore(): void,
41 | /**
42 | * Accepts a function that should be used as the implementation of the mock.
43 | * The mock itself will still record all calls that go into and instances
44 | * that come from itself -- the only difference is that the implementation
45 | * will also be executed when the mock is called.
46 | */
47 | mockImplementation(
48 | fn: (...args: TArguments) => TReturn
49 | ): JestMockFn,
50 | /**
51 | * Accepts a function that will be used as an implementation of the mock for
52 | * one call to the mocked function. Can be chained so that multiple function
53 | * calls produce different results.
54 | */
55 | mockImplementationOnce(
56 | fn: (...args: TArguments) => TReturn
57 | ): JestMockFn,
58 | /**
59 | * Just a simple sugar function for returning `this`
60 | */
61 | mockReturnThis(): void,
62 | /**
63 | * Deprecated: use jest.fn(() => value) instead
64 | */
65 | mockReturnValue(value: TReturn): JestMockFn,
66 | /**
67 | * Sugar for only returning a value once inside your mock
68 | */
69 | mockReturnValueOnce(value: TReturn): JestMockFn
70 | };
71 |
72 | type JestAsymmetricEqualityType = {
73 | /**
74 | * A custom Jasmine equality tester
75 | */
76 | asymmetricMatch(value: mixed): boolean
77 | };
78 |
79 | type JestCallsType = {
80 | allArgs(): mixed,
81 | all(): mixed,
82 | any(): boolean,
83 | count(): number,
84 | first(): mixed,
85 | mostRecent(): mixed,
86 | reset(): void
87 | };
88 |
89 | type JestClockType = {
90 | install(): void,
91 | mockDate(date: Date): void,
92 | tick(milliseconds?: number): void,
93 | uninstall(): void
94 | };
95 |
96 | type JestMatcherResult = {
97 | message?: string | (() => string),
98 | pass: boolean
99 | };
100 |
101 | type JestMatcher = (actual: any, expected: any) => JestMatcherResult;
102 |
103 | type JestPromiseType = {
104 | /**
105 | * Use rejects to unwrap the reason of a rejected promise so any other
106 | * matcher can be chained. If the promise is fulfilled the assertion fails.
107 | */
108 | rejects: JestExpectType,
109 | /**
110 | * Use resolves to unwrap the value of a fulfilled promise so any other
111 | * matcher can be chained. If the promise is rejected the assertion fails.
112 | */
113 | resolves: JestExpectType
114 | };
115 |
116 | /**
117 | * Plugin: jest-enzyme
118 | */
119 | type EnzymeMatchersType = {
120 | toBeChecked(): void,
121 | toBeDisabled(): void,
122 | toBeEmpty(): void,
123 | toBePresent(): void,
124 | toContainReact(element: React$Element): void,
125 | toHaveClassName(className: string): void,
126 | toHaveHTML(html: string): void,
127 | toHaveProp(propKey: string, propValue?: any): void,
128 | toHaveRef(refName: string): void,
129 | toHaveState(stateKey: string, stateValue?: any): void,
130 | toHaveStyle(styleKey: string, styleValue?: any): void,
131 | toHaveTagName(tagName: string): void,
132 | toHaveText(text: string): void,
133 | toIncludeText(text: string): void,
134 | toHaveValue(value: any): void,
135 | toMatchElement(element: React$Element): void,
136 | toMatchSelector(selector: string): void
137 | };
138 |
139 | type JestExpectType = {
140 | not: JestExpectType & EnzymeMatchersType,
141 | /**
142 | * If you have a mock function, you can use .lastCalledWith to test what
143 | * arguments it was last called with.
144 | */
145 | lastCalledWith(...args: Array): void,
146 | /**
147 | * toBe just checks that a value is what you expect. It uses === to check
148 | * strict equality.
149 | */
150 | toBe(value: any): void,
151 | /**
152 | * Use .toHaveBeenCalled to ensure that a mock function got called.
153 | */
154 | toBeCalled(): void,
155 | /**
156 | * Use .toBeCalledWith to ensure that a mock function was called with
157 | * specific arguments.
158 | */
159 | toBeCalledWith(...args: Array): void,
160 | /**
161 | * Using exact equality with floating point numbers is a bad idea. Rounding
162 | * means that intuitive things fail.
163 | */
164 | toBeCloseTo(num: number, delta: any): void,
165 | /**
166 | * Use .toBeDefined to check that a variable is not undefined.
167 | */
168 | toBeDefined(): void,
169 | /**
170 | * Use .toBeFalsy when you don't care what a value is, you just want to
171 | * ensure a value is false in a boolean context.
172 | */
173 | toBeFalsy(): void,
174 | /**
175 | * To compare floating point numbers, you can use toBeGreaterThan.
176 | */
177 | toBeGreaterThan(number: number): void,
178 | /**
179 | * To compare floating point numbers, you can use toBeGreaterThanOrEqual.
180 | */
181 | toBeGreaterThanOrEqual(number: number): void,
182 | /**
183 | * To compare floating point numbers, you can use toBeLessThan.
184 | */
185 | toBeLessThan(number: number): void,
186 | /**
187 | * To compare floating point numbers, you can use toBeLessThanOrEqual.
188 | */
189 | toBeLessThanOrEqual(number: number): void,
190 | /**
191 | * Use .toBeInstanceOf(Class) to check that an object is an instance of a
192 | * class.
193 | */
194 | toBeInstanceOf(cls: Class<*>): void,
195 | /**
196 | * .toBeNull() is the same as .toBe(null) but the error messages are a bit
197 | * nicer.
198 | */
199 | toBeNull(): void,
200 | /**
201 | * Use .toBeTruthy when you don't care what a value is, you just want to
202 | * ensure a value is true in a boolean context.
203 | */
204 | toBeTruthy(): void,
205 | /**
206 | * Use .toBeUndefined to check that a variable is undefined.
207 | */
208 | toBeUndefined(): void,
209 | /**
210 | * Use .toContain when you want to check that an item is in a list. For
211 | * testing the items in the list, this uses ===, a strict equality check.
212 | */
213 | toContain(item: any): void,
214 | /**
215 | * Use .toContainEqual when you want to check that an item is in a list. For
216 | *
217 | *
218 | *
219 | * ing the items in the list, this matcher recursively checks the
220 | * equality of all fields, rather than checking for object identity.
221 | */
222 | toContainEqual(item: any): void,
223 | /**
224 | * Use .toEqual when you want to check that two objects have the same value.
225 | * This matcher recursively checks the equality of all fields, rather than
226 | * checking for object identity.
227 | */
228 | toEqual(value: any): void,
229 | /**
230 | * Use .toHaveBeenCalled to ensure that a mock function got called.
231 | */
232 | toHaveBeenCalled(): void,
233 | /**
234 | * Use .toHaveBeenCalledTimes to ensure that a mock function got called exact
235 | * number of times.
236 | */
237 | toHaveBeenCalledTimes(number: number): void,
238 | /**
239 | * Use .toHaveBeenCalledWith to ensure that a mock function was called with
240 | * specific arguments.
241 | */
242 | toHaveBeenCalledWith(...args: Array): void,
243 | /**
244 | * Use .toHaveBeenLastCalledWith to ensure that a mock function was last called
245 | * with specific arguments.
246 | */
247 | toHaveBeenLastCalledWith(...args: Array): void,
248 | /**
249 | * Check that an object has a .length property and it is set to a certain
250 | * numeric value.
251 | */
252 | toHaveLength(number: number): void,
253 | /**
254 | *
255 | */
256 | toHaveProperty(propPath: string, value?: any): void,
257 | /**
258 | * Use .toMatch to check that a string matches a regular expression or string.
259 | */
260 | toMatch(regexpOrString: RegExp | string): void,
261 | /**
262 | * Use .toMatchObject to check that a javascript object matches a subset of the properties of an object.
263 | */
264 | toMatchObject(object: Object | Array): void,
265 | /**
266 | * This ensures that a React component matches the most recent snapshot.
267 | */
268 | toMatchSnapshot(name?: string): void,
269 | /**
270 | * Use .toThrow to test that a function throws when it is called.
271 | * If you want to test that a specific error gets thrown, you can provide an
272 | * argument to toThrow. The argument can be a string for the error message,
273 | * a class for the error, or a regex that should match the error.
274 | *
275 | * Alias: .toThrowError
276 | */
277 | toThrow(message?: string | Error | Class | RegExp): void,
278 | toThrowError(message?: string | Error | Class | RegExp): void,
279 | /**
280 | * Use .toThrowErrorMatchingSnapshot to test that a function throws a error
281 | * matching the most recent snapshot when it is called.
282 | */
283 | toThrowErrorMatchingSnapshot(): void
284 | };
285 |
286 | type JestObjectType = {
287 | /**
288 | * Disables automatic mocking in the module loader.
289 | *
290 | * After this method is called, all `require()`s will return the real
291 | * versions of each module (rather than a mocked version).
292 | */
293 | disableAutomock(): JestObjectType,
294 | /**
295 | * An un-hoisted version of disableAutomock
296 | */
297 | autoMockOff(): JestObjectType,
298 | /**
299 | * Enables automatic mocking in the module loader.
300 | */
301 | enableAutomock(): JestObjectType,
302 | /**
303 | * An un-hoisted version of enableAutomock
304 | */
305 | autoMockOn(): JestObjectType,
306 | /**
307 | * Clears the mock.calls and mock.instances properties of all mocks.
308 | * Equivalent to calling .mockClear() on every mocked function.
309 | */
310 | clearAllMocks(): JestObjectType,
311 | /**
312 | * Resets the state of all mocks. Equivalent to calling .mockReset() on every
313 | * mocked function.
314 | */
315 | resetAllMocks(): JestObjectType,
316 | /**
317 | * Restores all mocks back to their original value.
318 | */
319 | restoreAllMocks(): JestObjectType,
320 | /**
321 | * Removes any pending timers from the timer system.
322 | */
323 | clearAllTimers(): void,
324 | /**
325 | * The same as `mock` but not moved to the top of the expectation by
326 | * babel-jest.
327 | */
328 | doMock(moduleName: string, moduleFactory?: any): JestObjectType,
329 | /**
330 | * The same as `unmock` but not moved to the top of the expectation by
331 | * babel-jest.
332 | */
333 | dontMock(moduleName: string): JestObjectType,
334 | /**
335 | * Returns a new, unused mock function. Optionally takes a mock
336 | * implementation.
337 | */
338 | fn, TReturn>(
339 | implementation?: (...args: TArguments) => TReturn
340 | ): JestMockFn,
341 | /**
342 | * Determines if the given function is a mocked function.
343 | */
344 | isMockFunction(fn: Function): boolean,
345 | /**
346 | * Given the name of a module, use the automatic mocking system to generate a
347 | * mocked version of the module for you.
348 | */
349 | genMockFromModule(moduleName: string): any,
350 | /**
351 | * Mocks a module with an auto-mocked version when it is being required.
352 | *
353 | * The second argument can be used to specify an explicit module factory that
354 | * is being run instead of using Jest's automocking feature.
355 | *
356 | * The third argument can be used to create virtual mocks -- mocks of modules
357 | * that don't exist anywhere in the system.
358 | */
359 | mock(
360 | moduleName: string,
361 | moduleFactory?: any,
362 | options?: Object
363 | ): JestObjectType,
364 | /**
365 | * Returns the actual module instead of a mock, bypassing all checks on
366 | * whether the module should receive a mock implementation or not.
367 | */
368 | requireActual(moduleName: string): any,
369 | /**
370 | * Returns a mock module instead of the actual module, bypassing all checks
371 | * on whether the module should be required normally or not.
372 | */
373 | requireMock(moduleName: string): any,
374 | /**
375 | * Resets the module registry - the cache of all required modules. This is
376 | * useful to isolate modules where local state might conflict between tests.
377 | */
378 | resetModules(): JestObjectType,
379 | /**
380 | * Exhausts the micro-task queue (usually interfaced in node via
381 | * process.nextTick).
382 | */
383 | runAllTicks(): void,
384 | /**
385 | * Exhausts the macro-task queue (i.e., all tasks queued by setTimeout(),
386 | * setInterval(), and setImmediate()).
387 | */
388 | runAllTimers(): void,
389 | /**
390 | * Exhausts all tasks queued by setImmediate().
391 | */
392 | runAllImmediates(): void,
393 | /**
394 | * Executes only the macro task queue (i.e. all tasks queued by setTimeout()
395 | * or setInterval() and setImmediate()).
396 | */
397 | runTimersToTime(msToRun: number): void,
398 | /**
399 | * Executes only the macro-tasks that are currently pending (i.e., only the
400 | * tasks that have been queued by setTimeout() or setInterval() up to this
401 | * point)
402 | */
403 | runOnlyPendingTimers(): void,
404 | /**
405 | * Explicitly supplies the mock object that the module system should return
406 | * for the specified module. Note: It is recommended to use jest.mock()
407 | * instead.
408 | */
409 | setMock(moduleName: string, moduleExports: any): JestObjectType,
410 | /**
411 | * Indicates that the module system should never return a mocked version of
412 | * the specified module from require() (e.g. that it should always return the
413 | * real module).
414 | */
415 | unmock(moduleName: string): JestObjectType,
416 | /**
417 | * Instructs Jest to use fake versions of the standard timer functions
418 | * (setTimeout, setInterval, clearTimeout, clearInterval, nextTick,
419 | * setImmediate and clearImmediate).
420 | */
421 | useFakeTimers(): JestObjectType,
422 | /**
423 | * Instructs Jest to use the real versions of the standard timer functions.
424 | */
425 | useRealTimers(): JestObjectType,
426 | /**
427 | * Creates a mock function similar to jest.fn but also tracks calls to
428 | * object[methodName].
429 | */
430 | spyOn(object: Object, methodName: string): JestMockFn,
431 | /**
432 | * Set the default timeout interval for tests and before/after hooks in milliseconds.
433 | * Note: The default timeout interval is 5 seconds if this method is not called.
434 | */
435 | setTimeout(timeout: number): JestObjectType
436 | };
437 |
438 | type JestSpyType = {
439 | calls: JestCallsType
440 | };
441 |
442 | /** Runs this function after every test inside this context */
443 | declare function afterEach(
444 | fn: (done: () => void) => ?Promise,
445 | timeout?: number
446 | ): void;
447 | /** Runs this function before every test inside this context */
448 | declare function beforeEach(
449 | fn: (done: () => void) => ?Promise,
450 | timeout?: number
451 | ): void;
452 | /** Runs this function after all tests have finished inside this context */
453 | declare function afterAll(
454 | fn: (done: () => void) => ?Promise,
455 | timeout?: number
456 | ): void;
457 | /** Runs this function before any tests have started inside this context */
458 | declare function beforeAll(
459 | fn: (done: () => void) => ?Promise,
460 | timeout?: number
461 | ): void;
462 |
463 | /** A context for grouping tests together */
464 | declare var describe: {
465 | /**
466 | * Creates a block that groups together several related tests in one "test suite"
467 | */
468 | (name: string, fn: () => void): void,
469 |
470 | /**
471 | * Only run this describe block
472 | */
473 | only(name: string, fn: () => void): void,
474 |
475 | /**
476 | * Skip running this describe block
477 | */
478 | skip(name: string, fn: () => void): void
479 | };
480 |
481 | /** An individual test unit */
482 | declare var it: {
483 | /**
484 | * An individual test unit
485 | *
486 | * @param {string} Name of Test
487 | * @param {Function} Test
488 | * @param {number} Timeout for the test, in milliseconds.
489 | */
490 | (
491 | name: string,
492 | fn?: (done: () => void) => ?Promise,
493 | timeout?: number
494 | ): void,
495 | /**
496 | * Only run this test
497 | *
498 | * @param {string} Name of Test
499 | * @param {Function} Test
500 | * @param {number} Timeout for the test, in milliseconds.
501 | */
502 | only(
503 | name: string,
504 | fn?: (done: () => void) => ?Promise,
505 | timeout?: number
506 | ): void,
507 | /**
508 | * Skip running this test
509 | *
510 | * @param {string} Name of Test
511 | * @param {Function} Test
512 | * @param {number} Timeout for the test, in milliseconds.
513 | */
514 | skip(
515 | name: string,
516 | fn?: (done: () => void) => ?Promise,
517 | timeout?: number
518 | ): void,
519 | /**
520 | * Run the test concurrently
521 | *
522 | * @param {string} Name of Test
523 | * @param {Function} Test
524 | * @param {number} Timeout for the test, in milliseconds.
525 | */
526 | concurrent(
527 | name: string,
528 | fn?: (done: () => void) => ?Promise,
529 | timeout?: number
530 | ): void
531 | };
532 | declare function fit(
533 | name: string,
534 | fn: (done: () => void) => ?Promise,
535 | timeout?: number
536 | ): void;
537 | /** An individual test unit */
538 | declare var test: typeof it;
539 | /** A disabled group of tests */
540 | declare var xdescribe: typeof describe;
541 | /** A focused group of tests */
542 | declare var fdescribe: typeof describe;
543 | /** A disabled individual test */
544 | declare var xit: typeof it;
545 | /** A disabled individual test */
546 | declare var xtest: typeof it;
547 |
548 | /** The expect function is used every time you want to test a value */
549 | declare var expect: {
550 | /** The object that you want to make assertions against */
551 | (value: any): JestExpectType & JestPromiseType & EnzymeMatchersType,
552 | /** Add additional Jasmine matchers to Jest's roster */
553 | extend(matchers: { [name: string]: JestMatcher }): void,
554 | /** Add a module that formats application-specific data structures. */
555 | addSnapshotSerializer(serializer: (input: Object) => string): void,
556 | assertions(expectedAssertions: number): void,
557 | hasAssertions(): void,
558 | any(value: mixed): JestAsymmetricEqualityType,
559 | anything(): void,
560 | arrayContaining(value: Array): void,
561 | objectContaining(value: Object): void,
562 | /** Matches any received string that contains the exact expected string. */
563 | stringContaining(value: string): void,
564 | stringMatching(value: string | RegExp): void
565 | };
566 |
567 | // TODO handle return type
568 | // http://jasmine.github.io/2.4/introduction.html#section-Spies
569 | declare function spyOn(value: mixed, method: string): Object;
570 |
571 | /** Holds all functions related to manipulating test runner */
572 | declare var jest: JestObjectType;
573 |
574 | /**
575 | * The global Jasmine object, this is generally not exposed as the public API,
576 | * using features inside here could break in later versions of Jest.
577 | */
578 | declare var jasmine: {
579 | DEFAULT_TIMEOUT_INTERVAL: number,
580 | any(value: mixed): JestAsymmetricEqualityType,
581 | anything(): void,
582 | arrayContaining(value: Array): void,
583 | clock(): JestClockType,
584 | createSpy(name: string): JestSpyType,
585 | createSpyObj(
586 | baseName: string,
587 | methodNames: Array
588 | ): { [methodName: string]: JestSpyType },
589 | objectContaining(value: Object): void,
590 | stringMatching(value: string): void
591 | };
592 |
--------------------------------------------------------------------------------