@webkrafters/react-observable-context 4.0.0 → 4.1.0-alpha.0

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.
package/README.md CHANGED
@@ -207,6 +207,198 @@ store.setState({ ...state, a: { ...state.a, b: [ { ...first, y: 30 }, 22, ...res
207
207
  // Refrain from doing this, please!
208
208
  ```
209
209
 
210
+ <h3 id="setstate-tags"><b><i><u>Rewriting state using tag commands</u></i></b></h3>
211
+ By default setState merges new changes into the current state slices. To overwrite current state slices with new state values, <b>7</b> tag commands have been provided for:
212
+ <ol>
213
+ <li><span style="margin-left: 10px"><b><code>@@CLEAR:</code></b> setting state slice to its corresponding empty value</span></li>
214
+ <li><span style="margin-left: 10px"><b><code>@@DELETE:</code></b> deleting properties</span></li>
215
+ <li><span style="margin-left: 10px"><b><code>@@MOVE:</code></b> moving array elements</span></li>
216
+ <li><span style="margin-left: 10px"><b><code>@@PUSH:</code></b> pushing new items into an array</span></li>
217
+ <li><span style="margin-left: 10px"><b><code>@@REPLACE:</code></b> replacing property values</span></li>
218
+ <li><span style="margin-left: 10px"><b><code>@@SET:</code></b> setting property values</span></li>
219
+ <li><span style="margin-left: 10px"><b><code>@@SPLICE:</code></b> splicing array items</span></li>
220
+ </ol>
221
+ <strong>Examples:</strong>
222
+
223
+ <b><code>@@CLEAR:</code></b> <i>takes no arguments.</i>
224
+
225
+ ```jsx
226
+ const state = {
227
+ a: { b: [{ x: 7, y: 8, z: 9 }, { x: 17, y: 18, z: 19 }] },
228
+ j: 10
229
+ };
230
+
231
+ store.setState( '@@CLEAR' ) // or store.setState({ @@CLEAR: <anything> })
232
+
233
+ /* empties the value at state.a.b; sets state.a.b = [] */
234
+ store.setState({ a: { b: '@@CLEAR' } }) // or store.setState({ a: { b: { @@CLEAR: <anything> } } })
235
+
236
+ /* empties the value at state.a.j; sets state.a.j = null */
237
+ store.setState({ a: { j: '@@CLEAR' } }) // or store.setState({ a: { j: { @@CLEAR: <anything> } } })
238
+
239
+ /* empties the value at state.a.b[ 0 ]; sets state.a.b = [{}] */
240
+ store.setState({ a: { b: [ '@@CLEAR' ] } }) // or store.setState({ a: { b: [ { @@CLEAR: <anything> } ] } })
241
+
242
+ /* empties the value at state.a.b[0]; sets state.a.b = [{}, state.a.b[1]] */
243
+ store.setState({ a: { b: [ '@@CLEAR', state.a.b[1] ] } }) // or store.setState({ a: { b: [ { @@CLEAR: <anything> }, state.a.b[1] ] } })
244
+
245
+ /* empties the value at state.a.b[0]; sets state.a.b = [{}, a.b[1]] using indexing (RECOMMENDED) */
246
+ store.setState({ a: { b: { 0: '@@CLEAR' } } }) // or store.setState({ a: { b: { 0: { @@CLEAR: <anything> } } } })
247
+ ```
248
+
249
+ <b><code>@@DELETE:</code></b> <i>takes an array argument listing property keys to delete.</i>
250
+
251
+ ```jsx
252
+ const state = {
253
+ a: { b: [{ x: 7, y: 8, z: 9 }, { x: 17, y: 18, z: 19 }] },
254
+ j: 10
255
+ };
256
+
257
+ store.setState({ '@@DELETE': [ 'a' ] }) // removes state.a; sets state = {j: 10}
258
+
259
+ store.setState({ a: { '@@DELETE': [ 'b' ] } }) // removes state.a.b; sets state.a = {}
260
+
261
+ /* removes state.a.b[0]; leaving state.a.b = [{ x: 17, y: 18, z: 19 }] */
262
+ store.setState({ a: { b: { '@@DELETE': [ 0 ] } } }) // or store.setState({ a: { b: { '@@DELETE': [ -2 ] } } })
263
+
264
+ /* removes `x` and `z` properties from state.a.b[1]; sets state.a.b = [{ x: 7, y: 8, z: 9 }, {y: 18}] */
265
+ store.setState({ a: { b: [ state.a.b[ 0 ], { '@@DELETE': [ 'x', 'z' ] } ] } })
266
+
267
+ /* 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) */
268
+ store.setState({ a: { b: { 1: { '@@DELETE': [ 'x', 'z' ] } } } })
269
+ ```
270
+
271
+ <b><code>@@MOVE:</code></b> <i>takes an array argument listing: -/+fromIndex, -/+toIndex and optional +numItems?. numItems = 1 by default. </i>
272
+
273
+ ```jsx
274
+ const state = {
275
+ a: { b: [{ x: 7, y: 8, z: 9 }, { x: 17, y: 18, z: 19 }] },
276
+ j: 10,
277
+ q: [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
278
+ };
279
+
280
+ store.setState({ a: { '@@MOVE': [ 0, 1 ] } }) // assigning a @@MOVE command to a non-array property has no effect.
281
+
282
+ /* moves state.a.b[0] into index 1; leaving state.a.b = [{ x: 17, y: 18, z: 19 }, { x: 7, y: 8, z: 9 }] */
283
+ store.setState({ a: { b: { '@@MOVE': [ 0, 1 ] } } }) // or store.setState({ a: { b: { '@@MOVE': [ -2, -1 ] } } })
284
+
285
+ /* moves state.q[4] - [7] into indexes 1 - 4; leaving state.q = [ 1, 5, 6, 7, 8, 2, 3, 4, 9 ] */
286
+ store.setState({ a: { q: { '@@MOVE': [ 4, 1, 4 ] } } }) // or store.setState({ a: { q: { '@@MOVE': [ -5, -8, 4 ] } } })
287
+ ```
288
+
289
+ <b><code>@@PUSH:</code></b> <i>takes an array argument listing new values to append. </i>
290
+
291
+ ```jsx
292
+ const state = {
293
+ a: { b: [{ x: 7, y: 8, z: 9 }, { x: 17, y: 18, z: 19 }] },
294
+ j: 10
295
+ };
296
+
297
+ store.setState({ a: { '@@PUSH': [{ n: 5 }] } }) // assigning a @@PUSH command to a non-array property has no effect.
298
+
299
+ /* 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 }] */
300
+ store.setState({ a: { b: { '@@PUSH': [{ x: 27, y: 28, z: 29 }, { x: 37, y: 38, z: 39 }] } } })
301
+ ```
302
+
303
+ <b><code>@@REPLACE:</code></b> <i>takes an argument holding the replacment value. </i>
304
+
305
+ ```jsx
306
+ const state = {
307
+ a: { b: [{ x: 7, y: 8, z: 9 }, { x: 17, y: 18, z: 19 }] },
308
+ j: 10
309
+ };
310
+
311
+ store.setState({ '@@REPLACE': { a: 'Demo', j: 17 } }) // rewrites state to { a: 'Demo', j: 17 };
312
+
313
+ store.setState({ a: { '@@REPLACE': { message: 'Testing...' } } }) // rewrites state.a.b to { message: 'Testing...' }
314
+
315
+ /* 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 }] */
316
+ store.setState({ a: { b: [ state.a.b[ 0 ], { '@@REPLACE': { x: 97, y: 98, z: 99 } } ] } })
317
+
318
+ /* 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) */
319
+ store.setState({ a: { b: { 1: { '@@REPLACE': { x: 97, y: 98, z: 99 } } } } })
320
+ ```
321
+
322
+ <b><code>@@SET:</code></b> <i>takes an argument holding either the replacment value or a compute function returning the replacement value. </i>
323
+
324
+ ```jsx
325
+ /*
326
+ @@SET and @@REPLACE tags are functionally equivalent when using replacement value argument.
327
+ However, @@SET also accepts a compute function argument for calculating a replacement value based on current value.
328
+ 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.
329
+ */
330
+
331
+ const state = {
332
+ a: { b: [{ x: 7, y: 8, z: 9 }, { x: 17, y: 18, z: 19 }] },
333
+ j: 10
334
+ };
335
+
336
+ store.setState({ '@@SET': currentValue => ({ ...currentValue, a: 'Demo', j: 17 }) }) // rewrites state to { ...state, a: 'Demo', j: 17 };
337
+
338
+ store.setState({ a: { '@@SET': currentValue => ({ ...currentValue, message: 'Testing...' }) } }) // rewrites state.a.b to { ...state, message: 'Testing...' }
339
+
340
+ /* 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 }] */
341
+ store.setState({ a: { b: [ state.a.b[ 0 ], { '@@SET': currentValue => ({ ...currentValue, x: 97, y: 98, z: 99 }) } ] } })
342
+
343
+ /* 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) */
344
+ store.setState({ a: { b: { 1: { '@@SET': currentValue => ({ ...currentValue, x: 97, y: 98, z: 99 }) } } } })
345
+
346
+ /** be aware: currentValue may be `undefined` when adding new state slice properties. */
347
+ ```
348
+
349
+ <b><code>@@SPLICE:</code></b> <i>takes an array argument listing: -/+fromIndex, +deleteCount and optional ...newItems? newItems = ...[] by default. </i>
350
+
351
+ ```jsx
352
+ const state = {
353
+ a: { b: [{ x: 7, y: 8, z: 9 }, { x: 17, y: 18, z: 19 }] },
354
+ j: 10,
355
+ q: [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
356
+ };
357
+
358
+ store.setState({ a: { '@@SPLICE': [ 0, 1 ] } }) // assigning a @@SPLICE command to a non-array property has no effect.
359
+
360
+ /* removes state.a.b[0]; leaving state.a.b = [{ x: 17, y: 18, z: 19 }] */
361
+ store.setState({ a: { b: { '@@SPLICE': [ 0, 1 ] } } }) // or store.setState({ a: { b: { SPLICE': [ -2, -1 ] } } })
362
+
363
+ /* replaces state.q[4] - [7] with 2 items; leaving state.q = [ 1, 2, 3, 4, 33, 88, 9 ] */
364
+ store.setState({ a: { q: { '@@SPLICE': [ 4, 4, 33, 88 ] } } }) // or store.setState({ a: { q: { '@@SPLICE': [ -5, 4, 33, 88 ] } } })
365
+ ```
366
+
367
+ <b><code>Combination Usage:</code></b>
368
+
369
+ These tags may be used in combination with the default usage where all nth-level tag command results are sequentially merged into state followed by the merging of the rest of the nth-level changes.
370
+
371
+ <strong>Example:</strong>
372
+
373
+ ```jsx
374
+ const state = {
375
+ a: { b: [{ x: 7, y: 8, z: 9 }, { x: 17, y: 18, z: 19 }] },
376
+ j: 10,
377
+ q: [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
378
+ };
379
+
380
+ store.setState({
381
+ a: {
382
+ b: {
383
+ /* evaluated 1st */ '@@DELETE': [ 0 ], // upon deleting state.a.b[0] -> state.a.b[1] becomes the new state.a.b[0]
384
+ /* evaluated 3rd */ 0: '@@CLEAR', // clear the new state.a.b[0]
385
+ /* evaluated 4th */ 2: { x: 47, y: 48, z: 49 }, // add new item at state.a.b[2],
386
+ /* evaluated 2md */ '@@PUSH': [{ x: 107, y: 108, z: 109 }] // appends state.a.b[1]
387
+ },
388
+ j: { '@@SET': currentValue => currentValue < 10 ? currentValue : 0 },
389
+ q: {
390
+ /* evaluated 1st */ '@@MOVE': [ 5, 3, 2 ],
391
+ /* evaluated 2md */ 12: 11
392
+ }
393
+ }
394
+ })
395
+ // => {
396
+ // a: { b: [{}, { x: 107, y: 108, z: 109 }, { x: 47, y: 48, z: 49 }] },
397
+ // j: 0,
398
+ // q: [ 1, 2, 3, 6, 7, 4, 5, 8, 9, <empty>, <empty>, <empty>, 11 ]
399
+ // }
400
+ ```
401
+
210
402
  # API
211
403
 
212
404
  The React-Observable-Context module contains **4** exports namely:
@@ -389,6 +581,15 @@ ReactDOM.render( <Provider />, document.getElementById( 'root' ) );
389
581
  ```
390
582
 
391
583
  <h1 id="changes">What's Changed?</h1>
584
+ <b>v4.1.0</b>
585
+ <table>
586
+ <tbody>
587
+ <tr><td><b>1.</b></td><td>Added new setState command <a href="#setstate-tags">tags</a>: <b><code>@@CLEAR<b><code>, <b><code>@@DELETE</code></b>, <b><code>@@MOVE</code></b>, <b><code>@@PUSH</code></b>, <b><code>@@REPLACE</code></b>, <b><code>@@SET</code></b> and <b><code>@@SPLICE</code></b>.</td></tr>
588
+ </tbody>
589
+ </table>
590
+ <hr />
591
+
592
+ <b>v4.0.0</b>
392
593
  <table>
393
594
  <tbody>
394
595
  <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>
@@ -1,2 +1,9 @@
1
+ export const CLEAR_TAG: "@@CLEAR";
2
+ export const DELETE_TAG: "@@DELETE";
1
3
  export const FULL_STATE_SELECTOR: "@@STATE";
2
- export const NULL_STATE_SELECTOR: "";
4
+ export const MOVE_TAG: "@@MOVE";
5
+ export const NULL_STATE_SELECTOR: "";
6
+ export const PUSH_TAG: "@@PUSH";
7
+ export const REPLACE_TAG: "@@REPLACE";
8
+ export const SET_TAG: "@@SET";
9
+ export const SPLICE_TAG: "@@SPLICE";
package/dist/constants.js CHANGED
@@ -2,8 +2,22 @@
2
2
  Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
- exports.NULL_STATE_SELECTOR = exports.FULL_STATE_SELECTOR = void 0;
5
+ exports.SPLICE_TAG = exports.SET_TAG = exports.REPLACE_TAG = exports.PUSH_TAG = exports.NULL_STATE_SELECTOR = exports.MOVE_TAG = exports.FULL_STATE_SELECTOR = exports.DELETE_TAG = exports.CLEAR_TAG = void 0;
6
+ var CLEAR_TAG = '@@CLEAR';
7
+ exports.CLEAR_TAG = CLEAR_TAG;
8
+ var DELETE_TAG = '@@DELETE';
9
+ exports.DELETE_TAG = DELETE_TAG;
6
10
  var FULL_STATE_SELECTOR = '@@STATE';
7
11
  exports.FULL_STATE_SELECTOR = FULL_STATE_SELECTOR;
12
+ var MOVE_TAG = '@@MOVE';
13
+ exports.MOVE_TAG = MOVE_TAG;
8
14
  var NULL_STATE_SELECTOR = '';
9
- exports.NULL_STATE_SELECTOR = NULL_STATE_SELECTOR;
15
+ exports.NULL_STATE_SELECTOR = NULL_STATE_SELECTOR;
16
+ var PUSH_TAG = '@@PUSH';
17
+ exports.PUSH_TAG = PUSH_TAG;
18
+ var REPLACE_TAG = '@@REPLACE';
19
+ exports.REPLACE_TAG = REPLACE_TAG;
20
+ var SET_TAG = '@@SET';
21
+ exports.SET_TAG = SET_TAG;
22
+ var SPLICE_TAG = '@@SPLICE';
23
+ exports.SPLICE_TAG = SPLICE_TAG;
@@ -4,7 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  });
5
5
  exports["default"] = void 0;
6
6
  var _react = require("react");
7
- var _lodash = _interopRequireDefault(require("lodash.clonedeep"));
7
+ var _utils = require("../../../utils");
8
8
  var _accessorCache = _interopRequireDefault(require("../../../model/accessor-cache"));
9
9
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
10
10
  function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
@@ -15,7 +15,7 @@ function _iterableToArrayLimit(arr, i) { var _i = null == arr ? null : "undefine
15
15
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
16
16
  var useStateManager = function useStateManager(initStateValue) {
17
17
  var _useState = (0, _react.useState)(function () {
18
- return (0, _lodash["default"])(initStateValue);
18
+ return (0, _utils.clonedeep)(initStateValue);
19
19
  }),
20
20
  _useState2 = _slicedToArray(_useState, 1),
21
21
  state = _useState2[0];
@@ -4,6 +4,7 @@ export namespace deps {
4
4
  }
5
5
  export default useStore;
6
6
  export type IStorage<T extends import("../../../types").State> = import("../../../types").IStorage<T>;
7
+ export type UpdatePayload<T extends import("../../../types").State> = import("../../../types").UpdatePayload<PartialState<T>>;
7
8
  export type PartialState<T extends import("../../../types").State> = import('../../../types').PartialState<T>;
8
9
  export type Prehooks<T extends import("../../../types").State> = import("../../../types").Prehooks<T>;
9
10
  export type StoreInternal<T extends import("../../../types").State> = import("../../../types").StoreInternal<T>;
@@ -15,7 +16,7 @@ declare function useStore<T extends import("../../../types").State>(prehooks: Pr
15
16
  [propertyPaths: string]: Readonly<any>;
16
17
  };
17
18
  resetState: (propertyPaths?: string[]) => void;
18
- setState: (changes: import("../../../types").PartialState<T>) => void;
19
+ setState: (changes: import("../../../types").UpdatePayload<import("../../../types").PartialState<T>>) => void;
19
20
  subscribe: (listener: import("../../../types").Listener<T>) => VoidFunction;
20
21
  unlinkCache: (clientId: string) => void;
21
22
  };
@@ -4,8 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  });
5
5
  exports.deps = exports["default"] = void 0;
6
6
  var _react = require("react");
7
- var _lodash = _interopRequireDefault(require("lodash.clonedeep"));
8
- var _lodash2 = _interopRequireDefault(require("lodash.isboolean"));
7
+ var _lodash = _interopRequireDefault(require("lodash.isboolean"));
9
8
  var _uuid = require("uuid");
10
9
  var _constants = require("../../../constants");
11
10
  var _utils = require("../../../utils");
@@ -34,7 +33,7 @@ function runPrehook(prehooks, name, args) {
34
33
  return true;
35
34
  }
36
35
  var res = prehooks[name].apply(prehooks, _toConsumableArray(args));
37
- if (!(0, _lodash2["default"])(res)) {
36
+ if (!(0, _lodash["default"])(res)) {
38
37
  throw new TypeError("`".concat(name, "` prehook must return a boolean value."));
39
38
  }
40
39
  return res;
@@ -75,12 +74,12 @@ var useStore = function useStore(prehooks, value, storage) {
75
74
  var original = _storage.clone(_storage.getItem(storageKey.current));
76
75
  var resetData = !propertyPaths.length ? {} : propertyPaths.includes(_constants.FULL_STATE_SELECTOR) ? original : (0, _utils.mapPathsToObject)(original, propertyPaths);
77
76
  runPrehook(prehooksRef.current, 'resetState', [resetData, {
78
- current: (0, _lodash["default"])(state),
77
+ current: (0, _utils.clonedeep)(state),
79
78
  original: original
80
79
  }]) && deps.setState(state, resetData, onChange);
81
80
  }, []);
82
81
  var setState = (0, _react.useCallback)(function (changes) {
83
- changes = (0, _lodash["default"])(changes);
82
+ changes = (0, _utils.clonedeep)(changes);
84
83
  runPrehook(prehooksRef.current, 'setState', [changes]) && deps.setState(state, changes, onChange);
85
84
  }, []);
86
85
  var subscribe = (0, _react.useCallback)(function (listener) {
@@ -101,7 +100,7 @@ var useStore = function useStore(prehooks, value, storage) {
101
100
  mounted.current = true;
102
101
  return;
103
102
  }
104
- setState((0, _lodash["default"])(value));
103
+ setState((0, _utils.clonedeep)(value));
105
104
  }, [value]);
106
105
  (0, _react.useEffect)(function () {
107
106
  if (!listeners.size) {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @param {ObservableContext<T>} context Refers to the PublicObservableContext<T> type of the ObservableContext<T>
3
- * @param {{[selectorKey: string]: string|keyof T}} [selectorMap] Key:value pairs where `key` => arbitrary key given to a Store.data property holding a state slice and `value` => property path to a state slice used by this component: see examples below. May add a mapping for a certain arbitrary key='state' and value='@@STATE' to indicate a desire to obtain the entire state object and assign to a `state` property of Store.data. A change in any of the referenced properties results in this component render. When using '@@STATE', note that any change within the state object will result in this component render.
3
+ * @param {SelectorMap<T>} [selectorMap] Key:value pairs where `key` => arbitrary key given to a Store.data property holding a state slice and `value` => property path to a state slice used by this component: see examples below. May add a mapping for a certain arbitrary key='state' and value='@@STATE' to indicate a desire to obtain the entire state object and assign to a `state` property of Store.data. A change in any of the referenced properties results in this component render. When using '@@STATE', note that any change within the state object will result in this component render.
4
4
  * @returns {(WrappedComponent: C) => MemoExoticComponent<P>}
5
5
  * @template {State} T
6
6
  * @template {PartialStore<T> & {[x:string]:*}} [P=PartialStore<T>]
@@ -10,9 +10,7 @@
10
10
  */
11
11
  export function connect<T extends import("../types").State, P extends PartialStore<T> & {
12
12
  [x: string]: any;
13
- } = PartialStore<T>, C extends ComponentType<P> | import("react").ExoticComponent<ComponentType<P>>>(context: ObservableContext<T>, selectorMap?: {
14
- [selectorKey: string]: string | keyof T;
15
- }): (WrappedComponent: C) => MemoExoticComponent<P>;
13
+ } = PartialStore<T>, C extends ComponentType<P> | import("react").ExoticComponent<ComponentType<P>>>(context: ObservableContext<T>, selectorMap?: SelectorMap<T>): (WrappedComponent: C) => MemoExoticComponent<P>;
16
14
 
17
15
  /**
18
16
  * @returns {ObservableContext<T>} Refers to the IObservableContext<T> type of the ObservableContext<T>
@@ -27,7 +25,7 @@ export class UsageError extends Error {
27
25
  * Actively monitors the store and triggers component re-render if any of the watched keys in the state objects changes
28
26
  *
29
27
  * @param {ObservableContext<T>} context Refers to the PublicObservableContext<T> type of the ObservableContext<T>
30
- * @param {{[selectorKey: string]: string|keyof T}} [selectorMap = {}] Key:value pairs where `key` => arbitrary key given to a Store.data property holding a state slice and `value` => property path to a state slice used by this component: see examples below. May add a mapping for a certain arbitrary key='state' and value='@@STATE' to indicate a desire to obtain the entire state object and assign to a `state` property of Store.data. A change in any of the referenced properties results in this component render. When using '@@STATE', note that any change within the state object will result in this component render.
28
+ * @param {SelectorMap<T>} [selectorMap = {}] Key:value pairs where `key` => arbitrary key given to a Store.data property holding a state slice and `value` => property path to a state slice used by this component: see examples below. May add a mapping for a certain arbitrary key='state' and value='@@STATE' to indicate a desire to obtain the entire state object and assign to a `state` property of Store.data. A change in any of the referenced properties results in this component render. When using '@@STATE', note that any change within the state object will result in this component render.
31
29
  * @returns {Store<T>}
32
30
  * @template {State} T
33
31
  * @see {ObservableContext<T>}
@@ -48,9 +46,7 @@ export class UsageError extends Error {
48
46
  * {myX: 'd.e.f[1].x'} or {myX: 'd.e.f.1.x'} => {myX: 7} // same applies to {myY: 'd.e.f[1].y'} = {myY: 8}; {myZ: 'd.e.f[1].z'} = {myZ: 9}
49
47
  * {myData: '@@STATE'} => {myData: state}
50
48
  */
51
- export function useContext<T extends import("../types").State>(context: ObservableContext<T>, selectorMap?: {
52
- [selectorKey: string]: string | keyof T;
53
- }): Store<T>;
49
+ export function useContext<T extends import("../types").State>(context: ObservableContext<T>, selectorMap?: SelectorMap<T>): Store<T>;
54
50
  export type ObservableContext<T extends import("../types").State> = IObservableContext<T> | PublicObservableContext<T>;
55
51
  export type PublicObservableContext<T extends import("../types").State> = WithObservableProvider<Context<Store<T>>, T>;
56
52
  export type IObservableContext<T extends import("../types").State> = WithObservableProvider<Context<IStore>, T>;
@@ -66,11 +62,16 @@ export type ObservableProvider<T extends import("../types").State> = FC<{
66
62
  export type State = import("../types").State;
67
63
  export type PartialState<T extends import("../types").State> = import("../types").PartialState<T>;
68
64
  export type Prehooks<T extends import("../types").State> = import("../types").Prehooks<T>;
65
+ export type SelectorMap<T extends import("../types").State> = {
66
+ [dataPropKey: string]: string | keyof T;
67
+ } & {
68
+ [dataPropKey: string]: "@@STATE";
69
+ };
69
70
  export type StoreInternal<T extends import("../types").State> = import("../types").StoreInternal<T>;
70
71
  export type PartialStore<T extends import("../types").State> = {
71
72
  data?: import("../types").Data;
72
73
  resetState?: (propertyPaths?: string[]) => void;
73
- setState?: (changes: import("../types").PartialState<T>) => void;
74
+ setState?: (changes: import("../types").UpdatePayload<import("../types").PartialState<T>>) => void;
74
75
  };
75
76
  export type Store<T extends import("../types").State> = import("../types").Store<T>;
76
77
  export type IStore = import("../types").IStore;
@@ -1,4 +1,5 @@
1
1
  export default setState;
2
+ export type TagKey = import("./tag-functions").TagKey;
2
3
  export type HasArrayRoot<K extends KeyTypes = string> = HasRoot<K, Array<any>>;
3
4
  export type HasObjectRoot<K extends KeyTypes = string> = K extends number ? {
4
5
  [rootKey: number]: {
@@ -24,9 +25,8 @@ export type HasRoot<K extends KeyTypes = string, T> = K extends number ? {
24
25
  };
25
26
  export type KeyTypes = number | string | symbol;
26
27
  export type Listener<T extends import("../../types").State> = import("../../types").Listener<T>;
28
+ export type UpdatePayload<T> = import("../../types").UpdatePayload<T>;
27
29
  export type PartialState<T extends import("../../types").State> = import("../../types").PartialState<T>;
28
30
  export type State = import("../../types").State;
29
- export type Stats = {
30
- hasChanges: boolean;
31
- };
32
- declare function setState<T extends import("../../types").State>(state: T, newState: import("../../types").PartialState<T>, onStateChange?: Listener<T>): void;
31
+ export type Stats = import("../../types").UpdateStats;
32
+ declare function setState<T extends import("../../types").State>(state: T, changes: UpdatePayload<import("../../types").PartialState<T>>, onStateChange?: Listener<T>): void;
@@ -3,95 +3,122 @@ Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
5
  exports["default"] = void 0;
6
- var _lodash = _interopRequireDefault(require("lodash.clonedeep"));
7
- var _lodash2 = _interopRequireDefault(require("lodash.isequal"));
8
- var _lodash3 = _interopRequireDefault(require("lodash.isplainobject"));
6
+ var _lodash = _interopRequireDefault(require("lodash.isequal"));
7
+ var _lodash2 = _interopRequireDefault(require("lodash.isplainobject"));
8
+ var _utils = require("../../utils");
9
+ var _tagFunctions = _interopRequireWildcard(require("./tag-functions"));
10
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
11
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
9
12
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
10
- function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
11
- function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
12
- function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
13
- function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
14
- function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
15
- function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
16
- function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
17
- var isIndexBasedObj = function isIndexBasedObj(obj) {
18
- return Object.keys(obj).every(function (k) {
19
- var i = +k;
20
- return Number.isInteger(i) && i > -1;
21
- });
22
- };
23
- function setAtomic(state, newState, stateKey, stats) {
24
- if ((0, _lodash2["default"])(state[stateKey], newState[stateKey])) {
25
- return;
13
+ function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
14
+ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
15
+ function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
16
+ function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
17
+ var _default = setState;
18
+ exports["default"] = _default;
19
+ function isIndexBasedObj(obj) {
20
+ for (var k in obj) {
21
+ if (!(k in _tagFunctions["default"] || Number.isInteger(+k))) {
22
+ return false;
23
+ }
26
24
  }
27
- var isPlainObjectNewState = (0, _lodash3["default"])(newState[stateKey]);
28
- var isArrayNewState = Array.isArray(newState[stateKey]);
29
- if (Array.isArray(state[stateKey])) {
30
- if (isArrayNewState) {
31
- return setArray(state, newState, stateKey, stats);
25
+ return true;
26
+ }
27
+ function resolveTags(state, changes, stateKey, stats) {
28
+ var resolvedTags = [];
29
+ if ((0, _tagFunctions.isClosedTag)(changes[stateKey])) {
30
+ changes[stateKey] = _defineProperty({}, changes[stateKey], null);
31
+ }
32
+ if (!(0, _utils.isDataContainer)(changes[stateKey])) {
33
+ return resolvedTags;
34
+ }
35
+ for (var k in changes[stateKey]) {
36
+ if (!(stateKey in changes)) {
37
+ break;
32
38
  }
33
- if (isPlainObjectNewState && isIndexBasedObj(newState[stateKey])) {
34
- return setArrayIndex(state, newState, stateKey, stats);
39
+ if ((0, _tagFunctions.isClosedTag)(changes[stateKey][k])) {
40
+ changes[stateKey][k] = _defineProperty({}, changes[stateKey][k], null);
41
+ }
42
+ if (k in _tagFunctions["default"]) {
43
+ _tagFunctions["default"][k](state, stateKey, stats, changes);
44
+ resolvedTags.push(k);
35
45
  }
36
46
  }
37
- if (isPlainObjectNewState && (0, _lodash3["default"])(state[stateKey])) {
38
- return setPlainObject(state, newState, stateKey, stats);
47
+ return resolvedTags;
48
+ }
49
+ function set(state, changes, stats) {
50
+ for (var k in changes) {
51
+ setAtomic(state, changes, k, stats);
39
52
  }
40
- stats.hasChanges = true;
41
- state[stateKey] = isArrayNewState || isPlainObjectNewState ? (0, _lodash["default"])(newState[stateKey]) : newState[stateKey];
42
53
  }
43
- ;
44
- function setArray(state, newState, rootKey, stats) {
45
- var nsLength = newState[rootKey].length;
54
+ function setArray(state, changes, rootKey, stats) {
55
+ var nsLength = changes[rootKey].length;
46
56
  if (state[rootKey].length !== nsLength) {
47
57
  state[rootKey].length = nsLength;
48
58
  stats.hasChanges = true;
49
59
  }
50
60
  for (var i = 0; i < nsLength; i++) {
51
- setAtomic(state[rootKey], newState[rootKey], i, stats);
61
+ setAtomic(state[rootKey], changes[rootKey], i, stats);
52
62
  }
53
63
  }
54
- ;
55
- function setArrayIndex(state, newState, rootKey, stats) {
56
- var incomingIndexes = Object.keys(newState[rootKey]).map(function (i) {
57
- return +i;
58
- });
59
- var maxIncomingIndex = Math.max.apply(Math, _toConsumableArray(incomingIndexes));
64
+ function setArrayIndex(state, changes, rootKey, stats) {
65
+ var incomingIndexes = [];
66
+ for (var k in changes[rootKey]) {
67
+ var index = +k;
68
+ if (index < 0) {
69
+ index = state[rootKey].length + index;
70
+ changes[rootKey][index] = changes[rootKey][k];
71
+ delete changes[rootKey][k];
72
+ }
73
+ index >= 0 && incomingIndexes.push(index);
74
+ }
75
+ var maxIncomingIndex = Math.max.apply(Math, incomingIndexes);
60
76
  if (maxIncomingIndex >= state[rootKey].length) {
61
77
  state[rootKey].length = maxIncomingIndex + 1;
62
78
  stats.hasChanges = true;
63
79
  }
64
- var _iterator = _createForOfIteratorHelper(incomingIndexes),
65
- _step;
66
- try {
67
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
68
- var i = _step.value;
69
- setAtomic(state[rootKey], newState[rootKey], i, stats);
70
- }
71
- } catch (err) {
72
- _iterator.e(err);
73
- } finally {
74
- _iterator.f();
80
+ for (var _i = 0, _incomingIndexes = incomingIndexes; _i < _incomingIndexes.length; _i++) {
81
+ var i = _incomingIndexes[_i];
82
+ setAtomic(state[rootKey], changes[rootKey], i, stats);
75
83
  }
76
84
  }
77
- ;
78
- function setPlainObject(state, newState, rootKey, stats) {
79
- set(state[rootKey], newState[rootKey], stats);
80
- }
81
- ;
82
- function set(state, newState, stats) {
83
- for (var k in newState) {
84
- setAtomic(state, newState, k, stats);
85
+ function setAtomic(state, changes, stateKey, stats) {
86
+ if ((0, _lodash["default"])(state[stateKey], changes[stateKey])) {
87
+ return;
88
+ }
89
+ var tagsResolved = resolveTags(state, changes, stateKey, stats);
90
+ var isPlainObjectNewState = (0, _lodash2["default"])(changes[stateKey]);
91
+ var isArrayNewState = Array.isArray(changes[stateKey]);
92
+ if (Array.isArray(state[stateKey])) {
93
+ if (isArrayNewState) {
94
+ return setArray(state, changes, stateKey, stats);
95
+ }
96
+ if (isPlainObjectNewState && isIndexBasedObj(changes[stateKey])) {
97
+ return setArrayIndex(state, changes, stateKey, stats);
98
+ }
99
+ }
100
+ if (isPlainObjectNewState && (0, _lodash2["default"])(state[stateKey])) {
101
+ return setPlainObject(state, changes, stateKey, stats);
85
102
  }
103
+ if (tagsResolved.length || !(stateKey in changes)) {
104
+ return;
105
+ }
106
+ ;
107
+ stats.hasChanges = true;
108
+ state[stateKey] = isArrayNewState || isPlainObjectNewState ? (0, _utils.clonedeep)(changes[stateKey]) : changes[stateKey];
109
+ }
110
+ function setPlainObject(state, changes, rootKey, stats) {
111
+ set(state[rootKey], changes[rootKey], stats);
86
112
  }
87
- ;
88
- function setState(state, newState, onStateChange) {
113
+ function setState(state, changes, onStateChange) {
89
114
  var stats = {
90
115
  hasChanges: false
91
116
  };
92
- set(state, newState, stats);
93
- stats.hasChanges && (onStateChange === null || onStateChange === void 0 ? void 0 : onStateChange(newState));
94
- }
95
- ;
96
- var _default = setState;
97
- exports["default"] = _default;
117
+ var changeRequest = {
118
+ state: (0, _utils.clonedeep)(changes)
119
+ };
120
+ set({
121
+ state: state
122
+ }, changeRequest, stats);
123
+ stats.hasChanges && (onStateChange === null || onStateChange === void 0 ? void 0 : onStateChange(changes));
124
+ }