rask-ui 0.2.5 → 0.2.7

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 (200) hide show
  1. package/dist/vdom/AbstractVNode.d.ts +20 -1
  2. package/dist/vdom/AbstractVNode.d.ts.map +1 -1
  3. package/dist/vdom/AbstractVNode.js +151 -12
  4. package/dist/vdom/ComponentVNode.d.ts +2 -2
  5. package/dist/vdom/ComponentVNode.d.ts.map +1 -1
  6. package/dist/vdom/ComponentVNode.js +17 -8
  7. package/dist/vdom/ElementVNode.d.ts +6 -9
  8. package/dist/vdom/ElementVNode.d.ts.map +1 -1
  9. package/dist/vdom/ElementVNode.js +103 -34
  10. package/dist/vdom/FragmentVNode.d.ts +2 -2
  11. package/dist/vdom/FragmentVNode.d.ts.map +1 -1
  12. package/dist/vdom/FragmentVNode.js +18 -7
  13. package/dist/vdom/RootVNode.d.ts +2 -2
  14. package/dist/vdom/RootVNode.d.ts.map +1 -1
  15. package/dist/vdom/RootVNode.js +15 -6
  16. package/dist/vdom/dom-utils.d.ts +6 -1
  17. package/dist/vdom/dom-utils.d.ts.map +1 -1
  18. package/dist/vdom/dom-utils.js +20 -1
  19. package/dist/vdom/types.d.ts +12 -0
  20. package/dist/vdom/types.d.ts.map +1 -1
  21. package/package.json +1 -1
  22. package/dist/component.d.ts +0 -38
  23. package/dist/component.d.ts.map +0 -1
  24. package/dist/component.js +0 -130
  25. package/dist/context.d.ts +0 -5
  26. package/dist/context.d.ts.map +0 -1
  27. package/dist/context.js +0 -29
  28. package/dist/createAsync.test.d.ts +0 -2
  29. package/dist/createAsync.test.d.ts.map +0 -1
  30. package/dist/createAsync.test.js +0 -110
  31. package/dist/createAsyncState.d.ts +0 -16
  32. package/dist/createAsyncState.d.ts.map +0 -1
  33. package/dist/createAsyncState.js +0 -24
  34. package/dist/createContext.test.d.ts +0 -2
  35. package/dist/createContext.test.d.ts.map +0 -1
  36. package/dist/createContext.test.js +0 -136
  37. package/dist/createMutation.test.d.ts +0 -2
  38. package/dist/createMutation.test.d.ts.map +0 -1
  39. package/dist/createMutation.test.js +0 -168
  40. package/dist/createQuery.test.d.ts +0 -2
  41. package/dist/createQuery.test.d.ts.map +0 -1
  42. package/dist/createQuery.test.js +0 -156
  43. package/dist/createRef.test.d.ts +0 -2
  44. package/dist/createRef.test.d.ts.map +0 -1
  45. package/dist/createRef.test.js +0 -80
  46. package/dist/createState.test.d.ts +0 -2
  47. package/dist/createState.test.d.ts.map +0 -1
  48. package/dist/createState.test.js +0 -111
  49. package/dist/createView.test.d.ts +0 -2
  50. package/dist/createView.test.d.ts.map +0 -1
  51. package/dist/createView.test.js +0 -203
  52. package/dist/error.test.d.ts +0 -2
  53. package/dist/error.test.d.ts.map +0 -1
  54. package/dist/error.test.js +0 -144
  55. package/dist/integration.test.d.ts +0 -2
  56. package/dist/integration.test.d.ts.map +0 -1
  57. package/dist/integration.test.js +0 -155
  58. package/dist/jsx.d.ts.map +0 -1
  59. package/dist/jsx.js +0 -42
  60. package/dist/observation.test.d.ts +0 -2
  61. package/dist/observation.test.d.ts.map +0 -1
  62. package/dist/observation.test.js +0 -113
  63. package/dist/render-test.d.ts +0 -2
  64. package/dist/render-test.d.ts.map +0 -1
  65. package/dist/render-test.js +0 -21
  66. package/dist/render.d.ts +0 -7
  67. package/dist/render.d.ts.map +0 -1
  68. package/dist/render.js +0 -77
  69. package/dist/suspense.d.ts +0 -25
  70. package/dist/suspense.d.ts.map +0 -1
  71. package/dist/suspense.js +0 -97
  72. package/dist/tests/class.test.d.ts +0 -2
  73. package/dist/tests/class.test.d.ts.map +0 -1
  74. package/dist/tests/class.test.js +0 -185
  75. package/dist/tests/complex-rendering.test.d.ts +0 -2
  76. package/dist/tests/complex-rendering.test.d.ts.map +0 -1
  77. package/dist/tests/complex-rendering.test.js +0 -400
  78. package/dist/tests/component.cleanup.test.d.ts +0 -2
  79. package/dist/tests/component.cleanup.test.d.ts.map +0 -1
  80. package/dist/tests/component.cleanup.test.js +0 -325
  81. package/dist/tests/component.counter.test.d.ts +0 -2
  82. package/dist/tests/component.counter.test.d.ts.map +0 -1
  83. package/dist/tests/component.counter.test.js +0 -124
  84. package/dist/tests/component.interaction.test.d.ts +0 -2
  85. package/dist/tests/component.interaction.test.d.ts.map +0 -1
  86. package/dist/tests/component.interaction.test.js +0 -73
  87. package/dist/tests/component.props.test.d.ts +0 -2
  88. package/dist/tests/component.props.test.d.ts.map +0 -1
  89. package/dist/tests/component.props.test.js +0 -334
  90. package/dist/tests/component.return-types.test.d.ts +0 -2
  91. package/dist/tests/component.return-types.test.d.ts.map +0 -1
  92. package/dist/tests/component.return-types.test.js +0 -357
  93. package/dist/tests/component.state.test.d.ts +0 -2
  94. package/dist/tests/component.state.test.d.ts.map +0 -1
  95. package/dist/tests/component.state.test.js +0 -135
  96. package/dist/tests/component.test.d.ts +0 -2
  97. package/dist/tests/component.test.d.ts.map +0 -1
  98. package/dist/tests/component.test.js +0 -63
  99. package/dist/tests/createAsync.test.d.ts +0 -2
  100. package/dist/tests/createAsync.test.d.ts.map +0 -1
  101. package/dist/tests/createAsync.test.js +0 -110
  102. package/dist/tests/createContext.test.d.ts +0 -2
  103. package/dist/tests/createContext.test.d.ts.map +0 -1
  104. package/dist/tests/createContext.test.js +0 -141
  105. package/dist/tests/createMutation.test.d.ts +0 -2
  106. package/dist/tests/createMutation.test.d.ts.map +0 -1
  107. package/dist/tests/createMutation.test.js +0 -168
  108. package/dist/tests/createQuery.test.d.ts +0 -2
  109. package/dist/tests/createQuery.test.d.ts.map +0 -1
  110. package/dist/tests/createQuery.test.js +0 -156
  111. package/dist/tests/createRef.test.d.ts +0 -2
  112. package/dist/tests/createRef.test.d.ts.map +0 -1
  113. package/dist/tests/createRef.test.js +0 -84
  114. package/dist/tests/createState.test.d.ts +0 -2
  115. package/dist/tests/createState.test.d.ts.map +0 -1
  116. package/dist/tests/createState.test.js +0 -103
  117. package/dist/tests/createView.test.d.ts +0 -2
  118. package/dist/tests/createView.test.d.ts.map +0 -1
  119. package/dist/tests/createView.test.js +0 -203
  120. package/dist/tests/edge-cases.test.d.ts +0 -2
  121. package/dist/tests/edge-cases.test.d.ts.map +0 -1
  122. package/dist/tests/edge-cases.test.js +0 -637
  123. package/dist/tests/error-no-boundary.test.d.ts +0 -2
  124. package/dist/tests/error-no-boundary.test.d.ts.map +0 -1
  125. package/dist/tests/error-no-boundary.test.js +0 -174
  126. package/dist/tests/error.test.d.ts +0 -2
  127. package/dist/tests/error.test.d.ts.map +0 -1
  128. package/dist/tests/error.test.js +0 -199
  129. package/dist/tests/fragment.test.d.ts +0 -2
  130. package/dist/tests/fragment.test.d.ts.map +0 -1
  131. package/dist/tests/fragment.test.js +0 -618
  132. package/dist/tests/integration.test.d.ts +0 -2
  133. package/dist/tests/integration.test.d.ts.map +0 -1
  134. package/dist/tests/integration.test.js +0 -192
  135. package/dist/tests/keys.test.d.ts +0 -2
  136. package/dist/tests/keys.test.d.ts.map +0 -1
  137. package/dist/tests/keys.test.js +0 -293
  138. package/dist/tests/mount.test.d.ts +0 -2
  139. package/dist/tests/mount.test.d.ts.map +0 -1
  140. package/dist/tests/mount.test.js +0 -91
  141. package/dist/tests/observation.test.d.ts +0 -2
  142. package/dist/tests/observation.test.d.ts.map +0 -1
  143. package/dist/tests/observation.test.js +0 -113
  144. package/dist/tests/patch.test.d.ts +0 -2
  145. package/dist/tests/patch.test.d.ts.map +0 -1
  146. package/dist/tests/patch.test.js +0 -498
  147. package/dist/tests/patchChildren.test.d.ts +0 -2
  148. package/dist/tests/patchChildren.test.d.ts.map +0 -1
  149. package/dist/tests/patchChildren.test.js +0 -405
  150. package/dist/tests/primitives.test.d.ts +0 -2
  151. package/dist/tests/primitives.test.d.ts.map +0 -1
  152. package/dist/tests/primitives.test.js +0 -132
  153. package/dist/vdom/class.test.d.ts +0 -2
  154. package/dist/vdom/class.test.d.ts.map +0 -1
  155. package/dist/vdom/class.test.js +0 -143
  156. package/dist/vdom/complex-rendering.test.d.ts +0 -2
  157. package/dist/vdom/complex-rendering.test.d.ts.map +0 -1
  158. package/dist/vdom/complex-rendering.test.js +0 -400
  159. package/dist/vdom/component.cleanup.test.d.ts +0 -2
  160. package/dist/vdom/component.cleanup.test.d.ts.map +0 -1
  161. package/dist/vdom/component.cleanup.test.js +0 -323
  162. package/dist/vdom/component.counter.test.d.ts +0 -2
  163. package/dist/vdom/component.counter.test.d.ts.map +0 -1
  164. package/dist/vdom/component.counter.test.js +0 -124
  165. package/dist/vdom/component.interaction.test.d.ts +0 -2
  166. package/dist/vdom/component.interaction.test.d.ts.map +0 -1
  167. package/dist/vdom/component.interaction.test.js +0 -73
  168. package/dist/vdom/component.props.test.d.ts +0 -2
  169. package/dist/vdom/component.props.test.d.ts.map +0 -1
  170. package/dist/vdom/component.props.test.js +0 -88
  171. package/dist/vdom/component.return-types.test.d.ts +0 -2
  172. package/dist/vdom/component.return-types.test.d.ts.map +0 -1
  173. package/dist/vdom/component.return-types.test.js +0 -357
  174. package/dist/vdom/component.state.test.d.ts +0 -2
  175. package/dist/vdom/component.state.test.d.ts.map +0 -1
  176. package/dist/vdom/component.state.test.js +0 -129
  177. package/dist/vdom/component.test.d.ts +0 -2
  178. package/dist/vdom/component.test.d.ts.map +0 -1
  179. package/dist/vdom/component.test.js +0 -63
  180. package/dist/vdom/edge-cases.test.d.ts +0 -2
  181. package/dist/vdom/edge-cases.test.d.ts.map +0 -1
  182. package/dist/vdom/edge-cases.test.js +0 -637
  183. package/dist/vdom/fragment.test.d.ts +0 -2
  184. package/dist/vdom/fragment.test.d.ts.map +0 -1
  185. package/dist/vdom/fragment.test.js +0 -618
  186. package/dist/vdom/keys.test.d.ts +0 -2
  187. package/dist/vdom/keys.test.d.ts.map +0 -1
  188. package/dist/vdom/keys.test.js +0 -293
  189. package/dist/vdom/mount.test.d.ts +0 -2
  190. package/dist/vdom/mount.test.d.ts.map +0 -1
  191. package/dist/vdom/mount.test.js +0 -91
  192. package/dist/vdom/patch.test.d.ts +0 -2
  193. package/dist/vdom/patch.test.d.ts.map +0 -1
  194. package/dist/vdom/patch.test.js +0 -498
  195. package/dist/vdom/patchChildren.test.d.ts +0 -2
  196. package/dist/vdom/patchChildren.test.d.ts.map +0 -1
  197. package/dist/vdom/patchChildren.test.js +0 -392
  198. package/dist/vdom/primitives.test.d.ts +0 -2
  199. package/dist/vdom/primitives.test.d.ts.map +0 -1
  200. package/dist/vdom/primitives.test.js +0 -132
