@webkrafters/react-observable-context 4.7.3 → 4.7.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +9 -699
  2. package/package.json +6 -4
package/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <p align="center">
2
- <img alt="Eagle Eye" height="150px" src="eagle-eye.png" width="250px" />
2
+ <img alt="Eagle Eye" height="150px" src="/docs/public/img/logo.png" width="250px" />
3
3
  </p>
4
4
  <p align="center">
5
5
  <a href="https://typescriptlang.org">
@@ -23,10 +23,10 @@
23
23
  # React-Observable-Context [Eagle Eye]
24
24
 
25
25
  <ul>
26
- <li> Update-friendly context.</li>
27
- <li> A context bearing an observable consumer <a href="#store">store</a>.</li>
28
- <li> Recognizes <b>negative array indexing</b>. Please see <a href="#property-path">Property Path</a> and <code>store.setState</code> <a href="#indexing">Indexing</a>.</li>
29
- <li> Only re-renders subscribing components (<a href="#client">clients</a>) on context state changes.</li>
26
+ <li> Auto-immutable update-friendly context. See <a href="https://eagleeyejs.org/concepts/store/setstate"><code>store.setState</code></a>.</li>
27
+ <li> A context bearing an observable consumer <a href="https://eagleeyejs.org/concepts/store">store</a>.</li>
28
+ <li> Recognizes <b>negative array indexing</b>. Please see <a href="https://eagleeyejs.org/concepts/property-path">Property Path</a> and <code>store.setState</code> <a href="https://eagleeyejs.org/concepts/store/setstate#indexing">Indexing</a>.</li>
29
+ <li> Only re-renders subscribing components (<a href="https://eagleeyejs.org/concepts/client">clients</a>) on context state changes.</li>
30
30
  <li> Subscribing component decides which context state properties' changes to trigger its update.</li>
31
31
  </ul>
32
32
 
@@ -34,7 +34,7 @@
34
34
 
35
35
  **Moniker:** Eagle Eye
36
36
 
37
- **Usage:** Please see <b><a href="#getting-started">Getting Started</a></b>.
37
+ **Usage:** Please see <b><a href="https://eagleeyejs.org/getting-started">Getting Started</a></b>.
38
38
 
