@praxisjs/decorators 0.2.0 → 0.3.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.
Files changed (121) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/component/component.d.ts +2 -2
  3. package/dist/component/component.d.ts.map +1 -1
  4. package/dist/component/component.js +5 -2
  5. package/dist/component/component.js.map +1 -1
  6. package/dist/component/index.d.ts +0 -1
  7. package/dist/component/index.d.ts.map +1 -1
  8. package/dist/component/index.js +0 -1
  9. package/dist/component/index.js.map +1 -1
  10. package/dist/component/lazy.d.ts +2 -2
  11. package/dist/component/lazy.d.ts.map +1 -1
  12. package/dist/component/lazy.js +8 -8
  13. package/dist/component/lazy.js.map +1 -1
  14. package/dist/component/virtual.d.ts +2 -2
  15. package/dist/component/virtual.d.ts.map +1 -1
  16. package/dist/component/virtual.js +45 -14
  17. package/dist/component/virtual.js.map +1 -1
  18. package/dist/events/emit.d.ts +2 -1
  19. package/dist/events/emit.d.ts.map +1 -1
  20. package/dist/events/emit.js +11 -16
  21. package/dist/events/emit.js.map +1 -1
  22. package/dist/events/helper.d.ts +2 -2
  23. package/dist/events/helper.d.ts.map +1 -1
  24. package/dist/events/helper.js.map +1 -1
  25. package/dist/events/on-command.d.ts +2 -1
  26. package/dist/events/on-command.d.ts.map +1 -1
  27. package/dist/events/on-command.js +30 -27
  28. package/dist/events/on-command.js.map +1 -1
  29. package/dist/functions/bind.d.ts +2 -1
  30. package/dist/functions/bind.d.ts.map +1 -1
  31. package/dist/functions/bind.js +10 -15
  32. package/dist/functions/bind.js.map +1 -1
  33. package/dist/functions/debounce.d.ts +2 -1
  34. package/dist/functions/debounce.d.ts.map +1 -1
  35. package/dist/functions/debounce.js +20 -24
  36. package/dist/functions/debounce.js.map +1 -1
  37. package/dist/functions/log.d.ts +2 -1
  38. package/dist/functions/log.d.ts.map +1 -1
  39. package/dist/functions/log.js +5 -6
  40. package/dist/functions/log.js.map +1 -1
  41. package/dist/functions/memo.d.ts +2 -1
  42. package/dist/functions/memo.d.ts.map +1 -1
  43. package/dist/functions/memo.js +5 -6
  44. package/dist/functions/memo.js.map +1 -1
  45. package/dist/functions/once.d.ts +2 -1
  46. package/dist/functions/once.d.ts.map +1 -1
  47. package/dist/functions/once.js +3 -5
  48. package/dist/functions/once.js.map +1 -1
  49. package/dist/functions/retry.d.ts +2 -1
  50. package/dist/functions/retry.d.ts.map +1 -1
  51. package/dist/functions/retry.js +3 -5
  52. package/dist/functions/retry.js.map +1 -1
  53. package/dist/functions/throttle.d.ts +2 -1
  54. package/dist/functions/throttle.d.ts.map +1 -1
  55. package/dist/functions/throttle.js +18 -22
  56. package/dist/functions/throttle.js.map +1 -1
  57. package/dist/functions/watch.d.ts +7 -7
  58. package/dist/functions/watch.d.ts.map +1 -1
  59. package/dist/functions/watch.js +31 -35
  60. package/dist/functions/watch.js.map +1 -1
  61. package/dist/functions/when.d.ts +2 -1
  62. package/dist/functions/when.d.ts.map +1 -1
  63. package/dist/functions/when.js +24 -24
  64. package/dist/functions/when.js.map +1 -1
  65. package/dist/index.d.ts +2 -2
  66. package/dist/index.d.ts.map +1 -1
  67. package/dist/index.js +2 -2
  68. package/dist/index.js.map +1 -1
  69. package/dist/properties/history.d.ts +3 -2
  70. package/dist/properties/history.d.ts.map +1 -1
  71. package/dist/properties/history.js +35 -27
  72. package/dist/properties/history.js.map +1 -1
  73. package/dist/properties/persisted.d.ts +3 -2
  74. package/dist/properties/persisted.d.ts.map +1 -1
  75. package/dist/properties/persisted.js +20 -23
  76. package/dist/properties/persisted.js.map +1 -1
  77. package/dist/properties/prop.d.ts +2 -1
  78. package/dist/properties/prop.d.ts.map +1 -1
  79. package/dist/properties/prop.js +24 -13
  80. package/dist/properties/prop.js.map +1 -1
  81. package/dist/properties/slot.d.ts +4 -8
  82. package/dist/properties/slot.d.ts.map +1 -1
  83. package/dist/properties/slot.js +34 -24
  84. package/dist/properties/slot.js.map +1 -1
  85. package/dist/properties/state.d.ts +2 -1
  86. package/dist/properties/state.d.ts.map +1 -1
  87. package/dist/properties/state.js +19 -19
  88. package/dist/properties/state.js.map +1 -1
  89. package/package.json +3 -4
  90. package/src/component/component.ts +9 -2
  91. package/src/component/index.ts +0 -1
  92. package/src/component/lazy.ts +10 -8
  93. package/src/component/virtual.tsx +71 -28
  94. package/src/events/emit.ts +15 -22
  95. package/src/events/helper.ts +5 -2
  96. package/src/events/on-command.ts +43 -44
  97. package/src/functions/bind.ts +14 -18
  98. package/src/functions/debounce.ts +23 -26
  99. package/src/functions/log.ts +11 -11
  100. package/src/functions/memo.ts +8 -9
  101. package/src/functions/once.ts +7 -10
  102. package/src/functions/retry.ts +7 -12
  103. package/src/functions/throttle.ts +21 -24
  104. package/src/functions/watch.ts +44 -48
  105. package/src/functions/when.ts +30 -32
  106. package/src/index.ts +10 -2
  107. package/src/properties/history.ts +49 -32
  108. package/src/properties/persisted.ts +40 -31
  109. package/src/properties/prop.ts +30 -13
  110. package/src/properties/slot.ts +46 -50
  111. package/src/properties/state.ts +24 -18
  112. package/dist/component/lifecycle.d.ts +0 -3
  113. package/dist/component/lifecycle.d.ts.map +0 -1
  114. package/dist/component/lifecycle.js +0 -35
  115. package/dist/component/lifecycle.js.map +0 -1
  116. package/dist/component/memoize.d.ts +0 -5
  117. package/dist/component/memoize.d.ts.map +0 -1
  118. package/dist/component/memoize.js +0 -23
  119. package/dist/component/memoize.js.map +0 -1
  120. package/src/component/lifecycle.ts +0 -47
  121. package/src/component/memoize.ts +0 -31
