├── .editorconfig ├── .github └── dependabot.yml ├── .gitignore ├── LICENSE ├── README.md ├── babel.config.js ├── package-lock.json ├── package.json ├── rollup.config.js ├── src ├── __tests__ │ ├── __snapshots__ │ │ └── createReactContext.test.tsx.snap │ └── createReactContext.test.tsx ├── implementation.ts ├── index.d.ts └── index.ts ├── tsconfig.json └── types ├── gud.d.ts └── tiny-warning.d.ts /.editorconfig: -------------------------------------------------------------------------------- 1 | # Unix-style newlines with a newline ending every file 2 | [*] 3 | end_of_line = lf 4 | insert_final_newline = true 5 | charset = utf-8 6 | 7 | [*.ts,*.tsx, *.js] 8 | indent_style = tab 9 | indent_size = 4 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | end_of_line = lf 14 | insert_final_newline = true 15 | indent_style = space 16 | indent_size = 2 17 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" 5 | schedule: 6 | interval: weekly 7 | time: "04:00" 8 | open-pull-requests-limit: 10 9 | ignore: 10 | - dependency-name: rollup 11 | versions: 12 | - 2.42.1 13 | - 2.43.1 14 | - 2.45.1 15 | - dependency-name: "@babel/core" 16 | versions: 17 | - 7.12.10 18 | - 7.12.13 19 | - 7.12.16 20 | - 7.13.15 21 | - dependency-name: "@types/jest" 22 | versions: 23 | - 26.0.20 24 | - 26.0.21 25 | - 26.0.22 26 | - dependency-name: "@wessberg/rollup-plugin-ts" 27 | versions: 28 | - 1.3.10 29 | - 1.3.11 30 | - 1.3.8 31 | - dependency-name: "@babel/preset-env" 32 | versions: 33 | - 7.13.12 34 | - dependency-name: "@babel/preset-react" 35 | versions: 36 | - 7.13.13 37 | - dependency-name: react 38 | versions: 39 | - 17.0.1 40 | - dependency-name: "@babel/runtime" 41 | versions: 42 | - 7.13.10 43 | - dependency-name: "@types/enzyme" 44 | versions: 45 | - 3.10.8 46 | - dependency-name: "@babel/plugin-proposal-class-properties" 47 | versions: 48 | - 7.13.0 49 | - dependency-name: enzyme-adapter-react-16 50 | versions: 51 | - 1.15.6 52 | - dependency-name: "@types/react" 53 | versions: 54 | - 17.0.0 55 | - 17.0.1 56 | - 17.0.2 57 | - dependency-name: typescript 58 | versions: 59 | - 4.1.3 60 | - 4.1.5 61 | - dependency-name: jest 62 | versions: 63 | - 26.6.3 64 | - dependency-name: babel-jest 65 | versions: 66 | - 26.6.3 67 | - dependency-name: object-path 68 | versions: 69 | - 0.11.5 70 | - dependency-name: lodash 71 | versions: 72 | - 4.17.20 73 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log 3 | dist 4 | coverage 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019-present StringEpsilon 2 | 3 | Copyright (c) 2017-2019 James Kyle 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 | # mini-create-react-context 2 | 3 |

4 | 5 | npm install size 6 | 7 | 8 | npm bundle size 9 | 10 | 11 | npm 12 | 13 |

