rask-ui 0.2.5 → 0.2.6

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 (195) 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 +142 -11
  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 +10 -5
  7. package/dist/vdom/ElementVNode.d.ts +2 -8
  8. package/dist/vdom/ElementVNode.d.ts.map +1 -1
  9. package/dist/vdom/ElementVNode.js +11 -31
  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 +11 -6
  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 +7 -5
  16. package/package.json +1 -1
  17. package/dist/component.d.ts +0 -38
  18. package/dist/component.d.ts.map +0 -1
  19. package/dist/component.js +0 -130
  20. package/dist/context.d.ts +0 -5
  21. package/dist/context.d.ts.map +0 -1
  22. package/dist/context.js +0 -29
  23. package/dist/createAsync.test.d.ts +0 -2
  24. package/dist/createAsync.test.d.ts.map +0 -1
  25. package/dist/createAsync.test.js +0 -110
  26. package/dist/createAsyncState.d.ts +0 -16
  27. package/dist/createAsyncState.d.ts.map +0 -1
  28. package/dist/createAsyncState.js +0 -24
  29. package/dist/createContext.test.d.ts +0 -2
  30. package/dist/createContext.test.d.ts.map +0 -1
  31. package/dist/createContext.test.js +0 -136
  32. package/dist/createMutation.test.d.ts +0 -2
  33. package/dist/createMutation.test.d.ts.map +0 -1
  34. package/dist/createMutation.test.js +0 -168
  35. package/dist/createQuery.test.d.ts +0 -2
  36. package/dist/createQuery.test.d.ts.map +0 -1
  37. package/dist/createQuery.test.js +0 -156
  38. package/dist/createRef.test.d.ts +0 -2
  39. package/dist/createRef.test.d.ts.map +0 -1
  40. package/dist/createRef.test.js +0 -80
  41. package/dist/createState.test.d.ts +0 -2
  42. package/dist/createState.test.d.ts.map +0 -1
  43. package/dist/createState.test.js +0 -111
  44. package/dist/createView.test.d.ts +0 -2
  45. package/dist/createView.test.d.ts.map +0 -1
  46. package/dist/createView.test.js +0 -203
  47. package/dist/error.test.d.ts +0 -2
  48. package/dist/error.test.d.ts.map +0 -1
  49. package/dist/error.test.js +0 -144
  50. package/dist/integration.test.d.ts +0 -2
  51. package/dist/integration.test.d.ts.map +0 -1
  52. package/dist/integration.test.js +0 -155
  53. package/dist/jsx.d.ts.map +0 -1
  54. package/dist/jsx.js +0 -42
  55. package/dist/observation.test.d.ts +0 -2
  56. package/dist/observation.test.d.ts.map +0 -1
  57. package/dist/observation.test.js +0 -113
  58. package/dist/render-test.d.ts +0 -2
  59. package/dist/render-test.d.ts.map +0 -1
  60. package/dist/render-test.js +0 -21
  61. package/dist/render.d.ts +0 -7
  62. package/dist/render.d.ts.map +0 -1
  63. package/dist/render.js +0 -77
  64. package/dist/suspense.d.ts +0 -25
  65. package/dist/suspense.d.ts.map +0 -1
  66. package/dist/suspense.js +0 -97
  67. package/dist/tests/class.test.d.ts +0 -2
  68. package/dist/tests/class.test.d.ts.map +0 -1
  69. package/dist/tests/class.test.js +0 -185
  70. package/dist/tests/complex-rendering.test.d.ts +0 -2
  71. package/dist/tests/complex-rendering.test.d.ts.map +0 -1
  72. package/dist/tests/complex-rendering.test.js +0 -400
  73. package/dist/tests/component.cleanup.test.d.ts +0 -2
  74. package/dist/tests/component.cleanup.test.d.ts.map +0 -1
  75. package/dist/tests/component.cleanup.test.js +0 -325
  76. package/dist/tests/component.counter.test.d.ts +0 -2
  77. package/dist/tests/component.counter.test.d.ts.map +0 -1
  78. package/dist/tests/component.counter.test.js +0 -124
  79. package/dist/tests/component.interaction.test.d.ts +0 -2
  80. package/dist/tests/component.interaction.test.d.ts.map +0 -1
  81. package/dist/tests/component.interaction.test.js +0 -73
  82. package/dist/tests/component.props.test.d.ts +0 -2
  83. package/dist/tests/component.props.test.d.ts.map +0 -1
  84. package/dist/tests/component.props.test.js +0 -334
  85. package/dist/tests/component.return-types.test.d.ts +0 -2
  86. package/dist/tests/component.return-types.test.d.ts.map +0 -1
  87. package/dist/tests/component.return-types.test.js +0 -357
  88. package/dist/tests/component.state.test.d.ts +0 -2
  89. package/dist/tests/component.state.test.d.ts.map +0 -1
  90. package/dist/tests/component.state.test.js +0 -135
  91. package/dist/tests/component.test.d.ts +0 -2
  92. package/dist/tests/component.test.d.ts.map +0 -1
  93. package/dist/tests/component.test.js +0 -63
  94. package/dist/tests/createAsync.test.d.ts +0 -2
  95. package/dist/tests/createAsync.test.d.ts.map +0 -1
  96. package/dist/tests/createAsync.test.js +0 -110
  97. package/dist/tests/createContext.test.d.ts +0 -2
  98. package/dist/tests/createContext.test.d.ts.map +0 -1
  99. package/dist/tests/createContext.test.js +0 -141
  100. package/dist/tests/createMutation.test.d.ts +0 -2
  101. package/dist/tests/createMutation.test.d.ts.map +0 -1
  102. package/dist/tests/createMutation.test.js +0 -168
  103. package/dist/tests/createQuery.test.d.ts +0 -2
  104. package/dist/tests/createQuery.test.d.ts.map +0 -1
  105. package/dist/tests/createQuery.test.js +0 -156
  106. package/dist/tests/createRef.test.d.ts +0 -2
  107. package/dist/tests/createRef.test.d.ts.map +0 -1
  108. package/dist/tests/createRef.test.js +0 -84
  109. package/dist/tests/createState.test.d.ts +0 -2
  110. package/dist/tests/createState.test.d.ts.map +0 -1
  111. package/dist/tests/createState.test.js +0 -103
  112. package/dist/tests/createView.test.d.ts +0 -2
  113. package/dist/tests/createView.test.d.ts.map +0 -1
  114. package/dist/tests/createView.test.js +0 -203
  115. package/dist/tests/edge-cases.test.d.ts +0 -2
  116. package/dist/tests/edge-cases.test.d.ts.map +0 -1
  117. package/dist/tests/edge-cases.test.js +0 -637
  118. package/dist/tests/error-no-boundary.test.d.ts +0 -2
  119. package/dist/tests/error-no-boundary.test.d.ts.map +0 -1
  120. package/dist/tests/error-no-boundary.test.js +0 -174
  121. package/dist/tests/error.test.d.ts +0 -2
  122. package/dist/tests/error.test.d.ts.map +0 -1
  123. package/dist/tests/error.test.js +0 -199
  124. package/dist/tests/fragment.test.d.ts +0 -2
  125. package/dist/tests/fragment.test.d.ts.map +0 -1
  126. package/dist/tests/fragment.test.js +0 -618
  127. package/dist/tests/integration.test.d.ts +0 -2
  128. package/dist/tests/integration.test.d.ts.map +0 -1
  129. package/dist/tests/integration.test.js +0 -192
  130. package/dist/tests/keys.test.d.ts +0 -2
  131. package/dist/tests/keys.test.d.ts.map +0 -1
  132. package/dist/tests/keys.test.js +0 -293
  133. package/dist/tests/mount.test.d.ts +0 -2
  134. package/dist/tests/mount.test.d.ts.map +0 -1
  135. package/dist/tests/mount.test.js +0 -91
  136. package/dist/tests/observation.test.d.ts +0 -2
  137. package/dist/tests/observation.test.d.ts.map +0 -1
  138. package/dist/tests/observation.test.js +0 -113
  139. package/dist/tests/patch.test.d.ts +0 -2
  140. package/dist/tests/patch.test.d.ts.map +0 -1
  141. package/dist/tests/patch.test.js +0 -498
  142. package/dist/tests/patchChildren.test.d.ts +0 -2
  143. package/dist/tests/patchChildren.test.d.ts.map +0 -1
  144. package/dist/tests/patchChildren.test.js +0 -405
  145. package/dist/tests/primitives.test.d.ts +0 -2
  146. package/dist/tests/primitives.test.d.ts.map +0 -1
  147. package/dist/tests/primitives.test.js +0 -132
  148. package/dist/vdom/class.test.d.ts +0 -2
  149. package/dist/vdom/class.test.d.ts.map +0 -1
  150. package/dist/vdom/class.test.js +0 -143
  151. package/dist/vdom/complex-rendering.test.d.ts +0 -2
  152. package/dist/vdom/complex-rendering.test.d.ts.map +0 -1
  153. package/dist/vdom/complex-rendering.test.js +0 -400
  154. package/dist/vdom/component.cleanup.test.d.ts +0 -2
  155. package/dist/vdom/component.cleanup.test.d.ts.map +0 -1
  156. package/dist/vdom/component.cleanup.test.js +0 -323
  157. package/dist/vdom/component.counter.test.d.ts +0 -2
  158. package/dist/vdom/component.counter.test.d.ts.map +0 -1
  159. package/dist/vdom/component.counter.test.js +0 -124
  160. package/dist/vdom/component.interaction.test.d.ts +0 -2
  161. package/dist/vdom/component.interaction.test.d.ts.map +0 -1
  162. package/dist/vdom/component.interaction.test.js +0 -73
  163. package/dist/vdom/component.props.test.d.ts +0 -2
  164. package/dist/vdom/component.props.test.d.ts.map +0 -1
  165. package/dist/vdom/component.props.test.js +0 -88
  166. package/dist/vdom/component.return-types.test.d.ts +0 -2
  167. package/dist/vdom/component.return-types.test.d.ts.map +0 -1
  168. package/dist/vdom/component.return-types.test.js +0 -357
  169. package/dist/vdom/component.state.test.d.ts +0 -2
  170. package/dist/vdom/component.state.test.d.ts.map +0 -1
  171. package/dist/vdom/component.state.test.js +0 -129
  172. package/dist/vdom/component.test.d.ts +0 -2
  173. package/dist/vdom/component.test.d.ts.map +0 -1
  174. package/dist/vdom/component.test.js +0 -63
  175. package/dist/vdom/edge-cases.test.d.ts +0 -2
  176. package/dist/vdom/edge-cases.test.d.ts.map +0 -1
  177. package/dist/vdom/edge-cases.test.js +0 -637
  178. package/dist/vdom/fragment.test.d.ts +0 -2
  179. package/dist/vdom/fragment.test.d.ts.map +0 -1
  180. package/dist/vdom/fragment.test.js +0 -618
  181. package/dist/vdom/keys.test.d.ts +0 -2
  182. package/dist/vdom/keys.test.d.ts.map +0 -1
  183. package/dist/vdom/keys.test.js +0 -293
  184. package/dist/vdom/mount.test.d.ts +0 -2
  185. package/dist/vdom/mount.test.d.ts.map +0 -1
  186. package/dist/vdom/mount.test.js +0 -91
  187. package/dist/vdom/patch.test.d.ts +0 -2
  188. package/dist/vdom/patch.test.d.ts.map +0 -1
  189. package/dist/vdom/patch.test.js +0 -498
  190. package/dist/vdom/patchChildren.test.d.ts +0 -2
  191. package/dist/vdom/patchChildren.test.d.ts.map +0 -1
  192. package/dist/vdom/patchChildren.test.js +0 -392
  193. package/dist/vdom/primitives.test.d.ts +0 -2
  194. package/dist/vdom/primitives.test.d.ts.map +0 -1
  195. package/dist/vdom/primitives.test.js +0 -132