@@ -1,6 +1,9 @@
1
- import type { BaseComponent } from "@praxisjs/core";
1
+ import type { StatefulComponent } from "@praxisjs/core";
2
2
 
3
- export function readProp(instance: BaseComponent, propName: string): unknown {
3
+ export function readProp(
4
+ instance: StatefulComponent,
5
+ propName: string,
6
+ ): unknown {
4
7
  const fromParent = instance._rawProps[propName];
5
8
  if (fromParent !== undefined) return fromParent;
6
9
  return instance._defaults[propName];
@@ -1,4 +1,4 @@
1
- import type { BaseComponent } from "@praxisjs/core";
1
+ import type { StatefulComponent } from "@praxisjs/core";
2
2
 
3
3
  import { readProp } from "./helper";
4
4
 
@@ -6,50 +6,49 @@ import type { Command } from "./command";
6
6
 
7
7
  export function OnCommand(propName: string) {
8
8
  return function (
9
- target: object,
10
- _methodKey: string,
11
- descriptor: PropertyDescriptor,
12
- ): PropertyDescriptor {
13
- // eslint-disable-next-line @typescript-eslint/unbound-method
14
- const originalOnMount = (target as { onMount?(): void }).onMount;
15
- // eslint-disable-next-line @typescript-eslint/unbound-method
16
- const originalOnUnmount = (target as { onUnmount?(): void }).onUnmount;
17
-
18
- const method = descriptor.value as (...args: unknown[]) => void;
9
+ value: (this: StatefulComponent, ...args: unknown[]) => void,
10
+ context: ClassMethodDecoratorContext<StatefulComponent>,
11
+ ): void {
19
12
  const cleanups = new WeakMap<object, () => void>();
20
13
 
21
- (target as { onMount?(): void }).onMount = function (this: BaseComponent) {
22
- originalOnMount?.call(this);
23
-
24
- const command = readProp(this, propName) as Command<unknown> | undefined;
25
-
26
- if (!command) {
27
- console.warn(
28
- `[OnCommand] prop "${propName}" was not provided to ${this.constructor.name}`,
29
- );
30
- return;
31
- }
32
-
33
- if (typeof command.subscribe !== "function") {
34
- console.warn(
35
- `[OnCommand] prop "${propName}" is not a valid Command in ${this.constructor.name}`,
36
- );
37
- return;
38
- }
39
-
40
- const bound = method.bind(this);
41
- const unsub = command.subscribe((...args: unknown[]) => { bound(...args); });
42
- cleanups.set(this, unsub);
43
- };
44
-
45
- (target as { onUnmount?(): void }).onUnmount = function (
46
- this: BaseComponent,
47
- ) {
48
- originalOnUnmount?.call(this);
49
- cleanups.get(this)?.();
50
- cleanups.delete(this);
51
- };
52
-
53
- return descriptor;
14
+ context.addInitializer(function (this: unknown) {
15
+ const instance = this as StatefulComponent;
16
+ // eslint-disable-next-line @typescript-eslint/unbound-method
17
+ const originalOnMount = instance.onMount;
18
+ // eslint-disable-next-line @typescript-eslint/unbound-method
19
+ const originalOnUnmount = instance.onUnmount;
20
+
21
+ instance.onMount = function (this: StatefulComponent) {
22
+ originalOnMount?.call(this);
23
+
24
+ const command = readProp(this, propName) as Command<unknown> | undefined;
25
+
26
+ if (!command) {
27
+ console.warn(
28
+ `[OnCommand] prop "${propName}" was not provided to ${this.constructor.name}`,
29
+ );
30
+ return;
31
+ }
32
+
33
+ if (typeof command.subscribe !== "function") {
34
+ console.warn(
35
+ `[OnCommand] prop "${propName}" is not a valid Command in ${this.constructor.name}`,
36
+ );
37
+ return;
38
+ }
39
+
40
+ const bound = value.bind(this);
41
+ const unsub = command.subscribe((...args: unknown[]) => {
42
+ bound(...args);
43
+ });
44
+ cleanups.set(this, unsub);
45
+ };
46
+
47
+ instance.onUnmount = function (this: StatefulComponent) {
48
+ originalOnUnmount?.call(this);
49
+ cleanups.get(this)?.();
50
+ cleanups.delete(this);
51
+ };
52
+ });
54
53
  };
55
54
  }
@@ -1,22 +1,18 @@
1
+ import type { StatefulComponent } from "@praxisjs/core";
2
+
1
3
  export function Bind() {
2
4
  return function (
3
- _target: object,
4
- methodKey: string,
5
- descriptor: PropertyDescriptor,
6
- ): PropertyDescriptor {
7
- const originalMethod = descriptor.value as (...args: unknown[]) => unknown;
8
- return {
9
- enumerable: false,
10
- configurable: true,
11
- get(this: object) {
12
- const bound = originalMethod.bind(this);
13
- Object.defineProperty(this, methodKey, {
14
- value: bound,
15
- configurable: true,
16
- writable: true,
17
- });
18
- return bound;
19
- },
20
- };
5
+ value: (this: object, ...args: unknown[]) => unknown,
6
+ context: ClassMethodDecoratorContext<StatefulComponent>,
7
+ ): void {
8
+ context.addInitializer(function (this: unknown) {
9
+ const name = context.name as string;
10
+ const bound = value.bind(this as object);
11
+ Object.defineProperty(this as object, name, {
12
+ value: bound,
13
+ configurable: true,
14
+ writable: true,
15
+ });
16
+ });
21
17
  };
22
18
  }
@@ -1,34 +1,31 @@
1
+ import type { StatefulComponent } from "@praxisjs/core";
2
+
1
3
  export function Debounce(ms: number) {
2
4
  const timers = new WeakMap<object, ReturnType<typeof setTimeout>>();
3
5
 
4
6
  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 existing = timers.get(this);
16
- if (existing !== undefined) clearTimeout(existing);
7
+ value: (this: object, ...args: unknown[]) => unknown,
8
+ context: ClassMethodDecoratorContext<StatefulComponent>,
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[]) => {
14
+ const existing = timers.get(instance);
15
+ if (existing !== undefined) clearTimeout(existing);
17
16
 
18
- const timer = setTimeout(() => {
19
- timers.delete(this);
20
- originalMethod.apply(this, args);
21
- }, ms);
17
+ const timer = setTimeout(() => {
18
+ timers.delete(instance);
19
+ value.apply(instance, args);
20
+ }, ms);
22
21
 
23
- timers.set(this, timer);
24
- };
25
- Object.defineProperty(this, methodKey, {
26
- value: bound,
27
- configurable: true,
28
- writable: true,
29
- });
30
- return bound;
31
- },
32
- };
22
+ timers.set(instance, timer);
23
+ };
24
+ Object.defineProperty(instance, name, {
25
+ value: bound,
26
+ configurable: true,
27
+ writable: true,
28
+ });
29
+ });
33
30
  };
