@praxisjs/core 2.1.0 → 2.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 (126) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/component/internals.d.ts +12 -2
  3. package/dist/component/internals.d.ts.map +1 -1
  4. package/dist/component/internals.js +25 -7
  5. package/dist/component/internals.js.map +1 -1
  6. package/dist/internal.d.ts +3 -2
  7. package/dist/internal.d.ts.map +1 -1
  8. package/dist/internal.js +3 -2
  9. package/dist/internal.js.map +1 -1
  10. package/dist/reactive/history.d.ts +2 -0
  11. package/dist/reactive/history.d.ts.map +1 -1
  12. package/dist/reactive/history.js +2 -1
  13. package/dist/reactive/history.js.map +1 -1
  14. package/dist/signal/batch.d.ts +1 -3
  15. package/dist/signal/batch.d.ts.map +1 -1
  16. package/dist/signal/batch.js +4 -16
  17. package/dist/signal/batch.js.map +1 -1
  18. package/dist/signal/computed.d.ts.map +1 -1
  19. package/dist/signal/computed.js +19 -61
  20. package/dist/signal/computed.js.map +1 -1
  21. package/dist/signal/effect.d.ts +6 -12
  22. package/dist/signal/effect.d.ts.map +1 -1
  23. package/dist/signal/effect.js +11 -74
  24. package/dist/signal/effect.js.map +1 -1
  25. package/dist/signal/graph.d.ts +111 -0
  26. package/dist/signal/graph.d.ts.map +1 -0
  27. package/dist/signal/graph.js +513 -0
  28. package/dist/signal/graph.js.map +1 -0
  29. package/dist/signal/index.d.ts +2 -1
  30. package/dist/signal/index.d.ts.map +1 -1
  31. package/dist/signal/index.js +1 -0
  32. package/dist/signal/index.js.map +1 -1
  33. package/dist/signal/peek.d.ts.map +1 -1
  34. package/dist/signal/peek.js +2 -9
  35. package/dist/signal/peek.js.map +1 -1
  36. package/dist/signal/persisted.d.ts +11 -1
  37. package/dist/signal/persisted.d.ts.map +1 -1
  38. package/dist/signal/persisted.js +39 -5
  39. package/dist/signal/persisted.js.map +1 -1
  40. package/dist/signal/selector.d.ts +5 -0
  41. package/dist/signal/selector.d.ts.map +1 -0
  42. package/dist/signal/selector.js +128 -0
  43. package/dist/signal/selector.js.map +1 -0
  44. package/dist/signal/signal.d.ts +0 -5
  45. package/dist/signal/signal.d.ts.map +1 -1
  46. package/dist/signal/signal.js +11 -81
  47. package/dist/signal/signal.js.map +1 -1
  48. package/package.json +13 -4
  49. package/src/component/internals.ts +35 -10
  50. package/src/internal.ts +27 -0
  51. package/src/reactive/history.ts +4 -1
  52. package/src/signal/batch.ts +5 -19
  53. package/src/signal/computed.ts +20 -63
  54. package/src/signal/effect.ts +12 -83
  55. package/src/signal/graph.ts +562 -0
  56. package/src/signal/index.ts +2 -1
  57. package/src/signal/peek.ts +2 -8
  58. package/src/signal/persisted.ts +54 -5
  59. package/src/signal/selector.ts +140 -0
  60. package/src/signal/signal.ts +11 -79
  61. package/dist/__tests__/batch.test.d.ts +0 -2
  62. package/dist/__tests__/batch.test.d.ts.map +0 -1
  63. package/dist/__tests__/batch.test.js +0 -73
  64. package/dist/__tests__/batch.test.js.map +0 -1
  65. package/dist/__tests__/component.test.d.ts +0 -2
  66. package/dist/__tests__/component.test.d.ts.map +0 -1
  67. package/dist/__tests__/component.test.js +0 -124
  68. package/dist/__tests__/component.test.js.map +0 -1
  69. package/dist/__tests__/computed.test.d.ts +0 -2
  70. package/dist/__tests__/computed.test.d.ts.map +0 -1
  71. package/dist/__tests__/computed.test.js +0 -252
  72. package/dist/__tests__/computed.test.js.map +0 -1
  73. package/dist/__tests__/effect.test.d.ts +0 -2
  74. package/dist/__tests__/effect.test.d.ts.map +0 -1
  75. package/dist/__tests__/effect.test.js +0 -189
  76. package/dist/__tests__/effect.test.js.map +0 -1
  77. package/dist/__tests__/peek.test.d.ts +0 -2
  78. package/dist/__tests__/peek.test.d.ts.map +0 -1
  79. package/dist/__tests__/peek.test.js +0 -26
  80. package/dist/__tests__/peek.test.js.map +0 -1
  81. package/dist/__tests__/persisted-signal.test.d.ts +0 -2
  82. package/dist/__tests__/persisted-signal.test.d.ts.map +0 -1
  83. package/dist/__tests__/persisted-signal.test.js +0 -156
  84. package/dist/__tests__/persisted-signal.test.js.map +0 -1
  85. package/dist/__tests__/reactive.test.d.ts +0 -2
  86. package/dist/__tests__/reactive.test.d.ts.map +0 -1
  87. package/dist/__tests__/reactive.test.js +0 -264
  88. package/dist/__tests__/reactive.test.js.map +0 -1
  89. package/dist/__tests__/resource-focus.test.d.ts +0 -2
  90. package/dist/__tests__/resource-focus.test.d.ts.map +0 -1
  91. package/dist/__tests__/resource-focus.test.js +0 -50
  92. package/dist/__tests__/resource-focus.test.js.map +0 -1
  93. package/dist/__tests__/resource-server-pass.test.d.ts +0 -2
  94. package/dist/__tests__/resource-server-pass.test.d.ts.map +0 -1
  95. package/dist/__tests__/resource-server-pass.test.js +0 -78
  96. package/dist/__tests__/resource-server-pass.test.js.map +0 -1
  97. package/dist/__tests__/resource.test.d.ts +0 -2
  98. package/dist/__tests__/resource.test.d.ts.map +0 -1
  99. package/dist/__tests__/resource.test.js +0 -336
  100. package/dist/__tests__/resource.test.js.map +0 -1
  101. package/dist/__tests__/signal.test.d.ts +0 -2
  102. package/dist/__tests__/signal.test.d.ts.map +0 -1
  103. package/dist/__tests__/signal.test.js +0 -186
  104. package/dist/__tests__/signal.test.js.map +0 -1
  105. package/dist/__tests__/synced.test.d.ts +0 -2
  106. package/dist/__tests__/synced.test.d.ts.map +0 -1
  107. package/dist/__tests__/synced.test.js +0 -142
  108. package/dist/__tests__/synced.test.js.map +0 -1
  109. package/dist/__tests__/track.test.d.ts +0 -2
  110. package/dist/__tests__/track.test.d.ts.map +0 -1
  111. package/dist/__tests__/track.test.js +0 -54
  112. package/dist/__tests__/track.test.js.map +0 -1
  113. package/src/__tests__/batch.test.ts +0 -87
  114. package/src/__tests__/component.test.ts +0 -165
  115. package/src/__tests__/computed.test.ts +0 -290
  116. package/src/__tests__/effect.test.ts +0 -226
  117. package/src/__tests__/peek.test.ts +0 -31
  118. package/src/__tests__/persisted-signal.test.ts +0 -194
  119. package/src/__tests__/reactive.test.ts +0 -305
  120. package/src/__tests__/resource-focus.test.ts +0 -61
  121. package/src/__tests__/resource-server-pass.test.ts +0 -90
  122. package/src/__tests__/resource.test.ts +0 -421
  123. package/src/__tests__/signal.test.ts +0 -213
  124. package/src/__tests__/synced.test.ts +0 -173
  125. package/src/__tests__/track.test.ts +0 -61
  126. package/tsconfig.json +0 -8
