@esportsplus/reactivity 0.1.31 → 0.2.1

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/macro.d.ts CHANGED
@@ -1,10 +1,9 @@
1
1
  import CustomFunction from '@esportsplus/custom-function';
2
- import { Computed, Options } from './types';
3
- type Function<A extends unknown[], R> = Computed<(...args: A) => R>['fn'];
2
+ import { Options } from './types';
4
3
  declare class Macro<A extends unknown[], R> extends CustomFunction {
5
4
  private factory;
6
- constructor(fn: Function<A, R>, options?: Options);
5
+ constructor(fn: Macro<A, R>['factory']['fn'], options?: Options);
7
6
  dispose(): void;
8
7
  }
9
- declare const _default: <A extends unknown[], R>(fn: Function<A, R>, options?: Options) => Macro<A, R>;
8
+ declare const _default: <A extends unknown[], R>(fn: Macro<A, R>["factory"]["fn"], options?: Options) => Macro<A, R>;
10
9
  export default _default;
@@ -1,59 +1,49 @@
1
- import { Listener, Object, Options } from '../types';
1
+ import { Listener, Options, Signal } from '../types';
2
2
  import { ReactiveObject } from './object';
3
3
  type Events<T> = {
4
- fill: {
5
- value: T;
6
- };
7
4
  pop: {
8
- item: T;
5
+ item: R<T>;
9
6
  };
10
7
  push: {
11
- items: T[];
8
+ items: R<T>[];
12
9
  };
13
10
  reverse: undefined;
14
11
  shift: {
15
- item: T;
12
+ item: R<T>;
16
13
  };
17
14
  sort: undefined;
18
15
  splice: {
19
16
  deleteCount: number;
20
- items: T[];
17
+ items: R<T>[];
21
18
  start: number;
22
19
  };
23
20
  unshift: {
24
- items: T[];
21
+ items: R<T>[];
25
22
  };
26
23
  };
27
- declare class ReactiveArray<T> extends Array<T> {
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>> {
28
+ private options;
29
+ private self;
28
30
  private signal;
29
- constructor(data: T[]);
31
+ constructor(data: R<T>[], options?: Options);
30
32
  set length(n: number);
33
+ at(index: number): any;
31
34
  dispatch<E extends keyof Events<T>>(event: E, data?: Events<T>[E]): void;
32
35
  dispose(): void;
33
- fill(value: T, start?: number, end?: number): this;
34
- map<U>(fn: (this: ReactiveArray<T>, value: T, i: number) => U): U[];
36
+ map<U>(fn: (this: T[], value: T, i: number) => U): U[];
35
37
  on<E extends keyof Events<T>>(event: E, listener: Listener<Events<T>[E]>): void;
36
38
  once<E extends keyof Events<T>>(event: E, listener: Listener<Events<T>[E]>): void;
37
- pop(): T | undefined;
38
- push(...items: T[]): number;
39
+ pop(): R<T> | undefined;
40
+ push(...input: T[]): number;
39
41
  reverse(): this;
40
- shift(): T | undefined;
42
+ shift(): R<T> | undefined;
41
43
  sort(): this;
42
- splice(start: number, deleteCount?: number, ...items: T[]): T[];
43
- track(index?: number): T | undefined;
44
- trigger(): void;
45
- unshift(...items: T[]): number;
46
- }
47
- declare class ReactiveObjectArray<T extends Object> extends ReactiveArray<ReactiveObject<T>> {
48
- private options;
49
- constructor(data: T[], options?: Options);
50
- fill(): never;
51
- reverse(): never;
52
- pop(): ReactiveObject<T> | undefined;
53
- push(...values: T[]): number;
54
- shift(): ReactiveObject<T> | undefined;
55
- sort(): never;
56
- splice(start: number, deleteCount?: number, ...values: T[]): ReactiveObject<T> | ReactiveObject<T>[] | null | undefined;
57
- unshift(...values: T[]): number;
44
+ splice(start: number, deleteCount?: number, ...input: T[]): R<T>[];
45
+ unshift(...input: T[]): number;
58
46
  }
59
- export { ReactiveArray, ReactiveObjectArray };
47
+ declare const _default: <T>(input: T[], options?: Options) => any;
48
+ export default _default;
49
+ export { ReactiveArray };
@@ -1,19 +1,63 @@
1
- import { dispose, signal } from '../signal';
1
+ import { isInstanceOf, isNumber, isObject } from '@esportsplus/utilities';
2
+ import { dispose, signal, Reactive } from '../signal';
2
3
  import { ReactiveObject } from './object';
3
- function factory(data, options = {}) {
4
- let signals = [];
5
- for (let i = 0, n = data.length; i < n; i++) {
6
- signals.push(new ReactiveObject(data[i], options));
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
+ }
7
50
  }
8
- return signals;
9
- }
10
- function unsupported(method) {
11
- throw new Error(`Reactivity: '${method}' is not supported on reactive object array`);
51
+ return items;
12
52
  }
