@esportsplus/reactivity 0.2.3 → 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.
@@ -1,49 +1,76 @@
1
- import { Listener, Options, Signal } from '../types';
2
- import { ReactiveObject } from './object';
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: R<T>;
8
+ item: Item<T>;
6
9
  };
7
10
  push: {
8
- items: R<T>[];
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: R<T>;
19
+ item: Item<T>;
13
20
  };
14
21
  sort: undefined;
15
22
  splice: {
16
23
  deleteCount: number;
17
- items: R<T>[];
24
+ items: Item<T>[];
18
25
  start: number;
19
26
  };
20
27
  unshift: {
21
- items: R<T>[];
28
+ items: Item<T>[];
22
29
  };
23
30
  };
24
- type R<T> = Signal<T> | ReactiveObject<T extends Record<PropertyKey, unknown> ? {
25
- [K in keyof T]: T[K];
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 self;
34
+ private proxy;
30
35
  private signal;
31
- constructor(data: R<T>[], options?: Options);
36
+ constructor(data: Item<T>[], proxy: API<T>, options?: Options);
32
37
  set length(n: number);
33
- at(index: number): any;
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[], value: T, i: number) => U): U[];
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(): R<T> | undefined;
44
+ pop(): Item<T> | undefined;
40
45
  push(...input: T[]): number;
41
46
  reverse(): this;
42
- shift(): R<T> | undefined;
43
- sort(): this;
44
- splice(start: number, deleteCount?: number, ...input: T[]): R<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 const _default: <T>(input: T[], options?: Options) => any;
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 };
@@ -1,63 +1,14 @@
1
1
  import { isInstanceOf, isNumber, isObject } from '@esportsplus/utilities';
2
2
  import { dispose, signal, Reactive } from '../signal';
3
- import { ReactiveObject } from './object';
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
- self;
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.self = 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(index) {
70
- let value = super.at(index);
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.self);
32
+ dispose(this);
82
33
  }
