@praxisjs/devtools 0.2.34 → 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 (65) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/assets/uno.generated.css +5 -0
  3. package/dist/assets/logo.svg.js +4 -0
  4. package/dist/assets/tailwind-v4.css.js +4 -0
  5. package/dist/assets/uno.generated.css.js +4 -0
  6. package/dist/core/event-bus.js +21 -0
  7. package/dist/core/profiler.js +79 -0
  8. package/dist/core/registry.js +147 -0
  9. package/dist/decorators/debug.js +126 -0
  10. package/dist/decorators/trace.js +45 -0
  11. package/dist/icons/ellipsis-vertical.js +38 -0
  12. package/dist/icons/panel-bottom.js +28 -0
  13. package/dist/icons/panel-left.js +28 -0
  14. package/dist/icons/panel-right.js +28 -0
  15. package/dist/icons/panel-top.js +28 -0
  16. package/dist/icons/x.js +22 -0
  17. package/dist/index.d.ts +96 -3
  18. package/dist/index.js +10 -1157
  19. package/dist/plugins/components/components/component-detail.js +53 -0
  20. package/dist/plugins/components/components/component-row.js +22 -0
  21. package/dist/plugins/components/components/detail-row.js +15 -0
  22. package/dist/plugins/components/components/detail-section.js +14 -0
  23. package/dist/plugins/components/components/status-dot.js +15 -0
  24. package/dist/plugins/components/components-tab.js +54 -0
  25. package/dist/plugins/components/index.js +9 -0
  26. package/dist/plugins/performance/index.js +9 -0
  27. package/dist/plugins/performance/performance-tab.js +62 -0
  28. package/dist/plugins/signals/components/signal-detail.js +29 -0
  29. package/dist/plugins/signals/components/signal-row.js +17 -0
  30. package/dist/plugins/signals/index.js +9 -0
  31. package/dist/plugins/signals/signals-tab.js +53 -0
  32. package/dist/plugins/timeline/components/badge.js +16 -0
  33. package/dist/plugins/timeline/components/timeline-row.js +33 -0
  34. package/dist/plugins/timeline/constants.js +54 -0
  35. package/dist/plugins/timeline/index.js +9 -0
  36. package/dist/plugins/timeline/timeline-tab.js +46 -0
  37. package/dist/ui/dev-tools.js +74 -0
  38. package/dist/ui/panel.js +106 -0
  39. package/dist/ui/shared/empty-state.js +14 -0
  40. package/dist/ui/shared/icon-button.js +17 -0
  41. package/dist/ui/shared/panel-section.js +14 -0
  42. package/dist/ui/shared/search-input.js +17 -0
  43. package/dist/ui/shared/side-panel.js +15 -0
  44. package/dist/utils/format-time.js +7 -0
  45. package/dist/utils/format-value.js +14 -0
  46. package/package.json +14 -6
  47. package/src/core/profiler.ts +162 -0
  48. package/src/core/registry.ts +23 -21
  49. package/src/decorators/debug.ts +96 -32
  50. package/src/decorators/index.ts +1 -0
  51. package/src/decorators/trace.ts +27 -4
  52. package/src/index.ts +5 -0
  53. package/src/plugins/performance/index.ts +9 -0
  54. package/src/plugins/performance/performance-tab.tsx +111 -0
  55. package/src/ui/dev-tools.tsx +5 -0
  56. package/src/__tests__/debug.test.ts +0 -333
  57. package/src/__tests__/event-bus.test.ts +0 -123
  58. package/src/__tests__/format-time.test.ts +0 -52
  59. package/src/__tests__/format-value.test.ts +0 -46
  60. package/src/__tests__/plugins.test.ts +0 -101
  61. package/src/__tests__/registry.test.ts +0 -386
  62. package/src/__tests__/trace.test.ts +0 -200
  63. package/tsconfig.json +0 -21
  64. package/uno.config.ts +0 -57
  65. package/vite.config.ts +0 -38
