@praxisjs/decorators 0.1.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 +14 -0
- package/LICENSE +21 -0
- package/dist/component/component.d.ts +3 -0
- package/dist/component/component.d.ts.map +1 -0
- package/dist/component/component.js +13 -0
- package/dist/component/component.js.map +1 -0
- package/dist/component/index.d.ts +5 -0
- package/dist/component/index.d.ts.map +1 -0
- package/dist/component/index.js +5 -0
- package/dist/component/index.js.map +1 -0
- package/dist/component/lazy.d.ts +3 -0
- package/dist/component/lazy.d.ts.map +1 -0
- package/dist/component/lazy.js +44 -0
- package/dist/component/lazy.js.map +1 -0
- package/dist/component/lifecycle.d.ts +3 -0
- package/dist/component/lifecycle.d.ts.map +1 -0
- package/dist/component/lifecycle.js +35 -0
- package/dist/component/lifecycle.js.map +1 -0
- package/dist/component/memoize.d.ts +5 -0
- package/dist/component/memoize.d.ts.map +1 -0
- package/dist/component/memoize.js +23 -0
- package/dist/component/memoize.js.map +1 -0
- package/dist/component/virtual.d.ts +3 -0
- package/dist/component/virtual.d.ts.map +1 -0
- package/dist/component/virtual.js +66 -0
- package/dist/component/virtual.js.map +1 -0
- package/dist/events/command.d.ts +6 -0
- package/dist/events/command.d.ts.map +1 -0
- package/dist/events/command.js +13 -0
- package/dist/events/command.js.map +1 -0
- package/dist/events/emit.d.ts +2 -0
- package/dist/events/emit.d.ts.map +1 -0
- package/dist/events/emit.js +36 -0
- package/dist/events/emit.js.map +1 -0
- package/dist/events/helper.d.ts +3 -0
- package/dist/events/helper.d.ts.map +1 -0
- package/dist/events/helper.js +7 -0
- package/dist/events/helper.js.map +1 -0
- package/dist/events/index.d.ts +4 -0
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/index.js +4 -0
- package/dist/events/index.js.map +1 -0
- package/dist/events/on-command.d.ts +2 -0
- package/dist/events/on-command.d.ts.map +1 -0
- package/dist/events/on-command.js +33 -0
- package/dist/events/on-command.js.map +1 -0
- package/dist/functions/bind.d.ts +2 -0
- package/dist/functions/bind.d.ts.map +1 -0
- package/dist/functions/bind.js +19 -0
- package/dist/functions/bind.js.map +1 -0
- package/dist/functions/debounce.d.ts +2 -0
- package/dist/functions/debounce.d.ts.map +1 -0
- package/dist/functions/debounce.js +29 -0
- package/dist/functions/debounce.js.map +1 -0
- package/dist/functions/index.d.ts +10 -0
- package/dist/functions/index.d.ts.map +1 -0
- package/dist/functions/index.js +10 -0
- package/dist/functions/index.js.map +1 -0
- package/dist/functions/log.d.ts +9 -0
- package/dist/functions/log.d.ts.map +1 -0
- package/dist/functions/log.js +43 -0
- package/dist/functions/log.js.map +1 -0
- package/dist/functions/memo.d.ts +2 -0
- package/dist/functions/memo.d.ts.map +1 -0
- package/dist/functions/memo.js +45 -0
- package/dist/functions/memo.js.map +1 -0
- package/dist/functions/once.d.ts +2 -0
- package/dist/functions/once.d.ts.map +1 -0
- package/dist/functions/once.js +17 -0
- package/dist/functions/once.js.map +1 -0
- package/dist/functions/retry.d.ts +7 -0
- package/dist/functions/retry.d.ts.map +1 -0
- package/dist/functions/retry.js +28 -0
- package/dist/functions/retry.js.map +1 -0
- package/dist/functions/throttle.d.ts +2 -0
- package/dist/functions/throttle.d.ts.map +1 -0
- package/dist/functions/throttle.js +27 -0
- package/dist/functions/throttle.js.map +1 -0
- package/dist/functions/watch.d.ts +19 -0
- package/dist/functions/watch.d.ts.map +1 -0
- package/dist/functions/watch.js +45 -0
- package/dist/functions/watch.js.map +1 -0
- package/dist/functions/when.d.ts +2 -0
- package/dist/functions/when.d.ts.map +1 -0
- package/dist/functions/when.js +31 -0
- package/dist/functions/when.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/properties/history.d.ts +2 -0
- package/dist/properties/history.d.ts.map +1 -0
- package/dist/properties/history.js +39 -0
- package/dist/properties/history.js.map +1 -0
- package/dist/properties/index.d.ts +6 -0
- package/dist/properties/index.d.ts.map +1 -0
- package/dist/properties/index.js +6 -0
- package/dist/properties/index.js.map +1 -0
- package/dist/properties/persisted.d.ts +3 -0
- package/dist/properties/persisted.d.ts.map +1 -0
- package/dist/properties/persisted.js +46 -0
- package/dist/properties/persisted.js.map +1 -0
- package/dist/properties/prop.d.ts +2 -0
- package/dist/properties/prop.d.ts.map +1 -0
- package/dist/properties/prop.js +18 -0
- package/dist/properties/prop.js.map +1 -0
- package/dist/properties/slot.d.ts +9 -0
- package/dist/properties/slot.d.ts.map +1 -0
- package/dist/properties/slot.js +46 -0
- package/dist/properties/slot.js.map +1 -0
- package/dist/properties/state.d.ts +2 -0
- package/dist/properties/state.d.ts.map +1 -0
- package/dist/properties/state.js +24 -0
- package/dist/properties/state.js.map +1 -0
- package/package.json +26 -0
- package/src/component/component.ts +18 -0
- package/src/component/index.ts +4 -0
- package/src/component/lazy.ts +56 -0
- package/src/component/lifecycle.ts +47 -0
- package/src/component/memoize.ts +31 -0
- package/src/component/virtual.tsx +104 -0
- package/src/events/command.ts +17 -0
- package/src/events/emit.ts +47 -0
- package/src/events/helper.ts +7 -0
- package/src/events/index.ts +3 -0
- package/src/events/on-command.ts +55 -0
- package/src/functions/bind.ts +22 -0
- package/src/functions/debounce.ts +34 -0
- package/src/functions/index.ts +9 -0
- package/src/functions/log.ts +68 -0
- package/src/functions/memo.ts +63 -0
- package/src/functions/once.ts +22 -0
- package/src/functions/retry.ts +43 -0
- package/src/functions/throttle.ts +32 -0
- package/src/functions/watch.ts +99 -0
- package/src/functions/when.ts +44 -0
- package/src/index.ts +16 -0
- package/src/properties/history.ts +62 -0
- package/src/properties/index.ts +5 -0
- package/src/properties/persisted.ts +75 -0
- package/src/properties/prop.ts +18 -0
- package/src/properties/slot.ts +75 -0
- package/src/properties/state.ts +24 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export interface RetryOptions {
|
|
2
|
+
delay?: number;
|
|
3
|
+
backoff?: number;
|
|
4
|
+
onRetry?: (error: Error, attempt: number) => void;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function Retry(maxAttempts: number, options: RetryOptions = {}) {
|
|
8
|
+
const { delay = 0, backoff = 1, onRetry } = options;
|
|
9
|
+
|
|
10
|
+
return function (
|
|
11
|
+
_target: object,
|
|
12
|
+
_methodKey: string,
|
|
13
|
+
descriptor: PropertyDescriptor,
|
|
14
|
+
): PropertyDescriptor {
|
|
15
|
+
const originalMethod = descriptor.value as (
|
|
16
|
+
...args: unknown[]
|
|
17
|
+
) => Promise<unknown>;
|
|
18
|
+
|
|
19
|
+
descriptor.value = async function (this: object, ...args: unknown[]) {
|
|
20
|
+
let lastError: Error = new Error("Unknown error");
|
|
21
|
+
let currentDelay = delay;
|
|
22
|
+
|
|
23
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
24
|
+
try {
|
|
25
|
+
return await originalMethod.apply(this, args);
|
|
26
|
+
} catch (e: unknown) {
|
|
27
|
+
lastError = e instanceof Error ? e : new Error(String(e));
|
|
28
|
+
if (attempt === maxAttempts) break;
|
|
29
|
+
onRetry?.(lastError, attempt);
|
|
30
|
+
|
|
31
|
+
if (currentDelay > 0) {
|
|
32
|
+
await new Promise((res) => setTimeout(res, currentDelay));
|
|
33
|
+
currentDelay = Math.round(currentDelay * backoff);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
throw lastError;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
return descriptor;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export function Throttle(ms: number) {
|
|
2
|
+
const lastRun = new WeakMap<object, number>();
|
|
3
|
+
|
|
4
|
+
return function (
|
|
5
|
+
_target: object,
|
|
6
|
+
methodKey: string,
|
|
7
|
+
descriptor: PropertyDescriptor,
|
|
8
|
+
): PropertyDescriptor {
|
|
9
|
+
const originalMethod = descriptor.value as (...args: unknown[]) => unknown;
|
|
10
|
+
return {
|
|
11
|
+
enumerable: false,
|
|
12
|
+
configurable: true,
|
|
13
|
+
get(this: object) {
|
|
14
|
+
const bound = (...args: unknown[]) => {
|
|
15
|
+
const now = Date.now();
|
|
16
|
+
const last = lastRun.get(this) ?? 0;
|
|
17
|
+
|
|
18
|
+
if (now - last < ms) return;
|
|
19
|
+
|
|
20
|
+
lastRun.set(this, now);
|
|
21
|
+
return originalMethod.apply(this, args);
|
|
22
|
+
};
|
|
23
|
+
Object.defineProperty(this, methodKey, {
|
|
24
|
+
value: bound,
|
|
25
|
+
configurable: true,
|
|
26
|
+
writable: true,
|
|
27
|
+
});
|
|
28
|
+
return bound;
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { type BaseComponent, effect } from "@praxisjs/core";
|
|
2
|
+
import { type Computed, isComputed } from "@praxisjs/shared";
|
|
3
|
+
|
|
4
|
+
type BaseComponentKeys = keyof BaseComponent;
|
|
5
|
+
|
|
6
|
+
type WatchableKeys<T> = {
|
|
7
|
+
[K in Exclude<keyof T, BaseComponentKeys>]: T[K] extends (
|
|
8
|
+
...args: infer A
|
|
9
|
+
) => unknown
|
|
10
|
+
? A extends []
|
|
11
|
+
? T[K] extends Computed<unknown>
|
|
12
|
+
? K
|
|
13
|
+
: never
|
|
14
|
+
: never
|
|
15
|
+
: K;
|
|
16
|
+
}[Exclude<keyof T, BaseComponentKeys>] &
|
|
17
|
+
string;
|
|
18
|
+
|
|
19
|
+
type NoDuplicates<
|
|
20
|
+
Keys extends readonly string[],
|
|
21
|
+
Seen extends string = never,
|
|
22
|
+
> = Keys extends readonly [
|
|
23
|
+
infer Head extends string,
|
|
24
|
+
...infer Rest extends string[],
|
|
25
|
+
]
|
|
26
|
+
? Head extends Seen
|
|
27
|
+
? [`Error: prop '${Head}' is duplicated`, ...Rest]
|
|
28
|
+
: [Head, ...NoDuplicates<Rest, Seen | Head>]
|
|
29
|
+
: Keys;
|
|
30
|
+
|
|
31
|
+
type ValidateKeys<
|
|
32
|
+
T extends BaseComponent,
|
|
33
|
+
Keys extends ReadonlyArray<WatchableKeys<T>>,
|
|
34
|
+
> = NoDuplicates<[...Keys]> extends Keys ? Keys : NoDuplicates<[...Keys]>;
|
|
35
|
+
|
|
36
|
+
type Unwrap<T> =
|
|
37
|
+
T extends Computed<infer U> ? U : T extends () => infer U ? U : T;
|
|
38
|
+
|
|
39
|
+
export type WatchVal<T extends BaseComponent, K extends keyof T> = Unwrap<T[K]>;
|
|
40
|
+
export type WatchVals<T extends BaseComponent, K extends keyof T> = {
|
|
41
|
+
[P in K]: Unwrap<T[P]>;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
function readValue(instance: Record<string, unknown>, key: string): unknown {
|
|
45
|
+
const raw = instance[key];
|
|
46
|
+
return isComputed(raw) ? (raw as Computed<unknown>)() : raw;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function injectOnMount(
|
|
50
|
+
target: object,
|
|
51
|
+
fn: (this: Record<string, unknown>) => void,
|
|
52
|
+
): void {
|
|
53
|
+
const t = target as { onMount?: () => void };
|
|
54
|
+
const originalMethod = t.onMount;
|
|
55
|
+
t.onMount = function (this: Record<string, unknown>) {
|
|
56
|
+
originalMethod?.call(this);
|
|
57
|
+
fn.call(this);
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function Watch<
|
|
62
|
+
T extends BaseComponent,
|
|
63
|
+
const Keys extends ReadonlyArray<WatchableKeys<T>>,
|
|
64
|
+
>(...propNames: ValidateKeys<T, Keys>) {
|
|
65
|
+
return function (
|
|
66
|
+
target: T,
|
|
67
|
+
_key: string,
|
|
68
|
+
descriptor: PropertyDescriptor,
|
|
69
|
+
): PropertyDescriptor {
|
|
70
|
+
const props = propNames as unknown as string[];
|
|
71
|
+
const method = descriptor.value as (this: Record<string, unknown>, ...args: unknown[]) => void;
|
|
72
|
+
|
|
73
|
+
injectOnMount(target, function (this) {
|
|
74
|
+
if (props.length === 1) {
|
|
75
|
+
let oldVal = readValue(this, props[0]);
|
|
76
|
+
effect(() => {
|
|
77
|
+
const newVal = readValue(this, props[0]);
|
|
78
|
+
if (!Object.is(newVal, oldVal)) {
|
|
79
|
+
method.call(this, newVal, oldVal);
|
|
80
|
+
oldVal = newVal;
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
} else {
|
|
84
|
+
const read = () =>
|
|
85
|
+
Object.fromEntries(props.map((p) => [p, readValue(this, p)]));
|
|
86
|
+
let oldVals = read();
|
|
87
|
+
effect(() => {
|
|
88
|
+
const newVals = read();
|
|
89
|
+
if (props.some((p) => !Object.is(newVals[p], oldVals[p]))) {
|
|
90
|
+
method.call(this, newVals, oldVals);
|
|
91
|
+
oldVals = newVals;
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
return descriptor;
|
|
98
|
+
};
|
|
99
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type BaseComponent, when } from "@praxisjs/core";
|
|
2
|
+
import { isComputed } from "@praxisjs/shared";
|
|
3
|
+
|
|
4
|
+
export function When(propName: string) {
|
|
5
|
+
return function (
|
|
6
|
+
target: object,
|
|
7
|
+
_methodKey: string,
|
|
8
|
+
descriptor: PropertyDescriptor,
|
|
9
|
+
): PropertyDescriptor {
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
11
|
+
const originalOnMount = (target as { onMount?(): void }).onMount;
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
13
|
+
const originalOnUnmount = (target as { onUnmount?(): void }).onUnmount;
|
|
14
|
+
|
|
15
|
+
const method = descriptor.value as (value: unknown) => void;
|
|
16
|
+
const cancels = new WeakMap<object, () => void>();
|
|
17
|
+
|
|
18
|
+
(target as { onMount?(): void }).onMount = function (this: BaseComponent) {
|
|
19
|
+
originalOnMount?.call(this);
|
|
20
|
+
|
|
21
|
+
const instance = this as unknown as Record<string, unknown>;
|
|
22
|
+
const source = () => {
|
|
23
|
+
const raw = instance[propName];
|
|
24
|
+
return isComputed(raw) ? (raw as unknown as () => unknown)() : raw;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const cancel = when(source, (value) => {
|
|
28
|
+
method.call(this, value);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
cancels.set(this, cancel);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
(target as { onUnmount?(): void }).onUnmount = function (
|
|
35
|
+
this: BaseComponent,
|
|
36
|
+
) {
|
|
37
|
+
originalOnUnmount?.call(this);
|
|
38
|
+
cancels.get(this)?.();
|
|
39
|
+
cancels.delete(this);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
return descriptor;
|
|
43
|
+
};
|
|
44
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export { Component, Memoize, Lazy, Virtual } from "./component";
|
|
2
|
+
export {
|
|
3
|
+
Memo,
|
|
4
|
+
Bind,
|
|
5
|
+
Log,
|
|
6
|
+
Once,
|
|
7
|
+
Retry,
|
|
8
|
+
Debounce,
|
|
9
|
+
Throttle,
|
|
10
|
+
When,
|
|
11
|
+
Watch,
|
|
12
|
+
type WatchVal,
|
|
13
|
+
type WatchVals,
|
|
14
|
+
} from "./functions";
|
|
15
|
+
export { Prop, State, Persisted, Slot, initSlots, History } from "./properties";
|
|
16
|
+
export { type Command, createCommand, Emit, OnCommand } from "./events";
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { type HistoryElement, history } from "@praxisjs/core";
|
|
2
|
+
|
|
3
|
+
export function History(limit = 50) {
|
|
4
|
+
return function (target: object, propertyKey: string): void {
|
|
5
|
+
const historyKey = `${propertyKey}History`;
|
|
6
|
+
const histories = new WeakMap<object, HistoryElement<unknown>>();
|
|
7
|
+
|
|
8
|
+
const originalDescriptor = Object.getOwnPropertyDescriptor(
|
|
9
|
+
target,
|
|
10
|
+
propertyKey,
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
Object.defineProperty(target, historyKey, {
|
|
14
|
+
get(this: object): HistoryElement<unknown> {
|
|
15
|
+
if (!histories.has(this)) {
|
|
16
|
+
const source = () => {
|
|
17
|
+
const desc =
|
|
18
|
+
Object.getOwnPropertyDescriptor(this, propertyKey) ??
|
|
19
|
+
Object.getOwnPropertyDescriptor(
|
|
20
|
+
Object.getPrototypeOf(this),
|
|
21
|
+
propertyKey,
|
|
22
|
+
);
|
|
23
|
+
return desc?.get?.call(this) as unknown;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const h = history(source as () => unknown, limit);
|
|
27
|
+
|
|
28
|
+
const originalUndo = () => { h.undo(); };
|
|
29
|
+
const originalRedo = () => { h.redo(); };
|
|
30
|
+
|
|
31
|
+
h.undo = () => {
|
|
32
|
+
const prev = h.values()[h.values().length - 2];
|
|
33
|
+
if (prev === undefined) return;
|
|
34
|
+
originalUndo();
|
|
35
|
+
(
|
|
36
|
+
Object.getOwnPropertyDescriptor(
|
|
37
|
+
Object.getPrototypeOf(this),
|
|
38
|
+
propertyKey,
|
|
39
|
+
) ?? originalDescriptor
|
|
40
|
+
)?.set?.call(this, prev);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
h.redo = () => {
|
|
44
|
+
originalRedo();
|
|
45
|
+
const next = h.current();
|
|
46
|
+
(
|
|
47
|
+
Object.getOwnPropertyDescriptor(
|
|
48
|
+
Object.getPrototypeOf(this),
|
|
49
|
+
propertyKey,
|
|
50
|
+
) ?? originalDescriptor
|
|
51
|
+
)?.set?.call(this, next);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
histories.set(this, h);
|
|
55
|
+
}
|
|
56
|
+
return histories.get(this) as HistoryElement<unknown>;
|
|
57
|
+
},
|
|
58
|
+
enumerable: false,
|
|
59
|
+
configurable: true,
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { persistedSignal, type PersistedSignalOptions } from "@praxisjs/core";
|
|
2
|
+
import type { Signal } from "@praxisjs/shared";
|
|
3
|
+
|
|
4
|
+
const signalMap = new WeakMap<object, Map<string, Signal<unknown>>>();
|
|
5
|
+
const initMap = new WeakMap<object, Set<string>>();
|
|
6
|
+
|
|
7
|
+
function isInitialized(instance: object, propKey: string): boolean {
|
|
8
|
+
return initMap.get(instance)?.has(propKey) ?? false;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function markInitialized(instance: object, propKey: string): void {
|
|
12
|
+
if (!initMap.has(instance)) {
|
|
13
|
+
initMap.set(instance, new Set());
|
|
14
|
+
}
|
|
15
|
+
(initMap.get(instance) as Set<string>).add(propKey);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function getOrCreateSignal<T>(
|
|
19
|
+
instance: object,
|
|
20
|
+
storageKey: string,
|
|
21
|
+
initialValue: T,
|
|
22
|
+
options: PersistedSignalOptions<T>,
|
|
23
|
+
): Signal<T> {
|
|
24
|
+
if (!signalMap.has(instance)) {
|
|
25
|
+
signalMap.set(instance, new Map());
|
|
26
|
+
}
|
|
27
|
+
const map = signalMap.get(instance) as Map<string, Signal<unknown>>;
|
|
28
|
+
|
|
29
|
+
if (!map.has(storageKey)) {
|
|
30
|
+
map.set(
|
|
31
|
+
storageKey,
|
|
32
|
+
persistedSignal(storageKey, initialValue, options) as Signal<unknown>,
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return map.get(storageKey) as Signal<T>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function Persisted<T>(
|
|
40
|
+
key?: string,
|
|
41
|
+
options: PersistedSignalOptions<T> = {},
|
|
42
|
+
) {
|
|
43
|
+
return function (target: object, propertyKey: string): void {
|
|
44
|
+
const storageKey = key ?? propertyKey;
|
|
45
|
+
|
|
46
|
+
Object.defineProperty(target, propertyKey, {
|
|
47
|
+
get(this: object): T {
|
|
48
|
+
if (!isInitialized(this, propertyKey)) {
|
|
49
|
+
return undefined as T;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return getOrCreateSignal<T>(
|
|
53
|
+
this,
|
|
54
|
+
storageKey,
|
|
55
|
+
undefined as T,
|
|
56
|
+
options,
|
|
57
|
+
)();
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
set(this: object, value: T): void {
|
|
61
|
+
if (!isInitialized(this, propertyKey)) {
|
|
62
|
+
markInitialized(this, propertyKey);
|
|
63
|
+
getOrCreateSignal(this, storageKey, value, options);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
getOrCreateSignal<T>(this, storageKey, undefined as T, options).set(
|
|
67
|
+
value,
|
|
68
|
+
);
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
enumerable: true,
|
|
72
|
+
configurable: true,
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { BaseComponent } from "@praxisjs/core";
|
|
2
|
+
|
|
3
|
+
export function Prop() {
|
|
4
|
+
return function (target: object, propertyKey: string) {
|
|
5
|
+
Object.defineProperty(target, propertyKey, {
|
|
6
|
+
get(this: BaseComponent) {
|
|
7
|
+
const fromParent = this._rawProps[propertyKey];
|
|
8
|
+
if (fromParent !== undefined) return fromParent;
|
|
9
|
+
return this._defaults[propertyKey];
|
|
10
|
+
},
|
|
11
|
+
set(this: BaseComponent, value: unknown) {
|
|
12
|
+
this._defaults[propertyKey] = value;
|
|
13
|
+
},
|
|
14
|
+
enumerable: true,
|
|
15
|
+
configurable: true,
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { BaseComponent } from "@praxisjs/core";
|
|
2
|
+
import {
|
|
3
|
+
type Children,
|
|
4
|
+
type ChildrenInternal,
|
|
5
|
+
flattenChildren,
|
|
6
|
+
type VNode,
|
|
7
|
+
} from "@praxisjs/shared";
|
|
8
|
+
|
|
9
|
+
const slotsMap = new WeakMap<object, Map<string, ChildrenInternal[]>>();
|
|
10
|
+
|
|
11
|
+
export interface SlottedVNode extends VNode {
|
|
12
|
+
slot?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function resolveSlots(
|
|
16
|
+
children: ChildrenInternal | ChildrenInternal[] | undefined,
|
|
17
|
+
): Map<string, ChildrenInternal[]> {
|
|
18
|
+
const slots = new Map<string, ChildrenInternal[]>();
|
|
19
|
+
const defaultSlot: ChildrenInternal[] = [];
|
|
20
|
+
slots.set("default", defaultSlot);
|
|
21
|
+
|
|
22
|
+
if (!children) return slots;
|
|
23
|
+
|
|
24
|
+
const arr: ChildrenInternal[] = flattenChildren(children);
|
|
25
|
+
|
|
26
|
+
for (const child of arr as SlottedVNode[]) {
|
|
27
|
+
const slotName = (child.props.slot as string | undefined) ?? child.slot;
|
|
28
|
+
|
|
29
|
+
if (slotName) {
|
|
30
|
+
if (!slots.has(slotName)) slots.set(slotName, []);
|
|
31
|
+
(slots.get(slotName) as ChildrenInternal[]).push(
|
|
32
|
+
child as ChildrenInternal,
|
|
33
|
+
);
|
|
34
|
+
} else {
|
|
35
|
+
defaultSlot.push(child as ChildrenInternal);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return slots;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function initSlots(
|
|
43
|
+
instance: object,
|
|
44
|
+
children: Children | undefined,
|
|
45
|
+
): void {
|
|
46
|
+
slotsMap.set(instance, resolveSlots(children));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function getSlot(instance: object, name: string): ChildrenInternal[] {
|
|
50
|
+
return slotsMap.get(instance)?.get(name) ?? [];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function Slot(name?: string) {
|
|
54
|
+
return function (target: object, propertyKey: string): void {
|
|
55
|
+
const slotName =
|
|
56
|
+
name ?? (propertyKey === "default" ? "default" : propertyKey);
|
|
57
|
+
|
|
58
|
+
Object.defineProperty(target, propertyKey, {
|
|
59
|
+
get(this: BaseComponent): ChildrenInternal[] {
|
|
60
|
+
return getSlot(this, slotName);
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
set(_value: unknown): void {
|
|
64
|
+
if (process.env.NODE_ENV !== "production") {
|
|
65
|
+
console.warn(
|
|
66
|
+
`[Slot] "${propertyKey}" is a slot and cannot be assigned directly. Slots are filled by the parent component.`,
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
enumerable: true,
|
|
72
|
+
configurable: true,
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { signal } from "@praxisjs/core";
|
|
2
|
+
import type { ComponentInstance, Signal } from "@praxisjs/shared";
|
|
3
|
+
|
|
4
|
+
export function State() {
|
|
5
|
+
return function (target: object, propertyKey: string) {
|
|
6
|
+
const signalMap = new WeakMap<object, Signal<unknown>>();
|
|
7
|
+
|
|
8
|
+
Object.defineProperty(target, propertyKey, {
|
|
9
|
+
get(this: object) {
|
|
10
|
+
if (!signalMap.has(this)) signalMap.set(this, signal(undefined));
|
|
11
|
+
return (signalMap.get(this) as Signal<unknown>)();
|
|
12
|
+
},
|
|
13
|
+
set(this: object, value: unknown) {
|
|
14
|
+
if (!signalMap.has(this)) signalMap.set(this, signal(value));
|
|
15
|
+
else {
|
|
16
|
+
(this as ComponentInstance)._stateDirty = true;
|
|
17
|
+
(signalMap.get(this) as Signal<unknown>).set(value);
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
enumerable: true,
|
|
21
|
+
configurable: true,
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
}
|