@praxisjs/decorators 0.4.2 → 0.4.3

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 (48) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/__tests__/component.test.d.ts +2 -0
  3. package/dist/__tests__/component.test.d.ts.map +1 -0
  4. package/dist/__tests__/component.test.js +137 -0
  5. package/dist/__tests__/component.test.js.map +1 -0
  6. package/dist/__tests__/events.test.d.ts +2 -0
  7. package/dist/__tests__/events.test.d.ts.map +1 -0
  8. package/dist/__tests__/events.test.js +190 -0
  9. package/dist/__tests__/events.test.js.map +1 -0
  10. package/dist/__tests__/functions.test.js +157 -0
  11. package/dist/__tests__/functions.test.js.map +1 -1
  12. package/dist/__tests__/lazy.test.d.ts +2 -0
  13. package/dist/__tests__/lazy.test.d.ts.map +1 -0
  14. package/dist/__tests__/lazy.test.js +165 -0
  15. package/dist/__tests__/lazy.test.js.map +1 -0
  16. package/dist/__tests__/memo.test.js +13 -0
  17. package/dist/__tests__/memo.test.js.map +1 -1
  18. package/dist/__tests__/properties.test.js +191 -1
  19. package/dist/__tests__/properties.test.js.map +1 -1
  20. package/dist/__tests__/slot.test.d.ts +2 -0
  21. package/dist/__tests__/slot.test.d.ts.map +1 -0
  22. package/dist/__tests__/slot.test.js +115 -0
  23. package/dist/__tests__/slot.test.js.map +1 -0
  24. package/dist/__tests__/virtual.test.d.ts +2 -0
  25. package/dist/__tests__/virtual.test.d.ts.map +1 -0
  26. package/dist/__tests__/virtual.test.js +201 -0
  27. package/dist/__tests__/virtual.test.js.map +1 -0
  28. package/dist/component/lazy.d.ts +1 -1
  29. package/dist/component/lazy.d.ts.map +1 -1
  30. package/dist/component/lazy.js +4 -1
  31. package/dist/component/lazy.js.map +1 -1
  32. package/dist/component/virtual.d.ts +1 -1
  33. package/dist/component/virtual.d.ts.map +1 -1
  34. package/dist/functions/watch.d.ts.map +1 -1
  35. package/dist/functions/watch.js +10 -2
  36. package/dist/functions/watch.js.map +1 -1
  37. package/package.json +2 -2
  38. package/src/__tests__/component.test.ts +156 -0
  39. package/src/__tests__/events.test.ts +236 -0
  40. package/src/__tests__/functions.test.ts +207 -0
  41. package/src/__tests__/lazy.test.ts +220 -0
  42. package/src/__tests__/memo.test.ts +16 -0
  43. package/src/__tests__/properties.test.ts +249 -1
  44. package/src/__tests__/slot.test.ts +141 -0
  45. package/src/__tests__/virtual.test.ts +241 -0
  46. package/src/component/lazy.ts +4 -2
  47. package/src/component/virtual.tsx +1 -1
  48. package/src/functions/watch.ts +11 -2