13
53
  class ReactiveArray extends Array {
54
+ options;
55
+ self;
14
56
  signal;
15
- constructor(data) {
57
+ constructor(data, options = {}) {
16
58
  super(...data);
59
+ this.options = options;
60
+ this.self = this;
17
61
  this.signal = signal(false);
18
62
  }
19
63
  set length(n) {
@@ -22,22 +66,24 @@ class ReactiveArray extends Array {
22
66
  }
23
67
  this.splice(n);
24
68
  }
69
+ at(index) {
70
+ let value = super.at(index);
71
+ if (isInstanceOf(value, Reactive)) {
72
+ return value.get();
73
+ }
74
+ return value;
75
+ }
25
76
  dispatch(event, data) {
26
77
  this.signal.dispatch(event, data);
27
78
  }
28
79
  dispose() {
29
80
  this.signal.dispose();
30
- }
31
- fill(value, start, end) {
32
- super.fill(value, start, end);
33
- this.dispatch('fill', { value });
34
- this.trigger();
35
- return this;
81
+ dispose(this.self);
36
82
  }
37
83
  map(fn) {
38
- let values = [];
39
- for (let i = 0, n = this.length; i < n; i++) {
40
- values.push(fn.call(this, this[i], i));
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));
41
87
  }
42
88
  return values;
43
89
  }
