@esportsplus/reactivity 0.2.2 → 0.2.4
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/build/reactive/array.d.ts +48 -21
- package/build/reactive/array.js +88 -64
- package/build/reactive/index.d.ts +9 -12
- package/build/reactive/object.d.ts +8 -10
- package/build/reactive/object.js +0 -4
- package/build/signal.js +2 -5
- package/build/types.d.ts +7 -5
- package/package.json +1 -1
- package/src/reactive/array.ts +150 -89
- package/src/reactive/index.ts +10 -22
- package/src/reactive/object.ts +7 -9
- package/src/signal.ts +2 -6
- package/src/types.ts +16 -2
|
@@ -1,49 +1,76 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ReactiveObject } from '
|
|
1
|
+
import { Infer, Prettify } from '../types';
|
|
2
|
+
import { Listener, Options, ReactiveObject, Signal } from '../types';
|
|
3
|
+
type API<T> = Prettify<{
|
|
4
|
+
[index: number]: Infer<T>;
|
|
5
|
+
} & ReturnType<typeof methods<T>>>;
|
|
3
6
|
type Events<T> = {
|
|
4
7
|
pop: {
|
|
5
|
-
item:
|
|
8
|
+
item: Item<T>;
|
|
6
9
|
};
|
|
7
10
|
push: {
|
|
8
|
-
items:
|
|
11
|
+
items: Item<T>[];
|
|
9
12
|
};
|
|
10
13
|
reverse: undefined;
|
|
14
|
+
set: {
|
|
15
|
+
index: number;
|
|
16
|
+
item: Item<T>;
|
|
17
|
+
};
|
|
11
18
|
shift: {
|
|
12
|
-
item:
|
|
19
|
+
item: Item<T>;
|
|
13
20
|
};
|
|
14
21
|
sort: undefined;
|
|
15
22
|
splice: {
|
|
16
23
|
deleteCount: number;
|
|
17
|
-
items:
|
|
24
|
+
items: Item<T>[];
|
|
18
25
|
start: number;
|
|
19
26
|
};
|
|
20
27
|
unshift: {
|
|
21
|
-
items:
|
|
28
|
+
items: Item<T>[];
|
|
22
29
|
};
|
|
23
30
|
};
|
|
24
|
-
type
|
|
25
|
-
|
|
26
|
-
} : never>;
|
|
27
|
-
declare class ReactiveArray<T> extends Array<R<T>> {
|
|
31
|
+
type Item<T> = T extends Record<PropertyKey, unknown> ? ReactiveObject<T> : Signal<T>;
|
|
32
|
+
declare class ReactiveArray<T> extends Array<Item<T>> {
|
|
28
33
|
private options;
|
|
29
|
-
private
|
|
34
|
+
private proxy;
|
|
30
35
|
private signal;
|
|
31
|
-
constructor(data:
|
|
36
|
+
constructor(data: Item<T>[], proxy: API<T>, options?: Options);
|
|
32
37
|
set length(n: number);
|
|
33
|
-
at(
|
|
38
|
+
at(i: number): any;
|
|
34
39
|
dispatch<E extends keyof Events<T>>(event: E, data?: Events<T>[E]): void;
|
|
35
40
|
dispose(): void;
|
|
36
|
-
map<U>(fn: (this: T
|
|
41
|
+
map<U>(fn: (this: API<T>, value: T, i: number) => U, i?: number, n?: number): U[];
|
|
37
42
|
on<E extends keyof Events<T>>(event: E, listener: Listener<Events<T>[E]>): void;
|
|
38
43
|
once<E extends keyof Events<T>>(event: E, listener: Listener<Events<T>[E]>): void;
|
|
39
|
-
pop():
|
|
44
|
+
pop(): Item<T> | undefined;
|
|
40
45
|
push(...input: T[]): number;
|
|
41
46
|
reverse(): this;
|
|
42
|
-
shift():
|
|
43
|
-
sort(): this;
|
|
44
|
-
splice(start: number, deleteCount?: number, ...input: T[]):
|
|
47
|
+
shift(): Item<T> | undefined;
|
|
48
|
+
sort(fn: (a: T, b: T) => number): this;
|
|
49
|
+
splice(start: number, deleteCount?: number, ...input: T[]): Item<T>[];
|
|
45
50
|
unshift(...input: T[]): number;
|
|
46
51
|
}
|
|
47
|
-
declare
|
|
52
|
+
declare function methods<T>(a: ReactiveArray<T>): Prettify<{
|
|
53
|
+
get constructor(): typeof a['constructor'];
|
|
54
|
+
get length(): number;
|
|
55
|
+
set length(n: number);
|
|
56
|
+
} & Pick<typeof a, 'at' | 'dispatch' | 'dispose' | 'map' | 'on' | 'once' | 'pop' | 'push' | 'reverse' | 'shift' | 'sort' | 'splice' | 'unshift'>>;
|
|
57
|
+
declare const _default: <T>(input: T[], options?: Options) => {
|
|
58
|
+
[x: number]: Infer<T>;
|
|
59
|
+
readonly constructor: Function;
|
|
60
|
+
length: number;
|
|
61
|
+
dispatch: <E extends keyof Events<T>>(event: E, data?: Events<T>[E] | undefined) => void;
|
|
62
|
+
dispose: () => void;
|
|
63
|
+
on: <E extends keyof Events<T>>(event: E, listener: Listener<Events<T>[E]>) => void;
|
|
64
|
+
once: <E extends keyof Events<T>>(event: E, listener: Listener<Events<T>[E]>) => void;
|
|
65
|
+
at: (i: number) => any;
|
|
66
|
+
map: <U>(fn: (this: any, value: T, i: number) => U, i?: number, n?: number) => U[];
|
|
67
|
+
pop: () => Item<T> | undefined;
|
|
68
|
+
push: (...input: T[]) => number;
|
|
69
|
+
reverse: () => ReactiveArray<T>;
|
|
70
|
+
shift: () => Item<T> | undefined;
|
|
71
|
+
sort: (fn: (a: T, b: T) => number) => ReactiveArray<T>;
|
|
72
|
+
splice: (start: number, deleteCount?: number, ...input: T[]) => Item<T>[];
|
|
73
|
+
unshift: (...input: T[]) => number;
|
|
74
|
+
};
|
|
48
75
|
export default _default;
|
|
49
|
-
export { ReactiveArray };
|
|
76
|
+
export { API as ReactiveArray };
|
package/build/reactive/array.js
CHANGED
|
@@ -1,63 +1,14 @@
|
|
|
1
1
|
import { isInstanceOf, isNumber, isObject } from '@esportsplus/utilities';
|
|
2
2
|
import { dispose, signal, Reactive } from '../signal';
|
|
3
|
-
import
|
|
4
|
-
let handler = {
|
|
5
|
-
get(target, prop) {
|
|
6
|
-
let value = target[prop];
|
|
7
|
-
if (value === undefined) {
|
|
8
|
-
return value;
|
|
9
|
-
}
|
|
10
|
-
if (isInstanceOf(value, Reactive)) {
|
|
11
|
-
return value.get();
|
|
12
|
-
}
|
|
13
|
-
else if (supported.has(prop)) {
|
|
14
|
-
return value;
|
|
15
|
-
}
|
|
16
|
-
throw new Error(`Reactivity: '${prop}' is not supported on reactive arrays`);
|
|
17
|
-
},
|
|
18
|
-
set(target, prop, value) {
|
|
19
|
-
if (isNumber(prop)) {
|
|
20
|
-
let host = target[prop];
|
|
21
|
-
if (isInstanceOf(host, Reactive)) {
|
|
22
|
-
host.set(value);
|
|
23
|
-
return true;
|
|
24
|
-
}
|
|
25
|
-
return false;
|
|
26
|
-
}
|
|
27
|
-
return target[prop] = value;
|
|
28
|
-
}
|
|
29
|
-
}, supported = new Set([
|
|
30
|
-
'at',
|
|
31
|
-
'dispatch', 'dispose',
|
|
32
|
-
'length',
|
|
33
|
-
'map',
|
|
34
|
-
'on', 'once',
|
|
35
|
-
'pop', 'push',
|
|
36
|
-
'reverse',
|
|
37
|
-
'self', 'shift', 'sort', 'splice',
|
|
38
|
-
'unshift'
|
|
39
|
-
]);
|
|
40
|
-
function factory(input, options = {}) {
|
|
41
|
-
let items = [];
|
|
42
|
-
for (let i = 0, n = input.length; i < n; i++) {
|
|
43
|
-
let value = input[i];
|
|
44
|
-
if (isObject(value)) {
|
|
45
|
-
items[i] = new ReactiveObject(value, options);
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
items[i] = signal(value);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
return items;
|
|
52
|
-
}
|
|
3
|
+
import object from './object';
|
|
53
4
|
class ReactiveArray extends Array {
|
|
54
5
|
options;
|
|
55
|
-
|
|
6
|
+
proxy;
|
|
56
7
|
signal;
|
|
57
|
-
constructor(data, options = {}) {
|
|
8
|
+
constructor(data, proxy, options = {}) {
|
|
58
9
|
super(...data);
|
|
59
10
|
this.options = options;
|
|
60
|
-
this.
|
|
11
|
+
this.proxy = proxy;
|
|
61
12
|
this.signal = signal(false);
|
|
62
13
|
}
|
|
63
14
|
set length(n) {
|
|
@@ -66,8 +17,8 @@ class ReactiveArray extends Array {
|
|
|
66
17
|
}
|
|
67
18
|
this.splice(n);
|
|
68
19
|
}
|
|
69
|
-
at(
|
|
70
|
-
let value = super.at(
|
|
20
|
+
at(i) {
|
|
21
|
+
let value = super.at(i);
|
|
71
22
|
if (isInstanceOf(value, Reactive)) {
|
|
72
23
|
return value.get();
|
|
73
24
|
}
|
|
@@ -78,12 +29,20 @@ class ReactiveArray extends Array {
|
|
|
78
29
|
}
|
|
79
30
|
dispose() {
|
|
80
31
|
this.signal.dispose();
|
|
81
|
-
dispose(this
|
|
32
|
+
dispose(this);
|
|
82
33
|
}
|
|
83
|
-
map(fn) {
|
|
84
|
-
let
|
|
85
|
-
|
|
86
|
-
|
|
34
|
+
map(fn, i, n) {
|
|
35
|
+
let proxy = this.proxy, values = [];
|
|
36
|
+
if (i === undefined) {
|
|
37
|
+
i = 0;
|
|
38
|
+
}
|
|
39
|
+
if (n === undefined) {
|
|
40
|
+
n = this.length;
|
|
41
|
+
}
|
|
42
|
+
n = Math.min(n, this.length);
|
|
43
|
+
for (; i < n; i++) {
|
|
44
|
+
let item = this[i];
|
|
45
|
+
values.push(fn.call(proxy, isInstanceOf(item, Reactive) ? item.value : item, i));
|
|
87
46
|
}
|
|
88
47
|
return values;
|
|
89
48
|
}
|
|
@@ -119,8 +78,8 @@ class ReactiveArray extends Array {
|
|
|
119
78
|
}
|
|
120
79
|
return item;
|
|
121
80
|
}
|
|
122
|
-
sort() {
|
|
123
|
-
super.sort();
|
|
81
|
+
sort(fn) {
|
|
82
|
+
super.sort((a, b) => fn(isInstanceOf(a, Reactive) ? a.value : a, isInstanceOf(b, Reactive) ? b.value : b));
|
|
124
83
|
this.signal.dispatch('sort');
|
|
125
84
|
return this;
|
|
126
85
|
}
|
|
@@ -142,7 +101,72 @@ class ReactiveArray extends Array {
|
|
|
142
101
|
return length;
|
|
143
102
|
}
|
|
144
103
|
}
|
|
104
|
+
function factory(input, options = {}) {
|
|
105
|
+
let items = [];
|
|
106
|
+
for (let i = 0, n = input.length; i < n; i++) {
|
|
107
|
+
let value = input[i];
|
|
108
|
+
if (isObject(value)) {
|
|
109
|
+
items[i] = object(value, options);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
items[i] = signal(value);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return items;
|
|
116
|
+
}
|
|
117
|
+
function methods(a) {
|
|
118
|
+
return {
|
|
119
|
+
get constructor() {
|
|
120
|
+
return a.constructor;
|
|
121
|
+
},
|
|
122
|
+
get length() {
|
|
123
|
+
return a.length;
|
|
124
|
+
},
|
|
125
|
+
set length(n) {
|
|
126
|
+
a.length = n;
|
|
127
|
+
},
|
|
128
|
+
at: (index) => a.at(index),
|
|
129
|
+
dispatch: (event, data) => a.dispatch(event, data),
|
|
130
|
+
dispose: () => a.dispose(),
|
|
131
|
+
map: (fn, i, n) => a.map(fn, i, n),
|
|
132
|
+
on: (event, listener) => a.on(event, listener),
|
|
133
|
+
once: (event, listener) => a.once(event, listener),
|
|
134
|
+
pop: () => a.pop(),
|
|
135
|
+
push: (...input) => a.push(...input),
|
|
136
|
+
reverse: () => a.reverse(),
|
|
137
|
+
shift: () => a.shift(),
|
|
138
|
+
sort: (fn) => a.sort(fn),
|
|
139
|
+
splice: (start, deleteCount, ...input) => a.splice(start, deleteCount, ...input),
|
|
140
|
+
unshift: (...input) => a.unshift(...input)
|
|
141
|
+
};
|
|
142
|
+
}
|
|
145
143
|
export default (input, options = {}) => {
|
|
146
|
-
|
|
144
|
+
let proxy = new Proxy({}, {
|
|
145
|
+
get(_, key) {
|
|
146
|
+
if (isNumber(key)) {
|
|
147
|
+
let value = a[key];
|
|
148
|
+
if (isInstanceOf(value, Reactive)) {
|
|
149
|
+
return value.get();
|
|
150
|
+
}
|
|
151
|
+
return value;
|
|
152
|
+
}
|
|
153
|
+
else if (key in m) {
|
|
154
|
+
return m[key];
|
|
155
|
+
}
|
|
156
|
+
throw new Error(`Reactivity: '${key}' is not supported on reactive arrays`);
|
|
157
|
+
},
|
|
158
|
+
set(_, key, value) {
|
|
159
|
+
if (isNumber(key)) {
|
|
160
|
+
let host = a[key];
|
|
161
|
+
if (isInstanceOf(host, Reactive)) {
|
|
162
|
+
host.set(value);
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
return a[key] = value;
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
let a = new ReactiveArray(factory(input, options), proxy), m = methods(a);
|
|
171
|
+
return proxy;
|
|
147
172
|
};
|
|
148
|
-
export { ReactiveArray };
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
} : T;
|
|
11
|
-
type Never<K, V> = K extends keyof ReactiveObject<Record<PropertyKey, unknown>> ? never : V;
|
|
12
|
-
declare const _default: <T>(data: Guard<T>, options?: Options) => T extends Record<PropertyKey, unknown> ? { [K in keyof T]: Infer<T[K]>; } : Infer<T>;
|
|
1
|
+
import { Options, ReactiveArray, ReactiveObject } from '../types';
|
|
2
|
+
type Guard<T> = T extends {
|
|
3
|
+
dispose: any;
|
|
4
|
+
} | {
|
|
5
|
+
signals: any;
|
|
6
|
+
} ? {
|
|
7
|
+
never: '[ dispose, signals ] are reserved keys';
|
|
8
|
+
} : T extends Record<PropertyKey, unknown> | unknown[] ? T : never;
|
|
9
|
+
declare const _default: <T>(data: Guard<T>, options?: Options) => T extends Record<PropertyKey, unknown> ? ReactiveObject<T> : ReactiveArray<T>;
|
|
13
10
|
export default _default;
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
declare const _default: <T extends Record<PropertyKey, unknown>>(input: T, options?: Options) => ReactiveObject<T>;
|
|
1
|
+
import { Infer, Options, Prettify } from '../types';
|
|
2
|
+
type API<T> = Prettify<{
|
|
3
|
+
[K in keyof T]: Infer<T[K]>;
|
|
4
|
+
} & {
|
|
5
|
+
dispose: VoidFunction;
|
|
6
|
+
}>;
|
|
7
|
+
declare const _default: <T extends Record<PropertyKey, unknown>>(input: T, options?: Options) => API<T>;
|
|
10
8
|
export default _default;
|
|
11
|
-
export { ReactiveObject };
|
|
9
|
+
export { API as ReactiveObject };
|
package/build/reactive/object.js
CHANGED
|
@@ -39,9 +39,6 @@ class ReactiveObject {
|
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
|
-
get value() {
|
|
43
|
-
return this;
|
|
44
|
-
}
|
|
45
42
|
dispose() {
|
|
46
43
|
let signals = this.signals;
|
|
47
44
|
for (let key in signals) {
|
|
@@ -52,4 +49,3 @@ class ReactiveObject {
|
|
|
52
49
|
export default (input, options = {}) => {
|
|
53
50
|
return new ReactiveObject(input, options);
|
|
54
51
|
};
|
|
55
|
-
export { ReactiveObject };
|
package/build/signal.js
CHANGED
|
@@ -41,17 +41,14 @@ class Reactive {
|
|
|
41
41
|
if (this.listeners === null || this.listeners[event] === undefined) {
|
|
42
42
|
return;
|
|
43
43
|
}
|
|
44
|
-
let listeners = this.listeners[event]
|
|
45
|
-
data,
|
|
46
|
-
value: this.value
|
|
47
|
-
};
|
|
44
|
+
let listeners = this.listeners[event];
|
|
48
45
|
for (let i = 0, n = listeners.length; i < n; i++) {
|
|
49
46
|
let listener = listeners[i];
|
|
50
47
|
if (listener === null) {
|
|
51
48
|
continue;
|
|
52
49
|
}
|
|
53
50
|
try {
|
|
54
|
-
listener(
|
|
51
|
+
listener(data, this.value);
|
|
55
52
|
if (listener.once !== undefined) {
|
|
56
53
|
listeners[i] = null;
|
|
57
54
|
}
|
package/build/types.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Function, NeverAsync, Prettify } from '@esportsplus/typescript';
|
|
2
|
+
import { ReactiveArray } from './reactive/array';
|
|
3
|
+
import { ReactiveObject } from './reactive/object';
|
|
2
4
|
import { CHECK, CLEAN, COMPUTED, DIRTY, DISPOSED, EFFECT, ROOT, SIGNAL } from './constants';
|
|
3
5
|
import { Reactive } from './signal';
|
|
4
6
|
type Base<T> = Omit<Reactive<T>, 'changed' | 'fn' | 'get' | 'scheduler' | 'set' | 'task' | 'tracking'>;
|
|
@@ -13,13 +15,13 @@ type Effect = {
|
|
|
13
15
|
root: Root;
|
|
14
16
|
task: Function;
|
|
15
17
|
} & Omit<Base<void>, 'value'>;
|
|
18
|
+
type Infer<T> = T extends (...args: unknown[]) => unknown ? ReturnType<T> : T extends (infer U)[] ? ReactiveArray<U> : T extends ReactiveObject<T> ? ReactiveObject<T> : T extends Record<PropertyKey, unknown> ? {
|
|
19
|
+
[K in keyof T]: T[K];
|
|
20
|
+
} : T;
|
|
16
21
|
type Event = string;
|
|
17
22
|
type Listener<D> = {
|
|
18
23
|
once?: boolean;
|
|
19
|
-
<V>(
|
|
20
|
-
data?: D;
|
|
21
|
-
value: V;
|
|
22
|
-
}): void;
|
|
24
|
+
<V>(data: D, value: V): void;
|
|
23
25
|
};
|
|
24
26
|
type Options = {
|
|
25
27
|
changed?: Changed;
|
|
@@ -37,4 +39,4 @@ type Signal<T> = {
|
|
|
37
39
|
} & Base<T>;
|
|
38
40
|
type State = typeof CHECK | typeof CLEAN | typeof DIRTY | typeof DISPOSED;
|
|
39
41
|
type Type = typeof COMPUTED | typeof EFFECT | typeof ROOT | typeof SIGNAL;
|
|
40
|
-
export type { Changed, Computed, Effect, Event, Function, Listener, NeverAsync, Options, Prettify, Root, Scheduler, Signal, State, Type };
|
|
42
|
+
export type { Changed, Computed, Effect, Event, Function, Infer, Listener, NeverAsync, Options, Prettify, ReactiveArray, ReactiveObject, Root, Scheduler, Signal, State, Type };
|
package/package.json
CHANGED
package/src/reactive/array.ts
CHANGED
|
@@ -1,112 +1,54 @@
|
|
|
1
|
+
import { Infer, Prettify } from '~/types';
|
|
1
2
|
import { isInstanceOf, isNumber, isObject } from '@esportsplus/utilities';
|
|
2
3
|
import { dispose, signal, Reactive } from '~/signal';
|
|
3
|
-
import { Listener, Options, Signal } from '~/types';
|
|
4
|
-
import
|
|
4
|
+
import { Listener, Options, ReactiveObject, Signal } from '~/types';
|
|
5
|
+
import object from './object';
|
|
5
6
|
|
|
6
7
|
|
|
8
|
+
type API<T> = Prettify< { [index: number]: Infer<T> } & ReturnType<typeof methods<T>> >;
|
|
9
|
+
|
|
7
10
|
type Events<T> = {
|
|
8
11
|
pop: {
|
|
9
|
-
item:
|
|
12
|
+
item: Item<T>;
|
|
10
13
|
};
|
|
11
14
|
push: {
|
|
12
|
-
items:
|
|
15
|
+
items: Item<T>[];
|
|
13
16
|
};
|
|
14
17
|
reverse: undefined;
|
|
18
|
+
set: {
|
|
19
|
+
index: number;
|
|
20
|
+
item: Item<T>;
|
|
21
|
+
};
|
|
15
22
|
shift: {
|
|
16
|
-
item:
|
|
23
|
+
item: Item<T>;
|
|
17
24
|
};
|
|
18
25
|
sort: undefined;
|
|
19
26
|
splice: {
|
|
20
27
|
deleteCount: number;
|
|
21
|
-
items:
|
|
28
|
+
items: Item<T>[];
|
|
22
29
|
start: number;
|
|
23
30
|
};
|
|
24
31
|
unshift: {
|
|
25
|
-
items:
|
|
32
|
+
items: Item<T>[];
|
|
26
33
|
};
|
|
27
34
|
};
|
|
28
35
|
|
|
29
|
-
type
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
let handler = {
|
|
33
|
-
get(target: any, prop: any) {
|
|
34
|
-
let value = target[prop];
|
|
35
|
-
|
|
36
|
-
if (value === undefined) {
|
|
37
|
-
return value;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (isInstanceOf(value, Reactive)) {
|
|
41
|
-
return value.get();
|
|
42
|
-
}
|
|
43
|
-
else if (supported.has(prop)) {
|
|
44
|
-
return value;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
throw new Error(`Reactivity: '${prop}' is not supported on reactive arrays`);
|
|
48
|
-
},
|
|
49
|
-
set(target: any, prop: any, value: any) {
|
|
50
|
-
if (isNumber(prop)) {
|
|
51
|
-
let host = target[prop];
|
|
52
|
-
|
|
53
|
-
if (isInstanceOf(host, Reactive)) {
|
|
54
|
-
host.set(value);
|
|
55
|
-
return true;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return target[prop] = value;
|
|
62
|
-
}
|
|
63
|
-
},
|
|
64
|
-
supported = new Set([
|
|
65
|
-
'at',
|
|
66
|
-
'dispatch', 'dispose',
|
|
67
|
-
'length',
|
|
68
|
-
'map',
|
|
69
|
-
'on', 'once',
|
|
70
|
-
'pop', 'push',
|
|
71
|
-
'reverse',
|
|
72
|
-
'self', 'shift', 'sort', 'splice',
|
|
73
|
-
'unshift'
|
|
74
|
-
]);
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
function factory<T>(input: T[], options: Options = {}) {
|
|
78
|
-
let items: R<T>[] = [];
|
|
79
|
-
|
|
80
|
-
for (let i = 0, n = input.length; i < n; i++) {
|
|
81
|
-
let value = input[i];
|
|
82
|
-
|
|
83
|
-
if (isObject(value)) {
|
|
84
|
-
items[i] = new ReactiveObject(value, options);
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
items[i] = signal(value);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return items;
|
|
92
|
-
}
|
|
36
|
+
type Item<T> = T extends Record<PropertyKey, unknown> ? ReactiveObject<T> : Signal<T>;
|
|
93
37
|
|
|
94
38
|
|
|
95
39
|
// REMINDER:
|
|
96
40
|
// - @ts-ignore flags are supressing type mismatch error
|
|
97
41
|
// - Input values are being transformed by this class into reactive values and back during get
|
|
98
|
-
class ReactiveArray<T> extends Array<
|
|
42
|
+
class ReactiveArray<T> extends Array<Item<T>> {
|
|
99
43
|
private options: Options;
|
|
100
|
-
|
|
101
|
-
// - Use 'self' to avoid going through proxy for internal loops
|
|
102
|
-
private self: ReactiveArray<T>;
|
|
44
|
+
private proxy: API<T>;
|
|
103
45
|
private signal: Signal<boolean>;
|
|
104
46
|
|
|
105
47
|
|
|
106
|
-
constructor(data:
|
|
48
|
+
constructor(data: Item<T>[], proxy: API<T>, options: Options = {}) {
|
|
107
49
|
super(...data);
|
|
108
50
|
this.options = options;
|
|
109
|
-
this.
|
|
51
|
+
this.proxy = proxy;
|
|
110
52
|
this.signal = signal(false);
|
|
111
53
|
}
|
|
112
54
|
|
|
@@ -120,8 +62,8 @@ class ReactiveArray<T> extends Array<R<T>> {
|
|
|
120
62
|
}
|
|
121
63
|
|
|
122
64
|
|
|
123
|
-
at(
|
|
124
|
-
let value = super.at(
|
|
65
|
+
at(i: number) {
|
|
66
|
+
let value = super.at(i);
|
|
125
67
|
|
|
126
68
|
if (isInstanceOf(value, Reactive)) {
|
|
127
69
|
return value.get();
|
|
@@ -136,17 +78,30 @@ class ReactiveArray<T> extends Array<R<T>> {
|
|
|
136
78
|
|
|
137
79
|
dispose() {
|
|
138
80
|
this.signal.dispose();
|
|
139
|
-
dispose(this
|
|
81
|
+
dispose(this);
|
|
140
82
|
}
|
|
141
83
|
|
|
142
84
|
// @ts-ignore
|
|
143
|
-
map<U>(fn: (this: T
|
|
144
|
-
let
|
|
85
|
+
map<U>(fn: (this: API<T>, value: T, i: number) => U, i?: number, n?: number) {
|
|
86
|
+
let proxy = this.proxy,
|
|
145
87
|
values: U[] = [];
|
|
146
88
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
89
|
+
if (i === undefined) {
|
|
90
|
+
i = 0;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (n === undefined) {
|
|
94
|
+
n = this.length;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
n = Math.min(n, this.length);
|
|
98
|
+
|
|
99
|
+
for (; i < n; i++) {
|
|
100
|
+
let item = this[i];
|
|
101
|
+
|
|
102
|
+
values.push(
|
|
103
|
+
fn.call(proxy, isInstanceOf(item, Reactive) ? item.value : item, i)
|
|
104
|
+
);
|
|
150
105
|
}
|
|
151
106
|
|
|
152
107
|
return values;
|
|
@@ -200,8 +155,12 @@ class ReactiveArray<T> extends Array<R<T>> {
|
|
|
200
155
|
return item;
|
|
201
156
|
}
|
|
202
157
|
|
|
203
|
-
|
|
204
|
-
|
|
158
|
+
// @ts-ignore
|
|
159
|
+
sort(fn: (a: T, b: T) => number) {
|
|
160
|
+
super.sort((a, b) => fn(
|
|
161
|
+
isInstanceOf(a, Reactive) ? a.value : a,
|
|
162
|
+
isInstanceOf(b, Reactive) ? b.value : b
|
|
163
|
+
));
|
|
205
164
|
this.signal.dispatch('sort');
|
|
206
165
|
|
|
207
166
|
return this;
|
|
@@ -236,7 +195,109 @@ class ReactiveArray<T> extends Array<R<T>> {
|
|
|
236
195
|
}
|
|
237
196
|
|
|
238
197
|
|
|
198
|
+
function factory<T>(input: T[], options: Options = {}) {
|
|
199
|
+
let items: Item<T>[] = [];
|
|
200
|
+
|
|
201
|
+
for (let i = 0, n = input.length; i < n; i++) {
|
|
202
|
+
let value = input[i];
|
|
203
|
+
|
|
204
|
+
if (isObject(value)) {
|
|
205
|
+
// @ts-ignore
|
|
206
|
+
items[i] = object(value, options);
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
// @ts-ignore
|
|
210
|
+
items[i] = signal(value);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return items;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function methods<T>(a: ReactiveArray<T>): Prettify<
|
|
218
|
+
{
|
|
219
|
+
get constructor(): typeof a['constructor'];
|
|
220
|
+
get length(): number;
|
|
221
|
+
set length(n: number);
|
|
222
|
+
} & Pick<
|
|
223
|
+
typeof a,
|
|
224
|
+
'at' |
|
|
225
|
+
'dispatch' | 'dispose' |
|
|
226
|
+
'map' |
|
|
227
|
+
'on' | 'once' |
|
|
228
|
+
'pop' | 'push' |
|
|
229
|
+
'reverse' |
|
|
230
|
+
'shift' | 'sort' | 'splice' |
|
|
231
|
+
'unshift'
|
|
232
|
+
>
|
|
233
|
+
> {
|
|
234
|
+
return {
|
|
235
|
+
get constructor() {
|
|
236
|
+
return a.constructor;
|
|
237
|
+
},
|
|
238
|
+
get length() {
|
|
239
|
+
return a.length;
|
|
240
|
+
},
|
|
241
|
+
set length(n: number) {
|
|
242
|
+
a.length = n;
|
|
243
|
+
},
|
|
244
|
+
at: (index) => a.at(index),
|
|
245
|
+
dispatch: (event, data) => a.dispatch(event, data),
|
|
246
|
+
dispose: () => a.dispose(),
|
|
247
|
+
map: (fn, i, n) => a.map(fn, i, n),
|
|
248
|
+
on: (event, listener) => a.on(event, listener),
|
|
249
|
+
once: (event, listener) => a.once(event, listener),
|
|
250
|
+
pop: () => a.pop(),
|
|
251
|
+
push: (...input) => a.push(...input),
|
|
252
|
+
reverse: () => a.reverse(),
|
|
253
|
+
shift: () => a.shift(),
|
|
254
|
+
sort: (fn) => a.sort(fn),
|
|
255
|
+
splice: (start, deleteCount, ...input) => a.splice(start, deleteCount, ...input),
|
|
256
|
+
unshift: (...input) => a.unshift(...input)
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
// - Proxies are slow...
|
|
262
|
+
// - `this.[property]` goes through proxy
|
|
263
|
+
// - Wrapper slows down creation in exchange for 'faster' runtime use
|
|
239
264
|
export default <T>(input: T[], options: Options = {}) => {
|
|
240
|
-
|
|
265
|
+
let proxy = new Proxy({}, {
|
|
266
|
+
get(_: any, key: any) {
|
|
267
|
+
if (isNumber(key)) {
|
|
268
|
+
let value = a[key];
|
|
269
|
+
|
|
270
|
+
if (isInstanceOf(value, Reactive)) {
|
|
271
|
+
return value.get();
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return value;
|
|
275
|
+
}
|
|
276
|
+
else if (key in m) {
|
|
277
|
+
return m[key as keyof typeof m];
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
throw new Error(`Reactivity: '${key}' is not supported on reactive arrays`);
|
|
281
|
+
},
|
|
282
|
+
set(_: any, key: any, value: any) {
|
|
283
|
+
if (isNumber(key)) {
|
|
284
|
+
let host = a[key];
|
|
285
|
+
|
|
286
|
+
if (isInstanceOf(host, Reactive)) {
|
|
287
|
+
host.set(value);
|
|
288
|
+
return true;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return a[key] = value;
|
|
295
|
+
}
|
|
296
|
+
}) as API<T>;
|
|
297
|
+
|
|
298
|
+
let a = new ReactiveArray(factory(input, options), proxy),
|
|
299
|
+
m = methods(a);
|
|
300
|
+
|
|
301
|
+
return proxy;
|
|
241
302
|
};
|
|
242
|
-
export { ReactiveArray };
|
|
303
|
+
export { API as ReactiveArray };
|
package/src/reactive/index.ts
CHANGED
|
@@ -1,29 +1,15 @@
|
|
|
1
|
-
import { Prettify } from '@esportsplus/typescript';
|
|
2
1
|
import { isArray, isObject } from '@esportsplus/utilities';
|
|
3
|
-
import { Options } from '~/types';
|
|
4
|
-
import { default as array
|
|
5
|
-
import { default as object
|
|
2
|
+
import { Options, ReactiveArray, ReactiveObject } from '~/types';
|
|
3
|
+
import { default as array } from './array';
|
|
4
|
+
import { default as object } from './object';
|
|
6
5
|
|
|
7
6
|
|
|
8
7
|
type Guard<T> =
|
|
9
|
-
T extends
|
|
10
|
-
? { [
|
|
11
|
-
: T extends unknown[]
|
|
8
|
+
T extends { dispose: any } | { signals: any }
|
|
9
|
+
? { never: '[ dispose, signals ] are reserved keys' }
|
|
10
|
+
: T extends Record<PropertyKey, unknown> | unknown[]
|
|
12
11
|
? T
|
|
13
|
-
:
|
|
14
|
-
? never
|
|
15
|
-
: T;
|
|
16
|
-
|
|
17
|
-
type Infer<T> =
|
|
18
|
-
T extends (...args: unknown[]) => unknown
|
|
19
|
-
? ReturnType<T>
|
|
20
|
-
: T extends (infer U)[]
|
|
21
|
-
? Prettify< Omit<U[], 'map'> & Pick<ReactiveArray<U>, 'dispatch' | 'dispose' | 'map' | 'on' | 'once'> >
|
|
22
|
-
: T extends Record<PropertyKey, unknown>
|
|
23
|
-
? { [K in keyof T]: T[K] }
|
|
24
|
-
: T;
|
|
25
|
-
|
|
26
|
-
type Never<K,V> = K extends keyof ReactiveObject<Record<PropertyKey, unknown>> ? never : V;
|
|
12
|
+
: never;
|
|
27
13
|
|
|
28
14
|
|
|
29
15
|
export default <T>(data: Guard<T>, options: Options = {}) => {
|
|
@@ -39,5 +25,7 @@ export default <T>(data: Guard<T>, options: Options = {}) => {
|
|
|
39
25
|
throw new Error(`Reactivity: 'reactive' received invalid input - ${JSON.stringify(data)}`);
|
|
40
26
|
}
|
|
41
27
|
|
|
42
|
-
return value as T extends Record<PropertyKey, unknown>
|
|
28
|
+
return value as T extends Record<PropertyKey, unknown>
|
|
29
|
+
? ReactiveObject<T>
|
|
30
|
+
: ReactiveArray<T>;
|
|
43
31
|
};
|
package/src/reactive/object.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { defineProperty, isArray, isFunction } from '@esportsplus/utilities';
|
|
2
2
|
import { computed, signal } from '~/signal';
|
|
3
|
-
import { Computed, Options, Signal } from '~/types';
|
|
4
|
-
import { default as array
|
|
3
|
+
import { Computed, Infer, Options, Prettify, ReactiveArray, Signal } from '~/types';
|
|
4
|
+
import { default as array } from './array';
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
type API<T> = Prettify< { [K in keyof T]: Infer<T[K]> } & { dispose: VoidFunction } >;
|
|
5
8
|
|
|
6
9
|
|
|
7
10
|
class ReactiveObject<T extends Record<PropertyKey, unknown>> {
|
|
@@ -51,11 +54,6 @@ class ReactiveObject<T extends Record<PropertyKey, unknown>> {
|
|
|
51
54
|
}
|
|
52
55
|
|
|
53
56
|
|
|
54
|
-
get value() {
|
|
55
|
-
return this;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|
|
59
57
|
dispose() {
|
|
60
58
|
let signals = this.signals;
|
|
61
59
|
|
|
@@ -67,6 +65,6 @@ class ReactiveObject<T extends Record<PropertyKey, unknown>> {
|
|
|
67
65
|
|
|
68
66
|
|
|
69
67
|
export default <T extends Record<PropertyKey, unknown>>(input: T, options: Options = {}) => {
|
|
70
|
-
return new ReactiveObject(input, options)
|
|
68
|
+
return new ReactiveObject(input, options) as API<T>;
|
|
71
69
|
};
|
|
72
|
-
export { ReactiveObject };
|
|
70
|
+
export { API as ReactiveObject };
|
package/src/signal.ts
CHANGED
|
@@ -57,11 +57,7 @@ class Reactive<T> {
|
|
|
57
57
|
return;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
let listeners = this.listeners[event]
|
|
61
|
-
values = {
|
|
62
|
-
data,
|
|
63
|
-
value: this.value
|
|
64
|
-
};
|
|
60
|
+
let listeners = this.listeners[event];
|
|
65
61
|
|
|
66
62
|
for (let i = 0, n = listeners.length; i < n; i++) {
|
|
67
63
|
let listener = listeners[i];
|
|
@@ -71,7 +67,7 @@ class Reactive<T> {
|
|
|
71
67
|
}
|
|
72
68
|
|
|
73
69
|
try {
|
|
74
|
-
listener(
|
|
70
|
+
listener(data, this.value);
|
|
75
71
|
|
|
76
72
|
if (listener.once !== undefined) {
|
|
77
73
|
listeners[i] = null;
|
package/src/types.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Function, NeverAsync, Prettify } from '@esportsplus/typescript'
|
|
2
|
+
import { ReactiveArray } from './reactive/array';
|
|
3
|
+
import { ReactiveObject } from './reactive/object';
|
|
2
4
|
import { CHECK, CLEAN, COMPUTED, DIRTY, DISPOSED, EFFECT, ROOT, SIGNAL } from './constants';
|
|
3
5
|
import { Reactive } from './signal';
|
|
4
6
|
|
|
@@ -19,12 +21,23 @@ type Effect = {
|
|
|
19
21
|
task: Function;
|
|
20
22
|
} & Omit<Base<void>, 'value'>;
|
|
21
23
|
|
|
24
|
+
type Infer<T> =
|
|
25
|
+
T extends (...args: unknown[]) => unknown
|
|
26
|
+
? ReturnType<T>
|
|
27
|
+
: T extends (infer U)[]
|
|
28
|
+
? ReactiveArray<U>
|
|
29
|
+
: T extends ReactiveObject<T>
|
|
30
|
+
? ReactiveObject<T>
|
|
31
|
+
: T extends Record<PropertyKey, unknown>
|
|
32
|
+
? { [K in keyof T]: T[K] }
|
|
33
|
+
: T;
|
|
34
|
+
|
|
22
35
|
type Event = string;
|
|
23
36
|
|
|
24
37
|
type Listener<D> = {
|
|
25
38
|
once?: boolean;
|
|
26
39
|
|
|
27
|
-
<V>(
|
|
40
|
+
<V>(data: D, value: V): void;
|
|
28
41
|
};
|
|
29
42
|
|
|
30
43
|
type Options = {
|
|
@@ -54,11 +67,12 @@ export type {
|
|
|
54
67
|
Changed, Computed,
|
|
55
68
|
Effect, Event,
|
|
56
69
|
Function,
|
|
70
|
+
Infer,
|
|
57
71
|
Listener,
|
|
58
72
|
NeverAsync,
|
|
59
73
|
Options,
|
|
60
74
|
Prettify,
|
|
61
|
-
Root,
|
|
75
|
+
ReactiveArray, ReactiveObject, Root,
|
|
62
76
|
Scheduler, Signal, State,
|
|
63
77
|
Type
|
|
64
78
|
};
|