@microsoft/fast-element 2.0.0-beta.5 → 2.0.0-beta.6

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/CHANGELOG.json CHANGED
@@ -1,6 +1,21 @@
1
1
  {
2
2
  "name": "@microsoft/fast-element",
3
3
  "entries": [
4
+ {
5
+ "date": "Thu, 01 Sep 2022 21:53:34 GMT",
6
+ "tag": "@microsoft/fast-element_v2.0.0-beta.6",
7
+ "version": "2.0.0-beta.6",
8
+ "comments": {
9
+ "prerelease": [
10
+ {
11
+ "author": "roeisenb@microsoft.com",
12
+ "package": "@microsoft/fast-element",
13
+ "commit": "da9ebbe1b7471cd4e6f7b74f2f9bf02fcc54da4f",
14
+ "comment": "feat: add new state, ownedState, and computedState APIs"
15
+ }
16
+ ]
17
+ }
18
+ },
4
19
  {
5
20
  "date": "Thu, 18 Aug 2022 20:46:10 GMT",
6
21
  "tag": "@microsoft/fast-element_v2.0.0-beta.5",
package/CHANGELOG.md CHANGED
@@ -1,9 +1,17 @@
1
1
  # Change Log - @microsoft/fast-element
2
2
 
3
- This log was last generated on Thu, 18 Aug 2022 20:46:10 GMT and should not be manually modified.
3
+ This log was last generated on Thu, 01 Sep 2022 21:53:34 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
+ ## 2.0.0-beta.6
8
+
9
+ Thu, 01 Sep 2022 21:53:34 GMT
10
+
11
+ ### Changes
12
+
13
+ - feat: add new state, ownedState, and computedState APIs (roeisenb@microsoft.com)
14
+
7
15
  ## 2.0.0-beta.5
8
16
 
9
17
  Thu, 18 Aug 2022 20:46:10 GMT
@@ -197,3 +197,7 @@ export declare const isFunction: (object: any) => object is Function;
197
197
  * @internal
198
198
  */
199
199
  export declare const isString: (object: any) => object is string;
200
+ /**
201
+ * @internal
202
+ */
203
+ export declare const noop: () => undefined;
@@ -0,0 +1,3 @@
1
+ export { reactive } from "./reactive.js";
2
+ export { watch } from "./watch.js";
3
+ export * from "./state.js";
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Converts a plain object to a reactive, observable object.
3
+ * @param object - The object to make reactive.
4
+ * @param deep - Indicates whether or not to deeply convert the oject.
5
+ * @returns The converted object.
6
+ * @beta
7
+ */
8
+ export declare function reactive<T>(object: T, deep?: boolean): T;
@@ -0,0 +1,141 @@
1
+ import { Disposable } from "../interfaces.js";
2
+ import type { Subscriber } from "../observation/notifier.js";
3
+ /**
4
+ * Options for creating state.
5
+ * @beta
6
+ */
7
+ export declare type StateOptions = {
8
+ /**
9
+ * Indicates whether to deeply make the state value observable.
10
+ */
11
+ deep?: boolean;
12
+ /**
13
+ * A friendly name for the state.
14
+ */
15
+ name?: string;
16
+ };
17
+ /**
18
+ * A readonly stateful value.
19
+ * @beta
20
+ */
21
+ export declare type ReadonlyState<T> = {
22
+ /**
23
+ * Gets the current state value.
24
+ */
25
+ (): T;
26
+ /**
27
+ * Gets the current state value.
28
+ */
29
+ readonly current: T;
30
+ };
31
+ /**
32
+ * A read/write stateful value.
33
+ * @beta
34
+ */
35
+ export declare type State<T> = ReadonlyState<T> & {
36
+ /**
37
+ * Gets or sets the current state value.
38
+ */
39
+ current: T;
40
+ /**
41
+ * Sets the current state value.
42
+ * @param value The new state value.
43
+ */
44
+ set(value: T): void;
45
+ /**
46
+ * Creates a readonly version of the state.
47
+ */
48
+ asReadonly(): ReadonlyState<T>;
49
+ };
50
+ /**
51
+ * Creates a reactive state value.
52
+ * @param value - The initial state value.
53
+ * @param options - Options to customize the state or a friendly name.
54
+ * @returns A State instance.
55
+ * @beta
56
+ */
57
+ export declare function state<T>(value: T, options?: string | StateOptions): State<T>;
58
+ /**
59
+ * A readonly stateful value associated with an object owner.
60
+ * @beta
61
+ */
62
+ export declare type ReadonlyOwnedState<T> = {
63
+ /**
64
+ * Gets the current stateful value for the owner.
65
+ */
66
+ (owner: any): T;
67
+ };
68
+ /**
69
+ * A read/write stateful value associated with an owner.
70
+ * @beta
71
+ */
72
+ export declare type OwnedState<T> = ReadonlyOwnedState<T> & {
73
+ /**
74
+ * Sets
75
+ * @param owner - The object to set the state for the owner.
76
+ * @param value - The new state value.
77
+ */
78
+ set(owner: any, value: T): void;
79
+ /**
80
+ * Creates a readonly version of the state.
81
+ */
82
+ asReadonly(): ReadonlyOwnedState<T>;
83
+ };
84
+ /**
85
+ * Creates a reactive state that has its value associated with a specific owner.
86
+ * @param value - The initial value or a factory that provides an initial value for each owner.
87
+ * @param options - Options to customize the state or a friendly name.
88
+ * @returns An OwnedState instance.
89
+ * @beta
90
+ */
91
+ export declare function ownedState<T>(value: T | (() => T), options?: string | StateOptions): OwnedState<T>;
92
+ /**
93
+ * State whose value is computed from other dependencies.
94
+ * @beta
95
+ */
96
+ export declare type ComputedState<T> = ReadonlyState<T> & Disposable & {
97
+ /**
98
+ * Subscribes to notification of changes in the state.
99
+ * @param subscriber - The object that is subscribing for change notification.
100
+ */
101
+ subscribe(subscriber: Subscriber): void;
102
+ /**
103
+ * Unsubscribes from notification of changes in the state.
104
+ * @param subscriber - The object that is unsubscribing from change notification.
105
+ */
106
+ unsubscribe(subscriber: Subscriber): void;
107
+ };
108
+ /**
109
+ * A callback that enables computation setup.
110
+ * @beta
111
+ */
112
+ export declare type ComputedSetupCallback = () => (() => void) | void;
113
+ /**
114
+ * Provides computed state capabilities.
115
+ * @beta
116
+ */
117
+ export declare type ComputedBuilder = {
118
+ /**
119
+ * Callbacks related to computed state.
120
+ */
121
+ on: {
122
+ /**
123
+ * Provides a setup callback for the computation.
124
+ * @param callback The callback to run to setup the computation.
125
+ */
126
+ setup(callback: ComputedSetupCallback): void;
127
+ };
128
+ };
129
+ /**
130
+ * A callback that initializes the computation.
131
+ * @beta
132
+ */
133
+ export declare type ComputedInitializer<T> = (builder: ComputedBuilder) => () => T;
134
+ /**
135
+ * Creates a ComputedState.
136
+ * @param initialize - The initialization callback.
137
+ * @param name - A friendly name for this computation.
138
+ * @returns A ComputedState
139
+ * @beta
140
+ */
141
+ export declare function computedState<T>(initialize: ComputedInitializer<T>, name?: string): ComputedState<T>;
@@ -0,0 +1,6 @@
1
+ export interface ObjectVisitor<TVisitorData> {
2
+ visitObject(object: any, data: TVisitorData): void;
3
+ visitArray(array: any[], data: TVisitorData): void;
4
+ visitProperty(object: any, key: PropertyKey, value: any, data: TVisitorData): void;
5
+ }
6
+ export declare function visitObject<TVisitorData>(object: any, deep: boolean, visitor: ObjectVisitor<TVisitorData>, data: TVisitorData, traversed: WeakSet<any> | Set<any>): void;
@@ -0,0 +1,10 @@
1
+ import { Disposable } from "../interfaces.js";
2
+ import type { Subscriber } from "../observation/notifier.js";
3
+ /**
4
+ * Deeply subscribes to changes in existing observable objects.
5
+ * @param object - The observable object to watch.
6
+ * @param subscriber - The handler to call when changes are made to the object.
7
+ * @returns A disposable that can be used to unsubscribe from change updates.
8
+ * @beta
9
+ */
10
+ export declare function watch(object: any, subscriber: Subscriber | ((subject: any, args: any) => void)): Disposable;
@@ -1,21 +1,3 @@
1
- import { Disposable } from "./interfaces.js";
2
- import type { Subscriber } from "./observation/notifier.js";
3
- /**
4
- * Converts a plain object to an observable object.
5
- * @param object - The object to make observable.
6
- * @param deep - Indicates whether or not to deeply convert the oject.
7
- * @returns The converted object.
8
- * @beta
9
- */
10
- export declare function makeObservable<T>(object: T, deep?: boolean): T;
11
- /**
12
- * Deeply subscribes to changes in existing observable objects.
13
- * @param object - The observable object to watch.
14
- * @param subscriber - The handler to call when changes are made to the object.
15
- * @returns A disposable that can be used to unsubscribe from change updates.
16
- * @beta
17
- */
18
- export declare function watch(object: any, subscriber: Subscriber | ((subject: any, args: any) => void)): Disposable;
19
1
  /**
20
2
  * Retrieves the "composed parent" element of a node, ignoring DOM tree boundaries.
21
3
  * When the parent of a node is a shadow-root, it will return the host
@@ -6,3 +6,7 @@ export const isFunction = (object) => typeof object === "function";
6
6
  * @internal
7
7
  */
8
8
  export const isString = (object) => typeof object === "string";
9
+ /**
10
+ * @internal
11
+ */
12
+ export const noop = () => void 0;
@@ -0,0 +1,3 @@
1
+ export { reactive } from "./reactive.js";
2
+ export { watch } from "./watch.js";
3
+ export * from "./state.js";
@@ -0,0 +1,34 @@
1
+ import { noop } from "../interfaces.js";
2
+ import { Observable } from "../observation/observable.js";
3
+ import { visitObject } from "./visitor.js";
4
+ const observed = new WeakSet();
5
+ const makeObserverVisitor = {
6
+ visitObject: noop,
7
+ visitArray: noop,
8
+ visitProperty(object, propertyName, value) {
9
+ Reflect.defineProperty(object, propertyName, {
10
+ enumerable: true,
11
+ get() {
12
+ Observable.track(object, propertyName);
13
+ return value;
14
+ },
15
+ set(newValue) {
16
+ if (value !== newValue) {
17
+ value = newValue;
18
+ Observable.notify(object, propertyName);
19
+ }
20
+ },
21
+ });
22
+ },
23
+ };
24
+ /**
25
+ * Converts a plain object to a reactive, observable object.
26
+ * @param object - The object to make reactive.
27
+ * @param deep - Indicates whether or not to deeply convert the oject.
28
+ * @returns The converted object.
29
+ * @beta
30
+ */
31
+ export function reactive(object, deep = false) {
32
+ visitObject(object, deep, makeObserverVisitor, void 0, observed);
33
+ return object;
34
+ }
@@ -0,0 +1,148 @@
1
+ // Inspired by https://www.starbeamjs.com/
2
+ import { isFunction, isString } from "../interfaces.js";
3
+ import { Observable } from "../observation/observable.js";
4
+ import { reactive } from "./reactive.js";
5
+ const defaultStateOptions = {
6
+ deep: false,
7
+ };
8
+ /**
9
+ * Creates a reactive state value.
10
+ * @param value - The initial state value.
11
+ * @param options - Options to customize the state or a friendly name.
12
+ * @returns A State instance.
13
+ * @beta
14
+ */
15
+ export function state(value, options = defaultStateOptions) {
16
+ var _a;
17
+ if (isString(options)) {
18
+ options = { deep: false, name: options };
19
+ }
20
+ const host = reactive({ value }, options.deep);
21
+ const state = (() => host.value);
22
+ Object.defineProperty(state, "current", {
23
+ get: () => host.value,
24
+ set: (value) => (host.value = value),
25
+ });
26
+ Object.defineProperty(state, "name", {
27
+ value: (_a = options.name) !== null && _a !== void 0 ? _a : "SharedState",
28
+ });
29
+ state.set = (value) => (host.value = value);
30
+ state.asReadonly = () => {
31
+ const readonlyState = (() => host.value);
32
+ Object.defineProperty(readonlyState, "current", {
33
+ get: () => host.value,
34
+ });
35
+ Object.defineProperty(readonlyState, "name", {
36
+ value: `${state.name} (Readonly)`,
37
+ });
38
+ return Object.freeze(readonlyState);
39
+ };
40
+ return state;
41
+ }
42
+ /**
43
+ * Creates a reactive state that has its value associated with a specific owner.
44
+ * @param value - The initial value or a factory that provides an initial value for each owner.
45
+ * @param options - Options to customize the state or a friendly name.
46
+ * @returns An OwnedState instance.
47
+ * @beta
48
+ */
49
+ export function ownedState(value, options = defaultStateOptions) {
50
+ var _a;
51
+ if (isString(options)) {
52
+ options = { deep: false, name: options };
53
+ }
54
+ if (!isFunction(value)) {
55
+ const v = value;
56
+ value = () => v;
57
+ }
58
+ const storage = new WeakMap();
59
+ const getHost = (owner) => {
60
+ let host = storage.get(owner);
61
+ if (host === void 0) {
62
+ host = reactive({ value: value() }, options.deep);
63
+ storage.set(owner, host);
64
+ }
65
+ return host;
66
+ };
67
+ const state = ((owner) => getHost(owner).value);
68
+ Object.defineProperty(state, "name", {
69
+ value: (_a = options.name) !== null && _a !== void 0 ? _a : "OwnedState",
70
+ });
71
+ state.set = (owner, value) => (getHost(owner).value = value);
72
+ state.asReadonly = () => {
73
+ const readonlyState = ((owner) => getHost(owner).value);
74
+ Object.defineProperty(readonlyState, "name", {
75
+ value: `${state.name} (Readonly)`,
76
+ });
77
+ return Object.freeze(readonlyState);
78
+ };
79
+ return state;
80
+ }
81
+ /**
82
+ * Creates a ComputedState.
83
+ * @param initialize - The initialization callback.
84
+ * @param name - A friendly name for this computation.
85
+ * @returns A ComputedState
86
+ * @beta
87
+ */
88
+ export function computedState(initialize, name = "ComputedState") {
89
+ let setupCallback = null;
90
+ const builder = {
91
+ on: {
92
+ setup(callback) {
93
+ setupCallback = callback;
94
+ },
95
+ },
96
+ };
97
+ const computer = initialize(builder);
98
+ const host = reactive({ value: null }, false);
99
+ const output = (() => host.value);
100
+ Object.defineProperty(output, "current", {
101
+ get: () => host.value,
102
+ });
103
+ Object.defineProperty(output, "name", {
104
+ value: name,
105
+ });
106
+ // eslint-disable-next-line prefer-const
107
+ let computedNotifier;
108
+ const computedSubscriber = {
109
+ handleChange() {
110
+ host.value = computedNotifier.observe(null);
111
+ },
112
+ };
113
+ computedNotifier = Observable.binding(computer, computedSubscriber);
114
+ computedNotifier.setMode(false);
115
+ let cleanup;
116
+ let setupNotifier;
117
+ if (setupCallback) {
118
+ const setupSubscriber = {
119
+ handleChange() {
120
+ if (cleanup) {
121
+ cleanup();
122
+ }
123
+ cleanup = setupNotifier.observe(null);
124
+ host.value = computer();
125
+ },
126
+ };
127
+ setupNotifier = Observable.binding(setupCallback, setupSubscriber);
128
+ setupNotifier.setMode(false);
129
+ cleanup = setupNotifier.observe(null);
130
+ }
131
+ host.value = computedNotifier.observe(null);
132
+ output.dispose = () => {
133
+ if (cleanup) {
134
+ cleanup();
135
+ }
136
+ if (setupNotifier) {
137
+ setupNotifier.dispose();
138
+ }
139
+ computedNotifier.dispose();
140
+ };
141
+ output.subscribe = (subscriber) => {
142
+ computedNotifier.subscribe(subscriber);
143
+ };
144
+ output.unsubscribe = (subscriber) => {
145
+ computedNotifier.unsubscribe(subscriber);
146
+ };
147
+ return output;
148
+ }
@@ -0,0 +1,28 @@
1
+ function shouldTraverse(value, traversed) {
2
+ return (value !== null &&
3
+ value !== void 0 &&
4
+ typeof value === "object" &&
5
+ !traversed.has(value));
6
+ }
7
+ export function visitObject(object, deep, visitor, data, traversed) {
8
+ if (!shouldTraverse(object, traversed)) {
9
+ return;
10
+ }
11
+ traversed.add(object);
12
+ if (Array.isArray(object)) {
13
+ visitor.visitArray(object, data);
14
+ for (const item of object) {
15
+ visitObject(item, deep, visitor, data, traversed);
16
+ }
17
+ }
18
+ else {
19
+ visitor.visitObject(object, data);
20
+ for (const key in object) {
21
+ const value = object[key];
22
+ visitor.visitProperty(object, key, value, data);
23
+ if (deep) {
24
+ visitObject(value, deep, visitor, data, traversed);
25
+ }
26
+ }
27
+ }
28
+ }
@@ -0,0 +1,36 @@
1
+ import { isFunction, noop } from "../interfaces.js";
2
+ import { ArrayObserver } from "../observation/arrays.js";
3
+ import { Observable } from "../observation/observable.js";
4
+ import { visitObject } from "./visitor.js";
5
+ function watchObject(object, data) {
6
+ const notifier = Observable.getNotifier(object);
7
+ notifier.subscribe(data.subscriber);
8
+ data.notifiers.push(notifier);
9
+ }
10
+ const watchVisitor = {
11
+ visitProperty: noop,
12
+ visitObject: watchObject,
13
+ visitArray: watchObject,
14
+ };
15
+ /**
16
+ * Deeply subscribes to changes in existing observable objects.
17
+ * @param object - The observable object to watch.
18
+ * @param subscriber - The handler to call when changes are made to the object.
19
+ * @returns A disposable that can be used to unsubscribe from change updates.
20
+ * @beta
21
+ */
22
+ export function watch(object, subscriber) {
23
+ const data = {
24
+ notifiers: [],
25
+ subscriber: isFunction(subscriber) ? { handleChange: subscriber } : subscriber,
26
+ };
27
+ ArrayObserver.enable();
28
+ visitObject(object, true, watchVisitor, data, new Set());
29
+ return {
30
+ dispose() {
31
+ for (const n of data.notifiers) {
32
+ n.unsubscribe(data.subscriber);
33
+ }
34
+ },
35
+ };
36
+ }
@@ -1,98 +1,3 @@
1
- import { ArrayObserver } from "./index.debug.js";
2
- import { isFunction } from "./interfaces.js";
3
- import { Observable } from "./observation/observable.js";
4
- function shouldTraverse(value, traversed) {
5
- return (value !== null &&
6
- value !== void 0 &&
7
- typeof value === "object" &&
8
- !traversed.has(value));
9
- }
10
- function traverseObject(object, deep, visitor, data, traversed) {
11
- if (!shouldTraverse(object, traversed)) {
12
- return;
13
- }
14
- traversed.add(object);
15
- if (Array.isArray(object)) {
16
- visitor.visitArray(object, data);
17
- for (const item of object) {
18
- traverseObject(item, deep, visitor, data, traversed);
19
- }
20
- }
21
- else {
22
- visitor.visitObject(object, data);
23
- for (const key in object) {
24
- const value = object[key];
25
- visitor.visitProperty(object, key, value, data);
26
- if (deep) {
27
- traverseObject(value, deep, visitor, data, traversed);
28
- }
29
- }
30
- }
31
- }
32
- const noop = () => void 0;
33
- const observed = new WeakSet();
34
- const makeObserverVisitor = {
35
- visitObject: noop,
36
- visitArray: noop,
37
- visitProperty(object, propertyName, value) {
38
- Reflect.defineProperty(object, propertyName, {
39
- enumerable: true,
40
- get() {
41
- Observable.track(object, propertyName);
42
- return value;
43
- },
44
- set(newValue) {
45
- if (value !== newValue) {
46
- value = newValue;
47
- Observable.notify(object, propertyName);
48
- }
49
- },
50
- });
51
- },
52
- };
53
- function watchObject(object, data) {
54
- const notifier = Observable.getNotifier(object);
55
- notifier.subscribe(data.subscriber);
56
- data.notifiers.push(notifier);
57
- }
58
- const watchVisitor = {
59
- visitProperty: noop,
60
- visitObject: watchObject,
61
- visitArray: watchObject,
62
- };
63
- /**
64
- * Converts a plain object to an observable object.
65
- * @param object - The object to make observable.
66
- * @param deep - Indicates whether or not to deeply convert the oject.
67
- * @returns The converted object.
68
- * @beta
69
- */
70
- export function makeObservable(object, deep = false) {
71
- traverseObject(object, deep, makeObserverVisitor, void 0, observed);
72
- return object;
73
- }
74
- /**
75
- * Deeply subscribes to changes in existing observable objects.
76
- * @param object - The observable object to watch.
77
- * @param subscriber - The handler to call when changes are made to the object.
78
- * @returns A disposable that can be used to unsubscribe from change updates.
79
- * @beta
80
- */
81
- export function watch(object, subscriber) {
82
- const data = {
83
- notifiers: [],
84
- subscriber: isFunction(subscriber) ? { handleChange: subscriber } : subscriber,
85
- };
86
- ArrayObserver.enable();
87
- traverseObject(object, true, watchVisitor, data, new Set());
88
- return {
89
- dispose() {
90
- for (const n of data.notifiers) {
91
- n.unsubscribe(data.subscriber);
92
- }
93
- },
94
- };
95
- }
96
1
  /**
97
2
  * Retrieves the "composed parent" element of a node, ignoring DOM tree boundaries.
98
3
  * When the parent of a node is a shadow-root, it will return the host
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@microsoft/fast-element",
3
3
  "description": "A library for constructing Web Components",
4
- "version": "2.0.0-beta.5",
4
+ "version": "2.0.0-beta.6",
5
5
  "author": {
6
6
  "name": "Microsoft",
7
7
  "url": "https://discord.gg/FcSNfg4"
@@ -50,9 +50,9 @@
50
50
  "types": "./dist/dts/utilities.d.ts",
51
51
  "default": "./dist/esm/utilities.js"
52
52
  },
53
- "./hooks": {
54
- "types": "./dist/dts/hooks.d.ts",
55
- "default": "./dist/esm/hooks.js"
53
+ "./state": {
54
+ "types": "./dist/dts/state/exports.d.ts",
55
+ "default": "./dist/esm/state/exports.js"
56
56
  },
57
57
  "./context": {
58
58
  "types": "./dist/dts/context.d.ts",
@@ -1,20 +0,0 @@
1
- import { ExpressionNotifier } from "./observation/observable.js";
2
- /**
3
- * Functions used for getting and setting a stateful value.
4
- * @beta
5
- */
6
- export declare type State<T> = [() => T, (newValue: T) => T];
7
- /**
8
- * Creates an observable state value.
9
- * @param value The initial state value.
10
- * @param deep Whether or not to convert the state value to an observable.
11
- * @returns The state accessor functions.
12
- * @beta
13
- */
14
- export declare function useState<T>(value: T, deep?: boolean): State<T>;
15
- /**
16
- * Executes an action once, and then whenever any of its dependent state changes.
17
- * @param action An action that is affected by state changes.
18
- * @returns A BindingObserver which can be used to dispose of the effect.
19
- */
20
- export declare function useEffect(action: () => void): ExpressionNotifier;
package/dist/esm/hooks.js DELETED
@@ -1,32 +0,0 @@
1
- import { Observable } from "./observation/observable.js";
2
- import { makeObservable } from "./utilities.js";
3
- /**
4
- * Creates an observable state value.
5
- * @param value The initial state value.
6
- * @param deep Whether or not to convert the state value to an observable.
7
- * @returns The state accessor functions.
8
- * @beta
9
- */
10
- export function useState(value, deep = false) {
11
- const host = makeObservable({ value }, deep);
12
- return [() => host.value, newValue => (host.value = newValue)];
13
- }
14
- const effectModel = Object.freeze({});
15
- /**
16
- * Executes an action once, and then whenever any of its dependent state changes.
17
- * @param action An action that is affected by state changes.
18
- * @returns A BindingObserver which can be used to dispose of the effect.
19
- */
20
- export function useEffect(action) {
21
- /* eslint prefer-const: 0 */
22
- let observer;
23
- const subscriber = {
24
- handleChange() {
25
- observer.observe(effectModel);
26
- },
27
- };
28
- observer = Observable.binding(action, subscriber);
29
- observer.setMode(false);
30
- subscriber.handleChange();
31
- return observer;
32
- }