@@ -0,0 +1,115 @@
1
+ // @vitest-environment jsdom
2
+ import { describe, it, expect, vi } from "vitest";
3
+ import { initSlots, getSlot, Slot } from "../properties/slot";
4
+ import { StatefulComponent } from "@praxisjs/core";
5
+ // ── initSlots / getSlot ──────────────────────────────────────────────────────
6
+ describe("initSlots / getSlot", () => {
7
+ it("returns empty default slot when children is null", () => {
8
+ const instance = {};
9
+ initSlots(instance, null);
10
+ expect(getSlot(instance, "default")).toEqual([]);
11
+ });
12
+ it("returns empty array for unknown slot", () => {
13
+ const instance = {};
14
+ initSlots(instance, null);
15
+ expect(getSlot(instance, "unknown")).toEqual([]);
16
+ });
17
+ it("puts plain children into the default slot", () => {
18
+ const instance = {};
19
+ const child = document.createElement("span");
20
+ initSlots(instance, child);
21
+ expect(getSlot(instance, "default")).toEqual([child]);
22
+ });
23
+ it("flattens array children into the default slot", () => {
24
+ const instance = {};
25
+ const a = document.createElement("p");
26
+ const b = document.createElement("div");
27
+ initSlots(instance, [a, b]);
28
+ expect(getSlot(instance, "default")).toEqual([a, b]);
29
+ });
30
+ it("routes element with slot attribute to named slot", () => {
31
+ const instance = {};
32
+ const el = document.createElement("div");
33
+ el.setAttribute("slot", "header");
34
+ initSlots(instance, el);
35
+ expect(getSlot(instance, "header")).toEqual([el]);
36
+ expect(getSlot(instance, "default")).toEqual([]);
37
+ // slot attribute should be removed
38
+ expect(el.hasAttribute("slot")).toBe(false);
39
+ });
40
+ it("handles mixed named and default children", () => {
41
+ const instance = {};
42
+ const named = document.createElement("aside");
43
+ named.setAttribute("slot", "sidebar");
44
+ const plain = document.createElement("main");
45
+ initSlots(instance, [named, plain]);
46
+ expect(getSlot(instance, "sidebar")).toEqual([named]);
47
+ expect(getSlot(instance, "default")).toEqual([plain]);
48
+ });
49
+ it("skips null children in array", () => {
50
+ const instance = {};
51
+ const el = document.createElement("span");
52
+ initSlots(instance, [null, el, undefined]);
53
+ expect(getSlot(instance, "default")).toEqual([el]);
54
+ });
55
+ });
56
+ // ── Slot decorator ───────────────────────────────────────────────────────────
57
+ describe("Slot decorator", () => {
58
+ it("provides the default slot via field decorator", () => {
59
+ class MyComp extends StatefulComponent {
60
+ render() { return null; }
61
+ }
62
+ const initializers = [];
63
+ const ctx = {
64
+ name: "default",
65
+ kind: "field",
66
+ addInitializer(fn) { initializers.push(fn); },
67
+ };
68
+ Slot()(undefined, ctx);
69
+ const instance = new MyComp();
70
+ initializers.forEach((fn) => { fn.call(instance); });
71
+ // No children initialized — slot should be empty
72
+ const children = document.createElement("p");
73
+ initSlots(instance, children);
74
+ expect(Array.isArray(instance.default)).toBe(true);
75
+ });
76
+ it("uses custom slot name when provided", () => {
77
+ class MyComp extends StatefulComponent {
78
+ render() { return null; }
79
+ }
80
+ const initializers = [];
81
+ const ctx = {
82
+ name: "content",
83
+ kind: "field",
84
+ addInitializer(fn) { initializers.push(fn); },
85
+ };
86
+ Slot("header")(undefined, ctx);
87
+ const instance = new MyComp();
88
+ initializers.forEach((fn) => { fn.call(instance); });
89
+ const el = document.createElement("nav");
90
+ el.setAttribute("slot", "header");
91
+ initSlots(instance, el);
92
+ const slot = instance.content;
93
+ expect(slot).toHaveLength(1);
94
+ expect(slot[0]).toBe(el);
95
+ });
96
+ it("warns on direct assignment in non-production", () => {
97
+ class MyComp extends StatefulComponent {
98
+ render() { return null; }
99
+ }
100
+ const initializers = [];
101
+ const ctx = {
102
+ name: "default",
103
+ kind: "field",
104
+ addInitializer(fn) { initializers.push(fn); },
105
+ };
106
+ Slot()(undefined, ctx);
107
+ const instance = new MyComp();
108
+ initializers.forEach((fn) => { fn.call(instance); });
109
+ const warn = vi.spyOn(console, "warn").mockImplementation(() => { });
110
+ instance.default = "bad";
111
+ expect(warn).toHaveBeenCalledWith(expect.stringContaining("[Slot]"));
112
+ warn.mockRestore();
113
+ });
114
+ });
115
+ //# sourceMappingURL=slot.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slot.test.js","sourceRoot":"","sources":["../../src/__tests__/slot.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=virtual.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"virtual.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/virtual.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,201 @@
1
+ // @vitest-environment jsdom
2
+ import { describe, it, expect, vi } from "vitest";
3
+ import { StatefulComponent } from "@praxisjs/core";
4
+ import { Virtual } from "../component/virtual";
5
+ function applyVirtual(cls, itemHeight, buffer) {
6
+ return buffer !== undefined
7
+ ? Virtual(itemHeight, buffer)(cls, {})
8
+ : Virtual(itemHeight)(cls, {});
9
+ }
10
+ // A base component with items and renderItem for virtual scrolling
11
+ class ListComp extends StatefulComponent {
12
+ items = [];
13
+ renderItem(item, _index) {
14
+ const div = document.createElement("div");
15
+ div.textContent = String(item);
16
+ return div;
17
+ }
18
+ render() { return null; }
19
+ }
20
+ describe("Virtual decorator", () => {
21
+ it("warns and returns null when renderItem is not defined", () => {
22
+ class NoRenderItem extends StatefulComponent {
23
+ items = ["a", "b"];
24
+ render() { return null; }
25
+ }
26
+ const Wrapped = applyVirtual(NoRenderItem, 50);
27
+ const instance = new Wrapped();
28
+ const warn = vi.spyOn(console, "warn").mockImplementation(() => { });
29
+ const result = instance.render();
30
+ expect(result).toBeNull();
31
+ expect(warn).toHaveBeenCalledWith(expect.stringContaining("[Virtual]"));
32
+ warn.mockRestore();
33
+ });
34
+ it("renders a container div with the total height", () => {
35
+ class MyList extends StatefulComponent {
36
+ items = ["a", "b", "c"];
37
+ renderItem(item) {
38
+ const el = document.createElement("div");
39
+ el.textContent = String(item);
40
+ return el;
41
+ }
42
+ render() { return null; }
43
+ }
44
+ const Wrapped = applyVirtual(MyList, 50);
45
+ const instance = new Wrapped();
46
+ const result = instance.render();
47
+ expect(result).toBeInstanceOf(HTMLElement);
48
+ expect(result.tagName.toLowerCase()).toBe("div");
49
+ // Total height = 3 items * 50px
50
+ expect(result.getAttribute("style")).toContain("150px");
51
+ });
52
+ it("renders visible items within the viewport", () => {
53
+ class MyList extends StatefulComponent {
54
+ items = [1, 2, 3, 4, 5];
55
+ renderItem(item) {
56
+ const el = document.createElement("div");
57
+ el.textContent = String(item);
58
+ return el;
59
+ }
60
+ render() { return null; }
61
+ }
62
+ const Wrapped = applyVirtual(MyList, 100, 0);
63
+ const instance = new Wrapped();
64
+ const outer = instance.render();
65
+ // Should render some content
66
+ expect(outer).not.toBeNull();
67
+ expect(outer.children.length).toBeGreaterThan(0);
68
+ });
69
+ it("handles empty items list without errors", () => {
70
+ class EmptyList extends StatefulComponent {
71
+ items = [];
72
+ renderItem(_item) {
73
+ return document.createElement("div");
74
+ }
75
+ render() { return null; }
76
+ }
77
+ const Wrapped = applyVirtual(EmptyList, 50);
78
+ const instance = new Wrapped();
79
+ expect(() => instance.render()).not.toThrow();
80
+ });
81
+ it("onMount sets container styles when _anchor has a parent", () => {
82
+ const Wrapped = applyVirtual(ListComp, 50);
83
+ const instance = new Wrapped();
84
+ instance.items = ["a", "b"];
85
+ const container = document.createElement("div");
86
+ document.body.appendChild(container);
87
+ const anchor = document.createComment("end");
88
+ container.appendChild(anchor);
89
+ instance._anchor = anchor;
90
+ instance.onMount?.();
91
+ expect(container.style.overflowY).toBe("auto");
92
+ expect(container.style.position).toBe("relative");
93
+ document.body.removeChild(container);
94
+ });
95
+ it("onMount does nothing when _anchor has no parent", () => {
96
+ const Wrapped = applyVirtual(ListComp, 50);
97
+ const instance = new Wrapped();
98
+ const anchor = document.createComment("end");
99
+ instance._anchor = anchor;
100
+ expect(() => instance.onMount?.()).not.toThrow();
101
+ });
102
+ it("onUnmount disconnects scroll listener and cleans up effects", () => {
103
+ const Wrapped = applyVirtual(ListComp, 50);
104
+ const instance = new Wrapped();
105
+ const container = document.createElement("div");
106
+ document.body.appendChild(container);
107
+ const anchor = document.createComment("end");
108
+ container.appendChild(anchor);
109
+ instance._anchor = anchor;
110
+ instance.onMount?.();
111
+ // Should not throw
112
+ expect(() => instance.onUnmount?.()).not.toThrow();
113
+ document.body.removeChild(container);
114
+ });
115
+ it("re-renders visible items when scrollTop changes (covers while loop cleanup)", () => {
116
+ class ScrollList extends StatefulComponent {
117
+ items = Array.from({ length: 20 }, (_, i) => i);
118
+ renderItem(item) {
119
+ const el = document.createElement("div");
120
+ el.textContent = String(item);
121
+ return el;
122
+ }
123
+ render() { return null; }
124
+ }
125
+ const Wrapped = applyVirtual(ScrollList, 50, 0);
126
+ const instance = new Wrapped();
127
+ const container = document.createElement("div");
128
+ document.body.appendChild(container);
129
+ const anchor = document.createComment("end");
130
+ container.appendChild(anchor);
131
+ instance._anchor = anchor;
132
+ instance.onMount?.();
133
+ // First render - populates the itemsSlot
134
+ instance.render();
135
+ // Change scrollTop to trigger effect re-run (covers the while loop removing old nodes)
136
+ Object.defineProperty(container, "scrollTop", { configurable: true, value: 500 });
137
+ container.dispatchEvent(new Event("scroll"));
138
+ // Verify scrollTop was updated (effect should have re-run)
139
+ const scrollTop = instance._scrollTop;
140
+ expect(scrollTop()).toBe(500);
141
+ document.body.removeChild(container);
142
+ });
143
+ it("renderItem returning an array appends all child nodes", () => {
144
+ class ArrayItemList extends StatefulComponent {
145
+ items = ["item"];
146
+ renderItem(item) {
147
+ const a = document.createElement("span");
148
+ a.textContent = String(item) + "-1";
149
+ const b = document.createElement("span");
150
+ b.textContent = String(item) + "-2";
151
+ return [a, b];
152
+ }
153
+ render() { return null; }
154
+ }
155
+ const Wrapped = applyVirtual(ArrayItemList, 50, 0);
156
+ const instance = new Wrapped();
157
+ const outer = instance.render();
158
+ // outer structure: spacerTop, itemsSlot, spacerBottom
159
+ const itemsSlot = outer.children[1];
160
+ const wrapper = itemsSlot.children[0];
161
+ expect(wrapper.children.length).toBe(2);
162
+ });
163
+ it("renderItem returning null produces an empty wrapper div", () => {
164
+ class NullItemList extends StatefulComponent {
165
+ items = ["x"];
166
+ renderItem() { return null; }
167
+ render() { return null; }
168
+ }
169
+ const Wrapped = applyVirtual(NullItemList, 50, 0);
170
+ const instance = new Wrapped();
171
+ expect(() => instance.render()).not.toThrow();
172
+ const outer = instance.render();
173
+ const itemsSlot = outer.children[1];
174
+ const wrapper = itemsSlot.children[0];
175
+ // rendered is null — no child nodes appended
176
+ expect(wrapper.children.length).toBe(0);
177
+ });
178
+ it("onUnmount without prior onMount does not throw", () => {
179
+ const Wrapped = applyVirtual(ListComp, 50);
180
+ const instance = new Wrapped();
181
+ // _container is undefined — onUnmount should be a no-op
182
+ expect(() => instance.onUnmount?.()).not.toThrow();
183
+ });
184
+ it("updates scrollTop on scroll event", () => {
185
+ const Wrapped = applyVirtual(ListComp, 50);
186
+ const instance = new Wrapped();
187
+ instance.items = Array.from({ length: 20 }, (_, i) => i);
188
+ const container = document.createElement("div");
189
+ document.body.appendChild(container);
190
+ const anchor = document.createComment("end");
191
+ container.appendChild(anchor);
192
+ instance._anchor = anchor;
193
+ instance.onMount?.();
194
+ Object.defineProperty(container, "scrollTop", { configurable: true, value: 200 });
195
+ container.dispatchEvent(new Event("scroll"));
196
+ const scrollTop = instance._scrollTop;
197
+ expect(scrollTop()).toBe(200);
198
+ document.body.removeChild(container);
199
+ });
200
+ });
201
+ //# sourceMappingURL=virtual.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"virtual.test.js","sourceRoot":"","sources":["../../src/__tests__/virtual.test.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,3 @@
1
1
  import { type RootComponent } from "@praxisjs/core/internal";