14 | 15 | > (A smaller) Polyfill for the [React context API](https://github.com/reactjs/rfcs/pull/2) 16 | 17 | ## Install 18 | 19 | ```sh 20 | npm install mini-create-react-context 21 | ``` 22 | 23 | You'll need to also have `react` and `prop-types` installed. 24 | 25 | ## API 26 | 27 | ```js 28 | const Context = createReactContext(defaultValue); 29 | /* 30 | 31 | {children} 32 | 33 | 34 | ... 35 | 36 | 37 | {value => children} 38 | 39 | */ 40 | ``` 41 | 42 | ## Example 43 | 44 | ```js 45 | // @flow 46 | import React, { type Node } from 'react'; 47 | import createReactContext, { type Context } from 'mini-create-react-context'; 48 | 49 | type Theme = 'light' | 'dark'; 50 | // Pass a default theme to ensure type correctness 51 | const ThemeContext: Context = createReactContext('light'); 52 | 53 | class ThemeToggler extends React.Component< 54 | { children: Node }, 55 | { theme: Theme } 56 | > { 57 | state = { theme: 'light' }; 58 | render() { 59 | return ( 60 | // Pass the current context value to the Provider's `value` prop. 61 | // Changes are detected using strict comparison (Object.is) 62 | 63 | 72 | {this.props.children} 73 | 74 | ); 75 | } 76 | } 77 | 78 | class Title extends React.Component<{ children: Node }> { 79 | render() { 80 | return ( 81 | // The Consumer uses a render prop API. Avoids conflicts in the 82 | // props namespace. 83 | 84 | {theme => ( 85 |

86 | {this.props.children} 87 |

88 | )} 89 |
90 | ); 91 | } 92 | } 93 | ``` 94 | 95 | ## Compatibility 96 | 97 | This package only "ponyfills" the `React.createContext` API, not other unrelated React 16+ APIs. If you are using a version of React <16, keep in mind that you can only use features available in that version. 98 | 99 | For example, you cannot pass children types aren't valid pre React 16: 100 | 101 | ```js 102 | 103 |
104 |
105 | 106 | ``` 107 | 108 | It will throw `A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.` because `` can only receive a single child element. To fix the error just wrap everyting in a single `
`: 109 | 110 | ```js 111 | 112 |
113 |
114 |
115 |
116 | 117 | ``` 118 | 119 | ## Size difference to the original: 120 | | | original | **mini** 121 | |------------|----------|----- 122 | |install size| [**50 kB**](https://packagephobia.now.sh/result?p=create-react-context) | [140 kB](https://packagephobia.now.sh/result?p=mini-create-react-context) 123 | |minified | [3.3 kB](https://bundlephobia.com/result?p=create-react-context) | [**2.3kB**](https://bundlephobia.com/result?p=mini-create-react-context) 124 | |minzip | 1.3 kB | **1.0kB** 125 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | [ 4 | "@babel/env", 5 | { 6 | "loose": true, 7 | "targets": { 8 | "browsers": [ 9 | "last 2 versions", 10 | "ie >= 9" 11 | ] 12 | } 13 | } 14 | ], 15 | "@babel/react", 16 | "@babel/typescript" 17 | ], 18 | "plugins": [ 19 | "@babel/plugin-proposal-class-properties", 20 | ] 21 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mini-create-react-context", 3 | "version": "0.4.1", 4 | "description": "Smaller Polyfill for the proposed React context API", 5 | "main": "dist/cjs/index.js", 6 | "module": "dist/esm/index.js", 7 | "types": "dist/index.d.ts", 8 | "repository": "https://github.com/StringEpsilon/mini-create-react-context", 9 | "author": "StringEpsilon", 10 | "license": "MIT", 11 | "keywords": [ 12 | "react", 13 | "context", 14 | "contextTypes", 15 | "polyfill", 16 | "ponyfill" 17 | ], 18 | "files": [ 19 | "dist/**" 20 | ], 21 | "scripts": { 22 | "test": "jest", 23 | "build": "rollup -c rollup.config.js", 24 | "prepublish": "npm run build" 25 | }, 26 | "dependencies": { 27 | "@babel/runtime": "^7.13.10", 28 | "tiny-warning": "^1.0.3" 29 | }, 30 | "peerDependencies": { 31 | "prop-types": "^15.0.0", 32 | "react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" 33 | }, 34 | "devDependencies": { 35 | "@babel/core": "^7.13.14", 36 | "@babel/plugin-proposal-class-properties": "^7.13.0", 37 | "@babel/preset-env": "^7.13.12", 38 | "@babel/preset-react": "^7.13.13", 39 | "@babel/preset-typescript": "^7.13.0", 40 | "@types/enzyme": "^3.10.8", 41 | "@types/jest": "^26.0.22", 42 | "@types/react": "^16.14.5", 43 | "@wessberg/rollup-plugin-ts": "^1.3.11", 44 | "babel-jest": "^26.6.3", 45 | "enzyme": "^3.11.0", 46 | "enzyme-adapter-react-16": "^1.15.6", 47 | "enzyme-to-json": "^3.6.1", 48 | "jest": "^26.6.3", 49 | "prop-types": "^15.6.0", 50 | "raf": "^3.4.1", 51 | "react": "^16.13.1", 52 | "react-dom": "^16.13.1", 53 | "rollup": "^2.44.0", 54 | "rollup-plugin-commonjs": "^10.0.1", 55 | "rollup-plugin-terser": "^7.0.2", 56 | "typescript": "^4.2.3" 57 | }, 58 | "jest": { 59 | "snapshotSerializers": [ 60 | "enzyme-to-json/serializer" 61 | ] 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import ts from "@wessberg/rollup-plugin-ts"; 2 | import path from "path"; 3 | import { terser } from "rollup-plugin-terser"; 4 | 5 | function isBareModuleId(id) { 6 | if (id.startsWith(".")) { 7 | return false; 8 | } 9 | if (id.startsWith("src")) { 10 | return false; 11 | } 12 | return !id.includes(path.join(process.cwd(), "src")); 13 | } 14 | 15 | export default function configureRollup() { 16 | return [ 17 | // CJS: 18 | { 19 | input: "src/index.ts", 20 | output: [ 21 | { file: `dist/cjs/index.js`, format: "cjs", compact: true, exports: "auto"}, 22 | { file: `dist/cjs/index.min.js`, format: "cjs", compact: true, exports: "auto", plugins: [terser()],}, 23 | ], 24 | external: isBareModuleId, 25 | plugins: [ 26 | ts({ 27 | transpiler: "babel", 28 | }), 29 | ], 30 | }, 31 | // ESM: 32 | { 33 | input: "src/index.ts", 34 | output: { file: `dist/esm/index.js`, format: "esm" }, 35 | external: isBareModuleId, 36 | plugins: [ 37 | ts({ 38 | transpiler: "babel", 39 | }), 40 | ], 41 | }, 42 | ]; 43 | } 44 | -------------------------------------------------------------------------------- /src/__tests__/__snapshots__/createReactContext.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`with provider: with provider - after click 1`] = ` 4 | 5 | 8 | 13 | 14 | <Consumer> 15 | <h1 16 | style={ 17 | Object { 18 | "color": "#fff", 19 | } 20 | } 21 | > 22 | Hello World 23 | </h1> 24 | </Consumer> 25 | 26 | 27 | 28 | `; 29 | 30 | exports[`with provider: with provider - init 1`] = ` 31 | 32 | 35 | 40 | 41 | <Consumer> 42 | <h1 43 | style={ 44 | Object { 45 | "color": "#000", 46 | } 47 | } 48 | > 49 | Hello World 50 | </h1> 51 | </Consumer> 52 | 53 | 54 | 55 | `; 56 | 57 | exports[`without provider 1`] = ` 58 | 59 | <Consumer> 60 | <h1 61 | style={ 62 | Object { 63 | "color": "#000", 64 | } 65 | } 66 | > 67 | Hello World 68 | </h1> 69 | </Consumer> 70 | 71 | `; 72 | -------------------------------------------------------------------------------- /src/__tests__/createReactContext.test.tsx: -------------------------------------------------------------------------------- 1 | 2 | import 'raf/polyfill'; 3 | import createReactContext from '../implementation'; 4 | import React from 'react'; 5 | import Enzyme, { mount } from 'enzyme'; 6 | import Adapter from 'enzyme-adapter-react-16'; 7 | 8 | // TODO: Figure out that mess. 9 | Enzyme.configure({ adapter: new (Adapter as () => void)() }); 10 | 11 | type Theme = 'light' | 'dark'; 12 | // Pass a default theme to ensure type correctness 13 | const ThemeContext = createReactContext('light'); 14 | 15 | class ThemeToggler extends React.Component { 16 | constructor(props: any) { 17 | super(props); 18 | this.state = { theme: 'light' }; 19 | } 20 | 21 | render() { 22 | return ( 23 | // Pass the current context value to the Provider's `value` prop. 24 | // Changes are detected using strict comparison (Object.is) 25 | 26 | 37 | {this.props.children} 38 | 39 | ); 40 | } 41 | } 42 | 43 | class Title extends React.Component { 44 | shouldComponentUpdate() { 45 | return false; 46 | } 47 | 48 | render() { 49 | return ( 50 | // The Consumer uses a render prop API. Avoids conflicts in the 51 | // props namespace. 52 | 53 | {theme => ( 54 |

55 | {this.props.children} 56 |

57 | )} 58 |
59 | ); 60 | } 61 | } 62 | 63 | test('without provider', () => { 64 | const wrapper = mount(Hello World ); 65 | expect(wrapper).toMatchSnapshot(); 66 | }); 67 | 68 | test('with provider', () => { 69 | const wrapper = mount( 70 | 71 | Hello World 72 | 73 | ); 74 | 75 | expect(wrapper).toMatchSnapshot('with provider - init'); 76 | wrapper.find('button').simulate('click'); 77 | expect(wrapper).toMatchSnapshot('with provider - after click'); 78 | }); 79 | 80 | test('can skip consumers with bitmask', () => { 81 | let renders = { Foo: 0, Bar: 0 }; 82 | 83 | const Context = createReactContext({ foo: 0, bar: 0 }, (a, b) => { 84 | let result = 0; 85 | if (a.foo !== b.foo) { 86 | result |= 0b01; 87 | } 88 | if (a.bar !== b.bar) { 89 | result |= 0b10; 90 | } 91 | return result; 92 | }); 93 | 94 | function Provider(props) { 95 | return ( 96 | 97 | {props.children} 98 | 99 | ); 100 | } 101 | 102 | function Foo() { 103 | return ( 104 | 105 | {value => { 106 | renders.Foo += 1; 107 | return ; 108 | } 109 | } 110 | 111 | ); 112 | } 113 | 114 | function Bar() { 115 | return ( 116 | 117 | {value => { 118 | renders.Bar += 1; 119 | return ; 120 | } 121 | } 122 | 123 | ); 124 | } 125 | 126 | class Indirection extends React.Component { 127 | shouldComponentUpdate() { 128 | return false; 129 | } 130 | render() { 131 | return this.props.children; 132 | } 133 | } 134 | 135 | function App(props) { 136 | return ( 137 | 138 | 139 | 140 | 141 | 142 | < Indirection > 143 | 144 | 145 | 146 | 147 | ); 148 | } 149 | 150 | const wrapper = mount(); 151 | expect(renders.Foo).toBe(1); 152 | expect(renders.Bar).toBe(1); 153 | expect(wrapper.contains()).toBe(true); 154 | expect(wrapper.contains()).toBe(true); 155 | 156 | // Update only foo 157 | wrapper.setProps({ foo: 2, bar: 1 }); 158 | expect(renders.Foo).toBe(2); 159 | expect(renders.Bar).toBe(1); 160 | expect(wrapper.contains()).toBe(true); 161 | expect(wrapper.contains()).toBe(true); 162 | 163 | // Update only bar 164 | wrapper.setProps({ bar: 2, foo: 2 }); 165 | expect(renders.Foo).toBe(2); 166 | expect(renders.Bar).toBe(2); 167 | expect(wrapper.contains()).toBe(true); 168 | expect(wrapper.contains()).toBe(true); 169 | 170 | // Update both 171 | wrapper.setProps({ bar: 3, foo: 3 }); 172 | expect(renders.Foo).toBe(3); 173 | expect(renders.Bar).toBe(3); 174 | expect(wrapper.contains()).toBe(true); 175 | expect(wrapper.contains()).toBe(true); 176 | }); 177 | 178 | test('warns if calculateChangedBits returns larger than a 31-bit integer', () => { 179 | global.console.warn = jest.fn(); 180 | 181 | const Context = createReactContext( 182 | 0, 183 | (a, b) => Math.pow(2, 32) - 1 // Return 32 bit int 184 | ); 185 | 186 | const wrapper = mount( 187 | 188 | {value => value} 189 | 190 | ); 191 | 192 | // Update 193 | wrapper.setProps({ value: 2 }); 194 | 195 | wrapper.unmount(); 196 | 197 | if (process.env.NODE_ENV !== 'production') { 198 | expect(console.warn).toHaveBeenCalledTimes(1); 199 | expect(console.warn).lastCalledWith( 200 | 'Warning: calculateChangedBits: Expected the return value to be a 31-bit integer. Instead received: 4294967295' 201 | ); 202 | } 203 | (global.console.warn as jest.Mock).mockRestore(); 204 | }); 205 | -------------------------------------------------------------------------------- /src/implementation.ts: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import warning from 'tiny-warning'; 4 | 5 | const MAX_SIGNED_31_BIT_INT = 1073741823; 6 | 7 | const commonjsGlobal: any = 8 | typeof globalThis !== 'undefined' // 'global proper' 9 | ? globalThis 10 | : typeof window !== 'undefined' 11 | ? window // Browser 12 | : typeof global !== 'undefined' 13 | ? global // node.js 14 | : {} 15 | 16 | 17 | function getUniqueId() { 18 | const key = '__global_unique_id__'; 19 | return commonjsGlobal[key] = (commonjsGlobal[key] || 0) + 1; 20 | } 21 | 22 | // Inlined Object.is polyfill. 23 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is 24 | function objectIs(x: any, y: any) { 25 | if (x === y) { 26 | return x !== 0 || 1 / x === 1 / y; 27 | } else { 28 | return x !== x && y !== y; 29 | } 30 | } 31 | 32 | 33 | export type ConsumerState = { 34 | value: T 35 | }; 36 | 37 | type RenderFn = (value: T) => React.ReactNode; 38 | 39 | export type Context = { 40 | Provider: React.ComponentClass>; 41 | Consumer: React.ComponentClass>; 42 | }; 43 | 44 | export type ProviderProps = { 45 | value: T; 46 | children?: React.ReactNode; 47 | observedBits?: any, 48 | }; 49 | 50 | export type ConsumerProps = { 51 | children: RenderFn | [RenderFn]; 52 | observedBits?: number; 53 | }; 54 | 55 | 56 | 57 | function createEventEmitter(value: any) { 58 | let handlers: any[] = []; 59 | return { 60 | on(handler: any) { 61 | handlers.push(handler); 62 | }, 63 | 64 | off(handler: any) { 65 | handlers = handlers.filter(h => h !== handler); 66 | }, 67 | 68 | get() { 69 | return value; 70 | }, 71 | 72 | set(newValue: any, changedBits: any) { 73 | value = newValue; 74 | handlers.forEach(handler => handler(value, changedBits)); 75 | } 76 | }; 77 | } 78 | 79 | function onlyChild(children: any): any { 80 | return Array.isArray(children) ? children[0] : children; 81 | } 82 | 83 | export default function createReactContext(defaultValue: T, calculateChangedBits?: (a: T, b: T) => number): Context { 84 | const contextProp = '__create-react-context-' + getUniqueId() + '__'; 85 | 86 | class Provider extends Component> { 87 | emitter = createEventEmitter(this.props.value); 88 | 89 | static childContextTypes = { 90 | [contextProp]: PropTypes.object.isRequired 91 | }; 92 | 93 | getChildContext() { 94 | return { 95 | [contextProp]: this.emitter 96 | }; 97 | } 98 | 99 | componentWillReceiveProps(nextProps: any) { 100 | if (this.props.value !== nextProps.value) { 101 | let oldValue = this.props.value; 102 | let newValue = nextProps.value; 103 | let changedBits: number; 104 | 105 | if (objectIs(oldValue, newValue)) { 106 | changedBits = 0; // No change 107 | } else { 108 | changedBits = 109 | typeof calculateChangedBits === 'function' 110 | ? calculateChangedBits(oldValue, newValue) 111 | : MAX_SIGNED_31_BIT_INT; 112 | if (process.env.NODE_ENV !== 'production') { 113 | warning( 114 | (changedBits & MAX_SIGNED_31_BIT_INT) === changedBits, 115 | 'calculateChangedBits: Expected the return value to be a ' + 116 | '31-bit integer. Instead received: ' + changedBits, 117 | ); 118 | } 119 | 120 | changedBits |= 0; 121 | 122 | if (changedBits !== 0) { 123 | this.emitter.set(nextProps.value, changedBits); 124 | } 125 | } 126 | } 127 | } 128 | 129 | render() { 130 | return this.props.children; 131 | } 132 | } 133 | 134 | class Consumer extends Component, ConsumerState> { 135 | static contextTypes = { 136 | [contextProp]: PropTypes.object 137 | }; 138 | 139 | observedBits!: number; 140 | 141 | state: ConsumerState = { 142 | value: this.getValue() 143 | }; 144 | 145 | componentWillReceiveProps(nextProps: any) { 146 | let { observedBits } = nextProps; 147 | this.observedBits = 148 | observedBits === undefined || observedBits === null 149 | ? MAX_SIGNED_31_BIT_INT // Subscribe to all changes by default 150 | : observedBits; 151 | } 152 | 153 | componentDidMount() { 154 | if (this.context[contextProp]) { 155 | this.context[contextProp].on(this.onUpdate); 156 | } 157 | let { observedBits } = this.props; 158 | this.observedBits = 159 | observedBits === undefined || observedBits === null 160 | ? MAX_SIGNED_31_BIT_INT // Subscribe to all changes by default 161 | : observedBits; 162 | } 163 | 164 | componentWillUnmount() { 165 | if (this.context[contextProp]) { 166 | this.context[contextProp].off(this.onUpdate); 167 | } 168 | } 169 | 170 | getValue(): T { 171 | if (this.context[contextProp]) { 172 | return this.context[contextProp].get(); 173 | } else { 174 | return defaultValue; 175 | } 176 | } 177 | 178 | onUpdate = (newValue: any, changedBits: number) => { 179 | const observedBits: number = this.observedBits | 0; 180 | if ((observedBits & changedBits) !== 0) { 181 | this.setState({ value: this.getValue() }); 182 | } 183 | }; 184 | 185 | render() { 186 | return onlyChild(this.props.children)(this.state.value); 187 | } 188 | } 189 | 190 | return { 191 | Provider, 192 | Consumer 193 | }; 194 | } 195 | 196 | -------------------------------------------------------------------------------- /src/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | export default function createReactContext( 4 | defaultValue: T, 5 | calculateChangedBits?: (prev: T, next: T) => number 6 | ): Context; 7 | 8 | type RenderFn = (value: T) => React.ReactNode; 9 | 10 | export type Context = { 11 | Provider: React.ComponentClass>; 12 | Consumer: React.ComponentClass>; 13 | }; 14 | 15 | export type ProviderProps = { 16 | value: T; 17 | children?: React.ReactNode; 18 | observedBits?: any, 19 | }; 20 | 21 | export type ConsumerProps = { 22 | children: RenderFn | [RenderFn]; 23 | observedBits?: number; 24 | }; 25 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import createReactContext from './implementation'; 3 | 4 | export default React.createContext || createReactContext; 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "paths": { 5 | "*": [ 6 | "types/*" 7 | ] 8 | }, 9 | "moduleResolution": "node", 10 | "jsx": "react", 11 | "module": "es2015", 12 | "removeComments": true, 13 | "lib": [ 14 | "es2015", 15 | "es2016", 16 | "dom" 17 | ], 18 | "strict": true, 19 | "allowSyntheticDefaultImports": true, 20 | "typeRoots": [ 21 | "node_modules/@types" 22 | ], 23 | "noImplicitAny": true, 24 | "noImplicitReturns": true, 25 | "resolveJsonModule": true, 26 | "declaration": false, 27 | }, 28 | "include": [ 29 | "src" 30 | ], 31 | "exclude": [ 32 | "node_modules", 33 | "**/__tests__/**" 34 | ] 35 | } -------------------------------------------------------------------------------- /types/gud.d.ts: -------------------------------------------------------------------------------- 1 | export = index; 2 | declare function index(): any; 3 | -------------------------------------------------------------------------------- /types/tiny-warning.d.ts: -------------------------------------------------------------------------------- 1 | export default function warning(condition: any, message: string): void --------------------------------------------------------------------------------