@@ -50,92 +96,53 @@ class ReactiveArray extends Array {
50
96
  pop() {
51
97
  let item = super.pop();
52
98
  if (item !== undefined) {
53
- this.dispatch('pop', { item });
54
- this.trigger();
99
+ dispose(item);
100
+ this.signal.dispatch('pop', { item });
55
101
  }
56
102
  return item;
57
103
  }
58
- push(...items) {
59
- let n = super.push(...items);
60
- this.dispatch('push', { items });
61
- this.trigger();
104
+ push(...input) {
105
+ let items = factory(input, this.options), n = super.push(...items);
106
+ this.signal.dispatch('push', { items });
62
107
  return n;
63
108
  }
64
109
  reverse() {
65
110
  super.reverse();
66
- this.dispatch('reverse');
67
- this.trigger();
111
+ this.signal.dispatch('reverse');
68
112
  return this;
69
113
  }
70
114
  shift() {
71
115
  let item = super.shift();
72
116
  if (item !== undefined) {
73
- this.dispatch('shift', { item });
74
- this.trigger();
117
+ dispose(item);
118
+ this.signal.dispatch('shift', { item });
75
119
  }
76
120
  return item;
77
121
  }
78
122
  sort() {
79
123
  super.sort();
80
- this.dispatch('sort');
81
- this.trigger();
124
+ this.signal.dispatch('sort');
82
125
  return this;
83
126
  }
84
- splice(start, deleteCount = super.length, ...items) {
85
- let removed = super.splice(start, deleteCount, ...items);
127
+ splice(start, deleteCount = super.length, ...input) {
128
+ let items = factory(input, this.options), removed = super.splice(start, deleteCount, ...items);
86
129
  if (items.length > 0 || removed.length > 0) {
87
- this.dispatch('splice', {
130
+ dispose(removed);
131
+ this.signal.dispatch('splice', {
88
132
  deleteCount,
89
133
  items,
90
134
  start
91
135
  });
92
- this.trigger();
93
136
  }
94
137
  return removed;
95
138
  }
96
- track(index) {
97
- this.signal.get();
98
- return index === undefined ? undefined : this[index];
99
- }
100
- trigger() {
101
- this.signal.set(!this.signal.value);
102
- }
103
- unshift(...items) {
104
- let length = super.unshift(...items);
105
- this.dispatch('unshift', { items });
106
- this.trigger();
139
+ unshift(...input) {
140
+ let items = factory(input, this.options), length = super.unshift(...items);
141
+ this.signal.dispatch('unshift', { items });
107
142
  return length;
108
143
  }
109
144
  }
110
- class ReactiveObjectArray extends ReactiveArray {
111
- options;
112
- constructor(data, options = {}) {
113
- super(factory(data, options));
114
- this.options = options;
115
- }
116
- fill() {
117
- return unsupported('fill');
118
- }
119
- reverse() {
120
- return unsupported('reverse');
121
- }
122
- pop() {
123
- return dispose(super.pop());
124
- }
125
- push(...values) {
126
- return super.push(...factory(values, this.options));
127
- }
128
- shift() {
129
- return dispose(super.shift());
130
- }
131
- sort() {
132
- return unsupported('sort');
133
- }
134
- splice(start, deleteCount = super.length, ...values) {
135
- return dispose(super.splice(start, deleteCount, ...factory(values, this.options)));
136
- }
137
- unshift(...values) {
138
- return super.unshift(...factory(values, this.options));
139
- }
140
- }
141
- export { ReactiveArray, ReactiveObjectArray };
145
+ export default (input, options = {}) => {
146
+ return new Proxy(new ReactiveArray(factory(input, options)), handler);
147
+ };
148
+ export { ReactiveArray };
@@ -1,18 +1,13 @@
1
- import { Computed, Object, Options, Prettify, Signal } from '../types';
2
- import { ReactiveArray, ReactiveObjectArray } from './array';
1
+ import { Prettify } from '@esportsplus/typescript';
2
+ import { Options } from '../types';
3
+ import { ReactiveArray } from './array';
3
4
  import { ReactiveObject } from './object';
4
- type Guard<T> = T extends Object ? {
5
+ type Guard<T> = T extends Record<PropertyKey, unknown> ? {
5
6
  [K in keyof T]: Never<K, Guard<T[K]>>;
6
- } : T extends unknown[] ? Guard<T[number]>[] : T;
7
- type Infer<T> = T extends (...args: unknown[]) => unknown ? ReturnType<T> : T extends unknown[] ? T extends Object[] ? ReactiveObjectArray<T[0]> : ReactiveArray<T[0]> : T extends Object ? {
7
+ } : T extends unknown[] ? T : never;
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> ? {
8
9
  [K in keyof T]: T[K];
9
10
  } : T;
10
- type Never<K, V> = K extends keyof ReactiveObject<Object> ? never : V;
11
- type Nodes<T> = T extends (...args: unknown[]) => unknown ? Computed<T> : T extends unknown[] ? T extends Object[] ? ReactiveObjectArray<T[0]> : ReactiveArray<T[0]> : Signal<T>;
12
- type Signals<T extends Object> = {
13
- [K in keyof T]: Nodes<T[K]>;
14
- };
15
- declare const _default: <T extends Object>(data: Guard<T>, options?: Options) => Prettify<{ [K in keyof T]: Infer<T[K]>; } & Omit<ReactiveObject<T>, "signals"> & {
16
- signals: Signals<T>;
17
- }>;
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>;
18
13
  export default _default;
@@ -1,4 +1,16 @@
1
- import { ReactiveObject } from './object';
2
- export default (data, options) => {
3
- return new ReactiveObject(data, options);
1
+ import { isArray, isObject } from '@esportsplus/utilities';
2
+ import { default as array } from './array';
3
+ import { default as object } from './object';
4
+ export default (data, options = {}) => {
5
+ let value;
6
+ if (isArray(data)) {
7
+ value = array(data, options);
8
+ }
9
+ else if (isObject(data)) {
10
+ value = object(data, options);
11
+ }
12
+ else {
13
+ throw new Error('Reactivity: received invalid input for `reactive()`', data);
14
+ }
15
+ return value;
4
16
  };
@@ -1,9 +1,11 @@
1
- import { Computed, Object, Options, Signal } from '../types';
2
- import { ReactiveArray, ReactiveObjectArray } from './array';
3
- type Node = Computed<any> | ReactiveArray<any> | ReactiveObjectArray<Object> | Signal<any>;
4
- declare class ReactiveObject<T extends Object> {
5
- signals: Record<PropertyKey, Node>;
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>>;
6
5
  constructor(data: T, options?: Options);
6
+ get value(): this;
7
7
  dispose(): void;
8
8
  }
9
+ declare const _default: <T extends Record<PropertyKey, unknown>>(input: T, options?: Options) => ReactiveObject<T>;
10
+ export default _default;
9
11
  export { ReactiveObject };
@@ -1,34 +1,27 @@
1
+ import { defineProperty, isArray, isFunction } from '@esportsplus/utilities';
1
2
  import { computed, signal } from '../signal';
2
- import { defineProperty, isArray } from '../utilities';
3
- import { ReactiveArray, ReactiveObjectArray } from './array';
3
+ import { default as array } from './array';
4
4
  class ReactiveObject {
5
5
  signals = {};
6
6
  constructor(data, options = {}) {
7
7
  let signals = this.signals;
8
8
  for (let key in data) {
9
9
  let input = data[key];
10
- if (typeof input === 'function') {
11
- let s = signals[key] = computed(input, options);
10
+ if (isArray(input)) {
11
+ let s = signals[key] = array(input, options);
12
12
  defineProperty(this, key, {
13
13
  enumerable: true,
14
14
  get() {
15
- return s.get();
15
+ return s;
16
16
  }
17
17
  });
18
18
  }
19
- else if (isArray(input)) {
20
- let s, test = input[0];
21
- if (typeof test === 'object' && test !== null && test?.constructor?.name === 'Object') {
22
- s = signals[key] = new ReactiveObjectArray(input, options);
23
- }
24
- else {
25
- s = signals[key] = new ReactiveArray(input);
26
- }
19
+ else if (isFunction(input)) {
20
+ let s = signals[key] = computed(input, options);
27
21
  defineProperty(this, key, {
28
22
  enumerable: true,
29
23
  get() {
30
- s.track();
31
- return s;
24
+ return s.get();
32
25
  }
33
26
  });
34
27
  }
@@ -46,6 +39,9 @@ class ReactiveObject {
46
39
  }
47
40
  }
48
41
  }
42
+ get value() {
43
+ return this;
44
+ }
49
45
  dispose() {
50
46
  let signals = this.signals;
51
47
  for (let key in signals) {
@@ -53,4 +49,7 @@ class ReactiveObject {
53
49
  }
54
50
  }
55
51
  }
52
+ export default (input, options = {}) => {
53
+ return new ReactiveObject(input, options);
54
+ };
56
55
  export { ReactiveObject };
@@ -1,16 +1,15 @@
1
1
  import CustomFunction from '@esportsplus/custom-function';
2
2
  import { Options } from './types';
3
- type Function<A extends unknown[], R extends Promise<unknown>> = (...args: A) => R;
4
3
  declare class Resource<A extends unknown[], R extends Promise<unknown>> extends CustomFunction {
5
4
  private arguments;
6
5
  private okay;
7
6
  private response;
8
7
  stop: boolean | null;
9
- constructor(fn: Function<A, R>, options?: Options);
8
+ constructor(fn: (...args: A) => R, options?: Options);
10
9
  get data(): Awaited<R>;
11
10
  get input(): A | null;
12
11
  get ok(): boolean | null;
13
12
  dispose(): void;
14
13
  }
15
- declare const _default: <A extends unknown[], R extends Promise<unknown>>(fn: Function<A, R>, options?: Options) => Resource<A, R>;
14
+ declare const _default: <A extends unknown[], R extends Promise<unknown>>(fn: (...args: A) => R, options?: Options) => Resource<A, R>;
16
15
  export default _default;
package/build/signal.js CHANGED
@@ -1,5 +1,5 @@
1
+ import { isArray } from '@esportsplus/utilities';
1
2
  import { CHECK, CLEAN, COMPUTED, DIRTY, DISPOSED, EFFECT, ROOT, SIGNAL } from './constants';
2
- import { isArray } from './utilities';
3
3
  let index = 0, observer = null, observers = null, scope = null;
4
4
  class Reactive {
5
5
  changed = null;
package/build/types.d.ts CHANGED
@@ -21,7 +21,6 @@ type Listener<D> = {
21
21
  value: V;
22
22
  }): void;
23
23
  };
24
- type Object = Record<PropertyKey, unknown>;
25
24
  type Options = {
26
25
  changed?: Changed;
27
26
  };
@@ -38,4 +37,4 @@ type Signal<T> = {
38
37
  } & Base<T>;
39
38
  type State = typeof CHECK | typeof CLEAN | typeof DIRTY | typeof DISPOSED;
40
39
  type Type = typeof COMPUTED | typeof EFFECT | typeof ROOT | typeof SIGNAL;
41
- export type { Changed, Computed, Effect, Event, Function, Listener, Object, Options, NeverAsync, Prettify, Root, Scheduler, Signal, State, Type };
40
+ export type { Changed, Computed, Effect, Event, Function, Listener, NeverAsync, Options, Prettify, Root, Scheduler, Signal, State, Type };
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "author": "ICJR",
3
3
  "dependencies": {
4
- "@esportsplus/custom-function": "^0.0.7"
4
+ "@esportsplus/custom-function": "^0.0.7",
5
+ "@esportsplus/utilities": "^0.0.7"
5
6
  },
6
7
  "devDependencies": {
7
8
  "@esportsplus/typescript": "^0.4.9"
@@ -16,5 +17,5 @@
16
17
  "prepublishOnly": "npm run build"
17
18
  },
18
19
  "types": "build/index.d.ts",
19
- "version": "0.1.31"
20
+ "version": "0.2.1"
20
21
  }
package/src/macro.ts CHANGED
@@ -3,14 +3,11 @@ import { computed } from './signal';
3
3
  import { Computed, Options } from './types';
4
4
 
5
5
 
6
- type Function<A extends unknown[], R> = Computed<(...args: A) => R>['fn'];
7
-
8
-
9
6
  class Macro<A extends unknown[], R> extends CustomFunction {
10
7
  private factory: Computed<(...args: A) => R>;
11
8
 
12
9
 
13
- constructor(fn: Function<A,R>, options: Options = {}) {
10
+ constructor(fn: Macro<A,R>['factory']['fn'], options: Options = {}) {
14
11
  super((...args: A) => {
15
12
  return this.factory.get()(...args);
16
13
  });
@@ -24,6 +21,6 @@ class Macro<A extends unknown[], R> extends CustomFunction {
24
21
  }
25
22
 
26
23
 
27
- export default <A extends unknown[], R>(fn: Function<A,R>, options: Options = {}) => {
24
+ export default <A extends unknown[], R>(fn: Macro<A,R>['factory']['fn'], options: Options = {}) => {
28
25
  return new Macro(fn, options);
29
26
  };
@@ -1,41 +1,112 @@
1
- import { dispose, signal } from '~/signal';
2
- import { Listener, Object, Options, Signal } from '~/types';
1
+ import { isInstanceOf, isNumber, isObject } from '@esportsplus/utilities';
2
+ import { dispose, signal, Reactive } from '~/signal';
3
+ import { Listener, Options, Signal } from '~/types';
3
4
  import { ReactiveObject } from './object';
4
5
 
5
6
 
6
7
  type Events<T> = {
7
- fill: { value: T };
8
- pop: { item: T };
9
- push: { items: T[] };
8
+ pop: {
9
+ item: R<T>;
10
+ };
11
+ push: {
12
+ items: R<T>[];
13
+ };
10
14
  reverse: undefined;
11
- shift: { item: T };
15
+ shift: {
16
+ item: R<T>;
17
+ };
12
18
  sort: undefined;
13
- splice: { deleteCount: number, items: T[], start: number };
14
- unshift: { items: T[] };
19
+ splice: {
20
+ deleteCount: number;
21
+ items: R<T>[];
22
+ start: number;
23
+ };
24
+ unshift: {
25
+ items: R<T>[];
26
+ };
15
27
  };
16
28
 
29
+ type R<T> = Signal<T> | ReactiveObject< T extends Record<PropertyKey, unknown> ? { [K in keyof T]: T[K] } : never >;
17
30
 
18
- function factory<T extends Object>(data: T[], options: Options = {}) {
19
- let signals = [];
20
31
 
21
- for (let i = 0, n = data.length; i < n; i++) {
22
- signals.push( new ReactiveObject(data[i], options) );
23
- }
32
+ let handler = {
33
+ get(target: any, prop: any) {
34
+ let value = target[prop];
24
35
 
25
- return signals;
26
- }
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
+ }
27
57
 
28
- function unsupported(method: string): never {
29
- throw new Error(`Reactivity: '${method}' is not supported on reactive object array`);
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;
30
92
  }
31
93
 
32
94
 
33
- class ReactiveArray<T> extends Array<T> {
95
+ // REMINDER:
96
+ // - @ts-ignore flags are supressing type mismatch error
97
+ // - Input values are being transformed by this class into reactive values and back during get
98
+ class ReactiveArray<T> extends Array<R<T>> {
99
+ 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>;
34
103
  private signal: Signal<boolean>;
35
104
 
36
105
 
37
- constructor(data: T[]) {
106
+ constructor(data: R<T>[], options: Options = {}) {
38
107
  super(...data);
108
+ this.options = options;
109
+ this.self = this;
39
110
  this.signal = signal(false);
40
111
  }
41
112
 
@@ -49,29 +120,33 @@ class ReactiveArray<T> extends Array<T> {
49
120
  }
50
121
 
51
122
 
123
+ at(index: number) {
124
+ let value = super.at(index);
125
+
126
+ if (isInstanceOf(value, Reactive)) {
127
+ return value.get();
128
+ }
129
+
130
+ return value;
131
+ }
132
+
52
133
  dispatch<E extends keyof Events<T>>(event: E, data?: Events<T>[E]) {
53
134
  this.signal.dispatch(event, data);
54
135
  }
55
136
 
56
137
  dispose() {
57
138
  this.signal.dispose();
58
- }
59
-
60
- fill(value: T, start?: number, end?: number) {
61
- super.fill(value, start, end);
62
-
63
- this.dispatch('fill', { value });
64
- this.trigger();
65
-
66
- return this;
139
+ dispose(this.self as any);
67
140
  }
68
141
 
69
142
  // @ts-ignore
70
- map<U>(fn: (this: ReactiveArray<T>, value: T, i: number) => U) {
71
- let values: U[] = [];
143
+ map<U>(fn: (this: T[], value: T, i: number) => U) {
144
+ let self = this.self,
145
+ values: U[] = [];
72
146
 
73
- for (let i = 0, n = this.length; i < n; i++) {
74
- values.push( fn.call(this, this[i], i) );
147
+ for (let i = 0, n = self.length; i < n; i++) {
148
+ // @ts-ignore
149
+ values.push( fn.call(this, self[i].value, i) );
75
150
  }
76
151
 
77
152
  return values;
@@ -89,18 +164,19 @@ class ReactiveArray<T> extends Array<T> {
89
164
  let item = super.pop();
90
165
 
91
166
  if (item !== undefined) {
92
- this.dispatch('pop', { item });
93
- this.trigger();
167
+ dispose(item);
168
+ this.signal.dispatch('pop', { item });
94
169
  }
95
170
 
96
171
  return item;
97
172
  }
98
173
 
99
- push(...items: T[]) {
100
- let n = super.push(...items);
174
+ // @ts-ignore
175
+ push(...input: T[]) {
176
+ let items = factory(input, this.options),
177
+ n = super.push(...items);
101
178
 
102
- this.dispatch('push', { items });
103
- this.trigger();
179
+ this.signal.dispatch('push', { items });
104
180
 
105
181
  return n;
106
182
  }
@@ -108,9 +184,7 @@ class ReactiveArray<T> extends Array<T> {
108
184
  // @ts-ignore
109
185
  reverse() {
110
186
  super.reverse();
111
-
112
- this.dispatch('reverse');
113
- this.trigger();
187
+ this.signal.dispatch('reverse');
114
188
 
115
189
  return this;
116
190
  }
@@ -119,106 +193,50 @@ class ReactiveArray<T> extends Array<T> {
119
193
  let item = super.shift();
120
194
 
121
195
  if (item !== undefined) {
122
- this.dispatch('shift', { item });
123
- this.trigger();
196
+ dispose(item);
197
+ this.signal.dispatch('shift', { item });
124
198
  }
125
199
 
126
200
  return item;
127
201
  }
128
202
 
129
- // @ts-ignore
130
203
  sort() {
131
204
  super.sort();
132
-
133
- this.dispatch('sort');
134
- this.trigger();
205
+ this.signal.dispatch('sort');
135
206
 
136
207
  return this;
137
208
  }
138
209
 
139
- splice(start: number, deleteCount: number = super.length, ...items: T[]) {
140
- let removed = super.splice(start, deleteCount, ...items);
210
+ // @ts-ignore
211
+ splice(start: number, deleteCount: number = super.length, ...input: T[]) {
212
+ let items = factory(input, this.options),
213
+ removed = super.splice(start, deleteCount, ...items);
141
214
 
142
215
  if (items.length > 0 || removed.length > 0) {
143
- this.dispatch('splice', {
216
+ dispose(removed);
217
+ this.signal.dispatch('splice', {
144
218
  deleteCount,
145
219
  items,
146
220
  start
147
221
  });
148
- this.trigger();
149
222
  }
150
223
 
151
224
  return removed;
152
225
  }
153
226
 
154
- track(index?: number) {
155
- this.signal.get();
156
- return index === undefined ? undefined : this[index];
157
- }
158
-
159
- trigger() {
160
- this.signal.set(!this.signal.value);
161
- }
162
-
163
- unshift(...items: T[]) {
164
- let length = super.unshift(...items);
165
-
166
- this.dispatch('unshift', { items });
167
- this.trigger();
168
-
169
- return length;
170
- }
171
- }
172
-
173
-
174
- // REMINDER:
175
- // - @ts-ignore flags are supressing a type mismatch error
176
- // - Input values are being transformed by this class into signals
177
- class ReactiveObjectArray<T extends Object> extends ReactiveArray<ReactiveObject<T>> {
178
- private options: Options;
179
-
180
-
181
- constructor(data: T[], options: Options = {}) {
182
- super( factory(data, options) );
183
- this.options = options;
184
- }
185
-
186
-
187
- fill() {
188
- return unsupported('fill');
189
- }
190
-
191
- reverse() {
192
- return unsupported('reverse');
193
- }
194
-
195
- pop() {
196
- return dispose(super.pop()) as ReactiveObject<T>| undefined;
197
- }
198
-
199
227
  // @ts-ignore
200
- push(...values: T[]) {
201
- return super.push(...factory(values, this.options));
202
- }
228
+ unshift(...input: T[]) {
229
+ let items = factory(input, this.options),
230
+ length = super.unshift(...items);
203
231
 
204
- shift() {
205
- return dispose(super.shift()) as ReactiveObject<T> | undefined;
206
- }
232
+ this.signal.dispatch('unshift', { items });
207
233
 
208
- sort() {
209
- return unsupported('sort');
210
- }
211
-
212
- // @ts-ignore
213
- splice(start: number, deleteCount: number = super.length, ...values: T[]) {
214
- return dispose( super.splice(start, deleteCount, ...factory(values, this.options)) );
215
- }
216
-
217
- // @ts-ignore
218
- unshift(...values: T[]) {
219
- return super.unshift(...factory(values, this.options));
234
+ return length;
220
235
  }
221
236
  }
222
237
 
223
238
 
224
- export { ReactiveArray, ReactiveObjectArray };
239
+ export default <T>(input: T[], options: Options = {}) => {
240
+ return new Proxy(new ReactiveArray(factory(input, options)), handler);
241
+ };
242
+ export { ReactiveArray };
@@ -1,40 +1,41 @@
1
- import { Computed, Object, Options, Prettify, Signal } from '~/types';
2
- import { ReactiveArray, ReactiveObjectArray } from './array';
3
- import { ReactiveObject } from './object';
1
+ import { Prettify } from '@esportsplus/typescript';
2
+ 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';
4
6
 
5
7
 
6
8
  type Guard<T> =
7
- T extends Object
9
+ T extends Record<PropertyKey, unknown>
8
10
  ? { [K in keyof T]: Never<K, Guard<T[K]>> }
9
11
  : T extends unknown[]
10
- ? Guard<T[number]>[]
11
- : T;
12
+ ? T
13
+ : never;
12
14
 
13
15
  type Infer<T> =
14
16
  T extends (...args: unknown[]) => unknown
15
17
  ? ReturnType<T>
16
- : T extends unknown[]
17
- ? T extends Object[] ? ReactiveObjectArray<T[0]> : ReactiveArray<T[0]>
18
- : T extends Object
18
+ : T extends (infer U)[]
19
+ ? Prettify< Omit<U[], 'map'> & Pick<ReactiveArray<U>, 'dispatch' | 'dispose' | 'map' | 'on' | 'once'> >
20
+ : T extends Record<PropertyKey, unknown>
19
21
  ? { [K in keyof T]: T[K] }
20
22
  : T;
21
23
 
22
- type Never<K,V> = K extends keyof ReactiveObject<Object> ? never : V;
24
+ type Never<K,V> = K extends keyof ReactiveObject<Record<PropertyKey, unknown>> ? never : V;
23
25
 
24
- type Nodes<T> =
25
- T extends (...args: unknown[]) => unknown
26
- ? Computed<T>
27
- : T extends unknown[]
28
- ? T extends Object[] ? ReactiveObjectArray<T[0]> : ReactiveArray<T[0]>
29
- : Signal<T>;
30
26
 
31
- type Signals<T extends Object> = {
32
- [K in keyof T]: Nodes<T[K]>
33
- };
27
+ export default <T>(data: Guard<T>, options: Options = {}) => {
28
+ let value;
34
29
 
30
+ if (isArray(data)) {
31
+ value = array(data, options);
32
+ }
33
+ else if (isObject(data)) {
34
+ value = object(data as { [K in keyof T]: T[K] }, options);
35
+ }
36
+ else {
37
+ throw new Error('Reactivity: received invalid input for `reactive()`', data);
38
+ }
35
39
 
36
- export default <T extends Object>(data: Guard<T>, options?: Options) => {
37
- return new ReactiveObject(data, options) as any as Prettify<
38
- { [K in keyof T]: Infer<T[K]> } & Omit<ReactiveObject<T>, 'signals'> & { signals: Signals<T> }
39
- >;
40
+ return value as T extends Record<PropertyKey, unknown> ? { [K in keyof T]: Infer<T[K]> } : Infer<T>;
40
41
  };
@@ -1,14 +1,11 @@
1
+ import { defineProperty, isArray, isFunction } from '@esportsplus/utilities';
1
2
  import { computed, signal } from '~/signal';
2
- import { Computed, Object, Options, Signal } from '~/types';
3
- import { defineProperty, isArray } from '~/utilities';
4
- import { ReactiveArray, ReactiveObjectArray } from './array';
3
+ import { Computed, Options, Signal } from '~/types';
4
+ import { default as array, ReactiveArray } from './array';
5
5
 
6
6
 
7
- type Node = Computed<any> | ReactiveArray<any> | ReactiveObjectArray<Object> | Signal<any>;
8
-
9
-
10
- class ReactiveObject<T extends Object> {
11
- signals: Record<PropertyKey, Node> = {};
7
+ class ReactiveObject<T extends Record<PropertyKey, unknown>> {
8
+ signals: Record<PropertyKey, Computed<any> | ReactiveArray<any> | Signal<any>> = {};
12
9
 
13
10
 
14
11
  constructor(data: T, options: Options = {}) {
@@ -17,33 +14,23 @@ class ReactiveObject<T extends Object> {
17
14
  for (let key in data) {
18
15
  let input = data[key];
19
16
 
20
- if (typeof input === 'function') {
21
- let s = signals[key] = computed(input as Computed<T>['fn'], options);
17
+ if (isArray(input)) {
18
+ let s = signals[key] = array(input, options);
22
19
 
23
20
  defineProperty(this, key, {
24
21
  enumerable: true,
25
22
  get() {
26
- return s.get();
23
+ return s;
27
24
  }
28
25
  });
29
26
  }
30
- else if (isArray(input)) {
31
- let s: ReactiveArray<unknown> | ReactiveObjectArray<Object>,
32
- test = input[0];
33
-
34
- if (typeof test === 'object' && test !== null && test?.constructor?.name === 'Object') {
35
- s = signals[key] = new ReactiveObjectArray(input, options);
36
- }
37
- else {
38
- s = signals[key] = new ReactiveArray(input);
39
- }
27
+ else if (isFunction(input)) {
28
+ let s = signals[key] = computed(input as Computed<T>['fn'], options);
40
29
 
41
30
  defineProperty(this, key, {
42
31
  enumerable: true,
43
32
  get() {
44
- s.track();
45
-
46
- return s;
33
+ return s.get();
47
34
  }
48
35
  });
49
36
  }
@@ -64,6 +51,11 @@ class ReactiveObject<T extends Object> {
64
51
  }
65
52
 
66
53
 
54
+ get value() {
55
+ return this;
56
+ }
57
+
58
+
67
59
  dispose() {
68
60
  let signals = this.signals;
69
61
 
@@ -74,4 +66,7 @@ class ReactiveObject<T extends Object> {
74
66
  }
75
67
 
76
68
 
69
+ export default <T extends Record<PropertyKey, unknown>>(input: T, options: Options = {}) => {
70
+ return new ReactiveObject(input, options);
71
+ };
77
72
  export { ReactiveObject };
package/src/resource.ts CHANGED
@@ -3,9 +3,6 @@ import { signal } from './signal';
3
3
  import { Options, Signal } from './types';
4
4
 
5
5
 
6
- type Function<A extends unknown[], R extends Promise<unknown>> = (...args: A) => R;
7
-
8
-
9
6
  class Resource<A extends unknown[], R extends Promise<unknown>> extends CustomFunction {
10
7
  private arguments: Signal<A | null>;
11
8
  private okay: Signal<boolean | null>;
@@ -14,7 +11,7 @@ class Resource<A extends unknown[], R extends Promise<unknown>> extends CustomFu
14
11
  stop: boolean | null = null;
15
12
 
16
13
 
17
- constructor(fn: Function<A,R>, options: Options = {}) {
14
+ constructor(fn: (...args: A) => R, options: Options = {}) {
18
15
  super((...args: A) => {
19
16
  this.stop = null;
20
17
 
@@ -66,6 +63,6 @@ class Resource<A extends unknown[], R extends Promise<unknown>> extends CustomFu
66
63
  }
67
64
 
68
65
 
69
- export default <A extends unknown[], R extends Promise<unknown>>(fn: Function<A,R>, options: Options = {}) => {
66
+ export default <A extends unknown[], R extends Promise<unknown>>(fn: (...args: A) => R, options: Options = {}) => {
70
67
  return new Resource(fn, options);
71
68
  };
package/src/signal.ts CHANGED
@@ -1,6 +1,6 @@
1
+ import { isArray } from '@esportsplus/utilities';
1
2
  import { CHECK, CLEAN, COMPUTED, DIRTY, DISPOSED, EFFECT, ROOT, SIGNAL } from './constants';
2
3
  import { Computed, Changed, Effect, Event, Function, Listener, NeverAsync, Options, Root, Scheduler, Signal, State, Type } from './types';
3
- import { isArray } from './utilities';
4
4
 
5
5
 
6
6
  let index = 0,
package/src/types.ts CHANGED
@@ -27,8 +27,6 @@ type Listener<D> = {
27
27
  <V>(event: { data?: D, value: V }): void;
28
28
  };
29
29
 
30
- type Object = Record<PropertyKey, unknown>;
31
-
32
30
  type Options = {
33
31
  changed?: Changed;
34
32
  };
@@ -52,4 +50,15 @@ type State = typeof CHECK | typeof CLEAN | typeof DIRTY | typeof DISPOSED;
52
50
  type Type = typeof COMPUTED | typeof EFFECT | typeof ROOT | typeof SIGNAL;
53
51
 
54
52
 
55
- export type { Changed, Computed, Effect, Event, Function, Listener, Object, Options, NeverAsync, Prettify, Root, Scheduler, Signal, State, Type };
53
+ export type {
54
+ Changed, Computed,
55
+ Effect, Event,
56
+ Function,
57
+ Listener,
58
+ NeverAsync,
59
+ Options,
60
+ Prettify,
61
+ Root,
62
+ Scheduler, Signal, State,
63
+ Type
64
+ };
@@ -1,3 +0,0 @@
1
- declare const isArray: (arg: any) => arg is any[];
2
- declare const defineProperty: <T>(o: T, p: PropertyKey, attributes: PropertyDescriptor & ThisType<any>) => T;
3
- export { defineProperty, isArray };
@@ -1,3 +0,0 @@
1
- const { isArray } = Array;
2
- const { defineProperty } = Object;
3
- export { defineProperty, isArray };
package/src/utilities.ts DELETED
@@ -1,6 +0,0 @@
1
- const { isArray } = Array;
2
-
3
- const { defineProperty } = Object;
4
-
5
-
6
- export { defineProperty, isArray };