rask-ui 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. package/dist/component.d.ts +17 -0
  2. package/dist/component.d.ts.map +1 -1
  3. package/dist/component.js +4 -2
  4. package/dist/createAsync.d.ts +23 -0
  5. package/dist/createAsync.d.ts.map +1 -1
  6. package/dist/createAsync.js +23 -0
  7. package/dist/createAsync.test.d.ts +2 -0
  8. package/dist/createAsync.test.d.ts.map +1 -0
  9. package/dist/createAsync.test.js +110 -0
  10. package/dist/createContext.d.ts +26 -2
  11. package/dist/createContext.d.ts.map +1 -1
  12. package/dist/createContext.js +31 -5
  13. package/dist/createContext.test.d.ts +2 -0
  14. package/dist/createContext.test.d.ts.map +1 -0
  15. package/dist/createContext.test.js +136 -0
  16. package/dist/createMutation.d.ts +23 -0
  17. package/dist/createMutation.d.ts.map +1 -1
  18. package/dist/createMutation.js +23 -0
  19. package/dist/createMutation.test.d.ts +2 -0
  20. package/dist/createMutation.test.d.ts.map +1 -0
  21. package/dist/createMutation.test.js +168 -0
  22. package/dist/createQuery.d.ts +23 -0
  23. package/dist/createQuery.d.ts.map +1 -1
  24. package/dist/createQuery.js +23 -0
  25. package/dist/createQuery.test.d.ts +2 -0
  26. package/dist/createQuery.test.d.ts.map +1 -0
  27. package/dist/createQuery.test.js +156 -0
  28. package/dist/createRef.test.d.ts +2 -0
  29. package/dist/createRef.test.d.ts.map +1 -0
  30. package/dist/createRef.test.js +80 -0
  31. package/dist/createState.d.ts +24 -0
  32. package/dist/createState.d.ts.map +1 -1
  33. package/dist/createState.js +24 -0
  34. package/dist/createState.test.d.ts +2 -0
  35. package/dist/createState.test.d.ts.map +1 -0
  36. package/dist/createState.test.js +111 -0
  37. package/dist/createView.d.ts +54 -0
  38. package/dist/createView.d.ts.map +1 -0
  39. package/dist/createView.js +68 -0
  40. package/dist/createView.test.d.ts +2 -0
  41. package/dist/createView.test.d.ts.map +1 -0
  42. package/dist/createView.test.js +203 -0
  43. package/dist/error.d.ts.map +1 -1
  44. package/dist/error.js +15 -2
  45. package/dist/error.test.d.ts +2 -0
  46. package/dist/error.test.d.ts.map +1 -0
  47. package/dist/error.test.js +144 -0
  48. package/dist/index.d.ts +3 -2
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +3 -2
  51. package/dist/integration.test.d.ts +2 -0
  52. package/dist/integration.test.d.ts.map +1 -0
  53. package/dist/integration.test.js +155 -0
  54. package/dist/jsx-dev-runtime.d.ts +3 -3
  55. package/dist/jsx-dev-runtime.d.ts.map +1 -1
  56. package/dist/jsx-dev-runtime.js +2 -2
  57. package/dist/jsx-runtime.d.ts +1 -4
  58. package/dist/jsx-runtime.d.ts.map +1 -1
  59. package/dist/jsx-runtime.js +3 -14
  60. package/dist/observation.d.ts +1 -0
  61. package/dist/observation.d.ts.map +1 -1
  62. package/dist/observation.js +5 -0
  63. package/dist/observation.test.d.ts +2 -0
  64. package/dist/observation.test.d.ts.map +1 -0
  65. package/dist/observation.test.js +150 -0
  66. package/dist/render-test.d.ts +2 -0
  67. package/dist/render-test.d.ts.map +1 -0
  68. package/dist/render-test.js +21 -0
  69. package/dist/render.d.ts +1 -1
  70. package/dist/render.d.ts.map +1 -1
  71. package/dist/render.js +13 -1
  72. package/dist/test-setup.d.ts +16 -0
  73. package/dist/test-setup.d.ts.map +1 -0
  74. package/dist/test-setup.js +39 -0
  75. package/dist/tests/class.test.d.ts +2 -0
  76. package/dist/tests/class.test.d.ts.map +1 -0
  77. package/dist/tests/class.test.js +143 -0
  78. package/dist/tests/complex-rendering.test.d.ts +2 -0
  79. package/dist/tests/complex-rendering.test.d.ts.map +1 -0
  80. package/dist/tests/complex-rendering.test.js +400 -0
  81. package/dist/tests/component.cleanup.test.d.ts +2 -0
  82. package/dist/tests/component.cleanup.test.d.ts.map +1 -0
  83. package/dist/tests/component.cleanup.test.js +325 -0
  84. package/dist/tests/component.counter.test.d.ts +2 -0
  85. package/dist/tests/component.counter.test.d.ts.map +1 -0
  86. package/dist/tests/component.counter.test.js +124 -0
  87. package/dist/tests/component.interaction.test.d.ts +2 -0
  88. package/dist/tests/component.interaction.test.d.ts.map +1 -0
  89. package/dist/tests/component.interaction.test.js +73 -0
  90. package/dist/tests/component.props.test.d.ts +2 -0
  91. package/dist/tests/component.props.test.d.ts.map +1 -0
  92. package/dist/tests/component.props.test.js +88 -0
  93. package/dist/tests/component.return-types.test.d.ts +2 -0
  94. package/dist/tests/component.return-types.test.d.ts.map +1 -0
  95. package/dist/tests/component.return-types.test.js +357 -0
  96. package/dist/tests/component.state.test.d.ts +2 -0
  97. package/dist/tests/component.state.test.d.ts.map +1 -0
  98. package/dist/tests/component.state.test.js +129 -0
  99. package/dist/tests/component.test.d.ts +2 -0
  100. package/dist/tests/component.test.d.ts.map +1 -0
  101. package/dist/tests/component.test.js +63 -0
  102. package/dist/tests/createAsync.test.d.ts +2 -0
  103. package/dist/tests/createAsync.test.d.ts.map +1 -0
  104. package/dist/tests/createAsync.test.js +110 -0
  105. package/dist/tests/createContext.test.d.ts +2 -0
  106. package/dist/tests/createContext.test.d.ts.map +1 -0
  107. package/dist/tests/createContext.test.js +141 -0
  108. package/dist/tests/createMutation.test.d.ts +2 -0
  109. package/dist/tests/createMutation.test.d.ts.map +1 -0
  110. package/dist/tests/createMutation.test.js +168 -0
  111. package/dist/tests/createQuery.test.d.ts +2 -0
  112. package/dist/tests/createQuery.test.d.ts.map +1 -0
  113. package/dist/tests/createQuery.test.js +156 -0
  114. package/dist/tests/createRef.test.d.ts +2 -0
  115. package/dist/tests/createRef.test.d.ts.map +1 -0
  116. package/dist/tests/createRef.test.js +84 -0
  117. package/dist/tests/createState.test.d.ts +2 -0
  118. package/dist/tests/createState.test.d.ts.map +1 -0
  119. package/dist/tests/createState.test.js +111 -0
  120. package/dist/tests/createView.test.d.ts +2 -0
  121. package/dist/tests/createView.test.d.ts.map +1 -0
  122. package/dist/tests/createView.test.js +203 -0
  123. package/dist/tests/edge-cases.test.d.ts +2 -0
  124. package/dist/tests/edge-cases.test.d.ts.map +1 -0
  125. package/dist/tests/edge-cases.test.js +637 -0
  126. package/dist/tests/error-no-boundary.test.d.ts +2 -0
  127. package/dist/tests/error-no-boundary.test.d.ts.map +1 -0
  128. package/dist/tests/error-no-boundary.test.js +174 -0
  129. package/dist/tests/error.test.d.ts +2 -0
  130. package/dist/tests/error.test.d.ts.map +1 -0
  131. package/dist/tests/error.test.js +199 -0
  132. package/dist/tests/fragment.test.d.ts +2 -0
  133. package/dist/tests/fragment.test.d.ts.map +1 -0
  134. package/dist/tests/fragment.test.js +618 -0
  135. package/dist/tests/integration.test.d.ts +2 -0
  136. package/dist/tests/integration.test.d.ts.map +1 -0
  137. package/dist/tests/integration.test.js +192 -0
  138. package/dist/tests/keys.test.d.ts +2 -0
  139. package/dist/tests/keys.test.d.ts.map +1 -0
  140. package/dist/tests/keys.test.js +293 -0
  141. package/dist/tests/mount.test.d.ts +2 -0
  142. package/dist/tests/mount.test.d.ts.map +1 -0
  143. package/dist/tests/mount.test.js +91 -0
  144. package/dist/tests/observation.test.d.ts +2 -0
  145. package/dist/tests/observation.test.d.ts.map +1 -0
  146. package/dist/tests/observation.test.js +150 -0
  147. package/dist/tests/patch.test.d.ts +2 -0
  148. package/dist/tests/patch.test.d.ts.map +1 -0
  149. package/dist/tests/patch.test.js +498 -0
  150. package/dist/tests/patchChildren.test.d.ts +2 -0
  151. package/dist/tests/patchChildren.test.d.ts.map +1 -0
  152. package/dist/tests/patchChildren.test.js +387 -0
  153. package/dist/tests/primitives.test.d.ts +2 -0
  154. package/dist/tests/primitives.test.d.ts.map +1 -0
  155. package/dist/tests/primitives.test.js +132 -0
  156. package/dist/vdom/AbstractVNode.d.ts +22 -0
  157. package/dist/vdom/AbstractVNode.d.ts.map +1 -0
  158. package/dist/vdom/AbstractVNode.js +106 -0
  159. package/dist/vdom/ComponentVNode.d.ts +48 -0
  160. package/dist/vdom/ComponentVNode.d.ts.map +1 -0
  161. package/dist/vdom/ComponentVNode.js +209 -0
  162. package/dist/vdom/ElementVNode.d.ts +24 -0
  163. package/dist/vdom/ElementVNode.d.ts.map +1 -0
  164. package/dist/vdom/ElementVNode.js +126 -0
  165. package/dist/vdom/FragmentVNode.d.ts +13 -0
  166. package/dist/vdom/FragmentVNode.d.ts.map +1 -0
  167. package/dist/vdom/FragmentVNode.js +34 -0
  168. package/dist/vdom/RootVNode.d.ts +22 -0
  169. package/dist/vdom/RootVNode.d.ts.map +1 -0
  170. package/dist/vdom/RootVNode.js +55 -0
  171. package/dist/vdom/TextVNode.d.ts +11 -0
  172. package/dist/vdom/TextVNode.d.ts.map +1 -0
  173. package/dist/vdom/TextVNode.js +32 -0
  174. package/dist/vdom/class.test.d.ts +2 -0
  175. package/dist/vdom/class.test.d.ts.map +1 -0
  176. package/dist/vdom/class.test.js +143 -0
  177. package/dist/vdom/complex-rendering.test.d.ts +2 -0
  178. package/dist/vdom/complex-rendering.test.d.ts.map +1 -0
  179. package/dist/vdom/complex-rendering.test.js +400 -0
  180. package/dist/vdom/component.cleanup.test.d.ts +2 -0
  181. package/dist/vdom/component.cleanup.test.d.ts.map +1 -0
  182. package/dist/vdom/component.cleanup.test.js +323 -0
  183. package/dist/vdom/component.counter.test.d.ts +2 -0
  184. package/dist/vdom/component.counter.test.d.ts.map +1 -0
  185. package/dist/vdom/component.counter.test.js +124 -0
  186. package/dist/vdom/component.interaction.test.d.ts +2 -0
  187. package/dist/vdom/component.interaction.test.d.ts.map +1 -0
  188. package/dist/vdom/component.interaction.test.js +73 -0
  189. package/dist/vdom/component.props.test.d.ts +2 -0
  190. package/dist/vdom/component.props.test.d.ts.map +1 -0
  191. package/dist/vdom/component.props.test.js +88 -0
  192. package/dist/vdom/component.return-types.test.d.ts +2 -0
  193. package/dist/vdom/component.return-types.test.d.ts.map +1 -0
  194. package/dist/vdom/component.return-types.test.js +357 -0
  195. package/dist/vdom/component.state.test.d.ts +2 -0
  196. package/dist/vdom/component.state.test.d.ts.map +1 -0
  197. package/dist/vdom/component.state.test.js +129 -0
  198. package/dist/vdom/component.test.d.ts +2 -0
  199. package/dist/vdom/component.test.d.ts.map +1 -0
  200. package/dist/vdom/component.test.js +63 -0
  201. package/dist/vdom/dom-utils.d.ts +9 -0
  202. package/dist/vdom/dom-utils.d.ts.map +1 -0
  203. package/dist/vdom/dom-utils.js +74 -0
  204. package/dist/vdom/edge-cases.test.d.ts +2 -0
  205. package/dist/vdom/edge-cases.test.d.ts.map +1 -0
  206. package/dist/vdom/edge-cases.test.js +637 -0
  207. package/dist/vdom/fragment.test.d.ts +2 -0
  208. package/dist/vdom/fragment.test.d.ts.map +1 -0
  209. package/dist/vdom/fragment.test.js +618 -0
  210. package/dist/vdom/index.d.ts +10 -0
  211. package/dist/vdom/index.d.ts.map +1 -0
  212. package/dist/vdom/index.js +26 -0
  213. package/dist/vdom/keys.test.d.ts +2 -0
  214. package/dist/vdom/keys.test.d.ts.map +1 -0
  215. package/dist/vdom/keys.test.js +293 -0
  216. package/dist/vdom/mount.test.d.ts +2 -0
  217. package/dist/vdom/mount.test.d.ts.map +1 -0
  218. package/dist/vdom/mount.test.js +91 -0
  219. package/dist/vdom/patch.test.d.ts +2 -0
  220. package/dist/vdom/patch.test.d.ts.map +1 -0
  221. package/dist/vdom/patch.test.js +498 -0
  222. package/dist/vdom/patchChildren.test.d.ts +2 -0
  223. package/dist/vdom/patchChildren.test.d.ts.map +1 -0
  224. package/dist/vdom/patchChildren.test.js +392 -0
  225. package/dist/vdom/primitives.test.d.ts +2 -0
  226. package/dist/vdom/primitives.test.d.ts.map +1 -0
  227. package/dist/vdom/primitives.test.js +132 -0
  228. package/dist/vdom/types.d.ts +8 -0
  229. package/dist/vdom/types.d.ts.map +1 -0
  230. package/dist/vdom/types.js +1 -0
  231. package/dist/vdom/utils.d.ts +6 -0
  232. package/dist/vdom/utils.d.ts.map +1 -0
  233. package/dist/vdom/utils.js +63 -0
  234. package/package.json +1 -4