@@ -1,173 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from "vitest";
2
-
3
- import { syncedSignal } from "../signal/synced";
4
- import { effect } from "../signal/effect";
5
-
6
- // BroadcastChannel mock
7
- class MockBroadcastChannel {
8
- static instances: MockBroadcastChannel[] = [];
9
- static byChannel: Map<string, MockBroadcastChannel[]> = new Map();
10
-
11
- onmessage: ((event: MessageEvent) => void) | null = null;
12
- readonly name: string;
13
- closed = false;
14
-
15
- constructor(name: string) {
16
- this.name = name;
17
- MockBroadcastChannel.instances.push(this);
18
- if (!MockBroadcastChannel.byChannel.has(name)) {
19
- MockBroadcastChannel.byChannel.set(name, []);
20
- }
21
- MockBroadcastChannel.byChannel.get(name)!.push(this);
22
- }
23
-
24
- postMessage(data: unknown) {
25
- // Deliver to all OTHER instances on same channel
26
- MockBroadcastChannel.byChannel.get(this.name)?.forEach((ch) => {
27
- if (ch !== this && ch.onmessage) {
28
- ch.onmessage(new MessageEvent("message", { data }));
29
- }
30
- });
31
- }
32
-
33
- close() {
34
- this.closed = true;
35
- const list = MockBroadcastChannel.byChannel.get(this.name);
36
- if (list) {
37
- const idx = list.indexOf(this);
38
- if (idx !== -1) list.splice(idx, 1);
39
- }
40
- MockBroadcastChannel.instances.splice(
41
- MockBroadcastChannel.instances.indexOf(this),
42
- 1,
43
- );
44
- }
45
- }
46
-
47
- beforeEach(() => {
48
- MockBroadcastChannel.instances = [];
49
- MockBroadcastChannel.byChannel = new Map();
50
- vi.stubGlobal("BroadcastChannel", MockBroadcastChannel);
51
- });
52
-
53
- describe("syncedSignal", () => {
54
- it("reads initial value", () => {
55
- const s = syncedSignal("ch", 42);
56
- expect(s()).toBe(42);
57
- s.close();
58
- });
59
-
60
- it("set() updates the signal value", () => {
61
- const s = syncedSignal("ch", 0);
62
- s.set(10);
63
- expect(s()).toBe(10);
64
- s.close();
65
- });
66
-
67
- it("update() applies a transform", () => {
68
- const s = syncedSignal("ch", 5);
69
- s.update((v) => v * 2);
70
- expect(s()).toBe(10);
71
- s.close();
72
- });
73
-
74
- it("set() posts a JSON message to the channel", () => {
75
- const s = syncedSignal("ch", 0);
76
- const postSpy = vi.spyOn(
77
- MockBroadcastChannel.instances[0],
78
- "postMessage",
79
- );
80
- s.set(99);
81
- expect(postSpy).toHaveBeenCalledWith(JSON.stringify(99));
82
- s.close();
83
- });
84
-
85
- it("receiving a message from another tab updates the signal", () => {
86
- const s = syncedSignal("ch", 0);
87
- const channel = MockBroadcastChannel.instances[0];
88
-
89
- channel.onmessage!(new MessageEvent("message", { data: JSON.stringify(7) }));
90
- expect(s()).toBe(7);
91
- s.close();
92
- });
93
-
94
- it("does not echo own set() back to itself", () => {
95
- const s = syncedSignal("ch", 0);
96
-
97
- // Simulate two instances on the same channel
98
- const s2 = syncedSignal("ch", 0);
99
- const received: number[] = [];
100
- effect(() => { received.push(s2()); });
101
-
102
- s.set(5);
103
- // s2 should receive the message because it came from a different instance
104
- expect(s2()).toBe(5);
105
-
106
- // s itself should NOT trigger its own onmessage handler (no echo)
107
- const channel = MockBroadcastChannel.instances[0];
108
- const receivedBySelf: number[] = [];
109
- effect(() => { receivedBySelf.push(s()); });
110
- const beforeCount = receivedBySelf.length;
111
- // Manually simulate echo — should be ignored because posting=false after set
112
- channel.onmessage!(new MessageEvent("message", { data: JSON.stringify(5) }));
113
- // The value stays 5 (no spurious extra notification tested via subscribe count)
114
- expect(s()).toBe(5);
115
- expect(receivedBySelf.length).toBe(beforeCount); // no extra effect run (Object.is equality)
116
-
117
- s.close();
118
- s2.close();
119
- });
120
-
121
- it("subscribe fires immediately then on each remote change", () => {
122
- const s = syncedSignal("ch", 0);
123
- const channel = MockBroadcastChannel.instances[0];
124
- const received: number[] = [];
125
- s.subscribe((v) => received.push(v));
126
-
127
- expect(received).toEqual([0]);
128
-
129
- channel.onmessage!(new MessageEvent("message", { data: JSON.stringify(3) }));
130
- expect(received).toEqual([0, 3]);
131
- s.close();
132
- });
133
-
134
- it("close() shuts down the BroadcastChannel", () => {
135
- const s = syncedSignal("ch", 0);
136
- const channel = MockBroadcastChannel.instances[0];
137
- expect(channel.closed).toBe(false);
138
- s.close();
139
- expect(channel.closed).toBe(true);
140
- });
141
-
142
- it("has __isSignal marker", () => {
143
- const s = syncedSignal("ch", 0);
144
- expect(s.__isSignal).toBe(true);
145
- s.close();
146
- });
147
-
148
- it("does not update value when onmessage fires while posting (posting guard)", () => {
149
- // Use a self-delivering channel that echoes to itself during postMessage.
150
- // This covers the `if (posting) return;` branch in synced.ts.
151
- class SelfEchoChannel {
152
- onmessage: ((e: MessageEvent) => void) | null = null;
153
- postMessage(data: unknown) {
154
- this.onmessage?.(new MessageEvent("message", { data }));
155
- }
156
- close() {}
157
- }
158
- vi.stubGlobal("BroadcastChannel", SelfEchoChannel);
159
-
160
- const s = syncedSignal("echo-ch", 0);
161
- const received: number[] = [];
162
- s.subscribe((v) => received.push(v));
163
-
164
- // set() triggers postMessage → onmessage fires → posting=true → early return
165
- // Inner value should not be double-set
166
- s.set(42);
167
- expect(s()).toBe(42);
168
- // Only two notifications: initial (0) + the set (42), no echo re-set
169
- expect(received).toEqual([0, 42]);
170
-
171
- s.close();
172
- });
173
- });
@@ -1,61 +0,0 @@
1
- import { describe, it, expect, vi } from "vitest";
2
-
3
- import { track, runEffect, activeEffect } from "../signal/effect";
4
- import { signal } from "../signal/signal";
5
-
6
- describe("track", () => {
7
- it("runs the effect immediately", () => {
8
- const fn = vi.fn();
9
- track(fn);
10
- expect(fn).toHaveBeenCalledOnce();
11
- });
12
-
13
- it("sets activeEffect during execution, resets after", () => {
14
- let during: unknown = "not-set";
15
- track(() => {
16
- during = activeEffect;
17
- });
18
- expect(during).toBeTypeOf("function");
19
- expect(activeEffect).toBeNull();
20
- });
21
-
22
- it("supports nested track calls — restores outer effect", () => {
23
- const outer = vi.fn();
24
- const inner = vi.fn();
25
- let outerActive: unknown;
26
- let innerActive: unknown;
27
-
28
- track(() => {
29
- outer();
30
- outerActive = activeEffect;
31
- track(() => {
32
- inner();
33
- innerActive = activeEffect;
34
- });
35
- // after inner track, activeEffect should be back to outer
36
- expect(activeEffect).toBe(outerActive);
37
- });
38
-
39
- expect(outer).toHaveBeenCalledOnce();
40
- expect(inner).toHaveBeenCalledOnce();
41
- expect(innerActive).not.toBe(outerActive);
42
- });
43
-
44
- it("subscribes the tracked effect to signals read inside it", () => {
45
- const s = signal(1);
46
- const values: number[] = [];
47
- track(() => values.push(s()));
48
- s.set(2);
49
- expect(values).toEqual([1, 2]);
50
- });
51
- });
52
-
53
- describe("runEffect", () => {
54
- it("sets activeEffect to the given value", () => {
55
- const fn = () => {};
56
- runEffect(fn);
57
- expect(activeEffect).toBe(fn);
58
- runEffect(null);
59
- expect(activeEffect).toBeNull();
60
- });
61
- });
package/tsconfig.json DELETED
@@ -1,8 +0,0 @@
1
- {
2
- "extends": "../../../tsconfig.base.json",
3
- "compilerOptions": {
4
- "outDir": "./dist",
5
- "rootDir": "./src"
6
- },
7
- "include": ["src"]
8
- }