83
- map(fn) {
84
- let self = this.self, values = [];
85
- for (let i = 0, n = self.length; i < n; i++) {
86
- values.push(fn.call(this, self[i].value, i));
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
- return new Proxy(new ReactiveArray(factory(input, options)), handler);
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 { Prettify } from '@esportsplus/typescript';
2
- import { Options } from '../types';
3
- import { ReactiveArray } from './array';
4
- import { ReactiveObject } from './object';
5
- type Guard<T> = T extends Record<PropertyKey, unknown> ? {
6
- [K in keyof T]: Never<K, Guard<T[K]>>;
7
- } : T extends unknown[] ? T : T extends Function ? never : T;
8
- type Infer<T> = T extends (...args: unknown[]) => unknown ? ReturnType<T> : T extends (infer U)[] ? Prettify<Omit<U[], 'map'> & Pick<ReactiveArray<U>, 'dispatch' | 'dispose' | 'map' | 'on' | 'once'>> : T extends Record<PropertyKey, unknown> ? {
9
- [K in keyof T]: T[K];
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 { Computed, Options, Signal } from '../types';
2
- import { ReactiveArray } from './array';
3
- declare class ReactiveObject<T extends Record<PropertyKey, unknown>> {
4
- signals: Record<PropertyKey, Computed<any> | ReactiveArray<any> | Signal<any>>;
5
- constructor(data: T, options?: Options);
6
- get value(): this;
7
- dispose(): void;
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 };
@@ -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], values = {
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(values);
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,5 +1,6 @@
1
1
  import { Function, NeverAsync, Prettify } from '@esportsplus/typescript';
2
2
  import { ReactiveArray } from './reactive/array';
3
+ import { ReactiveObject } from './reactive/object';
3
4
  import { CHECK, CLEAN, COMPUTED, DIRTY, DISPOSED, EFFECT, ROOT, SIGNAL } from './constants';
4
5
  import { Reactive } from './signal';
5
6
  type Base<T> = Omit<Reactive<T>, 'changed' | 'fn' | 'get' | 'scheduler' | 'set' | 'task' | 'tracking'>;
@@ -14,13 +15,13 @@ type Effect = {
14
15
  root: Root;
15
16
  task: Function;
16
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;
17
21
  type Event = string;
18
22
  type Listener<D> = {
19
23
  once?: boolean;
20
- <V>(event: {
21
- data?: D;
22
- value: V;
23
- }): void;
24
+ <V>(data: D, value: V): void;
24
25
  };
25
26
  type Options = {
26
27
  changed?: Changed;
@@ -38,4 +39,4 @@ type Signal<T> = {
38
39
  } & Base<T>;
39
40
  type State = typeof CHECK | typeof CLEAN | typeof DIRTY | typeof DISPOSED;
40
41
  type Type = typeof COMPUTED | typeof EFFECT | typeof ROOT | typeof SIGNAL;
41
- export type { Changed, Computed, Effect, Event, Function, Listener, NeverAsync, Options, Prettify, ReactiveArray, 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
@@ -17,5 +17,5 @@
17
17
  "prepublishOnly": "npm run build"
18
18
  },
19
19
  "types": "build/index.d.ts",
20
- "version": "0.2.3"
20
+ "version": "0.2.4"
21
21
  }
@@ -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 { ReactiveObject } from './object';
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: R<T>;
12
+ item: Item<T>;
10
13
  };
11
14
  push: {
12
- items: R<T>[];
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: R<T>;
23
+ item: Item<T>;
17
24
  };
18
25
  sort: undefined;
19
26
  splice: {
20
27
  deleteCount: number;
21
- items: R<T>[];
28
+ items: Item<T>[];
22
29
  start: number;
23
30
  };
24
31
  unshift: {
25
- items: R<T>[];
32
+ items: Item<T>[];
26
33
  };
27
34
  };
28
35
 
29
- type R<T> = Signal<T> | ReactiveObject< T extends Record<PropertyKey, unknown> ? { [K in keyof T]: T[K] } : never >;
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<R<T>> {
42
+ class ReactiveArray<T> extends Array<Item<T>> {
99
43
  private options: Options;
100
- // - Proxy binds itself to methods on get
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: R<T>[], options: Options = {}) {
48
+ constructor(data: Item<T>[], proxy: API<T>, options: Options = {}) {
107
49
  super(...data);
108
50
  this.options = options;
109
- this.self = 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(index: number) {
124
- let value = super.at(index);
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.self as any);
81
+ dispose(this);
140
82
  }
141
83
 
142
84
  // @ts-ignore
143
- map<U>(fn: (this: T[], value: T, i: number) => U) {
144
- let self = this.self,
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
- for (let i = 0, n = self.length; i < n; i++) {
148
- // @ts-ignore
149
- values.push( fn.call(this, self[i].value, i) );
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
- sort() {
204
- super.sort();
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
- return new Proxy(new ReactiveArray(factory(input, options)), handler);
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 };
@@ -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, ReactiveArray } from './array';
5
- import { default as object, ReactiveObject } from './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 Record<PropertyKey, unknown>
10
- ? { [K in keyof T]: Never<K, Guard<T[K]>> }
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
- : T extends Function
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> ? { [K in keyof T]: Infer<T[K]> } : Infer<T>;
28
+ return value as T extends Record<PropertyKey, unknown>
29
+ ? ReactiveObject<T>
30
+ : ReactiveArray<T>;
43
31
  };
@@ -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, ReactiveArray } from './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(values);
70
+ listener(data, this.value);
75
71
 
76
72
  if (listener.once !== undefined) {
77
73
  listeners[i] = null;
package/src/types.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { Function, NeverAsync, Prettify } from '@esportsplus/typescript'
2
2
  import { ReactiveArray } from './reactive/array';
3
+ import { ReactiveObject } from './reactive/object';
3
4
  import { CHECK, CLEAN, COMPUTED, DIRTY, DISPOSED, EFFECT, ROOT, SIGNAL } from './constants';
4
5
  import { Reactive } from './signal';
5
6
 
@@ -20,12 +21,23 @@ type Effect = {
20
21
  task: Function;
21
22
  } & Omit<Base<void>, 'value'>;
22
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
+
23
35
  type Event = string;
24
36
 
25
37
  type Listener<D> = {
26
38
  once?: boolean;
27
39
 
28
- <V>(event: { data?: D, value: V }): void;
40
+ <V>(data: D, value: V): void;
29
41
  };
30
42
 
31
43
  type Options = {
@@ -55,12 +67,12 @@ export type {
55
67
  Changed, Computed,
56
68
  Effect, Event,
57
69
  Function,
70
+ Infer,
58
71
  Listener,
59
72
  NeverAsync,
60
73
  Options,
61
74
  Prettify,
62
- ReactiveArray,
63
- Root,
75
+ ReactiveArray, ReactiveObject, Root,
64
76
  Scheduler, Signal, State,
65
77
  Type
66
78
  };