39
39
  **Demo:** [Play with the app on codesandbox](https://codesandbox.io/s/github/webKrafters/react-observable-context-app)\
40
40
  If sandbox fails to load app, please refresh dependencies on its lower left.
@@ -43,700 +43,10 @@ If sandbox fails to load app, please refresh dependencies on its lower left.
43
43
  npm i -S @webkrafters/react-observable-context\
44
44
  npm install --save @webkrafters/react-observable-context
45
45
 
46
- May also see <b><a href="#changes">What's Changed?</a></b>.
46
+ May also see <b><a href="https://eagleeyejs.org/history/features">What's Changed?</a></b>
47
47
 
48
- <h1 id="toc">Table of Contents</h1>
49
-
50
- <a href="#intro">Intro</a><br /><a href="#getting-started">Getting Started</a><br />
51
- &nbsp;&nbsp;&nbsp;&nbsp;<a href="#create-context-usage">Creating context</a><br />
52
- &nbsp;&nbsp;&nbsp;&nbsp;<a href="#provider-usage">Setting up the Provider</a><br />
53
- &nbsp;&nbsp;&nbsp;&nbsp;<a href="#connect-usage">Consuming context (hoc method)</a><br />
54
- &nbsp;&nbsp;&nbsp;&nbsp;<a href="#usecontext-usage">Consuming context (hook with memo method)</a><br />
55
- <a href="#api">API</a><br />
56
- &nbsp;&nbsp;&nbsp;&nbsp;<a href="#connect">Connect HoC</a><br />
57
- &nbsp;&nbsp;&nbsp;&nbsp;<a href="#create-context">CreateContext Function</a><br />
58
- &nbsp;&nbsp;&nbsp;&nbsp;<a href="#usage-error">UsageError Exception</a><br />
59
- &nbsp;&nbsp;&nbsp;&nbsp;<a href="#usecontext">UseContext Hook</a><br />
60
- <a href="#concepts">Concepts</a><br />
61
- &nbsp;&nbsp;&nbsp;&nbsp;<a href="#client">Client</a><br />
62
- &nbsp;&nbsp;&nbsp;&nbsp;<a href="#prehooks">Prehooks</a><br />
63
- &nbsp;&nbsp;&nbsp;&nbsp;<a href="#property-path">Property Path</a><br />
64
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#fullstate-selectorkey"><b>@@STATE</b></a><br />
65
- &nbsp;&nbsp;&nbsp;&nbsp;<a href="#provider">Provider</a><br />
66
- &nbsp;&nbsp;&nbsp;&nbsp;<a href="#selector-map">Selector Map</a><br />
67
- &nbsp;&nbsp;&nbsp;&nbsp;<a href="#storage">Storage</a><br />
68
- &nbsp;&nbsp;&nbsp;&nbsp;<a href="#store">Store</a><br />
69
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#store-resetstate">Reset State</a><br />
70
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#store-setstate">Set State</a><br />
71
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#batched-update">Batched Update</a><br />
72
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#indexing">Array Indexing</a><br />
73
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#setstate-tags">Using Tag Commands</a><br />
74
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#clear-tag-usage"><b>@@CLEAR</b> Usage Example</a><br />
75
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#delete-tag-usage"><b>@@DELETE</b> Usage Example</a><br />
76
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#move-tag-usage"><b>@@MOVE</b> Usage Example</a><br />
77
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#push-tag-usage"><b>@@PUSH</b> Usage Example</a><br />
78
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#replace-tag-usage"><b>@@REPLACE</b> Usage Example</a><br />
79
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#set-tag-usage"><b>@@SET</b> Usage Example</a><br />
80
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#splice-tag-usage"><b>@@SPLICE</b> Usage Example</a><br />
81
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#set-state-with-tags">Combination Usage Example</a><br />
82
- <a href="#changes">What's Changed?</a><br />
83
- <a href="#license">License</a><br />
84
-
85
- # Intro
86
-
87
- A context bearing an observable consumer [store](#store) whose internal state is <u><b>immutable</b></u> and <u><b>private</b></u>. State changes within the store's internal state are only broadcasted to components (the [clients](#client)) subscribed to the store. In this way, the `React-Observable-Context` prevents repeated automatic re-renderings of entire component trees resulting from ***context*** state changes.
88
-
89
- <h1 id="getting-started">Getting Started</h1>
90
-
91
- <i><b><u>index.js</u></b></i>
92
-
93
- ```jsx
94
- import React from 'react';
95
- import ReactDOM from 'react-dom';
96
- import App from './app';
97
-
98
- ReactDOM.render( <App />, document.getElementById( 'root' ) );
99
- ```
100
-
101
- <i><b><u>app.js</u></b></i>
102
-
103
- ```jsx
104
- import React, { useEffect, useState } from 'react';
105
- import ProviderDeno from './provider-demo';
106
-
107
- const MILLIS_PER_MINUTE = 6e4;
108
-
109
- let numCreated = 0;
110
-
111
- const App = () => {
112
- const [ age, updateAge ] = useState( 0 );
113
- const [ testNumber ] = useState( () => ++numCreated );
114
-
115
- useEffect(() => {
116
- const t = setTimeout(
117
- () => updateAge( age => age + 1 ),
118
- MILLIS_PER_MINUTE
119
- );
120
- return () => clearTimeout( t );
121
- }, [ age ]);
122
-
123
- return (
124
- <div>
125
- <h2>App instance #: { testNumber }</H2>
126
- <ProviderDeno ageInMinutes={ age } />
127
- </div>
128
- );
129
- }
130
- export default App;
131
- ```
132
-
133
- <i id="create-context-usage"><u><b>context.js</b></u></i>
134
-
135
- ```jsx
136
- import { createContext } from '@webkrafters/react-observable-context';
137
- export default createContext();
138
- ```
139
-
140
- <i id="provider-usage"><b><u>provider-demo.js</u></b></i>
141
-
142
- ```jsx
143
- import React, { useEffect, useState } from 'react';
144
- import ObservableContext from './context';
145
- import Ui from './ui';
146
-
147
- const createInitialState = c = ({
148
- a: { b: { c, x: { y: { z: [ 2022 ] } } } }
149
- });
150
-
151
- const ProviderDemo = ({ ageInMinutes: c = 0 }) => {
152
-
153
- const [ value, setValue ] = useState(() => createInitialState( c ));
154
-
155
- useEffect(() => {
156
- // similar to `store.setState`, use the following to update
157
- // only the changed slice of the context internal state.
158
- // Please use the `Set State` link in the TOC for more details.
159
- setValue({ a: { b: { c } } }); // OR
160
- // setValue({ a: { b: { c: { '@@REPLACE': c } } } });
161
- // Do not do the following: it will override the context internal state.
162
- // setValue({ ...value, a: { ...value.a, b: { ...value.a.b, c } } });
163
- }, [ c ]);
164
-
165
- return (
166
- <ObservableContext.Provider value={ value }>
167
- <Ui />
168
- </ObservableContext.Provider>
169
- );
170
- };
171
- ProviderDemo.displayName = 'ProviderDemo';
172
-
173
- export default ProviderDemo;
174
- ```
175
-
176
- <i id="connect-usage"><u><b>ui.js</b></u> (connect method)</i>
177
-
178
- ```jsx
179
- import React, { useCallback, useEffect } from 'react';
180
- import { connect } from '@webkrafters/react-observable-context';
181
- import ObservableContext from './context';
182
-
183
- export const YearText = ({ data }) => ( <div>Year: { data.year }</div> );
184
-
185
- export const YearInput = ({ data, resetState, setState }) => {
186
- const onChange = useCallback( e => setState({
187
- a: { b: { x: { y: { z: { 0: e.target.value } } } } }
188
- }), [ setState ]);
189
-
190
- useEffect(() => {
191
- data.year > 2049 && resetState([ 'a.b.c' ]);
192
- }, [ data.year ]);
193
-
194
- return ( <div>Year: <input type="number" onChange={ onChange } /></div> );
195
- };
196
-
197
- const withConnector = connect( ObservablContext, { year: 'a.b.x.y.z[0]' } );
198
- const Client1 = withConnector( YearText );
199
- const Client2 = withConnector( YearInput );
200
-
201
- const Ui = () => (
202
- <div>
203
- <Client1 />
204
- <Client2 />
205
- </div>
206
- );
207
-
208
- export default Ui;
209
- ```
210
-
211
- <i id="usecontext-usage"><u><b>ui.js</b></u> (useContext with memo method)</i>
212
-
213
- ```jsx
214
- import React, { memo, useCallback, useEffect } from 'react';
215
- import { useContext } from '@webkrafters/react-observable-context';
216
- import ObservableContext from './context';
217
-
218
- const selectorMap = { year: 'a.b.x.y.z[0]' };
219
-
220
- const Client1 = memo(() => { // memoize to prevent 'no-change' renders from the parent.
221
- const { data } = useContext( ObservableContext, selectorMap );
222
- return ( <div>Year: { data.year }</div> );
223
- });
224
-
225
- const Client2 = memo(() => { // memoize to prevent 'no-change' renders from the parent.
226
- const { data, setState, resetState } = useContext( ObservableContext, selectorMap );
227
-
228
- const onChange = useCallback( e => setState({
229
- a: { b: { x: { y: { z: { 0: e.target.value } } } } }
230
- }), [ setState ]);
231
-
232
- useEffect(() => {
233
- data.year > 2049 && resetState([ 'a.b.c' ]);
234
- }, [ data.year ]);
235
-
236
- return ( <div>Year: <input type="number" onChange={ onChange } /></div> );
237
- });
238
-
239
- const Ui = () => (
240
- <div>
241
- <Client1 />
242
- <Client2 />
243
- </div>
244
- );
245
-
246
- export default Ui;
247
- ```
248
-
249
- # API
250
-
251
- The React-Observable-Context module exports named constants and the following **4** main entities namely:
252
- <ol>
253
- <li style="padding-bottom: 5px">
254
- <p style="margin: 0 0 5px 5px">
255
- <b id="connect">connect</b>
256
- <p style="margin: -5px 0 0 5px">
257
- <span style="margin: 5px 10px 0 0">-</span>is a function taking a <code>React-Observable-Context</code> context object and an optional <a href="#selector-map">selector map</a> parameters; and returning a reusable connector function.<br />
258
- <span style="margin: 5px 10px 0 0">-</span>The connector function takes a client as a parameter and returns an HOC.<br />
259
- <span style="margin: 5px 10px 0 0">-</span>Any client using similar context object and selector map may be passed to this connector.<br />
260
- <span style="margin: 5px 10px 0 0">-</span>The HOC injects the context <a href="#store">store</a> to the client and handles all of the context usage requirements.<br />
261
- <span style="margin: 5px 10px 0 0">-</span>The injected <a href="#store">store</a> monitors changes in the underlying state slices referenced by the selector map.<br />
262
- <span style="margin: 5px 10px 0 0">-</span>A change in any of the referenced state slices automatically triggers an update of the related <code>store.data</code> property and a subsequent render of the client.<br />
263
- <span style="margin: 5px 10px 0 0">-</span>Any prop name conflicts between injected <a href="#store">store properties</a> and the client's own props are resolved in favor of the client's own props.
264
- </p>
265
- </p>
266
- </li>
267
- <li style="padding-bottom: 5px">
268
- <p style="margin: 0 0 5px 5px">
269
- <b id="create-context">createContext</b> is a zero-parameter function returning a <code>React-Observable-Context</code> object. This object is the store-bearing context. To access the context's <a href="#store">store</a>, pass the context as a <code>context</code> parameter to either the <a href="#connect">connect</a> function or the <a href="#usecontext">useContext</a> hook.
270
- </p>
271
- </li>
272
- <li style="padding-bottom: 5px">
273
- <p style="margin: 0 0 5px 5px">
274
- <b id="usage-error">UsageError</b> class is the Error type reported for attempts to access this context's store outside of its Provider component tree.
275
- </p>
276
- </li>
277
- <li>
278
- <p style="margin: 0 0 5px 5px">
279
- <b id="usecontext">useContext</b>
280
- <p style="margin: -5px 0 0 5px">
281
- <span style="margin: 5px 10px 0 0">-</span>is a hook taking a <code>React-Observable-Context</code> context object and an optional <a href="#selector-map">selector map</a> parameters; and returning the context <a href="#store">store</a>.<br />
282
- <span style="margin: 5px 10px 0 0">-</span>The injected <a href="#store">store</a> monitors changes in the underlying state slices referenced by the selector map.<br />
283
- <span style="margin: 5px 10px 0 0">-</span>A change in any of the referenced state slices automatically triggers an update of the related <code>store.data</code> property and a subsequent render of the client.<br />
284
- <span style="margin: 5px 10px 0 0">-</span>The <a href="#connect">connect</a> function is axiomatically the more conducive method for consuming this conetxt.<br />
285
- <span style="margin: 5px 10px 0 0">-</span>In certain user-specific cases, direct access to this hook may be preferrable.<br />
286
- <span style="margin: 5px 10px 0 0">-</span>In such cases, it is advisable to wrap the client in a <code>React.memo</code>.
287
- </p>
288
- </p>
289
- </li>
290
- </ol>
291
-
292
- # Concepts
293
-
294
- ## Client
295
- A client is any component consuming the observable context. A client consumes the context either by using the <code>React-Observable-Context <a href="#usecontext">useContext</a></code> hook or by embedding itself within the connector returned by the <code>React-Observable-Context <a href="#connect">connect</a></code> function.
296
-
297
- ## Prehooks
298
- Prehooks provide a central place for sanitizing, modifying, transforming, validating etc. all related incoming state updates. The context store obtains its prehooks via its context [Provider's](#provider) `prehooks` optional prop.
299
-
300
- The context store **2** update operations each adhere to its own user-defined prehook when present. Otherwise, the update operation proceeds normally to completion. Thus, there are **2** prehooks named **resetState** and **setState** - after the store update methods they support.
301
-
302
- Each prehook returns a **boolean** value (`true` to continue AND `false` to abort the update operation). The prehook may modify (i.e. sanitize, transform, transpose) the argument to accurately reflect the intended update value. This is done by mutating part of the argument which holds the next `nextUpdate` values.
303
- <ol>
304
- <li>
305
- <p style="margin: 0 0 5px 10px">
306
- <b>resetState:</b>
307
- <code style="margin: 10px 5px">(resetData: PartialState&lt;State&gt;, state: {current: State, original: State}) => boolean;</code> // <b><i><code>resetData</code></i></b> holds the <code>nextUpdate</code> values.
308
- </p>
309
- </li>
310
- <li>
311
- <p style="margin: 0 0 5px 10px">
312
- <b>setState:</b>
313
- <code style="margin: 10px 5px">(newChanges: PartialState&lt;State&gt;) => boolean;</code> // <b><i><code>newChanges</code></i></b> holds the <code>nextUpdate</code> values.
314
- </p>
315
- </li>
316
- </ol>
317
-
318
- ***<u>Use case:</u>*** prehooks provide a central place for sanitizing, modifying, transforming, validating etc. all related incoming state updates.
319
-
320
- <h2 id="property-path">Property path</h2>
321
- A property path is a dot-notation string leading to a specific property within an object.<br />
322
- <code>React-Observable-Context</code> recognizes any property path abiding by the <b><i><u>Lodash</u></i></b> property path specifications. Such property paths may also contain negative integers.<br /><br />
323
-
324
- <b>Negative</b> integer (<i>-N</i>) in a property path indicates an array index derived at runtime by counting `abs(-N)` steps backward from array length.<br />
325
-
326
- <b id="property-path-example">Ex. Given the following object:</b>
327
-
328
- ```jsx
329
- { a: { c: { e: 5, f: [ 0, 2, 4 ] } } }
330
- ```
331
- The property path `a.c.e` accesses the `e=5` property.<br />
332
- Either of the property paths `a.c.f.1`, `a.c.f.-2`, `a.c.f[1]` and `a.c.f[-2]` is a valid property path to access the `[1]=2` property.<br />
333
- A special property path [@@STATE](#fullstate-selectorkey) may be used to access the full given object.<br />
334
-
335
- <strong id="fullstate-selectorkey"><u>@@STATE</u></strong> is a special property path to access the full state object as a single slice.<br />
336
- :warning: <b><i>Caution:</i></b> When this property path exists in a <a href="#selector-map">selector map</a>, any change in the state object results in an update of its <a href="#store"><code>store.data</code></a> and a subsequent render of its client(s).
337
-
338
- ## Provider
339
- The Provider component is a property of the `React-Observable-Context` context object. As a `React.context` based provider, it accepts the customary `children` and `value` props. It also accepts **2** optional props: <a href="#prehooks"><code>prehooks</code></a> and <a href="#storage"><code>storage</code></a>.
340
-
341
- External direct access to the context store may be obtained via the `ref` attribute. Please see a [Provider Usage](#provider-usage) sample.
342
-
343
- Routinely, the `value` prop is initialized with the full initial state. It may only be updated with parts of the state which are changing. Please see a [Provider Usage](#provider-usage) sample.
344
-
345
- <h2 id="selector-map">Selector Map</h2>
346
- A selector map is an object holding key:value pairs.<br />
347
- <i><b>An array of <a href="#property-path">property paths</a> is also acceptable:</b> indexes serve as keys for this purpose.</i><br />
348
- <span style="margin-right: 10px">-</span><code>key</code> refers to an arbitrary name to be assigned to a given property in the <a href="#store"><code>store.data</code></a>.<br />
349
- <span style="margin-right: 10px">-</span><code>value</code> refers to the <a href="#property-path">property path</a> leading to a state slice whose value will be assigned to and observed by this <a href="#store"><code>store.data</code></a> property.<br />
350
- <span style="margin-right: 10px">-</span>A special '<a href="#fullstate-selectorkey">@@STATE</a>' value may be used to access and observe the full state object.<br />
351
-
352
- <strong id="selector-map-example">Example:</strong>
353
-
354
- ```jsx
355
- // Given the following state object:
356
- const state = {
357
- a: 1, b: 2, c: 3, d: {
358
- e: 5,
359
- f: [ 6, {
360
- x: 7,
361
- y: 8,
362
- z: 9
363
- } ]
364
- }
365
- };
366
-
367
- /* --------------------------------------------- */
368
- /* a client observing the following selector map */
369
- /* --------------------------------------------- */
370
- const selectorMap = {
371
- all: '@@STATE',
372
- myData: 'd',
373
- secondFElement: 'd.f[1]'
374
- };
375
-
376
- // will receive the following store data
377
- store.data = {
378
- all: state,
379
- myData: state.d,
380
- secondFElement: state.d.f[1]
381
- };
382
-
383
- /* --------------------------------------------------- */
384
- /* a client observing the following property path list */
385
- /* --------------------------------------------------- */
386
- const propertyPaths = [ '@@STATE', 'd', 'd.f[1]' ];
387
-
388
- // will receive the following store data
389
- store.data = {
390
- 0: state,
391
- 1: state.d,
392
- 2: state.d.f[1]
393
- };
394
-
395
- ```
396
-
397
- ## Storage
398
- The `React.Observable.Context` context allows for a user-defined Storage object to be provided for maintaining the integrity of the initial context state at a location of the user's choosing. This, it accepts, via its Provider's `storage` optional prop. The context defaults to `window.sessionstorage` in supporting environments. Otherwise, it defaults to its own internal memory-based storage.
399
-
400
- A valid storage object is of the type: `IStorage<State>` implementing the following **4** methods:
401
- <ol>
402
- <li><code style="margin-left: 10px">clone: (data: State) => State; // expects a state clone</code></li>
403
- <li><code style="margin-left: 10px">getItem: (key: string) => State;</code></li>
404
- <li><code style="margin-left: 10px">removeItem: (key: string) => void;</code></li>
405
- <li><code style="margin-left: 10px">setItem: (key: string, data: State) => void;</code></li>
406
- </ol>
407
-
408
- ## Store
409
- The `React.Observable.Context` context `store` is the client's portal into the context's underlying state. It exposes **3** properties namely:
410
- <ol>
411
- <li>
412
- <p style="margin: 0 0 0 10px">
413
- <b>data:</b>
414
- <span style="margin-left: 5px">
415
- which is an object holding resolved state slices as declared in the selector map. <a href="#selector-map-example">See selector map to store data example here</a>
416
- </span>
417
- </p>
418
- </li>
419
- <li>
420
- <p style="margin: 0 0 0 10px">
421
- <a href="#store-resetstate"><b>resetState:</b></a>
422
- <code style="margin-left: 5px">(propertyPaths?: Array&lt;string&gt;) => void // resets slices of state referenced by the property paths to their initial values.</code>
423
- </p>
424
- </li>
425
- <li>
426
- <p style="margin: 0 0 0 10px">
427
- <a href="#store-setstate"><b>setState:</b></a>
428
- <code style="margin-left: 5px">(changes: Changes&lt;State&gt;) => void // merges only new/changed state slices.</code>
429
- </p>
430
- </li>
431
- </ol>
432
- <h3 id="store-resetstate"><code>store.resetState</code> Usage</h3>
433
- <span style="margin: 5px 10px 0 0">-</span>Resets slices of state to their initial state values as desired.<br />
434
- <span style="margin: 5px 10px 0 0">-</span>Accepts an array of property paths referencing the desired slices of state to reset.<br />
435
- <span style="margin: 5px 10px 0 0">-</span>Performs a total state reset when <code>'@@STATE'</code> is present in the property paths array.<br />
436
- <span style="margin: 5px 10px 0 0">-</span>Resets state slices referenced by the calling client's selector map when invoked with 0 arguments.<br />
437
- <span style="margin: 5px 10px 0 16px">-</span>Performs a total state reset when <code>'@@STATE'</code> is present in the calling client's selector map.<br />
438
- <span style="margin: 5px 10px 0 0">-</span>Performs no state reset when a client with no selector map invokes this method with 0 arguments.
439
-
440
- <h3 id="store-setstate" style="margin-top:10px"><code>store.setState</code> Usage</h3>
441
-
442
- <blockquote>[This store's] internal state is <u><b>immutable</b></u> and <u><b>private</b></u>.<br />Direct mutation attempts on its properties have no effect.</blockquote>
443
- New updates are merged into state by default. So only supply the exact changes to be merged <b><i>(i.e. do not spread the new state changes into the current state as is commonly done in React development)</i></b>. And to overwrite a slice of state, use the <a href="#setstate-tags">tag</a> command.<br />
444
- :warning: <b><i>Do this:</i></b> <code>setState({stateKey0: changes0});</code><br />
445
- :warning: <b><i>Not this:</i></b> <code>setState({...state, stateKey0: {...state.stateKey0, ...changes0}});</code><br />
446
-
447
- <h3 id="batched-update"><i><u>Batched update</u></i></h3>
448
- provides a way to update the state as a transaction of several state changes. This can be achieved by collecting a series of state changes in an array and passing that array as an argument to the <code>store.setState</code> method. The state changes are resolved sequentially from <code>index 0</code> to the <code>last index</code>. <a href="#client">Clients</a> are only notified at batched update completion.<br />
449
- :warning: <b><i>Do this:</i></b> <code>setState([<br />
450
- &nbsp;&nbsp;&nbsp;&nbsp;{stateKey0: changes0},<br />
451
- &nbsp;&nbsp;&nbsp;&nbsp;{stateKey1: changes1},<br />
452
- &nbsp;&nbsp;&nbsp;&nbsp;// et cetera ... et cetera<br />
453
- ]);</code><br />
454
- :warning: <b><i>Not this:</i></b> <code>setState([<br />
455
- &nbsp;&nbsp;&nbsp;&nbsp;{...state, stateKey0: {...state.stateKey0, ...changes0}},<br />
456
- &nbsp;&nbsp;&nbsp;&nbsp;{...state, stateKey1: {...state.stateKey1, ...changes1}},<br />
457
- &nbsp;&nbsp;&nbsp;&nbsp;// et cetera ... et cetera<br />
458
- ]);</code>
459
-
460
- <h3 id="indexing"><i><u>Indexing</u></i></h3>
461
- Traditionally, array state properties are updated by a new array replacement. This overwrites the existing state property.<br />
462
- Hence the need for <code>indexing</code>. Indexing provides a mechanism for updating array state properties at specific indexes using an indexed state change object.<br />
463
- The store also recognizes and resolves negative indexes when present in the indexed state change object. See additional <a href="#neg-idx-tip">tip</a> below.<br />
464
- <strong>Example:</strong>
465
-
466
- ```jsx
467
- // Given the following array bearing state object:
468
- const state = { a: { b: [ { x: 7, y: 8, z: 9 } ] }, j: 10 };
469
-
470
- // The following will override the existing array.
471
- store.setState({ a: { b: [ { y: 30 }, 22 ] } });
472
- // updates the state to: { a: { b: [ { y: 30 }, 22 ] }, j: 10 };
473
-
474
- // The followinng will update the existing array at indexes.
475
- store.setState({ a: { b: { 0: { y: 30 }, 1: 22 } } });
476
- // updates the state to: { a: { b: [ { x: 7, y: 30, z: 9 }, 22 ] }, j: 10 };
477
-
478
- // The followinng will update the existing array at indexes.
479
- store.setState({ a: { b: { '-1': { y: 30 }, 1: 22 } } });
480
- // updates the state to: { a: { b: [ { x: 7, y: 30, z: 9 }, 22 ] }, j: 10 };
481
-
482
- // The previous 2 statements are functionally equivalent to the following:
483
- const [ first, second, ...rest ] = state.a.b;
484
- store.setState({ ...state, a: { ...state.a, b: [ { ...first, y: 30 }, 22, ...rest ] } });
485
- // Refrain from doing this, please!
486
- ```
487
- :warning: <b id="neg-idx-tip"><i>Tip:</i></b> Negative indexing pointing at an out-of-bounds index is ignored.
488
-
489
- <h3 id="setstate-tags"><b><i><u>Overwriting state using tag commands</u></i></b></h3>
490
- By default, <code>store.setState</code> recursively merges new changes into current state.<br />
491
- To overwrite current state slices with new values, <b>7</b> tag commands have been provided:
492
- <ol>
493
- <li><span style="margin-left: 10px"><b style="margin-right: 6px"><i>@@CLEAR:</i></b> sets state slice to its corresponding empty value</span></li>
494
- <li><span style="margin-left: 10px"><b style="margin-right: 6px"><i>@@DELETE:</i></b> removes plain object properties and array items</span></li>
495
- <li><span style="margin-left: 10px"><b style="margin-right: 6px"><i>@@MOVE:</i></b> moves array elements</span></li>
496
- <li><span style="margin-left: 10px"><b style="margin-right: 6px"><i>@@PUSH:</i></b> pushes new items into an array</span></li>
497
- <li><span style="margin-left: 10px"><b style="margin-right: 6px"><i>@@REPLACE:</i></b> replaces property values</span></li>
498
- <li><span style="margin-left: 10px"><b style="margin-right: 6px"><i>@@SET:</i></b> sets property values</span></li>
499
- <li><span style="margin-left: 10px"><b style="margin-right: 6px"><i>@@SPLICE:</i></b> splices array items</span></li>
500
- </ol>
501
- <b>Examples:</b><br /><br />
502
-
503
- <i id="clear-tag-usage"><b>@@CLEAR:</b> (takes no arguments)</i>
504
-
505
- ```jsx
506
- import { CLEAR_TAG } from '@webkrafters/react-observable-context'; // CLEAR_TAG = "@@CLEAR"
507
-
508
- const state = {
509
- a: { b: [{ x: 7, y: 8, z: 9 }, { x: 17, y: 18, z: 19 }] },
510
- j: 10
511
- };
512
-
513
- /* empties the state; sets state = {} */
514
- store.setState( CLEAR_TAG ) // or store.setState({ [ CLEAR_TAG ]: <anything> })
515
-
516
- /* empties the value at state.a.b; sets state.a.b = [] */
517
- store.setState({ a: { b: CLEAR_TAG } }) // or store.setState({ a: { b: { [ CLEAR_TAG ]: <anything> } } })
518
-
519
- /* empties the value at state.a.j; sets state.a.j = null */
520
- store.setState({ a: { j: CLEAR_TAG } }) // or store.setState({ a: { j: { [ CLEAR_TAG ]: <anything> } } })
521
-
522
- /* empties the value at state.a.b[ 0 ]; sets state.a.b = [{}] */
523
- store.setState({ a: { b: [ CLEAR_TAG ] } }) // or store.setState({ a: { b: [ { [ CLEAR_TAG ]: <anything> } ] } })
524
-
525
- /* empties the value at state.a.b[0]; sets state.a.b = [{}, state.a.b[1]] */
526
- store.setState({ a: { b: [ CLEAR_TAG, state.a.b[1] ] } }) // or store.setState({ a: { b: [ { [ CLEAR_TAG ]: <anything> }, state.a.b[1] ] } })
527
-
528
- /* empties the value at state.a.b[0]; sets state.a.b = [{}, a.b[1]] using indexing (RECOMMENDED) */
529
- store.setState({ a: { b: { 0: CLEAR_TAG } } }) // or store.setState({ a: { b: { 0: { [ CLEAR_TAG ]: <anything> } } } })
530
- ```
531
-
532
- <i id="delete-tag-usage"><b>@@DELETE:</b> (takes an array argument listing property keys to delete)</i>
533
-
534
- ```jsx
535
- import { DELETE_TAG } from '@webkrafters/react-observable-context'; // DELETE_TAG = "@@DELETE"
536
-
537
- const state = {
538
- a: { b: [{ x: 7, y: 8, z: 9 }, { x: 17, y: 18, z: 19 }] },
539
- j: 10
540
- };
541
-
542
- store.setState({ [ DELETE_TAG ]: [ 'a' ] }) // removes state.a; sets state = {j: 10}
543
-
544
- store.setState({ a: { [ DELETE_TAG ]: [ 'b' ] } }) // removes state.a.b; sets state.a = {}
545
-
546
- /* removes state.a.b[0]; leaving state.a.b = [{ x: 17, y: 18, z: 19 }] */
547
- store.setState({ a: { b: { [ DELETE_TAG ]: [ 0 ] } } }) // or store.setState({ a: { b: { [ DELETE_TAG ]: [ -2 ] } } })
548
-
549
- /* removes `x` and `z` properties from state.a.b[1]; sets state.a.b = [{ x: 7, y: 8, z: 9 }, {y: 18}] */
550
- store.setState({ a: { b: [ state.a.b[ 0 ], { [ DELETE_TAG ]: [ 'x', 'z' ] } ] } })
551
-
552
- /* removes `x` and `z` properties from state.a.b[1]; sets state.a.b = [{ x: 7, y: 8, z: 9 }, {y: 18}] using indexing (RECOMMENDED) */
553
- store.setState({ a: { b: { 1: { [ DELETE_TAG ]: [ 'x', 'z' ] } } } })
554
- ```
555
-
556
- <i id="move-tag-usage"><b>@@MOVE:</b> (takes an array argument listing: -/+fromIndex, -/+toIndex and optional +numItems?. numItems = 1 by default)</i>
557
-
558
- ```jsx
559
- import { MOVE_TAG } from '@webkrafters/react-observable-context'; // MOVE_TAG = "@@MOVE"
560
-
561
- const state = {
562
- a: { b: [{ x: 7, y: 8, z: 9 }, { x: 17, y: 18, z: 19 }] },
563
- j: 10,
564
- q: [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
565
- };
566
-
567
- store.setState({ a: { [ MOVE_TAG ]: [ 0, 1 ] } }) // assigning a '@@MOVE' command to a non-array property has no effect.
568
-
569
- /* moves state.a.b[0] into index 1; leaving state.a.b = [{ x: 17, y: 18, z: 19 }, { x: 7, y: 8, z: 9 }] */
570
- store.setState({ a: { b: { [ MOVE_TAG ]: [ 0, 1 ] } } }) // or store.setState({ a: { b: { [ MOVE_TAG ]: [ -2, -1 ] } } })
571
-
572
- /* moves state.q[4] - [7] into indexes 1 - 4; leaving state.q = [ 1, 5, 6, 7, 8, 2, 3, 4, 9 ] */
573
- store.setState({ a: { q: { [ MOVE_TAG ]: [ 4, 1, 4 ] } } }) // or store.setState({ a: { q: { [ MOVE_TAG ]: [ -5, -8, 4 ] } } })
574
- ```
575
-
576
- <i id="push-tag-usage"><b>@@PUSH:</b> (takes an array argument listing new values to append)</i>
577
-
578
- ```jsx
579
- import { PUSH_TAG } from '@webkrafters/react-observable-context'; // PUSH_TAG = "@@PUSH"
580
-
581
- const state = {
582
- a: { b: [{ x: 7, y: 8, z: 9 }, { x: 17, y: 18, z: 19 }] },
583
- j: 10
584
- };
585
-
586
- store.setState({ a: { [ PUSH_TAG ]: [{ n: 5 }] } }) // assigning a '@@PUSH' command to a non-array property has no effect.
587
-
588
- /* appends 2 new items into state.a.b; leaving state.a.b = [...state.a.b, { x: 27, y: 28, z: 29 }, { x: 37, y: 38, z: 39 }] */
589
- store.setState({ a: { b: { [ PUSH_TAG ]: [{ x: 27, y: 28, z: 29 }, { x: 37, y: 38, z: 39 }] } } })
590
- ```
591
-
592
- <i id="replace-tag-usage"><b>@@REPLACE:</b> (takes an argument holding the replacement value)</i>
593
-
594
- ```jsx
595
- import { REPLACE_TAG } from '@webkrafters/react-observable-context'; // REPLACE_TAG = "@@REPLACE"
596
-
597
- const state = {
598
- a: { b: [{ x: 7, y: 8, z: 9 }, { x: 17, y: 18, z: 19 }] },
599
- j: 10
600
- };
601
-
602
- store.setState({ [ REPLACE_TAG ]: { a: 'Demo', j: 17 } }) // rewrites state to { a: 'Demo', j: 17 };
603
-
604
- store.setState({ a: { [ REPLACE_TAG ]: { message: 'Testing...' } } }) // rewrites state.a to { message: 'Testing...' }
605
-
606
- /* rewrites state.a.b[1] to { x: 97, y: 98, z: 99 }; leaving state.a.b = [{ x: 7, y: 8, z: 9 }, { x: 97, y: 98, z: 99 }] */
607
- store.setState({ a: { b: [ state.a.b[ 0 ], { [ REPLACE_TAG ]: { x: 97, y: 98, z: 99 } } ] } })
608
-
609
- /* rewrites state.a.b[1] to { x: 97, y: 98, z: 99 }; leaving state.a.b = [{ x: 7, y: 8, z: 9 }, { x: 97, y: 98, z: 99 }] using indexing (RECOMMENDED) */
610
- store.setState({ a: { b: { 1: { [ REPLACE_TAG ]: { x: 97, y: 98, z: 99 } } } } })
611
- ```
612
-
613
- <i id="set-tag-usage"><b>@@SET:</b> (takes an argument holding either the replacment value or a compute function returning the replacement value)</i>
614
-
615
- ```jsx
616
- /*
617
- This tag is for handling edge cases only. Please use sparingly. In most cases, store.setState with or without any of the other tags is sufficient and most efficient.
618
-
619
- This and the '@@REPLACE' tags are functionally equivalent when used with a replacement value argument.
620
-
621
- Be aware that the compute function argument may be `undefined` for properties which do not yet exist in the state.
622
- */
623
-
624
- import { SET_TAG } from '@webkrafters/react-observable-context'; // SET_TAG = "@@SET"
625
-
626
- const state = {
627
- a: { b: [{ x: 7, y: 8, z: 9 }, { x: 17, y: 18, z: 19 }] },
628
- j: 10
629
- };
630
-
631
- store.setState({ [ SET_TAG ]: currentValue => ({ ...currentValue, a: 'Demo', j: 17 }) }) // rewrites state to { ...state, a: 'Demo', j: 17 };
632
-
633
- store.setState({ a: { [ SET_TAG ]: currentValue => ({ ...currentValue, message: 'Testing...' }) } }) // rewrites state.a to { ...state, message: 'Testing...' }
634
-
635
- /* rewrites state.a.b[1] to { x: 97, y: 98, z: 99 }; leaving state.a.b = [{ x: 7, y: 8, z: 9 }, { x: 97, y: 98, z: 99 }] */
636
- store.setState({ a: { b: [ state.a.b[ 0 ], { [ SET_TAG ]: currentValue => ({ ...currentValue, x: 97, y: 98, z: 99 }) } ] } })
637
-
638
- /* rewrites state.a.b[1] to { x: 97, y: 98, z: 99 }; leaving state.a.b = [{ x: 7, y: 8, z: 9 }, { x: 97, y: 98, z: 99 }] using indexing (RECOMMENDED) */
639
- store.setState({ a: { b: { 1: { [ SET_TAG ]: currentValue => ({ ...currentValue, x: 97, y: 98, z: 99 }) } } } })
640
- ```
641
-
642
- <i id="splice-tag-usage"><b>@@SPLICE:</b> (takes an array argument listing: -/+fromIndex, +deleteCount and optional ...newItems? newItems = ...[] by default)</i>
643
-
644
- ```jsx
645
- import { SPLICE_TAG } from '@webkrafters/react-observable-context'; // SPLICE_TAG = "@@SPLICE"
646
-
647
- const state = {
648
- a: { b: [{ x: 7, y: 8, z: 9 }, { x: 17, y: 18, z: 19 }] },
649
- j: 10,
650
- q: [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
651
- };
652
-
653
- store.setState({ a: { [ SPLICE_TAG ]: [ 0, 1 ] } }) // assigning a '@@SPLICE' command to a non-array property has no effect.
654
-
655
- /* removes state.a.b[0]; leaving state.a.b = [{ x: 17, y: 18, z: 19 }] */
656
- store.setState({ a: { b: { [ SPLICE_TAG ]: [ 0, 1 ] } } }) // or store.setState({ a: { b: { [ SPLICE_TAG ]: [ -2, -1 ] } } })
657
-
658
- /* replaces state.q[4] - [7] with 2 items; leaving state.q = [ 1, 2, 3, 4, 33, 88, 9 ] */
659
- store.setState({ a: { q: { [ SPLICE_TAG ]: [ 4, 4, 33, 88 ] } } }) // or store.setState({ a: { q: { [ SPLICE_TAG ]: [ -5, 4, 33, 88 ] } } })
660
- ```
661
-
662
- <h3 id="set-state-with-tags"><b><i>Combination Usage:</i></b></h3>
663
-
664
- These tags may be used in combination with the default usage where all top-level tag command results in property are sequentially merged into state followed by the merging of the rest of the property changes.
665
-
666
- <strong>Example:</strong>
667
-
668
- ```jsx
669
- import * as ctx from '@webkrafters/react-observable-context';
670
-
671
- const state = {
672
- a: { b: [{ x: 7, y: 8, z: 9 }, { x: 17, y: 18, z: 19 }] },
673
- j: 10,
674
- q: [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
675
- };
676
-
677
- store.setState({
678
- a: {
679
- b: {
680
- /* evaluated 1st */ [ ctx.DELETE_TAG ]: [ 0 ], // upon deleting state.a.b[0] -> state.a.b[1] becomes the new state.a.b[0]
681
- /* evaluated 3rd */ 0: ctx.CLEAR_TAG, // clear the new state.a.b[0]
682
- /* evaluated 4th */ 2: { x: 47, y: 48, z: 49 }, // add new item at state.a.b[2],
683
- /* evaluated 2md */ [ ctx.PUSH_TAG ]: [{ x: 107, y: 108, z: 109 }] // appends state.a.b[1]
684
- }
685
- },
686
- j: { [ ctx.SET_TAG ]: currentValue => currentValue < 10 ? currentValue : 0 },
687
- q: {
688
- /* evaluated 1st */ [ ctx.MOVE_TAG ]: [ 5, 3, 2 ],
689
- /* evaluated 2md */ 12: 11
690
- }
691
- })
692
- // => {
693
- // a: { b: [{}, { x: 107, y: 108, z: 109 }, { x: 47, y: 48, z: 49 }] },
694
- // j: 0,
695
- // q: [ 1, 2, 3, 6, 7, 4, 5, 8, 9, <empty>, <empty>, <empty>, 11 ]
696
- // }
697
- ```
698
-
699
- <h1 id="changes">What's Changed?</h1>
700
-
701
- <table>
702
- <thead><tr><th>v4.7.0</th></tr></thead>
703
- <tbody>
704
- <tr><td><b>1.</b></td><td><a href="#store-setstate"><code>store.setState</code></a> can now accept an array of updates for gurranteed orderly processing.</td></tr>
705
- </tbody>
706
- <thead><tr><th>v4.6.0</th></tr></thead>
707
- <tbody>
708
- <tr><td><b>1.</b></td><td><a href="#store-resetstate"><code>store.resetState</code></a> can now update reset current state even when initial state does not exist. Formerly, a resetState call on a non-existent initial state had no effect.</td></tr>
709
- </tbody>
710
- <thead><tr><th>v4.5.0</th></tr></thead>
711
- <tbody>
712
- <tr><td><b>1.</b></td><td><a href="#setstate-tags">Tags</a> to update non-existent state slices are now recognized. <b>Previously,</b> they had resulted in no-ops. <b>From now on,</b> they will result in new default slices matching the result of the given tag operation.</td></tr>
713
- </tbody>
714
- <thead><tr><th>v4.4.0</th></tr></thead>
715
- <tbody>
716
- <tr><td><b>1.</b></td><td>Returns <code>undefined</code> for selector map pointing at a non-existent state slice. <i>(Previously returned <code>null</code>)</i>.</td></tr>
717
- </tbody>
718
- <thead><tr><th>v4.3.0</th></tr></thead>
719
- <tbody>
720
- <tr><td><b>1.</b></td><td>Added <code>React.Ref</code> forwarding to <code>connect</code>ed hoc client components.</td></tr>
721
- </tbody>
722
- <thead><tr><th>v4.1.0</th></tr></thead>
723
- <tbody>
724
- <tr><td><b>1.</b></td><td>Added new setState <a href="#setstate-tags">tags</a> to facilitate state update operations.</td></tr>
725
- <tr><td><b>2.</b></td><td>Added negative indexing capabilities.</td></tr>
726
- <tr><td><b>3.</b></td><td>Exposing the store via its Context Provider <code>ref</code> attribute.</td></tr>
727
- <tr><td><b>4.</b></td><td>Exporting crucial constants such as <b>@@STATE</b> and setState <a href="#setstate-tags">tags</a> such as <b>@@CLEAR</b>, <b>@@MOVE</b> etc.</td></tr>
728
- </tbody>
729
- <thead><tr><th>v4.0.0</th></tr></thead>
730
- <tbody>
731
- <tr><td><b>1.</b></td><td>Added the <a href="#connect"><code>connect</code></a> function to facilitate the encapsulated context-usage method.</td></tr>
732
- <tr><td><b>2.</b></td><td>Added stronger support for deeply nested state structure. See <a href="#store-setstate"><code>store.setState</code></a></td></tr>
733
- <tr><td><b>3.</b></td><td>Replaced the <a href="#usecontext"><code>useContext</code></a> watchedKeys array parameter with a <a href="#selector-map"><code>selectorMap</code></a> object.</td></tr>
734
- <tr><td><b>4.</b></td><td>Removed the necessity for direct store subscription.</td></tr>
735
- <tr><td><b>5.</b></td><td><a href="#store-resetstate"><code>store.resetState</code></a> can now take a <a href="#property-path">property path</a> array targeting which state slices to reset.</td></tr>
736
- <tr><td><b>6.</b></td><td>Context provider accepts an optional <a href="#storage">storage</a> prop for memorizing initial state.</td></tr>
737
- <tr><td><b>7.</b></td><td>Removed the need for <code>store.getState</code>. <code>store.data</code> now holds the state slices used at the client. Changes in any of the slices held by the <code>store.data</code> are automatically updated as they occur. The client is immediately notified of the update.</td></tr>
738
- </tbody>
739
- </table>
48
+ ## Please see full documentation here:
49
+ **[eagleeyejs.org](https://eagleeyejs.org)**
740
50
 
741
51
  # License
742
52
 
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
+ "alias": "eagle eye context",
2
3
  "author": "Stephen Isienyi <stephen.isienyi@webkrafting.com>",
3
4
  "bugs": {
4
- "url": "https://github.com/webKrafters/react-observable-context/issues"
5
+ "url": "https://github.com/webKrafters/eagleeye/issues"
5
6
  },
6
7
  "contributors": [
7
8
  "steveswork <stephen.isienyi@gmail.com> (https://github.com/steveswork)"
@@ -79,7 +80,7 @@
79
80
  "dist/constants.js",
80
81
  "dist/constants.d.ts"
81
82
  ],
82
- "homepage": "https://github.com/webKrafters/react-observable-context#readme",
83
+ "homepage": "https://eagleeyejs.org",
83
84
  "jest": {
84
85
  "collectCoverageFrom": [
85
86
  "src/**/*.js"
@@ -96,6 +97,7 @@
96
97
  "keywords": [
97
98
  "connect",
98
99
  "context",
100
+ "eagle eye",
99
101
  "hoc",
100
102
  "hooks",
101
103
  "observable",
@@ -122,7 +124,7 @@
122
124
  },
123
125
  "repository": {
124
126
  "type": "git",
125
- "url": "git+https://github.com/webKrafters/react-observable-context.git"
127
+ "url": "git+https://github.com/webKrafters/eagleeye.git"
126
128
  },
127
129
  "scripts": {
128
130
  "build": "eslint --fix && rm -rf dist && babel src -d dist --ignore '**/*.test.js' && tsc",
@@ -133,5 +135,5 @@
133
135
  "test:watch": "eslint --fix && jest --updateSnapshot --watchAll"
134
136
  },
135
137
  "types": "dist/main/index.d.ts",
136
- "version": "4.7.3"
138
+ "version": "4.7.5"
137
139
  }