@praxisjs/decorators 0.4.3 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -0
- package/dist/__tests__/component.test.js +10 -1
- package/dist/__tests__/component.test.js.map +1 -1
- package/dist/__tests__/compose.test.d.ts +2 -0
- package/dist/__tests__/compose.test.d.ts.map +1 -0
- package/dist/__tests__/compose.test.js +171 -0
- package/dist/__tests__/compose.test.js.map +1 -0
- package/dist/__tests__/events.test.js +26 -0
- package/dist/__tests__/events.test.js.map +1 -1
- package/dist/__tests__/functions.test.js +205 -47
- package/dist/__tests__/functions.test.js.map +1 -1
- package/dist/__tests__/lazy.test.js +5 -7
- package/dist/__tests__/lazy.test.js.map +1 -1
- package/dist/__tests__/memo.test.js +114 -25
- package/dist/__tests__/memo.test.js.map +1 -1
- package/dist/__tests__/properties.test.js +193 -0
- package/dist/__tests__/properties.test.js.map +1 -1
- package/dist/__tests__/resource.test.d.ts +2 -0
- package/dist/__tests__/resource.test.d.ts.map +1 -0
- package/dist/__tests__/resource.test.js +127 -0
- package/dist/__tests__/resource.test.js.map +1 -0
- package/dist/__tests__/slot.test.js +32 -0
- package/dist/__tests__/slot.test.js.map +1 -1
- package/dist/__tests__/until.test.d.ts +2 -0
- package/dist/__tests__/until.test.d.ts.map +1 -0
- package/dist/__tests__/until.test.js +88 -0
- package/dist/__tests__/until.test.js.map +1 -0
- package/dist/__tests__/virtual.test.js +164 -15
- package/dist/__tests__/virtual.test.js.map +1 -1
- package/dist/component/component.d.ts +1 -1
- package/dist/component/component.d.ts.map +1 -1
- package/dist/component/component.js +15 -10
- package/dist/component/component.js.map +1 -1
- package/dist/component/lazy.d.ts.map +1 -1
- package/dist/component/lazy.js +29 -30
- package/dist/component/lazy.js.map +1 -1
- package/dist/component/virtual.d.ts.map +1 -1
- package/dist/component/virtual.js +49 -50
- package/dist/component/virtual.js.map +1 -1
- package/dist/create-class-decorator.d.ts +16 -0
- package/dist/create-class-decorator.d.ts.map +1 -0
- package/dist/create-class-decorator.js +35 -0
- package/dist/create-class-decorator.js.map +1 -0
- package/dist/create-field-decorator.d.ts +14 -0
- package/dist/create-field-decorator.d.ts.map +1 -0
- package/dist/create-field-decorator.js +37 -0
- package/dist/create-field-decorator.js.map +1 -0
- package/dist/create-getter-decorator.d.ts +18 -0
- package/dist/create-getter-decorator.d.ts.map +1 -0
- package/dist/create-getter-decorator.js +15 -0
- package/dist/create-getter-decorator.js.map +1 -0
- package/dist/create-lifecycle-method-decorator.d.ts +6 -0
- package/dist/create-lifecycle-method-decorator.d.ts.map +1 -0
- package/dist/create-lifecycle-method-decorator.js +22 -0
- package/dist/create-lifecycle-method-decorator.js.map +1 -0
- package/dist/create-method-decorator.d.ts +6 -0
- package/dist/create-method-decorator.d.ts.map +1 -0
- package/dist/create-method-decorator.js +14 -0
- package/dist/create-method-decorator.js.map +1 -0
- package/dist/events/emit.d.ts +1 -1
- package/dist/events/emit.d.ts.map +1 -1
- package/dist/events/emit.js +24 -29
- package/dist/events/emit.js.map +1 -1
- package/dist/events/on-command.d.ts +1 -2
- package/dist/events/on-command.d.ts.map +1 -1
- package/dist/events/on-command.js +15 -32
- package/dist/events/on-command.js.map +1 -1
- package/dist/functions/bind.d.ts +1 -2
- package/dist/functions/bind.d.ts.map +1 -1
- package/dist/functions/bind.js +4 -11
- package/dist/functions/bind.js.map +1 -1
- package/dist/functions/debounce.d.ts.map +1 -1
- package/dist/functions/debounce.js +21 -20
- package/dist/functions/debounce.js.map +1 -1
- package/dist/functions/index.d.ts +1 -0
- package/dist/functions/index.d.ts.map +1 -1
- package/dist/functions/index.js +1 -0
- package/dist/functions/index.js.map +1 -1
- package/dist/functions/log.d.ts +1 -2
- package/dist/functions/log.d.ts.map +1 -1
- package/dist/functions/log.js +40 -38
- package/dist/functions/log.js.map +1 -1
- package/dist/functions/memo.d.ts +1 -2
- package/dist/functions/memo.d.ts.map +1 -1
- package/dist/functions/memo.js +29 -27
- package/dist/functions/memo.js.map +1 -1
- package/dist/functions/once.d.ts +1 -2
- package/dist/functions/once.d.ts.map +1 -1
- package/dist/functions/once.js +14 -12
- package/dist/functions/once.js.map +1 -1
- package/dist/functions/retry.d.ts +1 -2
- package/dist/functions/retry.d.ts.map +1 -1
- package/dist/functions/retry.js +23 -20
- package/dist/functions/retry.js.map +1 -1
- package/dist/functions/throttle.d.ts +1 -2
- package/dist/functions/throttle.d.ts.map +1 -1
- package/dist/functions/throttle.js +11 -17
- package/dist/functions/throttle.js.map +1 -1
- package/dist/functions/until.d.ts +2 -0
- package/dist/functions/until.d.ts.map +1 -0
- package/dist/functions/until.js +17 -0
- package/dist/functions/until.js.map +1 -0
- package/dist/functions/watch.d.ts +1 -1
- package/dist/functions/watch.d.ts.map +1 -1
- package/dist/functions/watch.js +25 -39
- package/dist/functions/watch.js.map +1 -1
- package/dist/functions/when.d.ts +1 -2
- package/dist/functions/when.d.ts.map +1 -1
- package/dist/functions/when.js +10 -26
- package/dist/functions/when.js.map +1 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -2
- package/dist/index.js.map +1 -1
- package/dist/properties/compose.d.ts +3 -0
- package/dist/properties/compose.d.ts.map +1 -0
- package/dist/properties/compose.js +40 -0
- package/dist/properties/compose.js.map +1 -0
- package/dist/properties/computed.d.ts +1 -2
- package/dist/properties/computed.d.ts.map +1 -1
- package/dist/properties/computed.js +10 -9
- package/dist/properties/computed.js.map +1 -1
- package/dist/properties/history.d.ts.map +1 -1
- package/dist/properties/history.js +37 -32
- package/dist/properties/history.js.map +1 -1
- package/dist/properties/index.d.ts +2 -0
- package/dist/properties/index.d.ts.map +1 -1
- package/dist/properties/index.js +2 -0
- package/dist/properties/index.js.map +1 -1
- package/dist/properties/persisted.d.ts +1 -2
- package/dist/properties/persisted.d.ts.map +1 -1
- package/dist/properties/persisted.js +13 -29
- package/dist/properties/persisted.js.map +1 -1
- package/dist/properties/prop.d.ts +1 -2
- package/dist/properties/prop.d.ts.map +1 -1
- package/dist/properties/prop.js +21 -25
- package/dist/properties/prop.js.map +1 -1
- package/dist/properties/resource.d.ts +14 -0
- package/dist/properties/resource.d.ts.map +1 -0
- package/dist/properties/resource.js +27 -0
- package/dist/properties/resource.js.map +1 -0
- package/dist/properties/slot.d.ts +1 -2
- package/dist/properties/slot.d.ts.map +1 -1
- package/dist/properties/slot.js +15 -20
- package/dist/properties/slot.js.map +1 -1
- package/dist/properties/state.d.ts +1 -2
- package/dist/properties/state.d.ts.map +1 -1
- package/dist/properties/state.js +13 -18
- package/dist/properties/state.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/component.test.ts +10 -0
- package/src/__tests__/compose.test.ts +202 -0
- package/src/__tests__/events.test.ts +32 -0
- package/src/__tests__/functions.test.ts +257 -46
- package/src/__tests__/lazy.test.ts +3 -5
- package/src/__tests__/memo.test.ts +143 -25
- package/src/__tests__/properties.test.ts +233 -0
- package/src/__tests__/resource.test.ts +141 -0
- package/src/__tests__/slot.test.ts +38 -0
- package/src/__tests__/until.test.ts +113 -0
- package/src/__tests__/virtual.test.ts +135 -7
- package/src/component/component.ts +27 -12
- package/src/component/lazy.ts +33 -37
- package/src/component/virtual.tsx +67 -75
- package/src/create-class-decorator.ts +61 -0
- package/src/create-field-decorator.ts +66 -0
- package/src/create-getter-decorator.ts +52 -0
- package/src/create-lifecycle-method-decorator.ts +38 -0
- package/src/create-method-decorator.ts +26 -0
- package/src/events/emit.ts +22 -33
- package/src/events/on-command.ts +22 -47
- package/src/functions/bind.ts +4 -15
- package/src/functions/debounce.ts +21 -23
- package/src/functions/index.ts +1 -0
- package/src/functions/log.ts +40 -43
- package/src/functions/memo.ts +28 -42
- package/src/functions/once.ts +13 -16
- package/src/functions/retry.ts +21 -22
- package/src/functions/throttle.ts +11 -24
- package/src/functions/until.ts +19 -0
- package/src/functions/watch.ts +27 -43
- package/src/functions/when.ts +11 -36
- package/src/index.ts +29 -0
- package/src/properties/compose.ts +53 -0
- package/src/properties/computed.ts +11 -13
- package/src/properties/history.ts +42 -41
- package/src/properties/index.ts +2 -0
- package/src/properties/persisted.ts +17 -58
- package/src/properties/prop.ts +21 -31
- package/src/properties/resource.ts +34 -0
- package/src/properties/slot.ts +17 -30
- package/src/properties/state.ts +14 -24
package/src/functions/once.ts
CHANGED
|
@@ -1,19 +1,16 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { createMethodDecorator } from "../create-method-decorator";
|
|
2
2
|
|
|
3
3
|
export function Once() {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
return result;
|
|
17
|
-
};
|
|
18
|
-
};
|
|
4
|
+
return createMethodDecorator({
|
|
5
|
+
wrap(original, instance) {
|
|
6
|
+
let called = false;
|
|
7
|
+
let result: unknown;
|
|
8
|
+
return (...args: unknown[]) => {
|
|
9
|
+
if (called) return result;
|
|
10
|
+
result = original.apply(instance, args);
|
|
11
|
+
called = true;
|
|
12
|
+
return result;
|
|
13
|
+
};
|
|
14
|
+
},
|
|
15
|
+
});
|
|
19
16
|
}
|
package/src/functions/retry.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { createMethodDecorator } from "../create-method-decorator";
|
|
2
2
|
|
|
3
3
|
export interface RetryOptions {
|
|
4
4
|
delay?: number;
|
|
@@ -9,30 +9,29 @@ export interface RetryOptions {
|
|
|
9
9
|
export function Retry(maxAttempts: number, options: RetryOptions = {}) {
|
|
10
10
|
const { delay = 0, backoff = 1, onRetry } = options;
|
|
11
11
|
|
|
12
|
-
return
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
let lastError: Error = new Error("Unknown error");
|
|
18
|
-
let currentDelay = delay;
|
|
12
|
+
return createMethodDecorator({
|
|
13
|
+
wrap(original, instance) {
|
|
14
|
+
return async (...args: unknown[]) => {
|
|
15
|
+
let lastError: Error = new Error("Unknown error");
|
|
16
|
+
let currentDelay = delay;
|
|
19
17
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
18
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
19
|
+
try {
|
|
20
|
+
return await (original.apply(instance, args) as Promise<unknown>);
|
|
21
|
+
} catch (e: unknown) {
|
|
22
|
+
lastError = e instanceof Error ? e : new Error(String(e));
|
|
23
|
+
if (attempt === maxAttempts) break;
|
|
24
|
+
onRetry?.(lastError, attempt);
|
|
27
25
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
if (currentDelay > 0) {
|
|
27
|
+
await new Promise((res) => setTimeout(res, currentDelay));
|
|
28
|
+
currentDelay = Math.round(currentDelay * backoff);
|
|
29
|
+
}
|
|
31
30
|
}
|
|
32
31
|
}
|
|
33
|
-
}
|
|
34
32
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
throw lastError;
|
|
34
|
+
};
|
|
35
|
+
},
|
|
36
|
+
});
|
|
38
37
|
}
|
|
@@ -1,29 +1,16 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { createMethodDecorator } from "../create-method-decorator";
|
|
2
2
|
|
|
3
3
|
export function Throttle(ms: number) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
): void {
|
|
10
|
-
context.addInitializer(function (this: unknown) {
|
|
11
|
-
const instance = this as object;
|
|
12
|
-
const name = context.name as string;
|
|
13
|
-
const bound = (...args: unknown[]) => {
|
|
4
|
+
return createMethodDecorator({
|
|
5
|
+
wrap(original, instance) {
|
|
6
|
+
const clampedMs = Math.max(0, ms);
|
|
7
|
+
let last = 0;
|
|
8
|
+
return (...args: unknown[]) => {
|
|
14
9
|
const now = Date.now();
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
lastRun.set(instance, now);
|
|
20
|
-
return value.apply(instance, args);
|
|
10
|
+
if (now - last < clampedMs) return;
|
|
11
|
+
last = now;
|
|
12
|
+
return original.apply(instance, args);
|
|
21
13
|
};
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
configurable: true,
|
|
25
|
-
writable: true,
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
};
|
|
14
|
+
},
|
|
15
|
+
});
|
|
29
16
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { until } from "@praxisjs/core/internal";
|
|
2
|
+
import type { Computed, Signal } from "@praxisjs/shared";
|
|
3
|
+
import { isComputed } from "@praxisjs/shared/internal";
|
|
4
|
+
|
|
5
|
+
import { createMethodDecorator } from "../create-method-decorator";
|
|
6
|
+
|
|
7
|
+
export function Until(propName: string) {
|
|
8
|
+
return createMethodDecorator({
|
|
9
|
+
wrap(_original, instance) {
|
|
10
|
+
return () => {
|
|
11
|
+
const raw = (instance as Record<string, unknown>)[propName];
|
|
12
|
+
const source = isComputed(raw)
|
|
13
|
+
? (raw as Computed<unknown>)
|
|
14
|
+
: (raw as Signal<unknown>);
|
|
15
|
+
return until(source);
|
|
16
|
+
};
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
}
|
package/src/functions/watch.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { effect } from "@praxisjs/core/internal";
|
|
|
3
3
|
import type { Computed } from "@praxisjs/shared";
|
|
4
4
|
import { isComputed } from "@praxisjs/shared/internal";
|
|
5
5
|
|
|
6
|
+
import { createLifecycleMethodDecorator } from "../create-lifecycle-method-decorator";
|
|
7
|
+
|
|
6
8
|
type BaseComponentKeys = keyof StatefulComponent;
|
|
7
9
|
|
|
8
10
|
type WatchableKeys<T> = {
|
|
@@ -54,51 +56,33 @@ export function Watch<
|
|
|
54
56
|
T extends StatefulComponent,
|
|
55
57
|
const Keys extends ReadonlyArray<WatchableKeys<T>>,
|
|
56
58
|
>(...propNames: ValidateKeys<T, Keys>) {
|
|
57
|
-
|
|
58
|
-
value: (this: T, ...args: unknown[]) => void,
|
|
59
|
-
context: ClassMethodDecoratorContext<T>,
|
|
60
|
-
): void {
|
|
61
|
-
const props = propNames as unknown as string[];
|
|
59
|
+
const props = propNames as unknown as string[];
|
|
62
60
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const originalOnMount = instance.onMount;
|
|
67
|
-
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
68
|
-
const originalOnUnmount = instance.onUnmount;
|
|
69
|
-
let stopEffect: (() => void) | undefined;
|
|
61
|
+
return createLifecycleMethodDecorator<T>({
|
|
62
|
+
register(callback, instance) {
|
|
63
|
+
const inst = instance as T & Record<string, unknown>;
|
|
70
64
|
|
|
71
|
-
|
|
72
|
-
|
|
65
|
+
if (props.length === 1) {
|
|
66
|
+
let oldVal = readValue(inst, props[0]);
|
|
67
|
+
return effect(() => {
|
|
68
|
+
const newVal = readValue(inst, props[0]);
|
|
69
|
+
if (!Object.is(newVal, oldVal)) {
|
|
70
|
+
callback(newVal, oldVal);
|
|
71
|
+
oldVal = newVal;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
73
75
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
});
|
|
83
|
-
} else {
|
|
84
|
-
const read = () =>
|
|
85
|
-
Object.fromEntries(props.map((p) => [p, readValue(this, p)]));
|
|
86
|
-
let oldVals = read();
|
|
87
|
-
stopEffect = effect(() => {
|
|
88
|
-
const newVals = read();
|
|
89
|
-
if (props.some((p) => !Object.is(newVals[p], oldVals[p]))) {
|
|
90
|
-
value.call(this as T, newVals, oldVals);
|
|
91
|
-
oldVals = newVals;
|
|
92
|
-
}
|
|
93
|
-
});
|
|
76
|
+
const read = () =>
|
|
77
|
+
Object.fromEntries(props.map((p) => [p, readValue(inst, p)]));
|
|
78
|
+
let oldVals = read();
|
|
79
|
+
return effect(() => {
|
|
80
|
+
const newVals = read();
|
|
81
|
+
if (props.some((p) => !Object.is(newVals[p], oldVals[p]))) {
|
|
82
|
+
callback(newVals, oldVals);
|
|
83
|
+
oldVals = newVals;
|
|
94
84
|
}
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
originalOnUnmount?.call(this);
|
|
99
|
-
stopEffect?.();
|
|
100
|
-
stopEffect = undefined;
|
|
101
|
-
};
|
|
102
|
-
});
|
|
103
|
-
};
|
|
85
|
+
});
|
|
86
|
+
},
|
|
87
|
+
});
|
|
104
88
|
}
|
package/src/functions/when.ts
CHANGED
|
@@ -1,42 +1,17 @@
|
|
|
1
|
-
import type { StatefulComponent } from "@praxisjs/core";
|
|
2
1
|
import { when } from "@praxisjs/core/internal";
|
|
3
2
|
import type { Computed, Signal } from "@praxisjs/shared";
|
|
4
3
|
import { isComputed } from "@praxisjs/shared/internal";
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
return function (
|
|
8
|
-
value: (this: StatefulComponent, val: unknown) => void,
|
|
9
|
-
context: ClassMethodDecoratorContext<StatefulComponent>,
|
|
10
|
-
): void {
|
|
11
|
-
const cancels = new WeakMap<object, () => void>();
|
|
12
|
-
|
|
13
|
-
context.addInitializer(function (this: unknown) {
|
|
14
|
-
const instance = this as StatefulComponent;
|
|
15
|
-
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
16
|
-
const originalOnMount = instance.onMount;
|
|
17
|
-
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
18
|
-
const originalOnUnmount = instance.onUnmount;
|
|
19
|
-
|
|
20
|
-
instance.onMount = function (this: StatefulComponent) {
|
|
21
|
-
originalOnMount?.call(this);
|
|
22
|
-
|
|
23
|
-
const raw = (this as unknown as Record<string, unknown>)[propName];
|
|
24
|
-
const source = isComputed(raw)
|
|
25
|
-
? (raw as Computed<unknown>)
|
|
26
|
-
: (raw as Signal<unknown>);
|
|
5
|
+
import { createLifecycleMethodDecorator } from "../create-lifecycle-method-decorator";
|
|
27
6
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
cancels.delete(this);
|
|
39
|
-
};
|
|
40
|
-
});
|
|
41
|
-
};
|
|
7
|
+
export function When(propName: string) {
|
|
8
|
+
return createLifecycleMethodDecorator({
|
|
9
|
+
register(callback, instance) {
|
|
10
|
+
const raw = (instance as unknown as Record<string, unknown>)[propName];
|
|
11
|
+
const source = isComputed(raw)
|
|
12
|
+
? (raw as Computed<unknown>)
|
|
13
|
+
: (raw as Signal<unknown>);
|
|
14
|
+
return when(source, (val) => { callback(val); });
|
|
15
|
+
},
|
|
16
|
+
});
|
|
42
17
|
}
|
package/src/index.ts
CHANGED
|
@@ -8,6 +8,7 @@ export {
|
|
|
8
8
|
Debounce,
|
|
9
9
|
Throttle,
|
|
10
10
|
When,
|
|
11
|
+
Until,
|
|
11
12
|
Watch,
|
|
12
13
|
type WatchVal,
|
|
13
14
|
type WatchVals,
|
|
@@ -21,5 +22,33 @@ export {
|
|
|
21
22
|
initSlots,
|
|
22
23
|
History,
|
|
23
24
|
type WithHistory,
|
|
25
|
+
Compose,
|
|
26
|
+
Resource,
|
|
27
|
+
type ResourceInstance,
|
|
28
|
+
type ResourceOptions,
|
|
24
29
|
} from "./properties";
|
|
25
30
|
export { type Command, createCommand, Emit, OnCommand } from "./events";
|
|
31
|
+
export {
|
|
32
|
+
createFieldDecorator,
|
|
33
|
+
type FieldBehavior,
|
|
34
|
+
type FieldBinding,
|
|
35
|
+
} from "./create-field-decorator";
|
|
36
|
+
export {
|
|
37
|
+
createClassDecorator,
|
|
38
|
+
ClassBehavior,
|
|
39
|
+
type ClassEnhancement,
|
|
40
|
+
} from "./create-class-decorator";
|
|
41
|
+
export {
|
|
42
|
+
createMethodDecorator,
|
|
43
|
+
type MethodBehavior,
|
|
44
|
+
} from "./create-method-decorator";
|
|
45
|
+
export {
|
|
46
|
+
createLifecycleMethodDecorator,
|
|
47
|
+
type LifecycleMethodBehavior,
|
|
48
|
+
} from "./create-lifecycle-method-decorator";
|
|
49
|
+
export {
|
|
50
|
+
createGetterDecorator,
|
|
51
|
+
type GetterBehavior,
|
|
52
|
+
createGetterObserverDecorator,
|
|
53
|
+
type GetterObserverBehavior,
|
|
54
|
+
} from "./create-getter-decorator";
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { StatefulComponent, Composable } from "@praxisjs/core";
|
|
2
|
+
|
|
3
|
+
import { createFieldDecorator } from "../create-field-decorator";
|
|
4
|
+
|
|
5
|
+
function isReactive(
|
|
6
|
+
value: unknown,
|
|
7
|
+
): value is () => unknown {
|
|
8
|
+
return (
|
|
9
|
+
typeof value === "function" &&
|
|
10
|
+
("__isSignal" in (value as object) || "__isComputed" in (value as object))
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function buildView(bindings: Record<string, unknown>): object {
|
|
15
|
+
const view: Record<string, unknown> = {};
|
|
16
|
+
for (const [key, value] of Object.entries(bindings)) {
|
|
17
|
+
if (isReactive(value)) {
|
|
18
|
+
Object.defineProperty(view, key, {
|
|
19
|
+
get: () => (value as () => unknown)(),
|
|
20
|
+
enumerable: true,
|
|
21
|
+
configurable: true,
|
|
22
|
+
});
|
|
23
|
+
} else {
|
|
24
|
+
view[key] = value;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return view;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function Compose(
|
|
31
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
32
|
+
ComposableClass: new (...args: any[]) => Composable,
|
|
33
|
+
...ctorArgs: unknown[]
|
|
34
|
+
) {
|
|
35
|
+
return createFieldDecorator({
|
|
36
|
+
bind(instance: StatefulComponent, _name: string, _initialValue: unknown) {
|
|
37
|
+
const resolvedArgs = ctorArgs.map((arg) =>
|
|
38
|
+
typeof arg === "string"
|
|
39
|
+
? (instance as unknown as Record<string, unknown>)[arg]
|
|
40
|
+
: arg,
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const composable = new ComposableClass(...resolvedArgs);
|
|
44
|
+
const view = buildView(composable.setup());
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
descriptor: { get: () => view },
|
|
48
|
+
onMount: composable.onMount?.bind(composable),
|
|
49
|
+
onUnmount: composable.onUnmount?.bind(composable),
|
|
50
|
+
};
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
}
|
|
@@ -1,20 +1,18 @@
|
|
|
1
|
-
import type { StatefulComponent } from "@praxisjs/core";
|
|
2
1
|
import { computed } from "@praxisjs/core/internal";
|
|
3
2
|
|
|
3
|
+
import { createGetterDecorator } from "../create-getter-decorator";
|
|
4
|
+
|
|
4
5
|
export function Computed() {
|
|
5
|
-
|
|
6
|
-
target: (this: This) => T,
|
|
7
|
-
_context: ClassGetterDecoratorContext<This, T>,
|
|
8
|
-
): (this: This) => T {
|
|
9
|
-
const computedMap = new WeakMap<object, () => T>();
|
|
6
|
+
const cache = new WeakMap<object, () => unknown>();
|
|
10
7
|
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
return createGetterDecorator({
|
|
9
|
+
wrap(original, instance) {
|
|
10
|
+
let c = cache.get(instance);
|
|
13
11
|
if (!c) {
|
|
14
|
-
c = computed(() =>
|
|
15
|
-
|
|
12
|
+
c = computed(() => original.call(instance));
|
|
13
|
+
cache.set(instance, c);
|
|
16
14
|
}
|
|
17
|
-
return c
|
|
18
|
-
}
|
|
19
|
-
};
|
|
15
|
+
return c;
|
|
16
|
+
},
|
|
17
|
+
});
|
|
20
18
|
}
|
|
@@ -2,52 +2,53 @@ import type { StatefulComponent } from "@praxisjs/core";
|
|
|
2
2
|
import { type HistoryElement, history } from "@praxisjs/core/internal";
|
|
3
3
|
import type { Signal } from "@praxisjs/shared";
|
|
4
4
|
|
|
5
|
+
import { createFieldDecorator } from "../create-field-decorator";
|
|
6
|
+
|
|
5
7
|
export type WithHistory<T, K extends keyof T> = Record<
|
|
6
8
|
`${string & K}History`,
|
|
7
9
|
HistoryElement<T[K]>
|
|
8
10
|
>;
|
|
9
11
|
|
|
10
12
|
export function History(limit = 50) {
|
|
11
|
-
return
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
13
|
+
return createFieldDecorator({
|
|
14
|
+
bind(instance: StatefulComponent, name: string, _initialValue: unknown) {
|
|
15
|
+
const historyKey = `${name}History`;
|
|
16
|
+
const inst = instance as unknown as Record<string, unknown>;
|
|
17
|
+
let h: HistoryElement<unknown> | undefined;
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
// descriptor omitted — @History does not replace the original field
|
|
21
|
+
additional: {
|
|
22
|
+
[historyKey]: {
|
|
23
|
+
get(): HistoryElement<unknown> {
|
|
24
|
+
if (!h) {
|
|
25
|
+
const source = () => inst[name];
|
|
26
|
+
const hInst = history(source as Signal<unknown>, limit);
|
|
27
|
+
|
|
28
|
+
const _undo = hInst.undo.bind(hInst);
|
|
29
|
+
const _redo = hInst.redo.bind(hInst);
|
|
30
|
+
|
|
31
|
+
hInst.undo = () => {
|
|
32
|
+
const prev = hInst.values()[hInst.values().length - 2];
|
|
33
|
+
if (prev === undefined) return;
|
|
34
|
+
_undo();
|
|
35
|
+
inst[name] = prev;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
hInst.redo = () => {
|
|
39
|
+
_redo();
|
|
40
|
+
inst[name] = hInst.current();
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
h = hInst;
|
|
44
|
+
}
|
|
45
|
+
return h;
|
|
46
|
+
},
|
|
47
|
+
enumerable: false,
|
|
48
|
+
configurable: true,
|
|
49
|
+
},
|
|
47
50
|
},
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
});
|
|
52
|
-
};
|
|
51
|
+
};
|
|
52
|
+
},
|
|
53
|
+
});
|
|
53
54
|
}
|
package/src/properties/index.ts
CHANGED
|
@@ -4,3 +4,5 @@ export { Computed } from "./computed";
|
|
|
4
4
|
export { Persisted } from "./persisted";
|
|
5
5
|
export { Slot, initSlots } from "./slot";
|
|
6
6
|
export { History, type WithHistory } from "./history";
|
|
7
|
+
export { Compose } from "./compose";
|
|
8
|
+
export { Resource, type ResourceInstance, type ResourceOptions } from "./resource";
|
|
@@ -1,19 +1,9 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import {
|
|
3
|
-
persistedSignal,
|
|
4
|
-
type PersistedSignalOptions,
|
|
5
|
-
} from "@praxisjs/core/internal";
|
|
1
|
+
import { persistedSignal, type PersistedSignalOptions } from "@praxisjs/core/internal";
|
|
6
2
|
import type { Signal } from "@praxisjs/shared";
|
|
7
3
|
|
|
8
|
-
|
|
9
|
-
const initMap = new WeakMap<object, Set<string>>();
|
|
4
|
+
import { createFieldDecorator } from "../create-field-decorator";
|
|
10
5
|
|
|
11
|
-
|
|
12
|
-
if (!initMap.has(instance)) {
|
|
13
|
-
initMap.set(instance, new Set());
|
|
14
|
-
}
|
|
15
|
-
(initMap.get(instance) as Set<string>).add(propKey);
|
|
16
|
-
}
|
|
6
|
+
const signalMap = new WeakMap<object, Map<string, Signal<unknown>>>();
|
|
17
7
|
|
|
18
8
|
function getOrCreateSignal<T>(
|
|
19
9
|
instance: object,
|
|
@@ -21,18 +11,14 @@ function getOrCreateSignal<T>(
|
|
|
21
11
|
initialValue: T,
|
|
22
12
|
options: PersistedSignalOptions<T>,
|
|
23
13
|
): Signal<T> {
|
|
24
|
-
if (!signalMap.has(instance))
|
|
25
|
-
signalMap.set(instance, new Map());
|
|
26
|
-
}
|
|
14
|
+
if (!signalMap.has(instance)) signalMap.set(instance, new Map());
|
|
27
15
|
const map = signalMap.get(instance) as Map<string, Signal<unknown>>;
|
|
28
|
-
|
|
29
16
|
if (!map.has(storageKey)) {
|
|
30
17
|
map.set(
|
|
31
18
|
storageKey,
|
|
32
19
|
persistedSignal(storageKey, initialValue, options) as Signal<unknown>,
|
|
33
20
|
);
|
|
34
21
|
}
|
|
35
|
-
|
|
36
22
|
return map.get(storageKey) as Signal<T>;
|
|
37
23
|
}
|
|
38
24
|
|
|
@@ -40,45 +26,18 @@ export function Persisted<T>(
|
|
|
40
26
|
key?: string,
|
|
41
27
|
options: PersistedSignalOptions<T> = {},
|
|
42
28
|
) {
|
|
43
|
-
return
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
] as T;
|
|
54
|
-
|
|
55
|
-
Reflect.deleteProperty(instance, propertyKey);
|
|
56
|
-
|
|
57
|
-
markInitialized(instance, propertyKey);
|
|
58
|
-
getOrCreateSignal(instance, storageKey, initialValue, options);
|
|
59
|
-
|
|
60
|
-
Object.defineProperty(instance, propertyKey, {
|
|
61
|
-
get(): T {
|
|
62
|
-
return getOrCreateSignal<T>(
|
|
63
|
-
instance,
|
|
64
|
-
storageKey,
|
|
65
|
-
undefined as T,
|
|
66
|
-
options,
|
|
67
|
-
)();
|
|
29
|
+
return createFieldDecorator({
|
|
30
|
+
bind(instance, name, initialValue) {
|
|
31
|
+
const storageKey = key ?? name;
|
|
32
|
+
getOrCreateSignal(instance, storageKey, initialValue as T, options);
|
|
33
|
+
return {
|
|
34
|
+
descriptor: {
|
|
35
|
+
get: () =>
|
|
36
|
+
getOrCreateSignal<T>(instance, storageKey, undefined as T, options)(),
|
|
37
|
+
set: (value: T) =>
|
|
38
|
+
{ getOrCreateSignal<T>(instance, storageKey, undefined as T, options).set(value); },
|
|
68
39
|
},
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
instance,
|
|
73
|
-
storageKey,
|
|
74
|
-
undefined as T,
|
|
75
|
-
options,
|
|
76
|
-
).set(value);
|
|
77
|
-
},
|
|
78
|
-
|
|
79
|
-
enumerable: true,
|
|
80
|
-
configurable: true,
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
};
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
});
|
|
84
43
|
}
|