@@ -1,637 +0,0 @@
1
- import { describe, it, expect, vi } from "vitest";
2
- import { jsx, render } from "./index";
3
- import { Fragment } from "./FragmentVNode";
4
- import { createState } from "../createState";
5
- describe("VDOM Edge Cases", () => {
6
- describe("Text Node Patching", () => {
7
- it("should patch element to text node", async () => {
8
- const container = document.createElement("div");
9
- let stateFn;
10
- const App = () => {
11
- const state = createState({ showElement: true });
12
- stateFn = state;
13
- return () => jsx("div", {
14
- children: state.showElement
15
- ? [jsx("span", { children: ["Element"] })]
16
- : ["Text"],
17
- });
18
- };
19
- render(jsx(App, {}), container);
20
- const wrapper = container.children[0];
21
- expect(wrapper.children.length).toBe(1);
22
- expect(wrapper.children[0].tagName).toBe("SPAN");
23
- stateFn.showElement = false;
24
- await new Promise((resolve) => setTimeout(resolve, 0));
25
- expect(wrapper.childNodes.length).toBe(1);
26
- expect(wrapper.childNodes[0].nodeType).toBe(Node.TEXT_NODE);
27
- expect(wrapper.textContent).toBe("Text");
28
- });
29
- it("should patch text node to element", async () => {
30
- const container = document.createElement("div");
31
- let stateFn;
32
- const App = () => {
33
- const state = createState({ showText: true });
34
- stateFn = state;
35
- return () => jsx("div", {
36
- children: state.showText
37
- ? ["Text"]
38
- : [jsx("span", { children: ["Element"] })],
39
- });
40
- };
41
- render(jsx(App, {}), container);
42
- const wrapper = container.children[0];
43
- expect(wrapper.childNodes[0].nodeType).toBe(Node.TEXT_NODE);
44
- stateFn.showText = false;
45
- await new Promise((resolve) => setTimeout(resolve, 0));
46
- expect(wrapper.children.length).toBe(1);
47
- expect(wrapper.children[0].tagName).toBe("SPAN");
48
- });
49
- it("should patch text node with different text", async () => {
50
- const container = document.createElement("div");
51
- let stateFn;
52
- const App = () => {
53
- const state = createState({ text: "Old Text" });
54
- stateFn = state;
55
- return () => jsx("div", {
56
- children: [state.text],
57
- });
58
- };
59
- render(jsx(App, {}), container);
60
- const wrapper = container.children[0];
61
- expect(wrapper.textContent).toBe("Old Text");
62
- stateFn.text = "New Text";
63
- await new Promise((resolve) => setTimeout(resolve, 0));
64
- expect(wrapper.textContent).toBe("New Text");
65
- expect(wrapper.childNodes.length).toBe(1);
66
- expect(wrapper.childNodes[0].nodeType).toBe(Node.TEXT_NODE);
67
- });
68
- it("should patch multiple text nodes", async () => {
69
- const container = document.createElement("div");
70
- let stateFn;
71
- const App = () => {
72
- const state = createState({ texts: ["First", "Second"] });
73
- stateFn = state;
74
- return () => jsx("div", {
75
- children: state.texts,
76
- });
77
- };
78
- render(jsx(App, {}), container);
79
- const wrapper = container.children[0];
80
- expect(wrapper.childNodes.length).toBe(2);
81
- stateFn.texts = ["Updated", "Text", "Nodes"];
82
- await new Promise((resolve) => setTimeout(resolve, 0));
83
- expect(wrapper.childNodes.length).toBe(3);
84
- expect(wrapper.childNodes[0].textContent).toBe("Updated");
85
- expect(wrapper.childNodes[1].textContent).toBe("Text");
86
- expect(wrapper.childNodes[2].textContent).toBe("Nodes");
87
- });
88
- });
89
- describe("Mixed Content Patching", () => {
90
- it("should patch mixed elements and text nodes", async () => {
91
- const container = document.createElement("div");
92
- let stateFn;
93
- const App = () => {
94
- const state = createState({ version: 1 });
95
- stateFn = state;
96
- return () => jsx("div", {
97
- children: state.version === 1
98
- ? ["Text", jsx("span", { children: ["Span"] }), "More text"]
99
- : [
100
- jsx("div", { children: ["Div"] }),
101
- "Middle",
102
- jsx("button", { children: ["Button"] }),
103
- ],
104
- });
105
- };
106
- render(jsx(App, {}), container);
107
- const wrapper = container.children[0];
108
- expect(wrapper.childNodes.length).toBe(3);
109
- stateFn.version = 2;
110
- await new Promise((resolve) => setTimeout(resolve, 0));
111
- expect(wrapper.childNodes.length).toBe(3);
112
- expect(wrapper.childNodes[0].tagName).toBe("DIV");
113
- expect(wrapper.childNodes[1].nodeType).toBe(Node.TEXT_NODE);
114
- expect(wrapper.childNodes[1].textContent).toBe("Middle");
115
- expect(wrapper.childNodes[2].tagName).toBe("BUTTON");
116
- });
117
- it("should patch from all text to all elements", async () => {
118
- const container = document.createElement("div");
119
- let stateFn;
120
- const App = () => {
121
- const state = createState({ showElements: false });
122
- stateFn = state;
123
- return () => jsx("div", {
124
- children: state.showElements
125
- ? [
126
- jsx("span", { children: ["A"] }),
127
- jsx("span", { children: ["B"] }),
128
- jsx("span", { children: ["C"] }),
129
- ]
130
- : ["One", "Two", "Three"],
131
- });
132
- };
133
- render(jsx(App, {}), container);
134
- const wrapper = container.children[0];
135
- expect(wrapper.childNodes.length).toBe(3);
136
- expect(wrapper.childNodes[0].nodeType).toBe(Node.TEXT_NODE);
137
- stateFn.showElements = true;
138
- await new Promise((resolve) => setTimeout(resolve, 0));
139
- expect(wrapper.children.length).toBe(3);
140
- expect(wrapper.children[0].tagName).toBe("SPAN");
141
- expect(wrapper.children[1].tagName).toBe("SPAN");
142
- expect(wrapper.children[2].tagName).toBe("SPAN");
143
- });
144
- it("should patch from all elements to all text", async () => {
145
- const container = document.createElement("div");
146
- let stateFn;
147
- const App = () => {
148
- const state = createState({ showElements: true });
149
- stateFn = state;
150
- return () => jsx("div", {
151
- children: state.showElements
152
- ? [
153
- jsx("span", { children: ["A"] }),
154
- jsx("span", { children: ["B"] }),
155
- jsx("span", { children: ["C"] }),
156
- ]
157
- : ["One", "Two", "Three"],
158
- });
159
- };
160
- render(jsx(App, {}), container);
161
- const wrapper = container.children[0];
162
- expect(wrapper.children.length).toBe(3);
163
- stateFn.showElements = false;
164
- await new Promise((resolve) => setTimeout(resolve, 0));
165
- expect(wrapper.childNodes.length).toBe(3);
166
- expect(wrapper.childNodes[0].nodeType).toBe(Node.TEXT_NODE);
167
- expect(wrapper.childNodes[1].nodeType).toBe(Node.TEXT_NODE);
168
- expect(wrapper.childNodes[2].nodeType).toBe(Node.TEXT_NODE);
169
- });
170
- });
171
- describe("Fragment Edge Cases", () => {
172
- it("should patch fragment with text nodes", async () => {
173
- const container = document.createElement("div");
174
- let stateFn;
175
- const App = () => {
176
- const state = createState({ showElement: true });
177
- stateFn = state;
178
- return () => jsx(Fragment, {
179
- children: state.showElement
180
- ? [jsx("span", { children: ["Element"] })]
181
- : ["Text 1", "Text 2"],
182
- });
183
- };
184
- render(jsx(App, {}), container);
185
- expect(container.children.length).toBe(1);
186
- expect(container.children[0].tagName).toBe("SPAN");
187
- stateFn.showElement = false;
188
- await new Promise((resolve) => setTimeout(resolve, 0));
189
- expect(container.childNodes.length).toBe(2);
190
- expect(container.childNodes[0].nodeType).toBe(Node.TEXT_NODE);
191
- expect(container.childNodes[0].textContent).toBe("Text 1");
192
- expect(container.childNodes[1].nodeType).toBe(Node.TEXT_NODE);
193
- expect(container.childNodes[1].textContent).toBe("Text 2");
194
- });
195
- it("should patch fragment with mixed content", async () => {
196
- const container = document.createElement("div");
197
- let stateFn;
198
- const App = () => {
199
- const state = createState({ showMixed: false });
200
- stateFn = state;
201
- return () => jsx(Fragment, {
202
- children: state.showMixed
203
- ? ["Text", jsx("div", { children: ["Element"] }), "More text"]
204
- : [jsx("span", { children: ["A"] })],
205
- });
206
- };
207
- render(jsx(App, {}), container);
208
- stateFn.showMixed = true;
209
- await new Promise((resolve) => setTimeout(resolve, 0));
210
- expect(container.childNodes.length).toBe(3);
211
- expect(container.childNodes[0].nodeType).toBe(Node.TEXT_NODE);
212
- expect(container.childNodes[0].textContent).toBe("Text");
213
- expect(container.childNodes[1].tagName).toBe("DIV");
214
- expect(container.childNodes[2].nodeType).toBe(Node.TEXT_NODE);
215
- expect(container.childNodes[2].textContent).toBe("More text");
216
- });
217
- it("should patch empty fragment to non-empty", async () => {
218
- const container = document.createElement("div");
219
- let stateFn;
220
- const App = () => {
221
- const state = createState({ isEmpty: true });
222
- stateFn = state;
223
- return () => jsx("div", {
224
- children: [
225
- jsx(Fragment, {
226
- children: state.isEmpty
227
- ? []
228
- : [
229
- jsx("span", { children: ["A"] }),
230
- jsx("span", { children: ["B"] }),
231
- ],
232
- }),
233
- ],
234
- });
235
- };
236
- render(jsx(App, {}), container);
237
- const wrapper = container.children[0];
238
- expect(wrapper.childNodes.length).toBe(0);
239
- stateFn.isEmpty = false;
240
- await new Promise((resolve) => setTimeout(resolve, 0));
241
- expect(wrapper.children.length).toBe(2);
242
- expect(wrapper.children[0].textContent).toBe("A");
243
- expect(wrapper.children[1].textContent).toBe("B");
244
- });
245
- it("should patch non-empty fragment to empty", async () => {
246
- const container = document.createElement("div");
247
- let stateFn;
248
- const App = () => {
249
- const state = createState({ isEmpty: false });
250
- stateFn = state;
251
- return () => jsx("div", {
252
- children: [
253
- jsx(Fragment, {
254
- children: state.isEmpty
255
- ? []
256
- : [
257
- jsx("span", { children: ["A"] }),
258
- jsx("span", { children: ["B"] }),
259
- ],
260
- }),
261
- ],
262
- });
263
- };
264
- render(jsx(App, {}), container);
265
- const wrapper = container.children[0];
266
- expect(wrapper.children.length).toBe(2);
267
- stateFn.isEmpty = true;
268
- await new Promise((resolve) => setTimeout(resolve, 0));
269
- expect(wrapper.childNodes.length).toBe(0);
270
- });
271
- });
272
- describe("Property Edge Cases", () => {
273
- it("should patch null attribute to string", async () => {
274
- const container = document.createElement("div");
275
- let stateFn;
276
- const App = () => {
277
- const state = createState({
278
- dataValue: null,
279
- });
280
- stateFn = state;
281
- return () => jsx("div", {
282
- "data-value": state.dataValue,
283
- });
284
- };
285
- render(jsx(App, {}), container);
286
- const div = container.children[0];
287
- expect(div.getAttribute("data-value")).toBeNull();
288
- stateFn.dataValue = "test";
289
- await new Promise((resolve) => setTimeout(resolve, 0));
290
- expect(div.getAttribute("data-value")).toBe("test");
291
- });
292
- it("should patch string attribute to null", async () => {
293
- const container = document.createElement("div");
294
- let stateFn;
295
- const App = () => {
296
- const state = createState({
297
- dataValue: "test",
298
- });
299
- stateFn = state;
300
- return () => jsx("div", {
301
- "data-value": state.dataValue,
302
- });
303
- };
304
- render(jsx(App, {}), container);
305
- const div = container.children[0];
306
- expect(div.getAttribute("data-value")).toBe("test");
307
- stateFn.dataValue = null;
308
- await new Promise((resolve) => setTimeout(resolve, 0));
309
- expect(div.getAttribute("data-value")).toBeNull();
310
- });
311
- it("should remove event listener when patching to null", async () => {
312
- const container = document.createElement("div");
313
- let stateFn;
314
- const handler = vi.fn();
315
- const App = () => {
316
- const state = createState({
317
- doClick: true,
318
- });
319
- stateFn = state;
320
- return () => jsx("button", {
321
- onClick: state.doClick ? handler : null,
322
- });
323
- };
324
- render(jsx(App, {}), container);
325
- const button = container.children[0];
326
- button.click();
327
- expect(handler).toHaveBeenCalledTimes(1);
328
- stateFn.doClick = false;
329
- await new Promise((resolve) => setTimeout(resolve, 0));
330
- button.click();
331
- // Should still be 1, not 2
332
- expect(handler).toHaveBeenCalledTimes(1);
333
- });
334
- it("should handle className changes", async () => {
335
- const container = document.createElement("div");
336
- let stateFn;
337
- const App = () => {
338
- const state = createState({ className: "old-class" });
339
- stateFn = state;
340
- return () => jsx("div", {
341
- className: state.className,
342
- });
343
- };
344
- render(jsx(App, {}), container);
345
- const div = container.children[0];
346
- expect(div.className).toBe("old-class");
347
- stateFn.className = "new-class another-class";
348
- await new Promise((resolve) => setTimeout(resolve, 0));
349
- expect(div.className).toBe("new-class another-class");
350
- });
351
- it("should handle style object changes", async () => {
352
- const container = document.createElement("div");
353
- let stateFn;
354
- const App = () => {
355
- const state = createState({
356
- style: { color: "red", fontSize: "16px" },
357
- });
358
- stateFn = state;
359
- return () => jsx("div", {
360
- style: state.style,
361
- });
362
- };
363
- render(jsx(App, {}), container);
364
- const div = container.children[0];
365
- expect(div.style.color).toBe("red");
366
- expect(div.style.fontSize).toBe("16px");
367
- stateFn.style = { color: "blue", fontWeight: "bold" };
368
- await new Promise((resolve) => setTimeout(resolve, 0));
369
- expect(div.style.color).toBe("blue");
370
- expect(div.style.fontWeight).toBe("bold");
371
- // fontSize should be removed or remain - depends on your implementation
372
- });
373
- });
374
- describe("Keys Edge Cases", () => {
375
- it("should handle keys with mixed text and elements", async () => {
376
- const container = document.createElement("div");
377
- let stateFn;
378
- const App = () => {
379
- const state = createState({ order: "initial" });
380
- stateFn = state;
381
- return () => jsx("div", {
382
- children: state.order === "initial"
383
- ? [
384
- "Text",
385
- jsx("span", { children: ["A"] }, "a"),
386
- jsx("span", { children: ["B"] }, "b"),
387
- ]
388
- : [
389
- jsx("span", { children: ["B"] }, "b"),
390
- "Text",
391
- jsx("span", { children: ["A"] }, "a"),
392
- ],
393
- });
394
- };
395
- render(jsx(App, {}), container);
396
- const wrapper = container.children[0];
397
- const initialSpanA = wrapper.children[0];
398
- const initialSpanB = wrapper.children[1];
399
- stateFn.order = "reordered";
400
- await new Promise((resolve) => setTimeout(resolve, 0));
401
- expect(wrapper.childNodes.length).toBe(3);
402
- expect(wrapper.children[0]).toBe(initialSpanB);
403
- expect(wrapper.children[1]).toBe(initialSpanA);
404
- });
405
- it("should handle duplicate keys gracefully", async () => {
406
- const container = document.createElement("div");
407
- let stateFn;
408
- const App = () => {
409
- const state = createState({ version: 1 });
410
- stateFn = state;
411
- return () => jsx("div", {
412
- children: state.version === 1
413
- ? [
414
- jsx("span", { children: ["A"] }, "key"),
415
- jsx("span", { children: ["B"] }, "key"), // duplicate key
416
- ]
417
- : [
418
- jsx("span", { children: ["C"] }, "key"),
419
- jsx("span", { children: ["D"] }, "other"),
420
- ],
421
- });
422
- };
423
- render(jsx(App, {}), container);
424
- const wrapper = container.children[0];
425
- expect(wrapper.children.length).toBe(2);
426
- stateFn.version = 2;
427
- await new Promise((resolve) => setTimeout(resolve, 0));
428
- // Should handle this without crashing
429
- expect(wrapper.children.length).toBe(2);
430
- });
431
- it("should handle numeric keys", async () => {
432
- const container = document.createElement("div");
433
- let stateFn;
434
- const App = () => {
435
- const state = createState({ reorder: false });
436
- stateFn = state;
437
- return () => jsx("div", {
438
- children: state.reorder
439
- ? [
440
- jsx("span", { children: ["2"] }, "2"),
441
- jsx("span", { children: ["0"] }, "0"),
442
- jsx("span", { children: ["1"] }, "1"),
443
- ]
444
- : [
445
- jsx("span", { children: ["0"] }, "0"),
446
- jsx("span", { children: ["1"] }, "1"),
447
- jsx("span", { children: ["2"] }, "2"),
448
- ],
449
- });
450
- };
451
- render(jsx(App, {}), container);
452
- const wrapper = container.children[0];
453
- const initialChildren = Array.from(wrapper.children);
454
- stateFn.reorder = true;
455
- await new Promise((resolve) => setTimeout(resolve, 0));
456
- const newChildren = Array.from(wrapper.children);
457
- expect(newChildren[0]).toBe(initialChildren[2]);
458
- expect(newChildren[1]).toBe(initialChildren[0]);
459
- expect(newChildren[2]).toBe(initialChildren[1]);
460
- });
461
- });
462
- describe("Empty and Null Cases", () => {
463
- it("should patch from children to no children", async () => {
464
- const container = document.createElement("div");
465
- let stateFn;
466
- const App = () => {
467
- const state = createState({ hasChildren: true });
468
- stateFn = state;
469
- return () => jsx("div", {
470
- children: state.hasChildren
471
- ? [
472
- jsx("span", { children: ["A"] }),
473
- jsx("span", { children: ["B"] }),
474
- ]
475
- : undefined,
476
- });
477
- };
478
- render(jsx(App, {}), container);
479
- const wrapper = container.children[0];
480
- expect(wrapper.children.length).toBe(2);
481
- stateFn.hasChildren = false;
482
- await new Promise((resolve) => setTimeout(resolve, 0));
483
- expect(wrapper.childNodes.length).toBe(0);
484
- });
485
- it("should patch from no children to children", async () => {
486
- const container = document.createElement("div");
487
- let stateFn;
488
- const App = () => {
489
- const state = createState({ hasChildren: false });
490
- stateFn = state;
491
- return () => jsx("div", {
492
- children: state.hasChildren
493
- ? [
494
- jsx("span", { children: ["A"] }),
495
- jsx("span", { children: ["B"] }),
496
- ]
497
- : undefined,
498
- });
499
- };
500
- render(jsx(App, {}), container);
501
- const wrapper = container.children[0];
502
- expect(wrapper.childNodes.length).toBe(0);
503
- stateFn.hasChildren = true;
504
- await new Promise((resolve) => setTimeout(resolve, 0));
505
- expect(wrapper.children.length).toBe(2);
506
- });
507
- it("should handle null and undefined in children array", async () => {
508
- const container = document.createElement("div");
509
- let stateFn;
510
- const App = () => {
511
- const state = createState({ version: 1 });
512
- stateFn = state;
513
- return () => jsx("div", {
514
- children: state.version === 1
515
- ? [null, jsx("span", { children: ["A"] }), undefined]
516
- : [
517
- jsx("span", { children: ["B"] }),
518
- null,
519
- jsx("span", { children: ["C"] }),
520
- ],
521
- });
522
- };
523
- render(jsx(App, {}), container);
524
- const wrapper = container.children[0];
525
- expect(wrapper.children.length).toBe(1);
526
- expect(wrapper.children[0].textContent).toBe("A");
527
- stateFn.version = 2;
528
- await new Promise((resolve) => setTimeout(resolve, 0));
529
- expect(wrapper.children.length).toBe(2);
530
- expect(wrapper.children[0].textContent).toBe("B");
531
- expect(wrapper.children[1].textContent).toBe("C");
532
- });
533
- });
534
- describe("Deeply Nested Patching", () => {
535
- it("should patch deeply nested structure with tag changes", async () => {
536
- const container = document.createElement("div");
537
- let stateFn;
538
- const App = () => {
539
- const state = createState({ version: 1 });
540
- stateFn = state;
541
- return () => jsx("div", {
542
- children: [
543
- jsx("section", {
544
- children: [
545
- jsx("article", {
546
- children: state.version === 1
547
- ? [
548
- jsx("p", {
549
- children: [
550
- jsx("span", { children: ["Deep text"] }),
551
- ],
552
- }),
553
- ]
554
- : [
555
- jsx("div", {
556
- children: [
557
- jsx("strong", { children: ["Updated text"] }),
558
- ],
559
- }),
560
- ],
561
- }),
562
- ],
563
- }),
564
- ],
565
- });
566
- };
567
- render(jsx(App, {}), container);
568
- stateFn.version = 2;
569
- await new Promise((resolve) => setTimeout(resolve, 0));
570
- const wrapper = container.children[0];
571
- const section = wrapper.children[0];
572
- const article = section.children[0];
573
- const div = article.children[0];
574
- expect(div.tagName).toBe("DIV");
575
- expect(div.children[0].tagName).toBe("STRONG");
576
- expect(div.children[0].textContent).toBe("Updated text");
577
- });
578
- it("should patch with alternating fragments and elements", async () => {
579
- const container = document.createElement("div");
580
- let stateFn;
581
- const App = () => {
582
- const state = createState({ version: 1 });
583
- stateFn = state;
584
- return () => jsx("div", {
585
- children: [
586
- jsx(Fragment, {
587
- children: [
588
- jsx("span", {
589
- children: [
590
- jsx(Fragment, {
591
- children: state.version === 1
592
- ? [jsx("em", { children: ["Nested"] })]
593
- : [
594
- jsx("em", { children: ["Updated"] }),
595
- jsx("strong", { children: ["Added"] }),
596
- ],
597
- }),
598
- ],
599
- }),
600
- ],
601
- }),
602
- ],
603
- });
604
- };
605
- render(jsx(App, {}), container);
606
- stateFn.version = 2;
607
- await new Promise((resolve) => setTimeout(resolve, 0));
608
- const wrapper = container.children[0];
609
- const span = wrapper.children[0];
610
- expect(span.children.length).toBe(2);
611
- expect(span.children[0].tagName).toBe("EM");
612
- expect(span.children[0].textContent).toBe("Updated");
613
- expect(span.children[1].tagName).toBe("STRONG");
614
- expect(span.children[1].textContent).toBe("Added");
615
- });
616
- });
617
- describe("Same Node Patching", () => {
618
- it("should handle patching node with itself", async () => {
619
- const container = document.createElement("div");
620
- let stateFn;
621
- const App = () => {
622
- const state = createState({ counter: 0 });
623
- stateFn = state;
624
- return () => jsx("div", {
625
- children: [jsx("span", { children: ["Text"] })],
626
- });
627
- };
628
- render(jsx(App, {}), container);
629
- const wrapper = container.children[0];
630
- const initialContent = wrapper.innerHTML;
631
- // Trigger re-render - should be a no-op since nothing changed
632
- stateFn.counter = 1;
633
- await new Promise((resolve) => setTimeout(resolve, 0));
634
- expect(wrapper.innerHTML).toBe(initialContent);
635
- });
636
- });
637
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=fragment.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"fragment.test.d.ts","sourceRoot":"","sources":["../../src/vdom/fragment.test.tsx"],"names":[],"mappings":""}