@@ -0,0 +1,618 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
2
+ import { jsx, render } from "../vdom/index";
3
+ import { Fragment } from "../vdom/FragmentVNode";
4
+ import { createState } from "../createState";
5
+ describe("VDOM Fragments", () => {
6
+ describe("Mounting", () => {
7
+ it("should mount a simple fragment with multiple children", () => {
8
+ const container = document.createElement("div");
9
+ const vnode = jsx(Fragment, {
10
+ children: [
11
+ jsx("span", { children: ["First"] }),
12
+ jsx("span", { children: ["Second"] }),
13
+ jsx("span", { children: ["Third"] }),
14
+ ],
15
+ });
16
+ render(vnode, container);
17
+ expect(container.children.length).toBe(3);
18
+ expect(container.children[0].tagName).toBe("SPAN");
19
+ expect(container.children[0].textContent).toBe("First");
20
+ expect(container.children[1].tagName).toBe("SPAN");
21
+ expect(container.children[1].textContent).toBe("Second");
22
+ expect(container.children[2].tagName).toBe("SPAN");
23
+ expect(container.children[2].textContent).toBe("Third");
24
+ });
25
+ it("should mount fragment inside an element", () => {
26
+ const container = document.createElement("div");
27
+ const vnode = jsx("div", {
28
+ className: "wrapper",
29
+ children: [
30
+ jsx(Fragment, {
31
+ children: [
32
+ jsx("span", { children: ["A"] }),
33
+ jsx("span", { children: ["B"] }),
34
+ ],
35
+ }),
36
+ ],
37
+ });
38
+ render(vnode, container);
39
+ const wrapper = container.children[0];
40
+ expect(wrapper.className).toBe("wrapper");
41
+ expect(wrapper.children.length).toBe(2);
42
+ expect(wrapper.children[0].textContent).toBe("A");
43
+ expect(wrapper.children[1].textContent).toBe("B");
44
+ });
45
+ it("should mount nested fragments", () => {
46
+ const container = document.createElement("div");
47
+ const vnode = jsx(Fragment, {
48
+ children: [
49
+ jsx("span", { children: ["Before"] }),
50
+ jsx(Fragment, {
51
+ children: [
52
+ jsx("span", { children: ["Nested 1"] }),
53
+ jsx("span", { children: ["Nested 2"] }),
54
+ ],
55
+ }),
56
+ jsx("span", { children: ["After"] }),
57
+ ],
58
+ });
59
+ render(vnode, container);
60
+ expect(container.children.length).toBe(4);
61
+ expect(container.children[0].textContent).toBe("Before");
62
+ expect(container.children[1].textContent).toBe("Nested 1");
63
+ expect(container.children[2].textContent).toBe("Nested 2");
64
+ expect(container.children[3].textContent).toBe("After");
65
+ });
66
+ it("should mount deeply nested fragments", () => {
67
+ const container = document.createElement("div");
68
+ const vnode = jsx(Fragment, {
69
+ children: [
70
+ jsx(Fragment, {
71
+ children: [
72
+ jsx(Fragment, {
73
+ children: [
74
+ jsx("span", { children: ["Deep 1"] }),
75
+ jsx("span", { children: ["Deep 2"] }),
76
+ ],
77
+ }),
78
+ jsx("span", { children: ["Middle"] }),
79
+ ],
80
+ }),
81
+ jsx("span", { children: ["Outer"] }),
82
+ ],
83
+ });
84
+ render(vnode, container);
85
+ expect(container.children.length).toBe(4);
86
+ expect(container.children[0].textContent).toBe("Deep 1");
87
+ expect(container.children[1].textContent).toBe("Deep 2");
88
+ expect(container.children[2].textContent).toBe("Middle");
89
+ expect(container.children[3].textContent).toBe("Outer");
90
+ });
91
+ it("should mount fragment with mixed element types", () => {
92
+ const container = document.createElement("div");
93
+ const vnode = jsx(Fragment, {
94
+ children: [
95
+ jsx("div", { children: ["Div"] }),
96
+ jsx("span", { children: ["Span"] }),
97
+ jsx("button", { children: ["Button"] }),
98
+ ],
99
+ });
100
+ render(vnode, container);
101
+ expect(container.children.length).toBe(3);
102
+ expect(container.children[0].tagName).toBe("DIV");
103
+ expect(container.children[1].tagName).toBe("SPAN");
104
+ expect(container.children[2].tagName).toBe("BUTTON");
105
+ });
106
+ });
107
+ describe("Patching", () => {
108
+ beforeEach(() => {
109
+ vi.useFakeTimers();
110
+ });
111
+ afterEach(() => {
112
+ vi.clearAllTimers();
113
+ });
114
+ it("should patch fragment by adding children", async () => {
115
+ const container = document.createElement("div");
116
+ let stateFn;
117
+ const App = () => {
118
+ const state = createState({ childCount: 1 });
119
+ stateFn = state;
120
+ return () => {
121
+ const children = [];
122
+ for (let i = 0; i < state.childCount; i++) {
123
+ const labels = ["First", "Second", "Third"];
124
+ children.push(jsx("span", { children: [labels[i]] }));
125
+ }
126
+ return jsx(Fragment, { children });
127
+ };
128
+ };
129
+ render(jsx(App, {}), container);
130
+ expect(container.children.length).toBe(1);
131
+ expect(container.children[0].textContent).toBe("First");
132
+ stateFn.childCount = 3;
133
+ await vi.runAllTimersAsync();
134
+ expect(container.children.length).toBe(3);
135
+ expect(container.children[0].textContent).toBe("First");
136
+ expect(container.children[1].textContent).toBe("Second");
137
+ expect(container.children[2].textContent).toBe("Third");
138
+ });
139
+ it("should patch fragment by removing children", async () => {
140
+ const container = document.createElement("div");
141
+ let stateFn;
142
+ const App = () => {
143
+ const state = createState({ childCount: 3 });
144
+ stateFn = state;
145
+ return () => {
146
+ const children = [];
147
+ for (let i = 0; i < state.childCount; i++) {
148
+ const labels = ["First", "Second", "Third"];
149
+ children.push(jsx("span", { children: [labels[i]] }));
150
+ }
151
+ return jsx(Fragment, { children });
152
+ };
153
+ };
154
+ render(jsx(App, {}), container);
155
+ expect(container.children.length).toBe(3);
156
+ stateFn.childCount = 1;
157
+ await vi.runAllTimersAsync();
158
+ expect(container.children.length).toBe(1);
159
+ expect(container.children[0].textContent).toBe("First");
160
+ });
161
+ it("should patch fragment by replacing children", async () => {
162
+ const container = document.createElement("div");
163
+ let stateFn;
164
+ const App = () => {
165
+ const state = createState({ useDiv: false });
166
+ stateFn = state;
167
+ return () => {
168
+ if (state.useDiv) {
169
+ return jsx(Fragment, {
170
+ children: [
171
+ jsx("div", { children: ["New 1"] }),
172
+ jsx("div", { children: ["New 2"] }),
173
+ ],
174
+ });
175
+ }
176
+ return jsx(Fragment, {
177
+ children: [
178
+ jsx("span", { children: ["Old 1"] }),
179
+ jsx("span", { children: ["Old 2"] }),
180
+ ],
181
+ });
182
+ };
183
+ };
184
+ render(jsx(App, {}), container);
185
+ expect(container.children.length).toBe(2);
186
+ expect(container.children[0].tagName).toBe("SPAN");
187
+ stateFn.useDiv = true;
188
+ await vi.runAllTimersAsync();
189
+ expect(container.children.length).toBe(2);
190
+ expect(container.children[0].tagName).toBe("DIV");
191
+ expect(container.children[0].textContent).toBe("New 1");
192
+ expect(container.children[1].tagName).toBe("DIV");
193
+ expect(container.children[1].textContent).toBe("New 2");
194
+ });
195
+ it("should patch fragment inside an element", async () => {
196
+ const container = document.createElement("div");
197
+ let stateFn;
198
+ const App = () => {
199
+ const state = createState({ showC: false });
200
+ stateFn = state;
201
+ return () => jsx("div", {
202
+ children: [
203
+ jsx(Fragment, {
204
+ children: [
205
+ jsx("span", { children: ["A"] }),
206
+ jsx("span", { children: ["B"] }),
207
+ ...(state.showC ? [jsx("span", { children: ["C"] })] : []),
208
+ ],
209
+ }),
210
+ ],
211
+ });
212
+ };
213
+ render(jsx(App, {}), container);
214
+ const wrapper = container.children[0];
215
+ expect(wrapper.children.length).toBe(2);
216
+ stateFn.showC = true;
217
+ await vi.runAllTimersAsync();
218
+ expect(wrapper.children.length).toBe(3);
219
+ expect(wrapper.children[0].textContent).toBe("A");
220
+ expect(wrapper.children[1].textContent).toBe("B");
221
+ expect(wrapper.children[2].textContent).toBe("C");
222
+ });
223
+ it("should patch nested fragments", async () => {
224
+ const container = document.createElement("div");
225
+ let stateFn;
226
+ const App = () => {
227
+ const state = createState({ showInner2: false });
228
+ stateFn = state;
229
+ return () => jsx(Fragment, {
230
+ children: [
231
+ jsx("span", { children: ["Outer"] }),
232
+ jsx(Fragment, {
233
+ children: [
234
+ jsx("span", { children: ["Inner 1"] }),
235
+ ...(state.showInner2
236
+ ? [jsx("span", { children: ["Inner 2"] })]
237
+ : []),
238
+ ],
239
+ }),
240
+ ],
241
+ });
242
+ };
243
+ render(jsx(App, {}), container);
244
+ expect(container.children.length).toBe(2);
245
+ stateFn.showInner2 = true;
246
+ await vi.runAllTimersAsync();
247
+ expect(container.children.length).toBe(3);
248
+ expect(container.children[0].textContent).toBe("Outer");
249
+ expect(container.children[1].textContent).toBe("Inner 1");
250
+ expect(container.children[2].textContent).toBe("Inner 2");
251
+ });
252
+ it("should patch by replacing element with fragment", async () => {
253
+ const container = document.createElement("div");
254
+ let stateFn;
255
+ const App = () => {
256
+ const state = createState({ useFragment: false });
257
+ stateFn = state;
258
+ return () => jsx("div", {
259
+ children: [
260
+ state.useFragment
261
+ ? jsx(Fragment, {
262
+ children: [
263
+ jsx("span", { children: ["First"] }),
264
+ jsx("span", { children: ["Second"] }),
265
+ ],
266
+ })
267
+ : jsx("span", { children: ["Single"] }),
268
+ ],
269
+ });
270
+ };
271
+ render(jsx(App, {}), container);
272
+ const wrapper = container.children[0];
273
+ expect(wrapper.children.length).toBe(1);
274
+ stateFn.useFragment = true;
275
+ await vi.runAllTimersAsync();
276
+ expect(wrapper.children.length).toBe(2);
277
+ expect(wrapper.children[0].textContent).toBe("First");
278
+ expect(wrapper.children[1].textContent).toBe("Second");
279
+ });
280
+ it("should patch by replacing fragment with element", async () => {
281
+ const container = document.createElement("div");
282
+ let stateFn;
283
+ const App = () => {
284
+ const state = createState({ useFragment: true });
285
+ stateFn = state;
286
+ return () => jsx("div", {
287
+ children: [
288
+ state.useFragment
289
+ ? jsx(Fragment, {
290
+ children: [
291
+ jsx("span", { children: ["First"] }),
292
+ jsx("span", { children: ["Second"] }),
293
+ ],
294
+ })
295
+ : jsx("span", { children: ["Single"] }),
296
+ ],
297
+ });
298
+ };
299
+ render(jsx(App, {}), container);
300
+ const wrapper = container.children[0];
301
+ expect(wrapper.children.length).toBe(2);
302
+ stateFn.useFragment = false;
303
+ await vi.runAllTimersAsync();
304
+ expect(wrapper.children.length).toBe(1);
305
+ expect(wrapper.children[0].textContent).toBe("Single");
306
+ });
307
+ it("should patch deeply nested fragments", async () => {
308
+ const container = document.createElement("div");
309
+ let stateFn;
310
+ const App = () => {
311
+ const state = createState({ showDeep2: false });
312
+ stateFn = state;
313
+ return () => jsx(Fragment, {
314
+ children: [
315
+ jsx(Fragment, {
316
+ children: [
317
+ jsx(Fragment, {
318
+ children: [
319
+ jsx("span", { children: ["Deep 1"] }),
320
+ ...(state.showDeep2
321
+ ? [jsx("span", { children: ["Deep 2"] })]
322
+ : []),
323
+ ],
324
+ }),
325
+ ],
326
+ }),
327
+ ],
328
+ });
329
+ };
330
+ render(jsx(App, {}), container);
331
+ expect(container.children.length).toBe(1);
332
+ expect(container.children[0].textContent).toBe("Deep 1");
333
+ stateFn.showDeep2 = true;
334
+ await vi.runAllTimersAsync();
335
+ expect(container.children.length).toBe(2);
336
+ expect(container.children[0].textContent).toBe("Deep 1");
337
+ expect(container.children[1].textContent).toBe("Deep 2");
338
+ });
339
+ it("should patch fragment with keys", async () => {
340
+ const container = document.createElement("div");
341
+ let stateFn;
342
+ const App = () => {
343
+ const state = createState({ reordered: false });
344
+ stateFn = state;
345
+ return () => jsx(Fragment, {
346
+ children: state.reordered
347
+ ? [
348
+ jsx("span", { children: ["C"] }, "c"),
349
+ jsx("span", { children: ["A"] }, "a"),
350
+ jsx("span", { children: ["B"] }, "b"),
351
+ ]
352
+ : [
353
+ jsx("span", { children: ["A"] }, "a"),
354
+ jsx("span", { children: ["B"] }, "b"),
355
+ jsx("span", { children: ["C"] }, "c"),
356
+ ],
357
+ });
358
+ };
359
+ render(jsx(App, {}), container);
360
+ const initialChildren = Array.from(container.children);
361
+ const itemA = initialChildren[0];
362
+ const itemB = initialChildren[1];
363
+ const itemC = initialChildren[2];
364
+ stateFn.reordered = true;
365
+ await vi.runAllTimersAsync();
366
+ const newChildren = Array.from(container.children);
367
+ // Elements should be reordered, not recreated
368
+ expect(newChildren[0]).toBe(itemC);
369
+ expect(newChildren[1]).toBe(itemA);
370
+ expect(newChildren[2]).toBe(itemB);
371
+ });
372
+ it("should patch complex nested structure with fragments", async () => {
373
+ const container = document.createElement("div");
374
+ let stateFn;
375
+ const App = () => {
376
+ const state = createState({ showAsides: false });
377
+ stateFn = state;
378
+ return () => jsx("div", {
379
+ children: [
380
+ jsx("header", { children: ["Header"] }),
381
+ jsx(Fragment, {
382
+ children: [
383
+ jsx("section", { children: ["Section 1"] }),
384
+ ...(state.showAsides
385
+ ? [
386
+ jsx(Fragment, {
387
+ children: [
388
+ jsx("aside", { children: ["Aside 1"] }),
389
+ jsx("aside", { children: ["Aside 2"] }),
390
+ ],
391
+ }),
392
+ ]
393
+ : []),
394
+ jsx("section", { children: ["Section 2"] }),
395
+ ],
396
+ }),
397
+ jsx("footer", { children: ["Footer"] }),
398
+ ],
399
+ });
400
+ };
401
+ render(jsx(App, {}), container);
402
+ const wrapper = container.children[0];
403
+ expect(wrapper.children.length).toBe(4);
404
+ stateFn.showAsides = true;
405
+ await vi.runAllTimersAsync();
406
+ expect(wrapper.children.length).toBe(6);
407
+ expect(wrapper.children[0].tagName).toBe("HEADER");
408
+ expect(wrapper.children[1].tagName).toBe("SECTION");
409
+ expect(wrapper.children[1].textContent).toBe("Section 1");
410
+ expect(wrapper.children[2].tagName).toBe("ASIDE");
411
+ expect(wrapper.children[2].textContent).toBe("Aside 1");
412
+ expect(wrapper.children[3].tagName).toBe("ASIDE");
413
+ expect(wrapper.children[3].textContent).toBe("Aside 2");
414
+ expect(wrapper.children[4].tagName).toBe("SECTION");
415
+ expect(wrapper.children[4].textContent).toBe("Section 2");
416
+ expect(wrapper.children[5].tagName).toBe("FOOTER");
417
+ });
418
+ it("should patch fragment removing all children", async () => {
419
+ const container = document.createElement("div");
420
+ let stateFn;
421
+ const App = () => {
422
+ const state = createState({ hasChildren: true });
423
+ stateFn = state;
424
+ return () => jsx("div", {
425
+ children: [
426
+ jsx(Fragment, {
427
+ children: state.hasChildren
428
+ ? [
429
+ jsx("span", { children: ["A"] }),
430
+ jsx("span", { children: ["B"] }),
431
+ jsx("span", { children: ["C"] }),
432
+ ]
433
+ : [],
434
+ }),
435
+ ],
436
+ });
437
+ };
438
+ render(jsx(App, {}), container);
439
+ const wrapper = container.children[0];
440
+ expect(wrapper.children.length).toBe(3);
441
+ stateFn.hasChildren = false;
442
+ await vi.runAllTimersAsync();
443
+ expect(wrapper.children.length).toBe(0);
444
+ });
445
+ it("should patch multiple sequential fragment changes", async () => {
446
+ const container = document.createElement("div");
447
+ let stateFn;
448
+ const App = () => {
449
+ const state = createState({ childCount: 1 });
450
+ stateFn = state;
451
+ return () => {
452
+ const children = [];
453
+ for (let i = 0; i < state.childCount; i++) {
454
+ const labels = ["One", "Two", "Three"];
455
+ children.push(jsx("span", { children: [labels[i]] }));
456
+ }
457
+ return jsx(Fragment, { children });
458
+ };
459
+ };
460
+ render(jsx(App, {}), container);
461
+ expect(container.children.length).toBe(1);
462
+ expect(container.children[0].textContent).toBe("One");
463
+ // Patch 1: Add element
464
+ stateFn.childCount = 2;
465
+ await vi.runAllTimersAsync();
466
+ expect(container.children.length).toBe(2);
467
+ expect(container.children[1].textContent).toBe("Two");
468
+ // Patch 2: Add another element
469
+ stateFn.childCount = 3;
470
+ await vi.runAllTimersAsync();
471
+ expect(container.children.length).toBe(3);
472
+ expect(container.children[2].textContent).toBe("Three");
473
+ // Patch 3: Remove middle element (simulate by updating the logic)
474
+ // We need to adjust the test to remove the middle element
475
+ // Let's create a different approach for this test
476
+ });
477
+ it("should patch multiple sequential fragment changes with removal", async () => {
478
+ const container = document.createElement("div");
479
+ let stateFn;
480
+ const App = () => {
481
+ const state = createState({ items: ["One"] });
482
+ stateFn = state;
483
+ return () => jsx(Fragment, {
484
+ children: state.items.map((item) => jsx("span", { children: [item] })),
485
+ });
486
+ };
487
+ render(jsx(App, {}), container);
488
+ expect(container.children.length).toBe(1);
489
+ expect(container.children[0].textContent).toBe("One");
490
+ // Patch 1: Add element
491
+ stateFn.items = ["One", "Two"];
492
+ await vi.runAllTimersAsync();
493
+ expect(container.children.length).toBe(2);
494
+ expect(container.children[1].textContent).toBe("Two");
495
+ // Patch 2: Add another element
496
+ stateFn.items = ["One", "Two", "Three"];
497
+ await vi.runAllTimersAsync();
498
+ expect(container.children.length).toBe(3);
499
+ expect(container.children[2].textContent).toBe("Three");
500
+ // Patch 3: Remove middle element
501
+ stateFn.items = ["One", "Three"];
502
+ await vi.runAllTimersAsync();
503
+ expect(container.children.length).toBe(2);
504
+ expect(container.children[0].textContent).toBe("One");
505
+ expect(container.children[1].textContent).toBe("Three");
506
+ });
507
+ });
508
+ describe("Component-Fragment interaction", () => {
509
+ beforeEach(() => {
510
+ vi.useFakeTimers();
511
+ });
512
+ afterEach(() => {
513
+ vi.clearAllTimers();
514
+ });
515
+ it("should patch by replacing element with component returning fragment", async () => {
516
+ const container = document.createElement("div");
517
+ let stateFn;
518
+ const FragmentComponent = () => {
519
+ return () => jsx(Fragment, {
520
+ children: [
521
+ jsx("p", { children: ["First"] }),
522
+ jsx("p", { children: ["Second"] }),
523
+ ],
524
+ });
525
+ };
526
+ const App = () => {
527
+ const state = createState({ useComponent: false });
528
+ stateFn = state;
529
+ return () => jsx("div", {
530
+ children: [
531
+ state.useComponent
532
+ ? jsx(FragmentComponent, {})
533
+ : jsx("p", { children: ["Single"] }),
534
+ ],
535
+ });
536
+ };
537
+ render(jsx(App, {}), container);
538
+ const wrapper = container.children[0];
539
+ expect(wrapper.children.length).toBe(1);
540
+ expect(wrapper.children[0].textContent).toBe("Single");
541
+ stateFn.useComponent = true;
542
+ await vi.runAllTimersAsync();
543
+ expect(wrapper.children.length).toBe(2);
544
+ expect(wrapper.children[0].textContent).toBe("First");
545
+ expect(wrapper.children[1].textContent).toBe("Second");
546
+ });
547
+ it("should patch by replacing component returning fragment with element", async () => {
548
+ const container = document.createElement("div");
549
+ let stateFn;
550
+ const FragmentComponent = () => {
551
+ return () => jsx(Fragment, {
552
+ children: [
553
+ jsx("p", { children: ["First"] }),
554
+ jsx("p", { children: ["Second"] }),
555
+ ],
556
+ });
557
+ };
558
+ const App = () => {
559
+ const state = createState({ useComponent: true });
560
+ stateFn = state;
561
+ return () => jsx("div", {
562
+ children: [
563
+ state.useComponent
564
+ ? jsx(FragmentComponent, {})
565
+ : jsx("p", { children: ["Single"] }),
566
+ ],
567
+ });
568
+ };
569
+ render(jsx(App, {}), container);
570
+ const wrapper = container.children[0];
571
+ expect(wrapper.children.length).toBe(2);
572
+ expect(wrapper.children[0].textContent).toBe("First");
573
+ expect(wrapper.children[1].textContent).toBe("Second");
574
+ stateFn.useComponent = false;
575
+ await vi.runAllTimersAsync();
576
+ expect(wrapper.children.length).toBe(1);
577
+ expect(wrapper.children[0].textContent).toBe("Single");
578
+ });
579
+ it("should conditionally switch between element and component returning fragment", async () => {
580
+ const container = document.createElement("div");
581
+ let globalState;
582
+ const FragmentComponent = () => {
583
+ return () => jsx(Fragment, {
584
+ children: [
585
+ jsx("p", { children: ["Fragment 1"] }),
586
+ jsx("p", { children: ["Fragment 2"] }),
587
+ ],
588
+ });
589
+ };
590
+ const App = () => {
591
+ const state = createState({ showFragment: false });
592
+ globalState = state;
593
+ return () => jsx("div", {
594
+ children: [
595
+ state.showFragment
596
+ ? jsx(FragmentComponent, {})
597
+ : jsx("p", { children: ["Single"] }),
598
+ ],
599
+ });
600
+ };
601
+ render(jsx(App, {}), container);
602
+ const wrapper = container.children[0];
603
+ expect(wrapper.children.length).toBe(1);
604
+ expect(wrapper.children[0].textContent).toBe("Single");
605
+ // Switch to fragment
606
+ globalState.showFragment = true;
607
+ await vi.runAllTimersAsync();
608
+ expect(wrapper.children.length).toBe(2);
609
+ expect(wrapper.children[0].textContent).toBe("Fragment 1");
610
+ expect(wrapper.children[1].textContent).toBe("Fragment 2");
611
+ // Switch back to element
612
+ globalState.showFragment = false;
613
+ await vi.runAllTimersAsync();
614
+ expect(wrapper.children.length).toBe(1);
615
+ expect(wrapper.children[0].textContent).toBe("Single");
616
+ });
617
+ });
618
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=integration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integration.test.d.ts","sourceRoot":"","sources":["../../src/tests/integration.test.ts"],"names":[],"mappings":""}