@@ -1,405 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { AbstractVNode } from "../vdom/AbstractVNode";
3
- // Helper to convert MockVNode arrays to VNode arrays
4
- const toVNodes = (nodes) => nodes;
5
- // Mock VNode for testing
6
- class MockVNode extends AbstractVNode {
7
- mountCalls = 0;
8
- patchCalls = 0;
9
- unmountCalls = 0;
10
- patchedWith;
11
- constructor(key) {
12
- super();
13
- this.key = key;
14
- }
15
- mount(parent) {
16
- this.mountCalls++;
17
- this.parent = parent;
18
- this.elm = document.createTextNode(`mock-${this.key || "no-key"}`);
19
- return this.elm;
20
- }
21
- patch(newNode) {
22
- this.patchCalls++;
23
- this.patchedWith = newNode;
24
- // In real implementation, old node updates itself from new node
25
- // but keeps the same object reference
26
- }
27
- unmount() {
28
- this.unmountCalls++;
29
- delete this.elm;
30
- delete this.parent;
31
- }
32
- rerender() {
33
- // No-op for mock
34
- }
35
- }
36
- // Parent mock that has children
37
- class MockParentVNode extends MockVNode {
38
- constructor(initialChildren, key) {
39
- super(key);
40
- this.children = (initialChildren || []);
41
- }
42
- }
43
- describe("patchChildren (new approach: keep old, patch in new)", () => {
44
- describe("Edge cases", () => {
45
- it("should mount all new children when starting with empty", () => {
46
- const newChild1 = new MockVNode("a");
47
- const newChild2 = new MockVNode("b");
48
- const parent = new MockParentVNode([]);
49
- const { children: result, hasChangedStructure } = parent.patchChildren(toVNodes([newChild1, newChild2]));
50
- // New children should be mounted
51
- expect(newChild1.mountCalls).toBe(1);
52
- expect(newChild2.mountCalls).toBe(1);
53
- expect(newChild1.parent).toBe(parent);
54
- expect(newChild2.parent).toBe(parent);
55
- // Result should be the new children (since old was empty)
56
- expect(result).toEqual([newChild1, newChild2]);
57
- expect(hasChangedStructure).toBe(true);
58
- });
59
- it("should unmount all old children when new is empty", () => {
60
- const oldChild1 = new MockVNode("a");
61
- const oldChild2 = new MockVNode("b");
62
- const parent = new MockParentVNode([oldChild1, oldChild2]);
63
- const { children: result, hasChangedStructure } = parent.patchChildren(toVNodes([]));
64
- // Old children should be unmounted
65
- expect(oldChild1.unmountCalls).toBe(1);
66
- expect(oldChild2.unmountCalls).toBe(1);
67
- // Result should be empty
68
- expect(result).toEqual([]);
69
- expect(hasChangedStructure).toBe(true);
70
- });
71
- });
72
- describe("Patching with keys", () => {
73
- it("should reuse old VNodes when keys match", () => {
74
- const oldChild1 = new MockVNode("a");
75
- const oldChild2 = new MockVNode("b");
76
- const oldChild3 = new MockVNode("c");
77
- const parent = new MockParentVNode([oldChild1, oldChild2, oldChild3]);
78
- const newChild1 = new MockVNode("a");
79
- const newChild2 = new MockVNode("b");
80
- const newChild3 = new MockVNode("c");
81
- const { children: result, hasChangedStructure } = parent.patchChildren(toVNodes([newChild1, newChild2, newChild3]));
82
- // OLD children should be patched with new children
83
- expect(oldChild1.patchCalls).toBe(1);
84
- expect(oldChild2.patchCalls).toBe(1);
85
- expect(oldChild3.patchCalls).toBe(1);
86
- expect(oldChild1.patchedWith).toBe(newChild1);
87
- expect(oldChild2.patchedWith).toBe(newChild2);
88
- expect(oldChild3.patchedWith).toBe(newChild3);
89
- // NEW children should NOT be mounted
90
- expect(newChild1.mountCalls).toBe(0);
91
- expect(newChild2.mountCalls).toBe(0);
92
- expect(newChild3.mountCalls).toBe(0);
93
- // OLD children should NOT be unmounted
94
- expect(oldChild1.unmountCalls).toBe(0);
95
- expect(oldChild2.unmountCalls).toBe(0);
96
- expect(oldChild3.unmountCalls).toBe(0);
97
- // Result should still be the OLD children (reused)
98
- expect(result).toEqual([oldChild1, oldChild2, oldChild3]);
99
- expect(hasChangedStructure).toBe(false);
100
- });
101
- it("should handle reordered children with keys", () => {
102
- const oldChild1 = new MockVNode("a");
103
- const oldChild2 = new MockVNode("b");
104
- const oldChild3 = new MockVNode("c");
105
- const parent = new MockParentVNode([oldChild1, oldChild2, oldChild3]);
106
- // Reordered: c, a, b
107
- const newChild1 = new MockVNode("c");
108
- const newChild2 = new MockVNode("a");
109
- const newChild3 = new MockVNode("b");
110
- const { children: result, hasChangedStructure } = parent.patchChildren(toVNodes([newChild1, newChild2, newChild3]));
111
- // Old nodes should be patched with corresponding new nodes by key
112
- expect(oldChild1.patchedWith).toBe(newChild2); // a->a
113
- expect(oldChild2.patchedWith).toBe(newChild3); // b->b
114
- expect(oldChild3.patchedWith).toBe(newChild1); // c->c
115
- // No unmounts
116
- expect(oldChild1.unmountCalls).toBe(0);
117
- expect(oldChild2.unmountCalls).toBe(0);
118
- expect(oldChild3.unmountCalls).toBe(0);
119
- // Result should be old children in NEW order (c, a, b)
120
- expect(result).toEqual([oldChild3, oldChild1, oldChild2]);
121
- // Verify correct keys
122
- expect(result[0].key).toBe("c");
123
- expect(result[1].key).toBe("a");
124
- expect(result[2].key).toBe("b");
125
- expect(hasChangedStructure).toBe(true);
126
- });
127
- it("should mount new children and unmount removed children", () => {
128
- const oldChild1 = new MockVNode("a");
129
- const oldChild2 = new MockVNode("b");
130
- const oldChild3 = new MockVNode("c");
131
- const parent = new MockParentVNode([oldChild1, oldChild2, oldChild3]);
132
- // Remove 'b', add 'd'
133
- const newChild1 = new MockVNode("a");
134
- const newChild2 = new MockVNode("c");
135
- const newChild3 = new MockVNode("d");
136
- const { children: result, hasChangedStructure } = parent.patchChildren(toVNodes([newChild1, newChild2, newChild3]));
137
- // a and c should be patched (reused)
138
- expect(oldChild1.patchedWith).toBe(newChild1);
139
- expect(oldChild3.patchedWith).toBe(newChild2);
140
- // d should be mounted
141
- expect(newChild3.mountCalls).toBe(1);
142
- // b should be unmounted
143
- expect(oldChild2.unmountCalls).toBe(1);
144
- // Result should contain old a, old c, and new d
145
- expect(result).toContain(oldChild1);
146
- expect(result).toContain(oldChild3);
147
- expect(result).toContain(newChild3);
148
- expect(result).not.toContain(oldChild2);
149
- expect(result.length).toBe(3);
150
- expect(hasChangedStructure).toBe(true);
151
- });
152
- it("should replace all children when all keys change", () => {
153
- const oldChild1 = new MockVNode("a");
154
- const oldChild2 = new MockVNode("b");
155
- const parent = new MockParentVNode([oldChild1, oldChild2]);
156
- const newChild1 = new MockVNode("x");
157
- const newChild2 = new MockVNode("y");
158
- const { children: result, hasChangedStructure } = parent.patchChildren(toVNodes([newChild1, newChild2]));
159
- // All new children should be mounted
160
- expect(newChild1.mountCalls).toBe(1);
161
- expect(newChild2.mountCalls).toBe(1);
162
- // All old children should be unmounted
163
- expect(oldChild1.unmountCalls).toBe(1);
164
- expect(oldChild2.unmountCalls).toBe(1);
165
- // Result should be the new children
166
- expect(result).toEqual([newChild1, newChild2]);
167
- expect(hasChangedStructure).toBe(true);
168
- });
169
- });
170
- describe("Patching without keys (index-based)", () => {
171
- it("should patch children by index when no keys", () => {
172
- const oldChild1 = new MockVNode();
173
- const oldChild2 = new MockVNode();
174
- const oldChild3 = new MockVNode();
175
- const parent = new MockParentVNode([oldChild1, oldChild2, oldChild3]);
176
- const newChild1 = new MockVNode();
177
- const newChild2 = new MockVNode();
178
- const newChild3 = new MockVNode();
179
- const { children: result, hasChangedStructure } = parent.patchChildren(toVNodes([newChild1, newChild2, newChild3]));
180
- // Should patch by index: 0->0, 1->1, 2->2
181
- expect(oldChild1.patchedWith).toBe(newChild1);
182
- expect(oldChild2.patchedWith).toBe(newChild2);
183
- expect(oldChild3.patchedWith).toBe(newChild3);
184
- // No unmounts
185
- expect(oldChild1.unmountCalls).toBe(0);
186
- expect(oldChild2.unmountCalls).toBe(0);
187
- expect(oldChild3.unmountCalls).toBe(0);
188
- // Result should be old children (reused)
189
- expect(result).toEqual([oldChild1, oldChild2, oldChild3]);
190
- expect(hasChangedStructure).toBe(false);
191
- });
192
- it("should mount new children when growing without keys", () => {
193
- const oldChild1 = new MockVNode();
194
- const oldChild2 = new MockVNode();
195
- const parent = new MockParentVNode([oldChild1, oldChild2]);
196
- const newChild1 = new MockVNode();
197
- const newChild2 = new MockVNode();
198
- const newChild3 = new MockVNode();
199
- const newChild4 = new MockVNode();
200
- const { children: result, hasChangedStructure } = parent.patchChildren(toVNodes([newChild1, newChild2, newChild3, newChild4]));
201
- // First two should be patched (reused)
202
- expect(oldChild1.patchedWith).toBe(newChild1);
203
- expect(oldChild2.patchedWith).toBe(newChild2);
204
- // Last two should be mounted
205
- expect(newChild3.mountCalls).toBe(1);
206
- expect(newChild4.mountCalls).toBe(1);
207
- // No unmounts
208
- expect(oldChild1.unmountCalls).toBe(0);
209
- expect(oldChild2.unmountCalls).toBe(0);
210
- // Result should be [oldChild1, oldChild2, newChild3, newChild4]
211
- expect(result).toEqual([oldChild1, oldChild2, newChild3, newChild4]);
212
- expect(hasChangedStructure).toBe(true);
213
- });
214
- it("should unmount old children when shrinking without keys", () => {
215
- const oldChild1 = new MockVNode();
216
- const oldChild2 = new MockVNode();
217
- const oldChild3 = new MockVNode();
218
- const oldChild4 = new MockVNode();
219
- const parent = new MockParentVNode([
220
- oldChild1,
221
- oldChild2,
222
- oldChild3,
223
- oldChild4,
224
- ]);
225
- const newChild1 = new MockVNode();
226
- const newChild2 = new MockVNode();
227
- const { children: result, hasChangedStructure } = parent.patchChildren(toVNodes([newChild1, newChild2]));
228
- // First two should be patched
229
- expect(oldChild1.patchedWith).toBe(newChild1);
230
- expect(oldChild2.patchedWith).toBe(newChild2);
231
- // Last two old children should be unmounted
232
- expect(oldChild3.unmountCalls).toBe(1);
233
- expect(oldChild4.unmountCalls).toBe(1);
234
- // First two should not be unmounted
235
- expect(oldChild1.unmountCalls).toBe(0);
236
- expect(oldChild2.unmountCalls).toBe(0);
237
- // Result should be [oldChild1, oldChild2]
238
- expect(result).toEqual([oldChild1, oldChild2]);
239
- expect(hasChangedStructure).toBe(true);
240
- });
241
- });
242
- describe("Mixed keys and indices", () => {
243
- it("should handle mix of keyed and non-keyed children", () => {
244
- const oldChild1 = new MockVNode("a"); // key: "a"
245
- const oldChild2 = new MockVNode(); // key: undefined -> index 1
246
- const oldChild3 = new MockVNode("c"); // key: "c"
247
- const parent = new MockParentVNode([oldChild1, oldChild2, oldChild3]);
248
- const newChild1 = new MockVNode("a"); // key: "a"
249
- const newChild2 = new MockVNode(); // key: undefined -> index 1
250
- const newChild3 = new MockVNode("c"); // key: "c"
251
- const { children: result, hasChangedStructure } = parent.patchChildren(toVNodes([newChild1, newChild2, newChild3]));
252
- // Keyed children should patch by key
253
- expect(oldChild1.patchedWith).toBe(newChild1);
254
- expect(oldChild3.patchedWith).toBe(newChild3);
255
- // Non-keyed child should patch by index
256
- expect(oldChild2.patchedWith).toBe(newChild2);
257
- // No unmounts
258
- expect(oldChild1.unmountCalls).toBe(0);
259
- expect(oldChild2.unmountCalls).toBe(0);
260
- expect(oldChild3.unmountCalls).toBe(0);
261
- // Result should be old children (reused)
262
- expect(result).toEqual([oldChild1, oldChild2, oldChild3]);
263
- expect(hasChangedStructure).toBe(false);
264
- });
265
- });
266
- describe("Real-world scenarios", () => {
267
- it("should handle conditional rendering (null -> component)", () => {
268
- const oldChild1 = new MockVNode("title");
269
- const parent = new MockParentVNode([oldChild1]);
270
- const newChild1 = new MockVNode("title");
271
- const newChild2 = new MockVNode("details");
272
- const { children: result, hasChangedStructure } = parent.patchChildren(toVNodes([newChild1, newChild2]));
273
- // Title should be patched (reused)
274
- expect(oldChild1.patchedWith).toBe(newChild1);
275
- // Details should be mounted
276
- expect(newChild2.mountCalls).toBe(1);
277
- // No unmounts
278
- expect(oldChild1.unmountCalls).toBe(0);
279
- // Result should be [oldChild1, newChild2]
280
- expect(result).toEqual([oldChild1, newChild2]);
281
- expect(hasChangedStructure).toBe(true);
282
- });
283
- it("should handle conditional rendering (component -> null)", () => {
284
- const oldChild1 = new MockVNode("title");
285
- const oldChild2 = new MockVNode("details");
286
- const parent = new MockParentVNode([oldChild1, oldChild2]);
287
- const newChild1 = new MockVNode("title");
288
- const { children: result, hasChangedStructure } = parent.patchChildren(toVNodes([newChild1]));
289
- // Title should be patched (reused)
290
- expect(oldChild1.patchedWith).toBe(newChild1);
291
- // Details should be unmounted
292
- expect(oldChild2.unmountCalls).toBe(1);
293
- // Title should not be unmounted
294
- expect(oldChild1.unmountCalls).toBe(0);
295
- // Result should be [oldChild1]
296
- expect(result).toEqual([oldChild1]);
297
- expect(hasChangedStructure).toBe(true);
298
- });
299
- it("should handle list with items added at beginning", () => {
300
- const oldChild1 = new MockVNode("item-1");
301
- const oldChild2 = new MockVNode("item-2");
302
- const parent = new MockParentVNode([oldChild1, oldChild2]);
303
- const newChild1 = new MockVNode("item-0"); // New item at start
304
- const newChild2 = new MockVNode("item-1");
305
- const newChild3 = new MockVNode("item-2");
306
- const { children: result, hasChangedStructure } = parent.patchChildren(toVNodes([newChild1, newChild2, newChild3]));
307
- // New item should be mounted
308
- expect(newChild1.mountCalls).toBe(1);
309
- // Existing items should be patched (reused)
310
- expect(oldChild1.patchedWith).toBe(newChild2);
311
- expect(oldChild2.patchedWith).toBe(newChild3);
312
- // No unmounts
313
- expect(oldChild1.unmountCalls).toBe(0);
314
- expect(oldChild2.unmountCalls).toBe(0);
315
- // Result should be [newChild1, oldChild1, oldChild2]
316
- expect(result).toEqual([newChild1, oldChild1, oldChild2]);
317
- expect(hasChangedStructure).toBe(true);
318
- });
319
- it("should handle list with items added at end", () => {
320
- const oldChild1 = new MockVNode("item-1");
321
- const oldChild2 = new MockVNode("item-2");
322
- const parent = new MockParentVNode([oldChild1, oldChild2]);
323
- const newChild1 = new MockVNode("item-1");
324
- const newChild2 = new MockVNode("item-2");
325
- const newChild3 = new MockVNode("item-3"); // New item at end
326
- const { children: result, hasChangedStructure } = parent.patchChildren(toVNodes([newChild1, newChild2, newChild3]));
327
- // Existing items should be patched (reused)
328
- expect(oldChild1.patchedWith).toBe(newChild1);
329
- expect(oldChild2.patchedWith).toBe(newChild2);
330
- // New item should be mounted
331
- expect(newChild3.mountCalls).toBe(1);
332
- // No unmounts
333
- expect(oldChild1.unmountCalls).toBe(0);
334
- expect(oldChild2.unmountCalls).toBe(0);
335
- // Result should be [oldChild1, oldChild2, newChild3]
336
- expect(result).toEqual([oldChild1, oldChild2, newChild3]);
337
- expect(hasChangedStructure).toBe(true);
338
- });
339
- it("should handle list with item removed from middle", () => {
340
- const oldChild1 = new MockVNode("item-1");
341
- const oldChild2 = new MockVNode("item-2");
342
- const oldChild3 = new MockVNode("item-3");
343
- const parent = new MockParentVNode([oldChild1, oldChild2, oldChild3]);
344
- const newChild1 = new MockVNode("item-1");
345
- const newChild2 = new MockVNode("item-3"); // item-2 removed
346
- const { children: result, hasChangedStructure } = parent.patchChildren(toVNodes([newChild1, newChild2]));
347
- // item-1 and item-3 should be patched (reused)
348
- expect(oldChild1.patchedWith).toBe(newChild1);
349
- expect(oldChild3.patchedWith).toBe(newChild2);
350
- // item-2 should be unmounted
351
- expect(oldChild2.unmountCalls).toBe(1);
352
- // Others should not be unmounted
353
- expect(oldChild1.unmountCalls).toBe(0);
354
- expect(oldChild3.unmountCalls).toBe(0);
355
- // Result should be [oldChild1, oldChild3]
356
- expect(result).toEqual([oldChild1, oldChild3]);
357
- expect(hasChangedStructure).toBe(true);
358
- });
359
- it("should handle empty -> multiple children", () => {
360
- const parent = new MockParentVNode([]);
361
- const newChild1 = new MockVNode("a");
362
- const newChild2 = new MockVNode("b");
363
- const newChild3 = new MockVNode("c");
364
- const { children: result, hasChangedStructure } = parent.patchChildren(toVNodes([newChild1, newChild2, newChild3]));
365
- // All should be mounted
366
- expect(newChild1.mountCalls).toBe(1);
367
- expect(newChild2.mountCalls).toBe(1);
368
- expect(newChild3.mountCalls).toBe(1);
369
- // Result should be the new children
370
- expect(result).toEqual([newChild1, newChild2, newChild3]);
371
- expect(hasChangedStructure).toBe(true);
372
- });
373
- it("should handle multiple children -> empty", () => {
374
- const oldChild1 = new MockVNode("a");
375
- const oldChild2 = new MockVNode("b");
376
- const oldChild3 = new MockVNode("c");
377
- const parent = new MockParentVNode([oldChild1, oldChild2, oldChild3]);
378
- const { children: result, hasChangedStructure } = parent.patchChildren(toVNodes([]));
379
- // All should be unmounted
380
- expect(oldChild1.unmountCalls).toBe(1);
381
- expect(oldChild2.unmountCalls).toBe(1);
382
- expect(oldChild3.unmountCalls).toBe(1);
383
- // Result should be empty
384
- expect(result).toEqual([]);
385
- expect(hasChangedStructure).toBe(true);
386
- });
387
- });
388
- describe("Object reference preservation", () => {
389
- it("should preserve old VNode object references when patching", () => {
390
- const oldChild1 = new MockVNode("a");
391
- const oldChild2 = new MockVNode("b");
392
- const parent = new MockParentVNode([oldChild1, oldChild2]);
393
- const newChild1 = new MockVNode("a");
394
- const newChild2 = new MockVNode("b");
395
- const { children: result, hasChangedStructure } = parent.patchChildren(toVNodes([newChild1, newChild2]));
396
- // The result should contain the EXACT SAME object references as the old children
397
- expect(result[0]).toBe(oldChild1); // Same object reference
398
- expect(result[1]).toBe(oldChild2); // Same object reference
399
- // NOT the new children
400
- expect(result[0]).not.toBe(newChild1);
401
- expect(result[1]).not.toBe(newChild2);
402
- expect(hasChangedStructure).toBe(false);
403
- });
404
- });
405
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=primitives.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"primitives.test.d.ts","sourceRoot":"","sources":["../../src/tests/primitives.test.ts"],"names":[],"mappings":""}
@@ -1,132 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { jsx, render } from "../vdom/index";
3
- describe("VDOM Primitives", () => {
4
- it("should render element with string child", () => {
5
- // Create a container element
6
- const container = document.createElement("div");
7
- // Create vnode with string child
8
- const vnode = jsx("div", {
9
- children: "Hello World",
10
- });
11
- // Render the vnode
12
- render(vnode, container);
13
- // Verify string was rendered as text content
14
- const div = container.children[0];
15
- expect(div.textContent).toBe("Hello World");
16
- expect(div.childNodes.length).toBe(1);
17
- expect(div.childNodes[0].nodeType).toBe(Node.TEXT_NODE);
18
- });
19
- it("should render element with number child", () => {
20
- // Create a container element
21
- const container = document.createElement("div");
22
- // Create vnode with number child
23
- const vnode = jsx("span", {
24
- children: 42,
25
- });
26
- // Render the vnode
27
- render(vnode, container);
28
- // Verify number was rendered as text content
29
- const span = container.children[0];
30
- expect(span.textContent).toBe("42");
31
- expect(span.childNodes.length).toBe(1);
32
- expect(span.childNodes[0].nodeType).toBe(Node.TEXT_NODE);
33
- });
34
- it("should render element with null child", () => {
35
- // Create a container element
36
- const container = document.createElement("div");
37
- // Create vnode with null child
38
- const vnode = jsx("div", {
39
- children: null,
40
- });
41
- // Render the vnode
42
- render(vnode, container);
43
- // Verify null renders as empty
44
- const div = container.children[0];
45
- expect(div.childNodes.length).toBe(0);
46
- });
47
- it("should render element with undefined child", () => {
48
- // Create a container element
49
- const container = document.createElement("div");
50
- // Create vnode with undefined child
51
- const vnode = jsx("div", {
52
- children: undefined,
53
- });
54
- // Render the vnode
55
- render(vnode, container);
56
- // Verify undefined renders as empty
57
- const div = container.children[0];
58
- expect(div.childNodes.length).toBe(0);
59
- });
60
- it("should render element with mixed children including primitives", () => {
61
- // Create a container element
62
- const container = document.createElement("div");
63
- // Create vnode with mixed children
64
- const vnode = jsx("div", {
65
- children: [
66
- "Text before",
67
- jsx("span", { textContent: "middle" }),
68
- "Text after",
69
- 42,
70
- null,
71
- jsx("div", { textContent: "end" }),
72
- ],
73
- });
74
- // Render the vnode
75
- render(vnode, container);
76
- // Verify mixed children were rendered correctly
77
- const div = container.children[0];
78
- // Should have: text node, span, text node, text node (42), div
79
- // null should be skipped
80
- expect(div.childNodes.length).toBe(5);
81
- expect(div.childNodes[0].nodeType).toBe(Node.TEXT_NODE);
82
- expect(div.childNodes[0].textContent).toBe("Text before");
83
- expect(div.childNodes[1].tagName).toBe("SPAN");
84
- expect(div.childNodes[2].textContent).toBe("Text after");
85
- expect(div.childNodes[3].textContent).toBe("42");
86
- expect(div.childNodes[4].tagName).toBe("DIV");
87
- });
88
- it("should render element with boolean children", () => {
89
- // Create a container element
90
- const container = document.createElement("div");
91
- // Create vnode with boolean children
92
- const vnode = jsx("div", {
93
- children: [true, false, "visible"],
94
- });
95
- // Render the vnode
96
- render(vnode, container);
97
- // Verify booleans render as empty (like React)
98
- const div = container.children[0];
99
- // Should only have the text node "visible", booleans should be skipped
100
- expect(div.childNodes.length).toBe(1);
101
- expect(div.childNodes[0].textContent).toBe("visible");
102
- });
103
- it("should render element with zero as child", () => {
104
- // Create a container element
105
- const container = document.createElement("div");
106
- // Create vnode with zero as child (should render, not be treated as falsy)
107
- const vnode = jsx("div", {
108
- children: 0,
109
- });
110
- // Render the vnode
111
- render(vnode, container);
112
- // Verify zero is rendered
113
- const div = container.children[0];
114
- expect(div.textContent).toBe("0");
115
- expect(div.childNodes.length).toBe(1);
116
- });
117
- it("should render element with empty string as child", () => {
118
- // Create a container element
119
- const container = document.createElement("div");
120
- // Create vnode with empty string as child
121
- const vnode = jsx("div", {
122
- children: "",
123
- });
124
- // Render the vnode
125
- render(vnode, container);
126
- // Verify empty string renders as empty text node
127
- const div = container.children[0];
128
- expect(div.textContent).toBe("");
129
- expect(div.childNodes.length).toBe(1);
130
- expect(div.childNodes[0].nodeType).toBe(Node.TEXT_NODE);
131
- });
132
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=class.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"class.test.d.ts","sourceRoot":"","sources":["../../src/vdom/class.test.tsx"],"names":[],"mappings":""}