@@ -1,386 +0,0 @@
1
- import { beforeEach, describe, it, expect, vi } from "vitest";
2
-
3
- import { Registry } from "../core/registry";
4
-
5
- // Reset singleton before each test to keep tests isolated
6
- beforeEach(() => {
7
- (Registry as unknown as { _instance: Registry | null })._instance = null;
8
- });
9
-
10
- describe("Registry singleton", () => {
11
- it("returns the same instance on subsequent accesses", () => {
12
- const a = Registry.instance;
13
- const b = Registry.instance;
14
- expect(a).toBe(b);
15
- });
16
-
17
- it("creates a fresh instance after reset", () => {
18
- const first = Registry.instance;
19
- (Registry as unknown as { _instance: Registry | null })._instance = null;
20
- const second = Registry.instance;
21
- expect(first).not.toBe(second);
22
- });
23
- });
24
-
25
- describe("Registry.registerSignal", () => {
26
- it("stores the signal and emits 'signal:registered'", () => {
27
- const registry = Registry.instance;
28
- const handler = vi.fn();
29
- registry.bus.on("signal:registered", handler);
30
-
31
- const instance = {};
32
- registry.registerSignal(instance, "count", 0, "Counter");
33
-
34
- const signals = registry.getSignals();
35
- expect(signals).toHaveLength(1);
36
- expect(signals[0].label).toBe("count");
37
- expect(signals[0].value).toBe(0);
38
- expect(signals[0].componentName).toBe("Counter");
39
- expect(handler).toHaveBeenCalledOnce();
40
- });
41
-
42
- it("builds the signal id as componentId:key", () => {
43
- const registry = Registry.instance;
44
- const instance = {};
45
- registry.registerSignal(instance, "name", "Alice", "MyComp");
46
- const signal = registry.getSignals()[0];
47
- expect(signal.id).toMatch(/:.+/);
48
- expect(signal.id.endsWith(":name")).toBe(true);
49
- });
50
-
51
- it("initialises history with the initial value", () => {
52
- const registry = Registry.instance;
53
- registry.registerSignal({}, "x", 42, "Comp");
54
- const signal = registry.getSignals()[0];
55
- expect(signal.history).toHaveLength(1);
56
- expect(signal.history[0].value).toBe(42);
57
- });
58
- });
59
-
60
- describe("Registry.updateSignal", () => {
61
- it("updates the value and appends to history", () => {
62
- const registry = Registry.instance;
63
- const instance = {};
64
- registry.registerSignal(instance, "count", 0, "Counter");
65
- registry.updateSignal(instance, "count", 1, 0);
66
-
67
- const signal = registry.getSignals()[0];
68
- expect(signal.value).toBe(1);
69
- expect(signal.history).toHaveLength(2);
70
- expect(signal.history[1].value).toBe(1);
71
- });
72
-
73
- it("emits 'signal:changed' with old and new value", () => {
74
- const registry = Registry.instance;
75
- const handler = vi.fn();
76
- registry.bus.on("signal:changed", handler);
77
-
78
- const instance = {};
79
- registry.registerSignal(instance, "val", "old", "Comp");
80
- registry.updateSignal(instance, "val", "new", "old");
81
-
82
- expect(handler).toHaveBeenCalledOnce();
83
- const payload = handler.mock.calls[0][0] as { entry: { value: unknown }; oldValue: unknown };
84
- expect(payload.entry.value).toBe("new");
85
- expect(payload.oldValue).toBe("old");
86
- });
87
-
88
- it("caps history at 20 entries", () => {
89
- const registry = Registry.instance;
90
- const instance = {};
91
- registry.registerSignal(instance, "n", 0, "Comp");
92
- for (let i = 1; i <= 25; i++) {
93
- registry.updateSignal(instance, "n", i, i - 1);
94
- }
95
- const signal = registry.getSignals()[0];
96
- expect(signal.history.length).toBe(20);
97
- });
98
-
99
- it("does nothing when the signal does not exist", () => {
100
- const registry = Registry.instance;
101
- const handler = vi.fn();
102
- registry.bus.on("signal:changed", handler);
103
- registry.updateSignal({}, "missing", 1, 0);
104
- expect(handler).not.toHaveBeenCalled();
105
- });
106
-
107
- it("pushes a 'signal:change' timeline entry", () => {
108
- const registry = Registry.instance;
109
- const instance = {};
110
- registry.registerSignal(instance, "x", 0, "Comp");
111
- registry.updateSignal(instance, "x", 5, 0);
112
- const timeline = registry.getTimeline();
113
- const entry = timeline.find((t) => t.type === "signal:change");
114
- expect(entry).toBeDefined();
115
- expect(entry?.data.new).toBe(5);
116
- expect(entry?.data.old).toBe(0);
117
- });
118
- });
119
-
120
- describe("Registry.registerComponent", () => {
121
- it("stores the component and emits 'component:registered'", () => {
122
- const registry = Registry.instance;
123
- const handler = vi.fn();
124
- registry.bus.on("component:registered", handler);
125
-
126
- const instance = {};
127
- registry.registerComponent(instance, "MyComp");
128
-
129
- const components = registry.getComponents();
130
- expect(components).toHaveLength(1);
131
- expect(components[0].name).toBe("MyComp");
132
- expect(components[0].renderCount).toBe(0);
133
- expect(components[0].status).toBe("mounted");
134
- expect(handler).toHaveBeenCalledOnce();
135
- });
136
- });
137
-
138
- describe("Registry.recordRender", () => {
139
- it("increments renderCount and emits 'component:render'", () => {
140
- const registry = Registry.instance;
141
- const handler = vi.fn();
142
- registry.bus.on("component:render", handler);
143
-
144
- const instance = {};
145
- registry.registerComponent(instance, "App");
146
- registry.recordRender(instance, 5.2);
147
-
148
- const comp = registry.getComponents()[0];
149
- expect(comp.renderCount).toBe(1);
150
- expect(comp.lastRenderDuration).toBe(5.2);
151
- expect(handler).toHaveBeenCalledOnce();
152
- });
153
-
154
- it("accumulates renderCount across multiple renders", () => {
155
- const registry = Registry.instance;
156
- const instance = {};
157
- registry.registerComponent(instance, "App");
158
- registry.recordRender(instance, 1);
159
- registry.recordRender(instance, 2);
160
- registry.recordRender(instance, 3);
161
- expect(registry.getComponents()[0].renderCount).toBe(3);
162
- });
163
-
164
- it("does nothing when the component does not exist", () => {
165
- const registry = Registry.instance;
166
- const handler = vi.fn();
167
- registry.bus.on("component:render", handler);
168
- registry.recordRender({}, 1);
169
- expect(handler).not.toHaveBeenCalled();
170
- });
171
-
172
- it("pushes a 'component:render' timeline entry", () => {
173
- const registry = Registry.instance;
174
- const instance = {};
175
- registry.registerComponent(instance, "App");
176
- registry.recordRender(instance, 3.5);
177
- const entry = registry.getTimeline().find((t) => t.type === "component:render");
178
- expect(entry).toBeDefined();
179
- expect(entry?.data.duration).toBe(3.5);
180
- });
181
- });
182
-
183
- describe("Registry.recordLifecycle", () => {
184
- it("records a lifecycle event and emits 'lifecycle'", () => {
185
- const registry = Registry.instance;
186
- const handler = vi.fn();
187
- registry.bus.on("lifecycle", handler);
188
-
189
- const instance = {};
190
- registry.registerComponent(instance, "Comp");
191
- registry.recordLifecycle(instance, "onMount");
192
-
193
- expect(handler).toHaveBeenCalledOnce();
194
- const payload = handler.mock.calls[0][0] as { hook: string; name: string };
195
- expect(payload.hook).toBe("onMount");
196
- expect(payload.name).toBe("Comp");
197
- });
198
-
199
- it("removes component and its signals on 'onUnmount'", () => {
200
- const registry = Registry.instance;
201
- const instance = {};
202
- registry.registerComponent(instance, "Comp");
203
- registry.registerSignal(instance, "val", 1, "Comp");
204
-
205
- expect(registry.getComponents()).toHaveLength(1);
206
- expect(registry.getSignals()).toHaveLength(1);
207
-
208
- registry.recordLifecycle(instance, "onUnmount");
209
-
210
- expect(registry.getComponents()).toHaveLength(0);
211
- expect(registry.getSignals()).toHaveLength(0);
212
- });
213
-
214
- it("emits 'component:unmount' on onUnmount", () => {
215
- const registry = Registry.instance;
216
- const handler = vi.fn();
217
- registry.bus.on("component:unmount", handler);
218
-
219
- const instance = {};
220
- registry.registerComponent(instance, "Comp");
221
- registry.recordLifecycle(instance, "onUnmount");
222
-
223
- expect(handler).toHaveBeenCalledOnce();
224
- });
225
-
226
- it("maps onBeforeMount hook to 'component:mount' timeline type", () => {
227
- const registry = Registry.instance;
228
- const instance = {};
229
- registry.registerComponent(instance, "Comp");
230
- registry.recordLifecycle(instance, "onBeforeMount");
231
- const entry = registry.getTimeline().find((t) => t.type === "component:mount");
232
- expect(entry).toBeDefined();
233
- });
234
-
235
- it("maps onUnmount hook to 'component:unmount' timeline type", () => {
236
- const registry = Registry.instance;
237
- const instance = {};
238
- registry.registerComponent(instance, "Comp");
239
- registry.recordLifecycle(instance, "onUnmount");
240
- const entry = registry.getTimeline().find((t) => t.type === "component:unmount");
241
- expect(entry).toBeDefined();
242
- });
243
-
244
- it("maps other hooks to 'lifecycle' timeline type", () => {
245
- const registry = Registry.instance;
246
- const instance = {};
247
- registry.registerComponent(instance, "Comp");
248
- registry.recordLifecycle(instance, "onUpdate");
249
- const entry = registry.getTimeline().find((t) => t.type === "lifecycle");
250
- expect(entry).toBeDefined();
251
- });
252
-
253
- it("does nothing when the component does not exist", () => {
254
- const registry = Registry.instance;
255
- const handler = vi.fn();
256
- registry.bus.on("lifecycle", handler);
257
- registry.recordLifecycle({}, "onMount");
258
- expect(handler).not.toHaveBeenCalled();
259
- });
260
- });
261
-
262
- describe("Registry.recordMethodCall", () => {
263
- it("pushes a 'method:call' timeline entry", () => {
264
- const registry = Registry.instance;
265
- const timelineHandler = vi.fn();
266
- registry.bus.on("timeline:push", timelineHandler);
267
-
268
- const instance = {};
269
- registry.recordMethodCall(instance, "doSomething", [1, 2], "result", 3.14, "MyComp");
270
-
271
- const entry = registry.getTimeline().find((t) => t.type === "method:call");
272
- expect(entry).toBeDefined();
273
- expect(entry?.label).toBe("MyComp.doSomething()");
274
- expect(entry?.data.args).toEqual([1, 2]);
275
- expect(entry?.data.result).toBe("result");
276
- expect(entry?.data.duration).toBe(3.14);
277
- expect(timelineHandler).toHaveBeenCalledOnce();
278
- });
279
- });
280
-
281
- describe("Registry.getSignalsByComponent", () => {
282
- it("returns only signals belonging to the given component", () => {
283
- const registry = Registry.instance;
284
- const inst1 = {};
285
- const inst2 = {};
286
- registry.registerComponent(inst1, "Comp1");
287
- registry.registerComponent(inst2, "Comp2");
288
- registry.registerSignal(inst1, "a", 1, "Comp1");
289
- registry.registerSignal(inst2, "b", 2, "Comp2");
290
-
291
- const comp1Id = registry.getComponents().find((c) => c.name === "Comp1")!.id;
292
- const signals = registry.getSignalsByComponent(comp1Id);
293
- expect(signals).toHaveLength(1);
294
- expect(signals[0].label).toBe("a");
295
- });
296
- });
297
-
298
- describe("Registry.recordLifecycle — onUnmount cross-component isolation", () => {
299
- it("only removes signals belonging to the unmounted component", () => {
300
- const registry = Registry.instance;
301
- const inst1 = {};
302
- const inst2 = {};
303
- registry.registerComponent(inst1, "Comp1");
304
- registry.registerComponent(inst2, "Comp2");
305
- registry.registerSignal(inst1, "a", 1, "Comp1");
306
- registry.registerSignal(inst2, "b", 2, "Comp2");
307
-
308
- registry.recordLifecycle(inst1, "onUnmount");
309
-
310
- // inst1's signal is gone, inst2's signal remains
311
- const remaining = registry.getSignals();
312
- expect(remaining).toHaveLength(1);
313
- expect(remaining[0].label).toBe("b");
314
- });
315
- });
316
-
317
- describe("Registry timeline cap", () => {
318
- it("caps timeline at 200 entries", () => {
319
- const registry = Registry.instance;
320
- const instance = {};
321
- registry.registerComponent(instance, "Comp");
322
-
323
- // Each updateSignal pushes one timeline entry (plus the registerSignal = 0 entries)
324
- registry.registerSignal(instance, "val", 0, "Comp");
325
- for (let i = 1; i <= 210; i++) {
326
- registry.updateSignal(instance, "val", i, i - 1);
327
- }
328
-
329
- expect(registry.getTimeline().length).toBe(200);
330
- });
331
- });
332
-
333
- describe("Registry — rapid signal updates", () => {
334
- it("records all rapid updates within the same millisecond separately", () => {
335
- const registry = Registry.instance;
336
- const instance = {};
337
- registry.registerSignal(instance, "count", 0, "Counter");
338
-
339
- // Perform multiple rapid updates (may share the same Date.now() value)
340
- registry.updateSignal(instance, "count", 1, 0);
341
- registry.updateSignal(instance, "count", 2, 1);
342
- registry.updateSignal(instance, "count", 3, 2);
343
-
344
- const signal = registry.getSignals()[0];
345
- // initial + 3 updates = 4 history entries
346
- expect(signal.history).toHaveLength(4);
347
- expect(signal.history.map((h) => h.value)).toEqual([0, 1, 2, 3]);
348
- });
349
- });
350
-
351
- describe("Registry — re-registering same signal", () => {
352
- it("overwrites the previous entry when the same instance+key is re-registered", () => {
353
- const registry = Registry.instance;
354
- const instance = {};
355
- registry.registerSignal(instance, "x", 10, "Comp");
356
- registry.registerSignal(instance, "x", 99, "Comp");
357
-
358
- const signals = registry.getSignals();
359
- expect(signals).toHaveLength(1);
360
- expect(signals[0].value).toBe(99);
361
- expect(signals[0].history).toHaveLength(1);
362
- expect(signals[0].history[0].value).toBe(99);
363
- });
364
- });
365
-
366
- describe("Registry timeline cap — oldest entry removed", () => {
367
- it("removes the oldest entry when the 201st entry is pushed", () => {
368
- const registry = Registry.instance;
369
- const instance = {};
370
- registry.registerComponent(instance, "Comp");
371
- registry.registerSignal(instance, "n", 0, "Comp");
372
-
373
- // Push exactly 200 entries
374
- for (let i = 1; i <= 200; i++) {
375
- registry.updateSignal(instance, "n", i, i - 1);
376
- }
377
- const firstId = registry.getTimeline()[0].id;
378
-
379
- // Push one more — the oldest should be evicted
380
- registry.updateSignal(instance, "n", 201, 200);
381
-
382
- const timeline = registry.getTimeline();
383
- expect(timeline).toHaveLength(200);
384
- expect(timeline[0].id).not.toBe(firstId);
385
- });
386
- });
@@ -1,200 +0,0 @@
1
- import { beforeEach, describe, it, expect, vi } from "vitest";
2
-
3
- import { Registry } from "../core/registry";
4
- import { Trace } from "../decorators/trace";
5
-
6
- // Reset the Registry singleton before each test
7
- beforeEach(() => {
8
- (Registry as unknown as { _instance: Registry | null })._instance = null;
9
- });
10
-
11
- // ── Helpers ───────────────────────────────────────────────────────────────────
12
-
13
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
14
- type AnyConstructor = new (...args: any[]) => any;
15
-
16
- function applyTrace<T extends AnyConstructor>(cls: T): T {
17
- return Trace()(cls, {} as ClassDecoratorContext);
18
- }
19
-
20
- // ── Trace decorator ───────────────────────────────────────────────────────────
21
-
22
- describe("Trace — render()", () => {
23
- it("records a render event after calling render()", () => {
24
- class MyComp {
25
- render() { return "html"; }
26
- }
27
- const Traced = applyTrace(MyComp);
28
- const instance = new Traced() as { render: () => string };
29
-
30
- const registry = Registry.instance;
31
- registry.registerComponent(instance, "MyComp");
32
-
33
- instance.render();
34
-
35
- const renders = registry.getTimeline().filter((e) => e.type === "component:render");
36
- expect(renders).toHaveLength(1);
37
- expect(renders[0].label).toBe("<MyComp>");
38
- });
39
-
40
- it("returns the original render result", () => {
41
- class Box {
42
- render() { return "<div>box</div>"; }
43
- }
44
- const Traced = applyTrace(Box);
45
- const instance = new Traced() as { render: () => string };
46
-
47
- Registry.instance.registerComponent(instance, "Box");
48
- expect(instance.render()).toBe("<div>box</div>");
49
- });
50
-
51
- it("wraps render even when it takes arguments", () => {
52
- class Comp {
53
- render(ctx: string) { return ctx; }
54
- }
55
- const Traced = applyTrace(Comp);
56
- const instance = new Traced() as { render: (ctx: string) => string };
57
-
58
- Registry.instance.registerComponent(instance, "Comp");
59
- const result = instance.render("ctx-arg");
60
- expect(result).toBe("ctx-arg");
61
- });
62
-
63
- it("does not wrap render when the class has no render method", () => {
64
- class NoRender {}
65
- const Traced = applyTrace(NoRender);
66
- const instance = new Traced() as Record<string, unknown>;
67
- expect(instance.render).toBeUndefined();
68
- });
69
- });
70
-
71
- describe("Trace — onBeforeMount()", () => {
72
- it("registers the component in the registry on onBeforeMount", () => {
73
- class Widget {
74
- onBeforeMount() {}
75
- }
76
- const Traced = applyTrace(Widget);
77
- const instance = new Traced() as { onBeforeMount: () => void };
78
-
79
- const registry = Registry.instance;
80
- instance.onBeforeMount();
81
-
82
- const components = registry.getComponents();
83
- expect(components).toHaveLength(1);
84
- expect(components[0].name).toBe("Widget");
85
- });
86
-
87
- it("calls the original onBeforeMount when it exists", () => {
88
- const originalSpy = vi.fn();
89
- class Panel {
90
- onBeforeMount() { originalSpy(); }
91
- }
92
- const Traced = applyTrace(Panel);
93
- const instance = new Traced() as { onBeforeMount: () => void };
94
-
95
- instance.onBeforeMount();
96
- expect(originalSpy).toHaveBeenCalled();
97
- });
98
-
99
- it("records a component:mount timeline event on onBeforeMount", () => {
100
- class App {
101
- onBeforeMount() {}
102
- }
103
- const Traced = applyTrace(App);
104
- const instance = new Traced() as { onBeforeMount: () => void };
105
-
106
- instance.onBeforeMount();
107
-
108
- const mounts = Registry.instance.getTimeline().filter((e) => e.type === "component:mount");
109
- expect(mounts).toHaveLength(1);
110
- });
111
- });
112
-
113
- describe("Trace — class with no render() method", () => {
114
- it("does not crash and no duration is recorded when render is absent", () => {
115
- class NoRender {
116
- onBeforeMount() {}
117
- }
118
- const Traced = applyTrace(NoRender);
119
- const instance = new Traced() as unknown as Record<string, () => void>;
120
-
121
- const registry = Registry.instance;
122
- instance.onBeforeMount();
123
-
124
- // render does not exist — calling it should not be attempted
125
- expect(instance.render).toBeUndefined();
126
-
127
- // No component:render timeline entries should exist
128
- const renderEntries = registry.getTimeline().filter((e) => e.type === "component:render");
129
- expect(renderEntries).toHaveLength(0);
130
- });
131
- });
132
-
133
- describe("Trace — lifecycle hook call order", () => {
134
- it("calls onBeforeMount → render → (async) onMount in correct order", async () => {
135
- const order: string[] = [];
136
-
137
- class App {
138
- onBeforeMount() { order.push("onBeforeMount"); }
139
- render() { order.push("render"); return "html"; }
140
- onMount() { order.push("onMount"); }
141
- }
142
- const Traced = applyTrace(App);
143
- const instance = new Traced() as {
144
- onBeforeMount: () => void;
145
- render: () => string;
146
- onMount: () => void;
147
- };
148
-
149
- const registry = Registry.instance;
150
-
151
- // Simulate the component lifecycle
152
- instance.onBeforeMount();
153
- instance.render();
154
-
155
- // onMount is called async (via the framework's create() hook), simulate it
156
- registry.registerComponent(instance, "App");
157
- instance.onMount();
158
-
159
- // The original methods (including Trace wrappers) run in call order
160
- expect(order).toEqual(["onBeforeMount", "render", "onMount"]);
161
- });
162
- });
163
-
164
- describe("Trace — lifecycle hooks", () => {
165
- const hooks = ["onMount", "onUnmount", "onBeforeUpdate", "onUpdate", "onAfterUpdate"] as const;
166
-
167
- for (const hook of hooks) {
168
- it(`wraps ${hook} and records the lifecycle event`, () => {
169
- class Comp {
170
- onBeforeMount() {}
171
- }
172
- const Traced = applyTrace(Comp);
173
- const instance = new Traced() as unknown as Record<string, () => void>;
174
-
175
- // Register the component first via onBeforeMount
176
- instance.onBeforeMount();
177
-
178
- instance[hook]?.();
179
-
180
- const events = Registry.instance.getTimeline().filter(
181
- (e) => e.data.hook === hook,
182
- );
183
- expect(events.length).toBeGreaterThanOrEqual(1);
184
- });
185
-
186
- it(`${hook}: calls original implementation if it exists`, () => {
187
- const spy = vi.fn();
188
- class Comp {
189
- onBeforeMount() {}
190
- }
191
- (Comp.prototype as unknown as Record<string, unknown>)[hook] = spy;
192
- const Traced = applyTrace(Comp);
193
- const instance = new Traced() as unknown as Record<string, () => void>;
194
-
195
- instance.onBeforeMount();
196
- instance[hook]?.();
197
- expect(spy).toHaveBeenCalled();
198
- });
199
- }
200
- });
package/tsconfig.json DELETED
@@ -1,21 +0,0 @@
1
- {
2
- "extends": "../../../tsconfig.base.json",
3
- "compilerOptions": {
4
- "outDir": "./dist",
5
- "rootDir": "./",
6
- "jsxImportSource": "@praxisjs/jsx",
7
- "module": "ESNext",
8
- "moduleResolution": "bundler",
9
- "paths": {
10
- "@/*": ["./src/*"],
11
- "@shared/*": ["./src/ui/shared/*"],
12
- "@assets/*": ["./assets/*"],
13
- "@core/*": ["./src/core/*"],
14
- "@plugins/*": ["./src/plugins/*"],
15
- "@decorators/*": ["./src/decorators/*"],
16
- "@utils/*": ["./src/utils/*"],
17
- "@icons": ["./src/icons/index.ts"]
18
- }
19
- },
20
- "include": ["src", "uno.config.ts", "vite.config.ts"]
21
- }
package/uno.config.ts DELETED
@@ -1,57 +0,0 @@
1
- import presetWind3 from "@unocss/preset-wind3";
2
- import { defineConfig } from "unocss";
3
-
4
- export default defineConfig({
5
- presets: [presetWind3()],
6
-
7
- theme: {
8
- colors: {
9
- bg: "#0f0d17",
10
- header: "#161326",
11
- section: "#1b1830",
12
- border: "rgba(155,144,230,0.25)",
13
-
14
- text: "#f4f2ff",
15
- muted: "#c7c3e6",
16
- subtle: "#6f6a8f",
17
-
18
- selected: "#221e3d",
19
- input: "#1b1830",
20
-
21
- accent: "#9b90e6",
22
- accent2: "#7c6dd6",
23
- accent3: "#6d5bbd",
24
- soft: "rgba(155,144,230,0.18)",
25
-
26
- success: "#0ea57a",
27
- warn: "#d97706",
28
- error: "#dc2626",
29
- important: "#9b90e6",
30
- },
31
- },
32
-
33
- preflights: [
34
- {
35
- getCSS: () => `
36
- :host { all: initial; display: block; font-family: Inter, ui-sans-serif, system-ui, -apple-system, sans-serif; }
37
- * { box-sizing: border-box; }
38
-
39
- input::placeholder { color: #6f6a8f; }
40
- input:focus {
41
- outline: none;
42
- box-shadow: 0 0 0 2px rgba(155,144,230,0.3);
43
- }
44
-
45
- ::-webkit-scrollbar { width: 4px; height: 4px; }
46
- ::-webkit-scrollbar-track { background: transparent; }
47
- ::-webkit-scrollbar-thumb {
48
- background: rgba(155,144,230,0.2);
49
- border-radius: 2px;
50
- }
51
- ::-webkit-scrollbar-thumb:hover {
52
- background: rgba(155,144,230,0.4);
53
- }
54
- `,
55
- },
56
- ],
57
- });