@expressive/mvc 1.0.0-beta.15 → 1.0.0-beta.17

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.js CHANGED
@@ -47,7 +47,8 @@ function setAlias(func, displayName) {
47
47
  function createEffect(callback) {
48
48
  let unSet;
49
49
  return function (value) {
50
- typeof unSet == "function" && unSet();
50
+ if (typeof unSet == "function")
51
+ unSet();
51
52
  unSet = callback.call(this, value);
52
53
  if (unSet instanceof Promise)
53
54
  unSet = undefined;
@@ -55,6 +56,22 @@ function createEffect(callback) {
55
56
  throw Oops$8.BadEffectCallback();
56
57
  };
57
58
  }
59
+ function createValueEffect(callback) {
60
+ let unSet;
61
+ return function (value) {
62
+ if (typeof unSet == "function")
63
+ unSet(value);
64
+ const out = callback.call(this, value);
65
+ if (typeof out == "boolean")
66
+ return out;
67
+ if (!out || out instanceof Promise)
68
+ return;
69
+ if (typeof out == "function")
70
+ unSet = out;
71
+ else
72
+ throw Oops$8.BadEffectCallback();
73
+ };
74
+ }
58
75
  function select(source, select) {
59
76
  const proxy = {};
60
77
  for (const k in source)
@@ -447,10 +464,11 @@ function flush(on) {
447
464
  }
448
465
 
449
466
  const Oops$6 = issues({
450
- DuplicateAction: (key) => `Invoked action ${key} but one is already active.`
467
+ DuplicateAction: (key) => `Invoked action ${key} but one is already active.`,
468
+ SourceNotSupported: () => `Computed from-instruction does not support source other than 'this'.`
451
469
  });
452
- const set = (instruction, name) => does(function set(key) {
453
- let output = instruction.call(this, key, this);
470
+ const set = (fn, name) => does(function set(key) {
471
+ let output = fn.call(this, key, this);
454
472
  if (typeof output == "function") {
455
473
  const getter = output;
456
474
  output = Object.assign(Object.assign({}, getOwnPropertyDescriptor(this.subject, key)), { get() {
@@ -459,9 +477,9 @@ const set = (instruction, name) => does(function set(key) {
459
477
  }
460
478
  if (output)
461
479
  defineProperty(this.subject, key, output);
462
- }, name || instruction.name || "pending");
480
+ }, name || fn.name || "pending");
463
481
  const ref = (cb) => set(function ref(key) {
464
- const refObjectFunction = this.setter(key, cb && createEffect(cb));
482
+ const refObjectFunction = this.setter(key, cb && createValueEffect(cb));
465
483
  defineProperty(refObjectFunction, "current", {
466
484
  set: refObjectFunction,
467
485
  get: () => this.state[key]
@@ -470,8 +488,8 @@ const ref = (cb) => set(function ref(key) {
470
488
  value: refObjectFunction
471
489
  };
472
490
  });
473
- const on = (value, cb) => set(function on(key) {
474
- this.manage(key, value, cb && createEffect(cb));
491
+ const on = (initial, cb) => set(function on(key) {
492
+ this.manage(key, initial, cb && createValueEffect(cb));
475
493
  });
476
494
  const memo = (factory, defer) => set(function memo(key) {
477
495
  const source = this.subject;
@@ -511,9 +529,19 @@ const act = (task) => set(function act(key) {
511
529
  writable: false
512
530
  };
513
531
  });
514
- const from = (getter) => set(function from(key) {
515
- prepare(this, key, getter);
516
- });
532
+ function from(source, fn) {
533
+ return set(function from(key) {
534
+ let getter;
535
+ if (typeof source == "function")
536
+ getter = source.call(this.subject, key);
537
+ else {
538
+ if (source !== this.subject)
539
+ throw Oops$6.SourceNotSupported();
540
+ getter = fn;
541
+ }
542
+ prepare(this, key, getter);
543
+ });
544
+ }
517
545
 
518
546
  const attach = (from, name) => set(function attach(key) {
519
547
  const proxyCache = new WeakMap();
@@ -1058,6 +1086,9 @@ class Singleton extends Model {
1058
1086
  instance.import(updates);
1059
1087
  return instance.update();
1060
1088
  }
1089
+ static is() {
1090
+ return this.find(true);
1091
+ }
1061
1092
  static find(strict) {
1062
1093
  const instance = this.current;
1063
1094
  if (!instance && strict)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expressive/mvc",
3
- "version": "1.0.0-beta.15",
3
+ "version": "1.0.0-beta.17",
4
4
  "description": "Use classes to define state in React!",
5
5
  "author": {
6
6
  "name": "Gabe Klein",
@@ -1,5 +1,5 @@
1
- import Model from '.';
2
- import { Async, Class, EffectCallback, InstanceOf } from './types';
1
+ import Model, { Selector } from '.';
2
+ import { Async, Class, InstanceOf, InterceptCallback } from './types';
3
3
 
4
4
  /**
5
5
  * Run instruction as controller sets itself up.
@@ -99,15 +99,22 @@ export function tap <T extends typeof Model> (Type: T, callback?: (instance?: In
99
99
  * @param required - Throw if instance of Type cannot be found.
100
100
  */
101
101
  export function tap <T extends Class> (Type: T, required?: boolean): InstanceOf<T>;
102
-
102
+
103
103
  /**
104
- * Sets property to synchronously call effect upon update.
104
+ * Cause property to synchronously run effect upon update.
105
+ *
106
+ * Callback may return an effect callback, Promise (ignored), or a boolean.
107
+ *
108
+ * If a boolean is returned explicitly, new value will be dropped. Useful to override.
109
+ *
110
+ * - `false` will prevent update.
111
+ * - `true` will emit update (unchanged).
105
112
  *
106
- * @param starting - Beginning value of host property.
107
- * @param callback - Effect-callback fired upon set of host property.
113
+ * @param initialValue - Beginning value of host property.
114
+ * @param onUpdate - Effect-callback fired upon set of host property.
108
115
  */
109
- export function on <T = any> (initial: undefined, callback: EffectCallback<T>): T | undefined;
110
- export function on <T = any> (initial: T, callback: EffectCallback<T>): T;
116
+ export function on <T = any> (initialValue: undefined, onUpdate: InterceptCallback<T>): T | undefined;
117
+ export function on <T = any> (initialValue: T, onUpdate: InterceptCallback<T>): T;
111
118
 
112
119
  /**
113
120
  * Creates a ref-compatible property for use with components.
@@ -117,7 +124,7 @@ export function on <T = any> (initial: T, callback: EffectCallback<T>): T;
117
124
  *
118
125
  * @param callback - Optional callback to synchronously fire when reference is first set or does update.
119
126
  */
120
- export function ref <T = HTMLElement> (this: any, callback?: (value: T) => Callback | Promise<any> | void): Model.Ref<T>;
127
+ export function ref <T = HTMLElement> (this: any, callback?: InterceptCallback<T>): Model.Ref<T>;
121
128
 
122
129
  /**
123
130
  * Sets an exotic method with managed ready-state. Property accepts an async function.
@@ -130,15 +137,24 @@ export function ref <T = HTMLElement> (this: any, callback?: (value: T) => Callb
130
137
  * @param action - Action to fire when resulting property is invoked.
131
138
  */
132
139
  export function act <T extends Async> (action: T): T & { active: boolean };
133
-
140
+
134
141
  /**
135
- * Implement a computed value; output will be generated by provided function.
142
+ * Implement a computed value; output is returned by function from provided factory.
136
143
  *
137
- * *Alternative to using native getters; works exactly the same!*
144
+ * @param fn - Factory function to generate a getter to subscribe dependancies.
145
+ */
146
+ export function from <R> (fn: (property: string) => (this: any, on: any) => R): R;
147
+
148
+ /**
149
+ * Implement a computed value; output will be generated by provided function.
138
150
  *
139
- * @param fn - Factory function to generate value and subscribe dependancies.
151
+ * @param source - Source model from which computed value will be subscribed.
152
+ * **Note:** Currently will only support `this`.
153
+ *
154
+ * @param fn - Compute function. Bound to a subscriber-proxy of source, returns output value.
155
+ * Will update automatically as accessed values change.
140
156
  */
141
- export function from <T, R> (fn: (this: T, on: T) => R): R;
157
+ export function from <T, R> (source: T, fn: (this: T, on: T) => R): R;
142
158
 
143
159
  /**
144
160
  * Memoized value. Computes and stores a value returned by provided factory.
package/types/model.d.ts CHANGED
@@ -476,6 +476,9 @@ export abstract class Model extends State {
476
476
  }
477
477
 
478
478
  export class Singleton extends Model {
479
+ /** Get current instance of this singleton. Will throw if one does not exist. */
480
+ static is<T extends Class>(this: T): InstanceOf<T>;
481
+
479
482
  /**
480
483
  * Update the active instance of this class.
481
484
  * Returns a thenable; resolves after successful update.
package/types/types.d.ts CHANGED
@@ -10,5 +10,6 @@ export type Callback = () => void;
10
10
  export type RequestCallback = (keys?: string[]) => void;
11
11
  export type EffectCallback<T, A = T> = (this: T, argument: A) => Callback | Promise<any> | void;
12
12
  export type UpdateCallback<T, P> = (this: T, value: IfApplicable<T, P>, changed: P) => void;
13
+ export type InterceptCallback<T> = (argument: T) => ((next: T) => void) | Promise<any> | void | boolean;
13
14
 
14
15
  export type RefFunction = (e: HTMLElement | null) => void;