2
- export declare function Lazy(placeholder?: number): <T extends new (...args: any[]) => RootComponent>(constructor: T, _context: ClassDecoratorContext) => T;
2
+ export declare function Lazy(placeholder?: number): <T extends new (...args: any[]) => RootComponent<Record<string, any>>>(constructor: T, _context: ClassDecoratorContext) => T;
3
3
  //# sourceMappingURL=lazy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"lazy.d.ts","sourceRoot":"","sources":["../../src/component/lazy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAU,MAAM,yBAAyB,CAAC;AAErE,wBAAgB,IAAI,CAAC,WAAW,SAAM,IAEnB,CAAC,SAAS,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,aAAa,EAC9D,aAAa,CAAC,EACd,UAAU,qBAAqB,KAC9B,CAAC,CAkDL"}
1
+ {"version":3,"file":"lazy.d.ts","sourceRoot":"","sources":["../../src/component/lazy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAU,MAAM,yBAAyB,CAAC;AAErE,wBAAgB,IAAI,CAAC,WAAW,SAAM,IAEnB,CAAC,SAAS,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,EACnF,aAAa,CAAC,EACd,UAAU,qBAAqB,KAC9B,CAAC,CAoDL"}
@@ -5,7 +5,10 @@ export function Lazy(placeholder = 200) {
5
5
  return class LazyWrapper extends constructor {
6
6
  _lazyVisible = signal(false);
7
7
  _observer;
8
- _originalRender = this.render.bind(this);
8
+ _originalRender =
9
+ // Capture the *parent* class render, not LazyWrapper's own override,
10
+ // to avoid infinite recursion when render() delegates here.
11
+ constructor.prototype.render.bind(this);
9
12
  onMount() {
10
13
  super.onMount?.();
11
14
  // Use the end anchor to find the parent element
@@ -1 +1 @@
1
- {"version":3,"file":"lazy.js","sourceRoot":"","sources":["../../src/component/lazy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAErE,MAAM,UAAU,IAAI,CAAC,WAAW,GAAG,GAAG;IACpC,8DAA8D;IAC9D,OAAO,UACL,WAAc,EACd,QAA+B;QAE/B,OAAO,MAAM,WAAY,SAAQ,WAAW;YACzB,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;YACtC,SAAS,CAAwB;YACxB,eAAe,GAC9B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAEzB,OAAO;gBACL,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;gBAElB,gDAAgD;gBAChD,MAAM,EAAE,GACL,IAAyC,CAAC,OAAO;oBAChD,EAAE,aAAa,IAAI,IAAI,CAAC;gBAC5B,IAAI,CAAC,EAAE;oBAAE,OAAO;gBAEhB,IAAI,CAAC,CAAC,sBAAsB,IAAI,MAAM,CAAC,EAAE,CAAC;oBACxC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;oBAC5B,OAAO;gBACT,CAAC;gBAED,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;oBACzB,EAAE,CAAC,KAAK,CAAC,SAAS,GAAG,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC;gBAClD,CAAC;gBAED,IAAI,CAAC,SAAS,GAAG,IAAI,oBAAoB,CACvC,CAAC,OAAO,EAAE,EAAE;oBACV,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC;wBAC/B,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;wBAC5B,EAAE,CAAC,KAAK,CAAC,SAAS,GAAG,EAAE,CAAC;wBACxB,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,CAAC;oBAC/B,CAAC;gBACH,CAAC,EACD,EAAE,UAAU,EAAE,OAAO,EAAE,CACxB,CAAC;gBAEF,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAC7B,CAAC;YAED,SAAS;gBACP,KAAK,CAAC,SAAS,EAAE,EAAE,CAAC;gBACpB,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,CAAC;YAC/B,CAAC;YAED,MAAM;gBACJ,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE;oBAAE,OAAO,IAAI,CAAC;gBACtC,OAAO,IAAI,CAAC,eAAe,EAAE,CAAC;YAChC,CAAC;SACc,CAAC;IACpB,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"lazy.js","sourceRoot":"","sources":["../../src/component/lazy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAErE,MAAM,UAAU,IAAI,CAAC,WAAW,GAAG,GAAG;IACpC,8DAA8D;IAC9D,OAAO,UACL,WAAc,EACd,QAA+B;QAE/B,OAAO,MAAM,WAAY,SAAQ,WAAW;YACzB,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;YACtC,SAAS,CAAwB;YACxB,eAAe;YAC9B,qEAAqE;YACrE,4DAA4D;YAC3D,WAAW,CAAC,SAAgD,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAElF,OAAO;gBACL,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;gBAElB,gDAAgD;gBAChD,MAAM,EAAE,GACL,IAAyC,CAAC,OAAO;oBAChD,EAAE,aAAa,IAAI,IAAI,CAAC;gBAC5B,IAAI,CAAC,EAAE;oBAAE,OAAO;gBAEhB,IAAI,CAAC,CAAC,sBAAsB,IAAI,MAAM,CAAC,EAAE,CAAC;oBACxC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;oBAC5B,OAAO;gBACT,CAAC;gBAED,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;oBACzB,EAAE,CAAC,KAAK,CAAC,SAAS,GAAG,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC;gBAClD,CAAC;gBAED,IAAI,CAAC,SAAS,GAAG,IAAI,oBAAoB,CACvC,CAAC,OAAO,EAAE,EAAE;oBACV,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC;wBAC/B,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;wBAC5B,EAAE,CAAC,KAAK,CAAC,SAAS,GAAG,EAAE,CAAC;wBACxB,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,CAAC;oBAC/B,CAAC;gBACH,CAAC,EACD,EAAE,UAAU,EAAE,OAAO,EAAE,CACxB,CAAC;gBAEF,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAC7B,CAAC;YAED,SAAS;gBACP,KAAK,CAAC,SAAS,EAAE,EAAE,CAAC;gBACpB,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,CAAC;YAC/B,CAAC;YAED,MAAM;gBACJ,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE;oBAAE,OAAO,IAAI,CAAC;gBACtC,OAAO,IAAI,CAAC,eAAe,EAAE,CAAC;YAChC,CAAC;SACc,CAAC;IACpB,CAAC,CAAC;AACJ,CAAC"}
@@ -1,3 +1,3 @@
1
1
  import { type RootComponent } from "@praxisjs/core/internal";
2
- export declare function Virtual(itemHeight: number, buffer?: number): <T extends new (...args: any[]) => RootComponent>(constructor: T, _context: ClassDecoratorContext) => T;
2
+ export declare function Virtual(itemHeight: number, buffer?: number): <T extends new (...args: any[]) => RootComponent<Record<string, any>>>(constructor: T, _context: ClassDecoratorContext) => T;
3
3
  //# sourceMappingURL=virtual.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"virtual.d.ts","sourceRoot":"","sources":["../../src/component/virtual.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,aAAa,EAAU,MAAM,yBAAyB,CAAC;AAQvF,wBAAgB,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,SAAI,IAEnC,CAAC,SAAS,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,aAAa,EAC9D,aAAa,CAAC,EACd,UAAU,qBAAqB,KAC9B,CAAC,CAqIL"}
1
+ {"version":3,"file":"virtual.d.ts","sourceRoot":"","sources":["../../src/component/virtual.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,aAAa,EAAU,MAAM,yBAAyB,CAAC;AAQvF,wBAAgB,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,SAAI,IAEnC,CAAC,SAAS,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,EACnF,aAAa,CAAC,EACd,UAAU,qBAAqB,KAC9B,CAAC,CAqIL"}
@@ -1 +1 @@
1
- {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../src/functions/watch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAGjD,KAAK,iBAAiB,GAAG,MAAM,iBAAiB,CAAC;AAEjD,KAAK,aAAa,CAAC,CAAC,IAAI;KACrB,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,EAAE,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CACvD,GAAG,IAAI,EAAE,MAAM,CAAC,KACb,OAAO,GACR,CAAC,SAAS,EAAE,GACV,CAAC,CAAC,CAAC,CAAC,SAAS,QAAQ,CAAC,OAAO,CAAC,GAC5B,CAAC,GACD,KAAK,GACP,KAAK,GACP,CAAC;CACN,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,iBAAiB,CAAC,CAAC,GACpC,MAAM,CAAC;AAET,KAAK,YAAY,CACf,IAAI,SAAS,SAAS,MAAM,EAAE,EAC9B,IAAI,SAAS,MAAM,GAAG,KAAK,IACzB,IAAI,SAAS,SAAS;IACxB,MAAM,IAAI,SAAS,MAAM;IACzB,GAAG,MAAM,IAAI,SAAS,MAAM,EAAE;CAC/B,GACG,IAAI,SAAS,IAAI,GACf,CAAC,gBAAgB,IAAI,iBAAiB,EAAE,GAAG,IAAI,CAAC,GAChD,CAAC,IAAI,EAAE,GAAG,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC,CAAC,GAC5C,IAAI,CAAC;AAET,KAAK,YAAY,CACf,CAAC,SAAS,iBAAiB,EAC3B,IAAI,SAAS,aAAa,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,IAC1C,YAAY,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,SAAS,IAAI,GAAG,IAAI,GAAG,YAAY,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;AAE1E,KAAK,MAAM,CAAC,CAAC,IACX,CAAC,SAAS,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,MAAM,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAEpE,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,iBAAiB,EAAE,CAAC,SAAS,MAAM,CAAC,IAAI,MAAM,CAC3E,CAAC,CAAC,CAAC,CAAC,CACL,CAAC;AACF,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,iBAAiB,EAAE,CAAC,SAAS,MAAM,CAAC,IAAI;KACrE,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACvB,CAAC;AAOF,wBAAgB,KAAK,CACnB,CAAC,SAAS,iBAAiB,EAC3B,KAAK,CAAC,IAAI,SAAS,aAAa,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAClD,GAAG,SAAS,EAAE,YAAY,CAAC,CAAC,EAAE,IAAI,CAAC,IAEjC,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,EAC5C,SAAS,2BAA2B,CAAC,CAAC,CAAC,KACtC,IAAI,CAmCR"}
1
+ {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../src/functions/watch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAGjD,KAAK,iBAAiB,GAAG,MAAM,iBAAiB,CAAC;AAEjD,KAAK,aAAa,CAAC,CAAC,IAAI;KACrB,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,EAAE,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CACvD,GAAG,IAAI,EAAE,MAAM,CAAC,KACb,OAAO,GACR,CAAC,SAAS,EAAE,GACV,CAAC,CAAC,CAAC,CAAC,SAAS,QAAQ,CAAC,OAAO,CAAC,GAC5B,CAAC,GACD,KAAK,GACP,KAAK,GACP,CAAC;CACN,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,iBAAiB,CAAC,CAAC,GACpC,MAAM,CAAC;AAET,KAAK,YAAY,CACf,IAAI,SAAS,SAAS,MAAM,EAAE,EAC9B,IAAI,SAAS,MAAM,GAAG,KAAK,IACzB,IAAI,SAAS,SAAS;IACxB,MAAM,IAAI,SAAS,MAAM;IACzB,GAAG,MAAM,IAAI,SAAS,MAAM,EAAE;CAC/B,GACG,IAAI,SAAS,IAAI,GACf,CAAC,gBAAgB,IAAI,iBAAiB,EAAE,GAAG,IAAI,CAAC,GAChD,CAAC,IAAI,EAAE,GAAG,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC,CAAC,GAC5C,IAAI,CAAC;AAET,KAAK,YAAY,CACf,CAAC,SAAS,iBAAiB,EAC3B,IAAI,SAAS,aAAa,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,IAC1C,YAAY,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,SAAS,IAAI,GAAG,IAAI,GAAG,YAAY,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;AAE1E,KAAK,MAAM,CAAC,CAAC,IACX,CAAC,SAAS,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,MAAM,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAEpE,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,iBAAiB,EAAE,CAAC,SAAS,MAAM,CAAC,IAAI,MAAM,CAC3E,CAAC,CAAC,CAAC,CAAC,CACL,CAAC;AACF,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,iBAAiB,EAAE,CAAC,SAAS,MAAM,CAAC,IAAI;KACrE,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACvB,CAAC;AAOF,wBAAgB,KAAK,CACnB,CAAC,SAAS,iBAAiB,EAC3B,KAAK,CAAC,IAAI,SAAS,aAAa,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAClD,GAAG,SAAS,EAAE,YAAY,CAAC,CAAC,EAAE,IAAI,CAAC,IAEjC,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,EAC5C,SAAS,2BAA2B,CAAC,CAAC,CAAC,KACtC,IAAI,CA4CR"}
@@ -11,11 +11,14 @@ export function Watch(...propNames) {
11
11
  const instance = this;
12
12
  // eslint-disable-next-line @typescript-eslint/unbound-method
13
13
  const originalOnMount = instance.onMount;
14
+ // eslint-disable-next-line @typescript-eslint/unbound-method
15
+ const originalOnUnmount = instance.onUnmount;
16
+ let stopEffect;
14
17
  instance.onMount = function () {
15
18
  originalOnMount?.call(this);
16
19
  if (props.length === 1) {
17
20
  let oldVal = readValue(this, props[0]);
18
- effect(() => {
21
+ stopEffect = effect(() => {
19
22
  const newVal = readValue(this, props[0]);
20
23
  if (!Object.is(newVal, oldVal)) {
21
24
  value.call(this, newVal, oldVal);
@@ -26,7 +29,7 @@ export function Watch(...propNames) {
26
29
  else {
27
30
  const read = () => Object.fromEntries(props.map((p) => [p, readValue(this, p)]));
28
31
  let oldVals = read();
29
- effect(() => {
32
+ stopEffect = effect(() => {
30
33
  const newVals = read();
31
34
  if (props.some((p) => !Object.is(newVals[p], oldVals[p]))) {
32
35
  value.call(this, newVals, oldVals);
@@ -35,6 +38,11 @@ export function Watch(...propNames) {
35
38
  });
36
39
  }
37
40
  };
41
+ instance.onUnmount = function () {
42
+ originalOnUnmount?.call(this);
43
+ stopEffect?.();
44
+ stopEffect = undefined;
45
+ };
38
46
  });
39
47
  };
40
48
  }
@@ -1 +1 @@
1
- {"version":3,"file":"watch.js","sourceRoot":"","sources":["../../src/functions/watch.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEjD,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AA4CvD,SAAS,SAAS,CAAC,QAAiC,EAAE,GAAW;IAC/D,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC1B,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,GAAyB,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;AAC9D,CAAC;AAED,MAAM,UAAU,KAAK,CAGnB,GAAG,SAAgC;IACnC,OAAO,UACL,KAA4C,EAC5C,OAAuC;QAEvC,MAAM,KAAK,GAAG,SAAgC,CAAC;QAE/C,OAAO,CAAC,cAAc,CAAC;YACrB,MAAM,QAAQ,GAAG,IAAmC,CAAC;YACrD,6DAA6D;YAC7D,MAAM,eAAe,GAAG,QAAQ,CAAC,OAAO,CAAC;YAEzC,QAAQ,CAAC,OAAO,GAAG;gBACjB,eAAe,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;gBAE5B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBACvB,IAAI,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;oBACvC,MAAM,CAAC,GAAG,EAAE;wBACV,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;wBACzC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;4BAC/B,KAAK,CAAC,IAAI,CAAC,IAAS,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;4BACtC,MAAM,GAAG,MAAM,CAAC;wBAClB,CAAC;oBACH,CAAC,CAAC,CAAC;gBACL,CAAC;qBAAM,CAAC;oBACN,MAAM,IAAI,GAAG,GAAG,EAAE,CAChB,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;oBAChE,IAAI,OAAO,GAAG,IAAI,EAAE,CAAC;oBACrB,MAAM,CAAC,GAAG,EAAE;wBACV,MAAM,OAAO,GAAG,IAAI,EAAE,CAAC;wBACvB,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;4BAC1D,KAAK,CAAC,IAAI,CAAC,IAAS,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;4BACxC,OAAO,GAAG,OAAO,CAAC;wBACpB,CAAC;oBACH,CAAC,CAAC,CAAC;gBACL,CAAC;YACH,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"watch.js","sourceRoot":"","sources":["../../src/functions/watch.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEjD,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AA4CvD,SAAS,SAAS,CAAC,QAAiC,EAAE,GAAW;IAC/D,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC1B,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,GAAyB,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;AAC9D,CAAC;AAED,MAAM,UAAU,KAAK,CAGnB,GAAG,SAAgC;IACnC,OAAO,UACL,KAA4C,EAC5C,OAAuC;QAEvC,MAAM,KAAK,GAAG,SAAgC,CAAC;QAE/C,OAAO,CAAC,cAAc,CAAC;YACrB,MAAM,QAAQ,GAAG,IAAmC,CAAC;YACrD,6DAA6D;YAC7D,MAAM,eAAe,GAAG,QAAQ,CAAC,OAAO,CAAC;YACzC,6DAA6D;YAC7D,MAAM,iBAAiB,GAAG,QAAQ,CAAC,SAAS,CAAC;YAC7C,IAAI,UAAoC,CAAC;YAEzC,QAAQ,CAAC,OAAO,GAAG;gBACjB,eAAe,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;gBAE5B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBACvB,IAAI,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;oBACvC,UAAU,GAAG,MAAM,CAAC,GAAG,EAAE;wBACvB,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;wBACzC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;4BAC/B,KAAK,CAAC,IAAI,CAAC,IAAS,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;4BACtC,MAAM,GAAG,MAAM,CAAC;wBAClB,CAAC;oBACH,CAAC,CAAC,CAAC;gBACL,CAAC;qBAAM,CAAC;oBACN,MAAM,IAAI,GAAG,GAAG,EAAE,CAChB,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;oBAChE,IAAI,OAAO,GAAG,IAAI,EAAE,CAAC;oBACrB,UAAU,GAAG,MAAM,CAAC,GAAG,EAAE;wBACvB,MAAM,OAAO,GAAG,IAAI,EAAE,CAAC;wBACvB,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;4BAC1D,KAAK,CAAC,IAAI,CAAC,IAAS,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;4BACxC,OAAO,GAAG,OAAO,CAAC;wBACpB,CAAC;oBACH,CAAC,CAAC,CAAC;gBACL,CAAC;YACH,CAAC,CAAC;YAEF,QAAQ,CAAC,SAAS,GAAG;gBACnB,iBAAiB,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC9B,UAAU,EAAE,EAAE,CAAC;gBACf,UAAU,GAAG,SAAS,CAAC;YACzB,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@praxisjs/decorators",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -15,7 +15,7 @@
15
15
  "typescript": "^5.9.3"
16
16
  },
17
17
  "dependencies": {
18
- "@praxisjs/core": "0.4.1",
18
+ "@praxisjs/core": "0.4.2",
19
19
  "@praxisjs/shared": "0.2.0"
20
20
  },
21
21
  "scripts": {
@@ -0,0 +1,156 @@
1
+ import { describe, it, expect } from "vitest";
2
+
3
+ import { StatefulComponent, StatelessComponent } from "@praxisjs/core";
4
+
5
+ import { Component } from "../component/component";
6
+
7
+ // ── Component decorator ───────────────────────────────────────────────────────
8
+
9
+ describe("Component decorator", () => {
10
+ it("sets __isComponent = true on the enhanced class", () => {
11
+ class MyComp extends StatefulComponent {
12
+ render() { return null; }
13
+ }
14
+ const Enhanced = Component()(MyComp, {} as ClassDecoratorContext);
15
+ expect(Enhanced.__isComponent).toBe(true);
16
+ });
17
+
18
+ it("preserves the original class name", () => {
19
+ class MyButton extends StatefulComponent {
20
+ render() { return null; }
21
+ }
22
+ const Enhanced = Component()(MyButton, {} as ClassDecoratorContext);
23
+ expect(Enhanced.name).toBe("MyButton");
24
+ });
25
+
26
+ it("marks __isStateless = false for StatefulComponent subclasses", () => {
27
+ class MyStateful extends StatefulComponent {
28
+ render() { return null; }
29
+ }
30
+ const Enhanced = Component()(MyStateful, {} as ClassDecoratorContext);
31
+ expect(Enhanced.__isStateless).toBe(false);
32
+ });
33
+
34
+ it("marks __isStateless = true for StatelessComponent subclasses", () => {
35
+ class MyStateless extends StatelessComponent {
36
+ render() { return null; }
37
+ }
38
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
39
+ const Enhanced = Component()(MyStateless as any, {} as ClassDecoratorContext);
40
+ expect(Enhanced.__isStateless).toBe(true);
41
+ });
42
+
43
+ it("enhanced class can still be instantiated", () => {
44
+ class Counter extends StatefulComponent {
45
+ render() { return null; }
46
+ }
47
+ const Enhanced = Component()(Counter, {} as ClassDecoratorContext);
48
+ const instance = new Enhanced();
49
+ expect(instance).toBeInstanceOf(Counter);
50
+ });
51
+
52
+ it("returns a subclass of the original constructor", () => {
53
+ class Base extends StatefulComponent {
54
+ render() { return null; }
55
+ }
56
+ const Enhanced = Component()(Base, {} as ClassDecoratorContext);
57
+ expect(Enhanced.prototype).toBeInstanceOf(Base);
58
+ });
59
+
60
+ // ── Happy paths ──────────────────────────────────────────────────────────────
61
+
62
+ it("forwards constructor args — props reach the base constructor", () => {
63
+ class WithProps extends StatefulComponent {
64
+ render() { return null; }
65
+ }
66
+ const Enhanced = Component()(WithProps, {} as ClassDecoratorContext);
67
+ const instance = new Enhanced({ greeting: "hello" });
68
+ expect(instance.props.greeting).toBe("hello");
69
+ });
70
+
71
+ it("instance methods from the original class remain accessible", () => {
72
+ class Greeter extends StatefulComponent {
73
+ greet() { return "hello"; }
74
+ render() { return null; }
75
+ }
76
+ const Enhanced = Component()(Greeter, {} as ClassDecoratorContext);
77
+ const instance = new Enhanced();
78
+ expect((instance as Greeter).greet()).toBe("hello");
79
+ });
80
+
81
+ it("static properties of the original class are preserved on Enhanced", () => {
82
+ class WithStatic extends StatefulComponent {
83
+ static readonly version = "1.0";
84
+ render() { return null; }
85
+ }
86
+ const Enhanced = Component()(WithStatic, {} as ClassDecoratorContext);
87
+ expect((Enhanced as typeof WithStatic).version).toBe("1.0");
88
+ });
89
+
90
+ // ── Edge cases ───────────────────────────────────────────────────────────────
91
+
92
+ it("applying Component() twice preserves name and flags", () => {
93
+ class MyComp extends StatefulComponent {
94
+ render() { return null; }
95
+ }
96
+ const E1 = Component()(MyComp, {} as ClassDecoratorContext);
97
+ const E2 = Component()(E1, {} as ClassDecoratorContext);
98
+ expect(E2.__isComponent).toBe(true);
99
+ expect(E2.__isStateless).toBe(false);
100
+ expect(E2.name).toBe("MyComp"); // name survives double-wrap
101
+ });
102
+
103
+ it("deep StatelessComponent inheritance — __isStateless is still true", () => {
104
+ class BaseStateless extends StatelessComponent {
105
+ render() { return null; }
106
+ }
107
+ class DeepChild extends BaseStateless {
108
+ render() { return null; }
109
+ }
110
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
111
+ const Enhanced = Component()(DeepChild as any, {} as ClassDecoratorContext);
112
+ expect(Enhanced.__isStateless).toBe(true);
113
+ });
114
+
115
+ it("anonymous class gets an empty name", () => {
116
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
117
+ const Enhanced = Component()(
118
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
119
+ class extends StatefulComponent { render() { return null; } } as any,
120
+ {} as ClassDecoratorContext,
121
+ );
122
+ expect(Enhanced.name).toBe("");
123
+ });
124
+
125
+ it("__isComponent and __isStateless are static — not own properties of instances", () => {
126
+ class MyComp extends StatefulComponent {
127
+ render() { return null; }
128
+ }
129
+ const Enhanced = Component()(MyComp, {} as ClassDecoratorContext);
130
+ const instance = new Enhanced();
131
+ // Static fields live on the class, not on instances
132
+ expect(Object.prototype.hasOwnProperty.call(instance, "__isComponent")).toBe(false);
133
+ expect(Object.prototype.hasOwnProperty.call(instance, "__isStateless")).toBe(false);
134
+ });
135
+
136
+ it("subclassing Enhanced inherits __isComponent and __isStateless", () => {
137
+ class MyComp extends StatefulComponent {
138
+ render() { return null; }
139
+ }
140
+ const Enhanced = Component()(MyComp, {} as ClassDecoratorContext);
141
+ // `class Sub extends Enhanced` sets Object.getPrototypeOf(Sub) === Enhanced,
142
+ // making static fields visible through the chain. Simulate that here to
143
+ // avoid TS2510 (conflicting constructor return types in the intersection type).
144
+ const Sub = Object.create(Enhanced) as typeof Enhanced;
145
+ expect(Sub.__isComponent).toBe(true);
146
+ expect(Sub.__isStateless).toBe(false);
147
+ });
148
+
149
+ it("Enhanced is a different reference from the original constructor", () => {
150
+ class MyComp extends StatefulComponent {
151
+ render() { return null; }
152
+ }
153
+ const Enhanced = Component()(MyComp, {} as ClassDecoratorContext);
154
+ expect(Enhanced).not.toBe(MyComp);
155
+ });
156
+ });