rask-ui 0.28.2 → 0.28.4
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/dist/component.d.ts +1 -0
- package/dist/component.d.ts.map +1 -1
- package/dist/component.js +7 -2
- package/dist/tests/batch.test.js +202 -12
- package/dist/tests/createContext.test.js +50 -37
- package/dist/tests/error.test.js +25 -12
- package/dist/tests/renderCount.test.d.ts +2 -0
- package/dist/tests/renderCount.test.d.ts.map +1 -0
- package/dist/tests/renderCount.test.js +95 -0
- package/dist/tests/scopeEnforcement.test.d.ts +2 -0
- package/dist/tests/scopeEnforcement.test.d.ts.map +1 -0
- package/dist/tests/scopeEnforcement.test.js +157 -0
- package/dist/tests/useAction.test.d.ts +2 -0
- package/dist/tests/useAction.test.d.ts.map +1 -0
- package/dist/tests/useAction.test.js +132 -0
- package/dist/tests/useAsync.test.d.ts +2 -0
- package/dist/tests/useAsync.test.d.ts.map +1 -0
- package/dist/tests/useAsync.test.js +499 -0
- package/dist/tests/useDerived.test.d.ts +2 -0
- package/dist/tests/useDerived.test.d.ts.map +1 -0
- package/dist/tests/useDerived.test.js +407 -0
- package/dist/tests/useEffect.test.d.ts +2 -0
- package/dist/tests/useEffect.test.d.ts.map +1 -0
- package/dist/tests/useEffect.test.js +600 -0
- package/dist/tests/useLookup.test.d.ts +2 -0
- package/dist/tests/useLookup.test.d.ts.map +1 -0
- package/dist/tests/useLookup.test.js +299 -0
- package/dist/tests/useRef.test.d.ts +2 -0
- package/dist/tests/useRef.test.d.ts.map +1 -0
- package/dist/tests/useRef.test.js +189 -0
- package/dist/tests/useState.test.d.ts +2 -0
- package/dist/tests/useState.test.d.ts.map +1 -0
- package/dist/tests/useState.test.js +178 -0
- package/dist/tests/useSuspend.test.d.ts +2 -0
- package/dist/tests/useSuspend.test.d.ts.map +1 -0
- package/dist/tests/useSuspend.test.js +752 -0
- package/dist/tests/useView.test.d.ts +2 -0
- package/dist/tests/useView.test.d.ts.map +1 -0
- package/dist/tests/useView.test.js +305 -0
- package/dist/transformer.d.ts.map +1 -1
- package/dist/transformer.js +1 -5
- package/dist/useState.js +4 -2
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useView.test.d.ts","sourceRoot":"","sources":["../../src/tests/useView.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import { jsx as _jsx } from "rask-ui/jsx-runtime";
|
|
2
|
+
import { describe, it, expect } from "vitest";
|
|
3
|
+
import { useView } from "../useView";
|
|
4
|
+
import { useState } from "../useState";
|
|
5
|
+
import { Observer } from "../observation";
|
|
6
|
+
import { render } from "../";
|
|
7
|
+
describe("createView", () => {
|
|
8
|
+
it("should merge two plain objects", () => {
|
|
9
|
+
let view;
|
|
10
|
+
function Component() {
|
|
11
|
+
const a = { x: 1, y: 2 };
|
|
12
|
+
const b = { z: 3 };
|
|
13
|
+
view = useView(a, b);
|
|
14
|
+
return () => _jsx("div", { children: "test" });
|
|
15
|
+
}
|
|
16
|
+
const container = document.createElement("div");
|
|
17
|
+
render(_jsx(Component, {}), container);
|
|
18
|
+
expect(view.x).toBe(1);
|
|
19
|
+
expect(view.y).toBe(2);
|
|
20
|
+
expect(view.z).toBe(3);
|
|
21
|
+
});
|
|
22
|
+
it("should allow later arguments to override earlier ones", () => {
|
|
23
|
+
let view;
|
|
24
|
+
function Component() {
|
|
25
|
+
const a = { x: 1, y: 2 };
|
|
26
|
+
const b = { y: 3, z: 4 };
|
|
27
|
+
view = useView(a, b);
|
|
28
|
+
return () => _jsx("div", { children: "test" });
|
|
29
|
+
}
|
|
30
|
+
const container = document.createElement("div");
|
|
31
|
+
render(_jsx(Component, {}), container);
|
|
32
|
+
expect(view.x).toBe(1);
|
|
33
|
+
expect(view.y).toBe(3); // b.y overrides a.y
|
|
34
|
+
expect(view.z).toBe(4);
|
|
35
|
+
});
|
|
36
|
+
it("should maintain reactivity with reactive objects", async () => {
|
|
37
|
+
let view;
|
|
38
|
+
let state;
|
|
39
|
+
function Component() {
|
|
40
|
+
state = useState({ count: 0 });
|
|
41
|
+
view = useView(state);
|
|
42
|
+
return () => _jsx("div", { children: "test" });
|
|
43
|
+
}
|
|
44
|
+
const container = document.createElement("div");
|
|
45
|
+
render(_jsx(Component, {}), container);
|
|
46
|
+
let renderCount = 0;
|
|
47
|
+
let lastValue = 0;
|
|
48
|
+
const observer = new Observer(() => {
|
|
49
|
+
renderCount++;
|
|
50
|
+
});
|
|
51
|
+
const dispose = observer.observe();
|
|
52
|
+
lastValue = view.count; // Track the property
|
|
53
|
+
dispose();
|
|
54
|
+
expect(renderCount).toBe(0);
|
|
55
|
+
state.count = 5;
|
|
56
|
+
// Wait for microtask to process notification
|
|
57
|
+
await new Promise((resolve) => {
|
|
58
|
+
queueMicrotask(() => {
|
|
59
|
+
expect(renderCount).toBe(1);
|
|
60
|
+
lastValue = view.count;
|
|
61
|
+
expect(lastValue).toBe(5);
|
|
62
|
+
resolve(undefined);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
it("should merge reactive and plain objects while maintaining reactivity", () => {
|
|
67
|
+
let view;
|
|
68
|
+
let state;
|
|
69
|
+
function Component() {
|
|
70
|
+
state = useState({ count: 0 });
|
|
71
|
+
const helpers = {
|
|
72
|
+
increment() {
|
|
73
|
+
state.count++;
|
|
74
|
+
},
|
|
75
|
+
decrement() {
|
|
76
|
+
state.count--;
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
view = useView(state, helpers);
|
|
80
|
+
return () => _jsx("div", { children: "test" });
|
|
81
|
+
}
|
|
82
|
+
const container = document.createElement("div");
|
|
83
|
+
render(_jsx(Component, {}), container);
|
|
84
|
+
expect(view.count).toBe(0);
|
|
85
|
+
expect(typeof view.increment).toBe("function");
|
|
86
|
+
expect(typeof view.decrement).toBe("function");
|
|
87
|
+
view.increment();
|
|
88
|
+
expect(view.count).toBe(1);
|
|
89
|
+
view.decrement();
|
|
90
|
+
expect(view.count).toBe(0);
|
|
91
|
+
});
|
|
92
|
+
it("should merge multiple reactive objects", () => {
|
|
93
|
+
let view;
|
|
94
|
+
let state1;
|
|
95
|
+
let state2;
|
|
96
|
+
let state3;
|
|
97
|
+
function Component() {
|
|
98
|
+
state1 = useState({ count: 0 });
|
|
99
|
+
state2 = useState({ name: "Alice" });
|
|
100
|
+
state3 = useState({ age: 25 });
|
|
101
|
+
view = useView(state1, state2, state3);
|
|
102
|
+
return () => _jsx("div", { children: "test" });
|
|
103
|
+
}
|
|
104
|
+
const container = document.createElement("div");
|
|
105
|
+
render(_jsx(Component, {}), container);
|
|
106
|
+
expect(view.count).toBe(0);
|
|
107
|
+
expect(view.name).toBe("Alice");
|
|
108
|
+
expect(view.age).toBe(25);
|
|
109
|
+
state1.count = 10;
|
|
110
|
+
state2.name = "Bob";
|
|
111
|
+
state3.age = 30;
|
|
112
|
+
expect(view.count).toBe(10);
|
|
113
|
+
expect(view.name).toBe("Bob");
|
|
114
|
+
expect(view.age).toBe(30);
|
|
115
|
+
});
|
|
116
|
+
it("should reflect changes in source objects", () => {
|
|
117
|
+
let view;
|
|
118
|
+
let source;
|
|
119
|
+
function Component() {
|
|
120
|
+
source = { x: 1 };
|
|
121
|
+
view = useView(source);
|
|
122
|
+
return () => _jsx("div", { children: "test" });
|
|
123
|
+
}
|
|
124
|
+
const container = document.createElement("div");
|
|
125
|
+
render(_jsx(Component, {}), container);
|
|
126
|
+
expect(view.x).toBe(1);
|
|
127
|
+
source.x = 2;
|
|
128
|
+
expect(view.x).toBe(2);
|
|
129
|
+
});
|
|
130
|
+
it("should handle property override order correctly", () => {
|
|
131
|
+
let view;
|
|
132
|
+
function Component() {
|
|
133
|
+
const a = { x: 1, y: 2, z: 3 };
|
|
134
|
+
const b = { y: 20 };
|
|
135
|
+
const c = { z: 30 };
|
|
136
|
+
view = useView(a, b, c);
|
|
137
|
+
return () => _jsx("div", { children: "test" });
|
|
138
|
+
}
|
|
139
|
+
const container = document.createElement("div");
|
|
140
|
+
render(_jsx(Component, {}), container);
|
|
141
|
+
expect(view.x).toBe(1); // From a
|
|
142
|
+
expect(view.y).toBe(20); // From b (overrides a)
|
|
143
|
+
expect(view.z).toBe(30); // From c (overrides a)
|
|
144
|
+
});
|
|
145
|
+
it("should only include enumerable properties", () => {
|
|
146
|
+
let view;
|
|
147
|
+
function Component() {
|
|
148
|
+
const obj = { x: 1 };
|
|
149
|
+
Object.defineProperty(obj, "hidden", {
|
|
150
|
+
value: 42,
|
|
151
|
+
enumerable: false,
|
|
152
|
+
});
|
|
153
|
+
view = useView(obj);
|
|
154
|
+
return () => _jsx("div", { children: "test" });
|
|
155
|
+
}
|
|
156
|
+
const container = document.createElement("div");
|
|
157
|
+
render(_jsx(Component, {}), container);
|
|
158
|
+
expect(view.x).toBe(1);
|
|
159
|
+
expect(view.hidden).toBeUndefined();
|
|
160
|
+
});
|
|
161
|
+
it("should handle symbol keys", () => {
|
|
162
|
+
let view;
|
|
163
|
+
let sym;
|
|
164
|
+
function Component() {
|
|
165
|
+
sym = Symbol("test");
|
|
166
|
+
const obj = { x: 1, [sym]: "symbol value" };
|
|
167
|
+
view = useView(obj);
|
|
168
|
+
return () => _jsx("div", { children: "test" });
|
|
169
|
+
}
|
|
170
|
+
const container = document.createElement("div");
|
|
171
|
+
render(_jsx(Component, {}), container);
|
|
172
|
+
expect(view.x).toBe(1);
|
|
173
|
+
expect(view[sym]).toBe("symbol value");
|
|
174
|
+
});
|
|
175
|
+
it("should track dependencies for each property independently", async () => {
|
|
176
|
+
let view;
|
|
177
|
+
let state;
|
|
178
|
+
function Component() {
|
|
179
|
+
state = useState({ count: 0, name: "Alice" });
|
|
180
|
+
view = useView(state);
|
|
181
|
+
return () => _jsx("div", { children: "test" });
|
|
182
|
+
}
|
|
183
|
+
const container = document.createElement("div");
|
|
184
|
+
render(_jsx(Component, {}), container);
|
|
185
|
+
let countRenderCount = 0;
|
|
186
|
+
let nameRenderCount = 0;
|
|
187
|
+
// Observer that only accesses count
|
|
188
|
+
const countObserver = new Observer(() => {
|
|
189
|
+
countRenderCount++;
|
|
190
|
+
});
|
|
191
|
+
const dispose1 = countObserver.observe();
|
|
192
|
+
view.count; // Track count
|
|
193
|
+
dispose1();
|
|
194
|
+
expect(countRenderCount).toBe(0);
|
|
195
|
+
// Change count - should trigger
|
|
196
|
+
state.count = 1;
|
|
197
|
+
await new Promise((resolve) => {
|
|
198
|
+
queueMicrotask(() => {
|
|
199
|
+
expect(countRenderCount).toBe(1);
|
|
200
|
+
resolve(undefined);
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
// Change name - should NOT trigger (not tracked)
|
|
204
|
+
state.name = "Bob";
|
|
205
|
+
await new Promise((resolve) => {
|
|
206
|
+
queueMicrotask(() => {
|
|
207
|
+
expect(countRenderCount).toBe(1); // Still 1
|
|
208
|
+
resolve(undefined);
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
// Now track name with a different observer
|
|
212
|
+
const nameObserver = new Observer(() => {
|
|
213
|
+
nameRenderCount++;
|
|
214
|
+
});
|
|
215
|
+
const dispose2 = nameObserver.observe();
|
|
216
|
+
view.name; // Track name
|
|
217
|
+
dispose2();
|
|
218
|
+
expect(nameRenderCount).toBe(0);
|
|
219
|
+
// Change name - should trigger name observer
|
|
220
|
+
state.name = "Charlie";
|
|
221
|
+
await new Promise((resolve) => {
|
|
222
|
+
queueMicrotask(() => {
|
|
223
|
+
expect(nameRenderCount).toBe(1);
|
|
224
|
+
resolve(undefined);
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
it("should return the same value type as source", () => {
|
|
229
|
+
let view;
|
|
230
|
+
function Component() {
|
|
231
|
+
const obj = { nums: [1, 2, 3], nested: { x: 1 } };
|
|
232
|
+
view = useView(obj);
|
|
233
|
+
return () => _jsx("div", { children: "test" });
|
|
234
|
+
}
|
|
235
|
+
const container = document.createElement("div");
|
|
236
|
+
render(_jsx(Component, {}), container);
|
|
237
|
+
expect(Array.isArray(view.nums)).toBe(true);
|
|
238
|
+
expect(view.nums).toEqual([1, 2, 3]);
|
|
239
|
+
expect(typeof view.nested).toBe("object");
|
|
240
|
+
expect(view.nested.x).toBe(1);
|
|
241
|
+
});
|
|
242
|
+
it("should handle empty merge", () => {
|
|
243
|
+
let view;
|
|
244
|
+
function Component() {
|
|
245
|
+
view = useView({});
|
|
246
|
+
return () => _jsx("div", { children: "test" });
|
|
247
|
+
}
|
|
248
|
+
const container = document.createElement("div");
|
|
249
|
+
render(_jsx(Component, {}), container);
|
|
250
|
+
expect(Object.keys(view).length).toBe(0);
|
|
251
|
+
});
|
|
252
|
+
it("should merge single object", () => {
|
|
253
|
+
let view;
|
|
254
|
+
function Component() {
|
|
255
|
+
const obj = { x: 1, y: 2 };
|
|
256
|
+
view = useView(obj);
|
|
257
|
+
return () => _jsx("div", { children: "test" });
|
|
258
|
+
}
|
|
259
|
+
const container = document.createElement("div");
|
|
260
|
+
render(_jsx(Component, {}), container);
|
|
261
|
+
expect(view.x).toBe(1);
|
|
262
|
+
expect(view.y).toBe(2);
|
|
263
|
+
});
|
|
264
|
+
it("should maintain function context", () => {
|
|
265
|
+
let view;
|
|
266
|
+
let state;
|
|
267
|
+
function Component() {
|
|
268
|
+
state = useState({ count: 0 });
|
|
269
|
+
const methods = {
|
|
270
|
+
increment() {
|
|
271
|
+
state.count++;
|
|
272
|
+
},
|
|
273
|
+
};
|
|
274
|
+
view = useView(state, methods);
|
|
275
|
+
return () => _jsx("div", { children: "test" });
|
|
276
|
+
}
|
|
277
|
+
const container = document.createElement("div");
|
|
278
|
+
render(_jsx(Component, {}), container);
|
|
279
|
+
expect(view.count).toBe(0);
|
|
280
|
+
view.increment();
|
|
281
|
+
expect(view.count).toBe(1);
|
|
282
|
+
expect(state.count).toBe(1);
|
|
283
|
+
});
|
|
284
|
+
it("should work with reactive state and computed-like patterns", () => {
|
|
285
|
+
let view;
|
|
286
|
+
let state;
|
|
287
|
+
function Component() {
|
|
288
|
+
state = useState({ firstName: "John", lastName: "Doe" });
|
|
289
|
+
const computed = {
|
|
290
|
+
get fullName() {
|
|
291
|
+
return `${state.firstName} ${state.lastName}`;
|
|
292
|
+
},
|
|
293
|
+
};
|
|
294
|
+
view = useView(state, computed);
|
|
295
|
+
return () => _jsx("div", { children: "test" });
|
|
296
|
+
}
|
|
297
|
+
const container = document.createElement("div");
|
|
298
|
+
render(_jsx(Component, {}), container);
|
|
299
|
+
expect(view.firstName).toBe("John");
|
|
300
|
+
expect(view.lastName).toBe("Doe");
|
|
301
|
+
expect(view.fullName).toBe("John Doe");
|
|
302
|
+
state.firstName = "Jane";
|
|
303
|
+
expect(view.fullName).toBe("Jane Doe");
|
|
304
|
+
});
|
|
305
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transformer.d.ts","sourceRoot":"","sources":["../src/transformer.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,cAAc,EACd,eAAe,EACf,cAAc,EACd,SAAS,GACV,MAAM,SAAS,CAAC;AAEjB,OAAO,EAEL,KAAK,EACN,MAAM,SAAS,CAAC;AAIjB,wBAAgB,oBAAoB,CAClC,CAAC,EAAE,GAAG,EACN,SAAS,EAAE,GAAG,EACd,KAAK,EAAE,GAAG,YAAK,EACf,GAAG,EAAE,GAAG,EACR,GAAG,EAAE,GAAG,GACP,KAAK,
|
|
1
|
+
{"version":3,"file":"transformer.d.ts","sourceRoot":"","sources":["../src/transformer.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,cAAc,EACd,eAAe,EACf,cAAc,EACd,SAAS,GACV,MAAM,SAAS,CAAC;AAEjB,OAAO,EAEL,KAAK,EACN,MAAM,SAAS,CAAC;AAIjB,wBAAgB,oBAAoB,CAClC,CAAC,EAAE,GAAG,EACN,SAAS,EAAE,GAAG,EACd,KAAK,EAAE,GAAG,YAAK,EACf,GAAG,EAAE,GAAG,EACR,GAAG,EAAE,GAAG,GACP,KAAK,CASP"}
|
package/dist/transformer.js
CHANGED
|
@@ -3,9 +3,5 @@ import { createComponentVNode as infernoCreateComponentVnode, } from "inferno";
|
|
|
3
3
|
import { RaskComponent } from "./component";
|
|
4
4
|
export function createComponentVNode(_, component, props = {}, key, ref) {
|
|
5
5
|
props.__component = component;
|
|
6
|
-
return infernoCreateComponentVnode(4 /* VNodeFlags.ComponentClass */, RaskComponent, props,
|
|
7
|
-
// Since RaskComponent is generic for all components we need to differentiate changing out the component, which
|
|
8
|
-
// we do simply by using the name as a key. There is not chance two different components has the same name,
|
|
9
|
-
// but is not the same component in the same component tree position
|
|
10
|
-
key || component.name, ref);
|
|
6
|
+
return infernoCreateComponentVnode(4 /* VNodeFlags.ComponentClass */, RaskComponent, props, key, ref);
|
|
11
7
|
}
|
package/dist/useState.js
CHANGED
|
@@ -73,8 +73,10 @@ function getProxy(value, notifyInspectorRef) {
|
|
|
73
73
|
const signal = (signals[key] = signals[key] || new Signal());
|
|
74
74
|
observer.subscribeSignal(signal);
|
|
75
75
|
}
|
|
76
|
-
if (
|
|
77
|
-
|
|
76
|
+
if (value instanceof Date || value === null) {
|
|
77
|
+
return value;
|
|
78
|
+
}
|
|
79
|
+
if (Array.isArray(value) || typeof value === "object") {
|
|
78
80
|
return getProxy(value, INSPECTOR_ENABLED && notifyInspectorRef.current
|
|
79
81
|
? {
|
|
80
82
|
current: {
|