34
31
  }
@@ -1,3 +1,5 @@
1
+ import type { StatefulComponent } from "@praxisjs/core";
2
+
1
3
  export interface LogOptions {
2
4
  level?: "log" | "warn" | "error" | "debug";
3
5
  args?: boolean;
@@ -16,29 +18,29 @@ export function Log(options: LogOptions = {}) {
16
18
  } = options;
17
19
 
18
20
  return function (
19
- _target: object,
20
- methodKey: string,
21
- descriptor: PropertyDescriptor,
22
- ): PropertyDescriptor {
23
- const originalMethod = descriptor.value as (...args: unknown[]) => unknown;
21
+ value: (this: object, ...args: unknown[]) => unknown,
22
+ context: ClassMethodDecoratorContext<StatefulComponent>,
23
+ ): (this: object, ...args: unknown[]) => unknown {
24
+ const methodKey = context.name as string;
24
25
 
25
- descriptor.value = function (this: object, ...args: unknown[]) {
26
+ return function (this: object, ...args: unknown[]) {
26
27
  if (
27
28
  devOnly &&
28
29
  typeof process !== "undefined" &&
29
30
  process.env.NODE_ENV === "production"
30
31
  ) {
31
- return originalMethod.apply(this, args);
32
+ return value.apply(this, args);
32
33
  }
33
34
 
34
- const className = (this.constructor as { name?: string }).name ?? "Unknown";
35
+ const className =
36
+ (this.constructor as { name?: string }).name ?? "Unknown";
35
37
  const label = `[${className}.${methodKey}]`;
36
38
  const logger = console[level].bind(console);
37
39
 
38
40
  if (logArgs) logger(`${label} args:`, args);
39
41
 
40
42
  const start = time ? performance.now() : 0;
41
- const output = originalMethod.apply(this, args);
43
+ const output = value.apply(this, args);
42
44
 
43
45
  if (output instanceof Promise) {
44
46
  return (output as Promise<unknown>)
@@ -62,7 +64,5 @@ export function Log(options: LogOptions = {}) {
62
64
 
63
65
  return output;
64
66
  };
65
-
66
- return descriptor;
67
67
  };
68
68
  }
@@ -1,4 +1,5 @@
1
- import { computed } from "@praxisjs/core";
1
+ import type { StatefulComponent } from "@praxisjs/core";
2
+ import { computed } from "@praxisjs/core/internal";
2
3
  import type { Computed } from "@praxisjs/shared";
3
4
 
4
5
  const instanceCache = new WeakMap<
@@ -46,18 +47,16 @@ function serializeArgs(args: unknown[]) {
46
47
 
47
48
  export function Memo() {
48
49
  return function (
49
- _target: object,
50
- methodName: string,
51
- descriptor: PropertyDescriptor,
52
- ): PropertyDescriptor {
53
- const originalMethod = descriptor.value as (...args: unknown[]) => unknown;
54
- descriptor.value = function (this: object, ...args: unknown[]) {
50
+ value: (this: object, ...args: unknown[]) => unknown,
51
+ context: ClassMethodDecoratorContext<StatefulComponent>,
52
+ ): (this: object, ...args: unknown[]) => unknown {
53
+ const methodName = context.name as string;
54
+ return function (this: object, ...args: unknown[]) {
55
55
  const argKey = serializeArgs(args);
56
56
  const memoized = getCache(this, methodName, argKey, () =>
57
- originalMethod.apply(this, args),
57
+ value.apply(this, args),
58
58
  );
59
59
  return memoized();
60
60
  };
61
- return descriptor;
62
61
  };
63
62
  }
@@ -1,22 +1,19 @@
1
+ import type { StatefulComponent } from "@praxisjs/core";
2
+
1
3
  export function Once() {
2
4
  const called = new WeakMap<object, boolean>();
3
5
  const results = new WeakMap<object, unknown>();
4
6
 
5
7
  return function (
6
- _target: object,
7
- _methodKey: string,
8
- descriptor: PropertyDescriptor,
9
- ): PropertyDescriptor {
10
- const originalMethod = descriptor.value as (...args: unknown[]) => unknown;
11
-
12
- descriptor.value = function (this: object, ...args: unknown[]) {
8
+ value: (this: object, ...args: unknown[]) => unknown,
9
+ _context: ClassMethodDecoratorContext<StatefulComponent>,
10
+ ): (this: object, ...args: unknown[]) => unknown {
11
+ return function (this: object, ...args: unknown[]) {
13
12
  if (called.get(this)) return results.get(this);
14
- const result = originalMethod.apply(this, args);
13
+ const result = value.apply(this, args);
15
14
  called.set(this, true);
16
15
  results.set(this, result);
17
16
  return result;
18
17
  };
19
-
20
- return descriptor;
21
18
  };
22
19
  }
@@ -1,3 +1,5 @@
1
+ import type { StatefulComponent } from "@praxisjs/core";
2
+
1
3
  export interface RetryOptions {
2
4
  delay?: number;
3
5
  backoff?: number;
@@ -8,21 +10,16 @@ export function Retry(maxAttempts: number, options: RetryOptions = {}) {
8
10
  const { delay = 0, backoff = 1, onRetry } = options;
9
11
 
10
12
  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[]) {
13
+ value: (this: object, ...args: unknown[]) => Promise<unknown>,
14
+ _context: ClassMethodDecoratorContext<StatefulComponent>,
15
+ ): (this: object, ...args: unknown[]) => Promise<unknown> {
16
+ return async function (this: object, ...args: unknown[]) {
20
17
  let lastError: Error = new Error("Unknown error");
21
18
  let currentDelay = delay;
22
19
 
23
20
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
24
21
  try {
25
- return await originalMethod.apply(this, args);
22
+ return await value.apply(this, args);
26
23
  } catch (e: unknown) {
27
24
  lastError = e instanceof Error ? e : new Error(String(e));
28
25
  if (attempt === maxAttempts) break;
@@ -37,7 +34,5 @@ export function Retry(maxAttempts: number, options: RetryOptions = {}) {
37
34
 
38
35
  throw lastError;
39
36
  };
40
-
41
- return descriptor;
42
37
  };
43
38
  }
@@ -1,32 +1,29 @@
1
+ import type { StatefulComponent } from "@praxisjs/core";
2
+
1
3
  export function Throttle(ms: number) {
2
4
  const lastRun = new WeakMap<object, number>();
3
5
 
4
6
  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;
7
+ value: (this: object, ...args: unknown[]) => unknown,
8
+ context: ClassMethodDecoratorContext<StatefulComponent>,
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[]) => {
14
+ const now = Date.now();
15
+ const last = lastRun.get(instance) ?? 0;
17
16
 
18
- if (now - last < ms) return;
17
+ if (now - last < ms) return;
19
18
 
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
- };
19
+ lastRun.set(instance, now);
20
+ return value.apply(instance, args);
21
+ };
22
+ Object.defineProperty(instance, name, {
23
+ value: bound,
24
+ configurable: true,
25
+ writable: true,
26
+ });
27
+ });
31
28
  };
32
29
  }
@@ -1,7 +1,9 @@
1
- import { type BaseComponent, effect } from "@praxisjs/core";
2
- import { type Computed, isComputed } from "@praxisjs/shared";
1
+ import type { StatefulComponent } from "@praxisjs/core";
2
+ import { effect } from "@praxisjs/core/internal";
3
+ import type { Computed } from "@praxisjs/shared";
4
+ import { isComputed } from "@praxisjs/shared/internal";
3
5
 
4
- type BaseComponentKeys = keyof BaseComponent;
6
+ type BaseComponentKeys = keyof StatefulComponent;
5
7
 
6
8
  type WatchableKeys<T> = {
7
9
  [K in Exclude<keyof T, BaseComponentKeys>]: T[K] extends (
@@ -29,15 +31,17 @@ type NoDuplicates<
29
31
  : Keys;
30
32
 
31
33
  type ValidateKeys<
32
- T extends BaseComponent,
34
+ T extends StatefulComponent,
33
35
  Keys extends ReadonlyArray<WatchableKeys<T>>,
34
36
  > = NoDuplicates<[...Keys]> extends Keys ? Keys : NoDuplicates<[...Keys]>;
35
37
 
36
38
  type Unwrap<T> =
37
39
  T extends Computed<infer U> ? U : T extends () => infer U ? U : T;
38
40
 
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
+ export type WatchVal<T extends StatefulComponent, K extends keyof T> = Unwrap<
42
+ T[K]
43
+ >;
44
+ export type WatchVals<T extends StatefulComponent, K extends keyof T> = {
41
45
  [P in K]: Unwrap<T[P]>;
42
46
  };
43
47
 
@@ -46,54 +50,46 @@ function readValue(instance: Record<string, unknown>, key: string): unknown {
46
50
  return isComputed(raw) ? (raw as Computed<unknown>)() : raw;
47
51
  }
48
52
 
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
53
  export function Watch<
62
- T extends BaseComponent,
54
+ T extends StatefulComponent,
63
55
  const Keys extends ReadonlyArray<WatchableKeys<T>>,
64
56
  >(...propNames: ValidateKeys<T, Keys>) {
65
57
  return function (
66
- target: T,
67
- _key: string,
68
- descriptor: PropertyDescriptor,
69
- ): PropertyDescriptor {
58
+ value: (this: T, ...args: unknown[]) => void,
59
+ context: ClassMethodDecoratorContext<T>,
60
+ ): void {
70
61
  const props = propNames as unknown as string[];
71
- const method = descriptor.value as (this: Record<string, unknown>, ...args: unknown[]) => void;
72
62
 
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
- });
63
+ context.addInitializer(function (this: unknown) {
64
+ const instance = this as T & Record<string, unknown>;
65
+ // eslint-disable-next-line @typescript-eslint/unbound-method
66
+ const originalOnMount = instance.onMount;
67
+
68
+ instance.onMount = function (this: T & Record<string, unknown>) {
69
+ originalOnMount?.call(this);
96
70
 
97
- return descriptor;
71
+ if (props.length === 1) {
72
+ let oldVal = readValue(this, props[0]);
73
+ effect(() => {
74
+ const newVal = readValue(this, props[0]);
75
+ if (!Object.is(newVal, oldVal)) {
76
+ value.call(this as T, newVal, oldVal);
77
+ oldVal = newVal;
78
+ }
79
+ });
80
+ } else {
81
+ const read = () =>
82
+ Object.fromEntries(props.map((p) => [p, readValue(this, p)]));
83
+ let oldVals = read();
84
+ effect(() => {
85
+ const newVals = read();
86
+ if (props.some((p) => !Object.is(newVals[p], oldVals[p]))) {
87
+ value.call(this as T, newVals, oldVals);
88
+ oldVals = newVals;
89
+ }
90
+ });
91
+ }
92
+ };
93
+ });
98
94
  };
99
95
  }
@@ -1,44 +1,42 @@
1
- import { type BaseComponent, when } from "@praxisjs/core";
2
- import { isComputed } from "@praxisjs/shared";
1
+ import type { StatefulComponent } from "@praxisjs/core";
2
+ import { when } from "@praxisjs/core/internal";
3
+ import type { Computed, Signal } from "@praxisjs/shared";
4
+ import { isComputed } from "@praxisjs/shared/internal";
3
5
 
4
6
  export function When(propName: string) {
5
7
  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;
8
+ value: (this: StatefulComponent, val: unknown) => void,
9
+ context: ClassMethodDecoratorContext<StatefulComponent>,
10
+ ): void {
16
11
  const cancels = new WeakMap<object, () => void>();
17
12
 
18
- (target as { onMount?(): void }).onMount = function (this: BaseComponent) {
19
- originalOnMount?.call(this);
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;
20
19
 
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
- };
20
+ instance.onMount = function (this: StatefulComponent) {
21
+ originalOnMount?.call(this);
26
22
 
27
- const cancel = when(source, (value) => {
28
- method.call(this, value);
29
- });
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>);
30
27
 
31
- cancels.set(this, cancel);
32
- };
28
+ const cancel = when(source, (val) => {
29
+ value.call(this, val);
30
+ });
33
31
 
34
- (target as { onUnmount?(): void }).onUnmount = function (
35
- this: BaseComponent,
36
- ) {
37
- originalOnUnmount?.call(this);
38
- cancels.get(this)?.();
39
- cancels.delete(this);
40
- };
32
+ cancels.set(this, cancel);
33
+ };
41
34
 
42
- return descriptor;
35
+ instance.onUnmount = function (this: StatefulComponent) {
36
+ originalOnUnmount?.call(this);
37
+ cancels.get(this)?.();
38
+ cancels.delete(this);
39
+ };
40
+ });
43
41
  };
44
42
  }
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { Component, Memoize, Lazy, Virtual } from "./component";
1
+ export { Component, Lazy, Virtual } from "./component";
2
2
  export {
3
3
  Memo,
4
4
  Bind,
@@ -12,5 +12,13 @@ export {
12
12
  type WatchVal,
13
13
  type WatchVals,
14
14
  } from "./functions";
15
- export { Prop, State, Persisted, Slot, initSlots, History, type WithHistory } from "./properties";
15
+ export {
16
+ Prop,
17
+ State,
18
+ Persisted,
19
+ Slot,
20
+ initSlots,
21
+ History,
22
+ type WithHistory,
23
+ } from "./properties";
16
24
  export { type Command, createCommand, Emit, OnCommand } from "./events";