@expressive/mvc 0.2.0 → 0.2.3

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/lib/index.d.ts CHANGED
@@ -364,6 +364,18 @@ declare function set<T>(factory: set.Factory<T>, required?: boolean): T;
364
364
  declare function set<T, S>(factory: set.Factory<T, S>, required?: boolean): T;
365
365
  declare function set<T>(value: set.Factory<T>, onUpdate: set.Callback<T>): T;
366
366
  declare function set<T, S>(value: set.Factory<T, S>, onUpdate: set.Callback<T, S>): T;
367
+ /**
368
+ * Assign a property with result of a promise.
369
+ */
370
+ declare function set<T>(factory: Promise<T>, required: false): T | undefined;
371
+ declare function set<T>(factory: Promise<T>, required?: boolean): T;
372
+ declare function set<T>(value: Promise<T>, onUpdate: set.Callback<T>): T;
373
+ /**
374
+ * Assign a property.
375
+ */
376
+ declare function set<T>(factory: T, required: false): T | undefined;
377
+ declare function set<T>(factory: T, required?: boolean): T;
378
+ declare function set<T>(value: T, onUpdate: set.Callback<T>): T;
367
379
 
368
380
  /**
369
381
  * Create a placeholder for specified Model type.
@@ -418,19 +430,26 @@ declare class MVC extends Model {
418
430
  /**
419
431
  * **React Hook** - Fetch most instance of this controller from context, if it exists.
420
432
  *
421
- * @param required - If false, may return undefined.
433
+ * @param required - Unless false, will throw where instance cannot be found.
422
434
  */
423
- static get<T extends Class>(this: T, required?: true): InstanceOf<T>;
435
+ static get<T extends Class>(this: T, required?: boolean): InstanceOf<T>;
424
436
  /**
425
437
  * **React Hook** - Fetch most instance of this controller from context.
426
438
  *
427
- * @param required - Unless false, will throw where instance cannot be found.
439
+ * @param required - If false, may return undefined.
428
440
  */
429
- static get<T extends Class>(this: T, required: boolean): InstanceOf<T> | undefined;
441
+ static get<T extends Class>(this: T, required: false): InstanceOf<T> | undefined;
430
442
  /**
431
443
  * **React Hook** - Fetch specific value from instance of this controller in context.
432
444
  */
433
445
  static get<T extends Class, I extends InstanceOf<T>, K extends Model.Field<I>>(this: T, key: K): I[K];
446
+ /**
447
+ * **React Hook** - Fetch instance.
448
+ *
449
+ * Effect callback will run once if found, throw if not found.
450
+ * Returned function is called on unmount.
451
+ */
452
+ static get<T extends Class, I extends InstanceOf<T>>(type: T, effect: (found: I) => Callback | void): I;
434
453
  /**
435
454
  * **React Hook** - Fetch and subscribe to instance of this controller within ambient component.
436
455
  */
@@ -599,7 +618,10 @@ declare function tap<T extends Class>(Type: T, required?: boolean): InstanceOf<T
599
618
  declare function useFrom<T extends Stateful, R>(source: (() => T) | T, compute: (this: T, from: T) => R, expect: true): Exclude<R, undefined>;
600
619
  declare function useFrom<T extends Stateful, R>(source: (() => T) | T, compute: (this: T, from: T) => R, expect?: boolean): R;
601
620
 
602
- declare function useLocal<T extends typeof Model>(Type: T, arg?: boolean | string): any;
621
+ declare function useLocal<T extends typeof Model>(Type: T, required: false): InstanceOf<T> | undefined;
622
+ declare function useLocal<T extends typeof Model>(Type: T, arg?: boolean): InstanceOf<T>;
623
+ declare function useLocal<T extends typeof Model, I extends InstanceOf<T>>(Type: T, effect: (found: I) => Callback | void): I;
624
+ declare function useLocal<T extends typeof Model, I extends InstanceOf<T>, K extends Model.Field<I>>(Type: T, key: K): I[K];
603
625
 
604
626
  declare function useModel<T extends Class, I extends InstanceOf<T>>(source: T, watch: Model.Field<I>[], callback?: (instance: I) => void): I;
605
627
  declare function useModel<T extends Class, I extends InstanceOf<T>>(source: T, callback?: (instance: I) => void): I;
package/lib/index.esm.js CHANGED
@@ -1,4 +1,4 @@
1
- import React, { useState, useMemo } from 'react';
1
+ import React, { useLayoutEffect, useState, useMemo } from 'react';
2
2
 
3
3
  /*! *****************************************************************************
4
4
  Copyright (c) Microsoft Corporation.
@@ -824,28 +824,74 @@ function createRef(key, cb) {
824
824
 
825
825
  const Oops$7 = issues({
826
826
  NonOptional: (Parent, key) => `Property ${Parent}.${key} is marked as required.`,
827
- BadFactory: () => `Set instruction can only accept a factory or undefined.`,
828
827
  NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
829
828
  Failed: (model, key) => `Generating initial value for ${model}.${key} failed.`
830
829
  });
831
830
  function set(factory, argument) {
832
831
  return apply(function set(key) {
832
+ const { subject, state } = this;
833
+ const required = argument === true || argument === undefined;
833
834
  let set;
834
835
  let get;
835
836
  let suspense;
836
- const required = argument === true || argument === undefined;
837
837
  if (factory === undefined)
838
838
  suspense = true;
839
- else if (typeof factory === "function")
840
- get = pendingFactory(this, key, factory, required);
841
- else
842
- throw Oops$7.BadFactory();
839
+ else {
840
+ let pending;
841
+ let error;
842
+ const init = () => {
843
+ const output = typeof factory == "function" ?
844
+ mayRetry(() => factory.call(subject, key, subject)) :
845
+ factory;
846
+ if (output instanceof Promise) {
847
+ pending = output
848
+ .catch(err => error = err)
849
+ .then(val => state[key] = val)
850
+ .finally(() => {
851
+ pending = undefined;
852
+ this.update(key);
853
+ });
854
+ return;
855
+ }
856
+ return state[key] = output;
857
+ };
858
+ const suspend = () => {
859
+ if (required === false)
860
+ return undefined;
861
+ const issue = Oops$7.NotReady(subject, key);
862
+ Object.assign(pending, {
863
+ message: issue.message,
864
+ stack: issue.stack
865
+ });
866
+ throw pending;
867
+ };
868
+ if (required)
869
+ try {
870
+ init();
871
+ }
872
+ catch (err) {
873
+ Oops$7.Failed(subject, key).warn();
874
+ throw err;
875
+ }
876
+ get = () => {
877
+ if (pending)
878
+ return suspend();
879
+ if (error)
880
+ throw error;
881
+ if (key in state)
882
+ return state[key];
883
+ let output = init();
884
+ return pending
885
+ ? suspend()
886
+ : output;
887
+ };
888
+ }
843
889
  if (typeof argument == "function")
844
890
  set = createValueEffect(argument);
845
891
  else
846
892
  set = (value) => {
847
893
  if (value === undefined && required)
848
- throw Oops$7.NonOptional(this.subject, key);
894
+ throw Oops$7.NonOptional(subject, key);
849
895
  };
850
896
  return {
851
897
  set,
@@ -853,57 +899,6 @@ function set(factory, argument) {
853
899
  suspense
854
900
  };
855
901
  });
856
- }
857
- function pendingFactory(parent, key, fn, required) {
858
- const { subject, state } = parent;
859
- let pending;
860
- let error;
861
- const init = () => {
862
- const output = mayRetry(() => {
863
- return fn.call(subject, key, subject);
864
- });
865
- if (output instanceof Promise) {
866
- pending = output
867
- .catch(err => error = err)
868
- .then(val => state[key] = val)
869
- .finally(() => {
870
- pending = undefined;
871
- parent.update(key);
872
- });
873
- return;
874
- }
875
- return state[key] = output;
876
- };
877
- const suspend = () => {
878
- if (required === false)
879
- return undefined;
880
- const issue = Oops$7.NotReady(subject, key);
881
- Object.assign(pending, {
882
- message: issue.message,
883
- stack: issue.stack
884
- });
885
- throw pending;
886
- };
887
- if (required)
888
- try {
889
- init();
890
- }
891
- catch (err) {
892
- Oops$7.Failed(subject, key).warn();
893
- throw err;
894
- }
895
- return () => {
896
- if (pending)
897
- return suspend();
898
- if (error)
899
- throw error;
900
- if (key in state)
901
- return state[key];
902
- let output = init();
903
- return pending
904
- ? suspend()
905
- : output;
906
- };
907
902
  }
908
903
 
909
904
  const Parent = new WeakMap();
@@ -1032,9 +1027,14 @@ function useLocal(Type, arg) {
1032
1027
  const instance = useLookup().get(Type);
1033
1028
  if (!instance && arg !== false)
1034
1029
  throw Oops$4.NotFound(Type.name);
1035
- return typeof arg == "string" ?
1036
- instance[arg] :
1037
- instance;
1030
+ switch (typeof arg) {
1031
+ case "string":
1032
+ return instance[arg];
1033
+ case "function":
1034
+ useLayoutEffect(() => arg(instance), []);
1035
+ default:
1036
+ return instance;
1037
+ }
1038
1038
  }
1039
1039
 
1040
1040
  const Oops$3 = issues({
@@ -1230,8 +1230,8 @@ class MVC extends Model {
1230
1230
  use(arg, callback) {
1231
1231
  return useModel(this, arg, callback);
1232
1232
  }
1233
- static get(required) {
1234
- return useLocal(this, required);
1233
+ static get(arg) {
1234
+ return useLocal(this, arg);
1235
1235
  }
1236
1236
  static tap(key, expect) {
1237
1237
  return useTap(this, key, expect);