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,5 +1,16 @@
1
1
  import { RootVNode } from "./RootVNode";
2
2
  import { VNode } from "./types";
3
+ export type PatchOperation = {
4
+ type: "add";
5
+ elm: Node | Node[];
6
+ } | {
7
+ type: "replace";
8
+ oldElm: Node | Node[];
9
+ newElm: Node | Node[];
10
+ } | {
11
+ type: "remove";
12
+ elm: Node | Node[];
13
+ };
3
14
  export declare abstract class AbstractVNode {
4
15
  key?: string;
5
16
  parent?: VNode;
@@ -9,7 +20,7 @@ export declare abstract class AbstractVNode {
9
20
  abstract mount(parent?: VNode): Node | Node[];
10
21
  abstract patch(oldNode: VNode): void;
11
22
  abstract unmount(): void;
12
- abstract rerender(): void;
23
+ abstract rerender(operations?: PatchOperation[]): void;
13
24
  protected getHTMLElement(): HTMLElement;
14
25
  /**
15
26
  * A VNode can represent multiple elements (fragment of component)
@@ -20,6 +31,14 @@ export declare abstract class AbstractVNode {
20
31
  patchChildren(newChildren: VNode[]): {
21
32
  children: VNode[];
22
33
  hasChangedStructure: boolean;
34
+ operations: PatchOperation[];
23
35
  };
36
+ applyPatchOperations(target: HTMLElement, operations: PatchOperation[]): void;
37
+ /**
38
+ * Intelligently sync DOM to match children VNode order.
39
+ * Only performs DOM operations when elements are out of position.
40
+ * This is used by both patch() and rerender() to efficiently update children.
41
+ */
42
+ protected syncDOMChildren(): void;
24
43
  }
25
44
  //# sourceMappingURL=AbstractVNode.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AbstractVNode.d.ts","sourceRoot":"","sources":["../../src/vdom/AbstractVNode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC,8BAAsB,aAAa;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,GAAG,CAAC,EAAE,IAAI,CAAC;IACX,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC;IACnB,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,GAAG,IAAI,GAAG,IAAI,EAAE;IAC7C,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,GAAG,IAAI;IACpC,QAAQ,CAAC,OAAO,IAAI,IAAI;IACxB,QAAQ,CAAC,QAAQ,IAAI,IAAI;IACzB,SAAS,CAAC,cAAc;IAOxB;;OAEG;IACH,WAAW,IAAI,IAAI,EAAE;IAWrB,gBAAgB,IAAI,WAAW;IAiB/B,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,GAAG,OAAO;IAoB3D,aAAa,CAAC,WAAW,EAAE,KAAK,EAAE,GAAG;QACnC,QAAQ,EAAE,KAAK,EAAE,CAAC;QAClB,mBAAmB,EAAE,OAAO,CAAC;KAC9B;CAqEF"}
1
+ {"version":3,"file":"AbstractVNode.d.ts","sourceRoot":"","sources":["../../src/vdom/AbstractVNode.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC,MAAM,MAAM,cAAc,GACtB;IACE,IAAI,EAAE,KAAK,CAAC;IACZ,GAAG,EAAE,IAAI,GAAG,IAAI,EAAE,CAAC;CACpB,GACD;IACE,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,IAAI,GAAG,IAAI,EAAE,CAAC;IACtB,MAAM,EAAE,IAAI,GAAG,IAAI,EAAE,CAAC;CACvB,GACD;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,GAAG,EAAE,IAAI,GAAG,IAAI,EAAE,CAAC;CACpB,CAAC;AAEN,8BAAsB,aAAa;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,GAAG,CAAC,EAAE,IAAI,CAAC;IACX,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC;IACnB,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,GAAG,IAAI,GAAG,IAAI,EAAE;IAC7C,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,GAAG,IAAI;IACpC,QAAQ,CAAC,OAAO,IAAI,IAAI;IACxB,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,cAAc,EAAE,GAAG,IAAI;IACtD,SAAS,CAAC,cAAc;IAOxB;;OAEG;IACH,WAAW,IAAI,IAAI,EAAE;IAWrB,gBAAgB,IAAI,WAAW;IAiB/B,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,GAAG,OAAO;IAoB3D,aAAa,CAAC,WAAW,EAAE,KAAK,EAAE,GAAG;QACnC,QAAQ,EAAE,KAAK,EAAE,CAAC;QAClB,mBAAmB,EAAE,OAAO,CAAC;QAC7B,UAAU,EAAE,cAAc,EAAE,CAAC;KAC9B;IAkJD,oBAAoB,CAAC,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE;IAqCtE;;;;OAIG;IACH,SAAS,CAAC,eAAe;CA6B1B"}
@@ -1,3 +1,4 @@
1
+ import { elementsToFragment } from "./dom-utils";
1
2
  export class AbstractVNode {
2
3
  key;
3
4
  parent;
@@ -57,12 +58,16 @@ export class AbstractVNode {
57
58
  // When there are only new children, we just mount them
58
59
  if (newChildren && prevChildren.length === 0) {
59
60
  newChildren.forEach((child) => child.mount(this));
60
- return { children: newChildren, hasChangedStructure: true };
61
+ return {
62
+ children: newChildren,
63
+ hasChangedStructure: true,
64
+ operations: [],
65
+ };
61
66
  }
62
67
  // If we want to remove all children, we just unmount the previous ones
63
68
  if (!newChildren.length && prevChildren.length) {
64
69
  prevChildren.forEach((child) => child.unmount());
65
- return { children: [], hasChangedStructure: true };
70
+ return { children: [], hasChangedStructure: true, operations: [] };
66
71
  }
67
72
  const oldKeys = {};
68
73
  prevChildren.forEach((prevChild, index) => {
@@ -73,43 +78,169 @@ export class AbstractVNode {
73
78
  });
74
79
  // Build result array in the NEW order
75
80
  const result = [];
76
- let hasChangedStructure = false;
81
+ const operations = [];
82
+ // Track indices of reused nodes in their original order
83
+ const reusedOldIndices = [];
84
+ // Track which result positions contain new nodes (not reused/replaced)
85
+ const isNewNode = [];
86
+ let forceStructuralChange = false;
77
87
  newChildren.forEach((newChild, index) => {
78
88
  const key = newChild.key || index;
79
89
  const prevChild = oldKeys[key];
80
90
  if (!prevChild) {
81
91
  // New child - mount and add to result
82
- newChild.mount(this);
92
+ const elm = newChild.mount(this);
83
93
  result.push(newChild);
84
- hasChangedStructure = true;
94
+ isNewNode.push(true);
95
+ operations.push({ type: "add", elm });
85
96
  }
86
97
  else if (prevChild?.vnode === newChild) {
87
98
  // Same instance - no patching needed, just reuse
88
99
  result.push(prevChild.vnode);
100
+ isNewNode.push(false);
101
+ reusedOldIndices.push(prevChild.index);
89
102
  delete oldKeys[key];
90
- hasChangedStructure = hasChangedStructure || prevChild.index !== index;
91
103
  }
92
104
  else if (this.canPatch(prevChild.vnode, newChild)) {
93
105
  // Compatible types - patch and reuse old VNode
94
106
  prevChild.vnode.patch(newChild);
95
107
  result.push(prevChild.vnode);
108
+ isNewNode.push(false);
109
+ reusedOldIndices.push(prevChild.index);
96
110
  delete oldKeys[key];
97
- hasChangedStructure = hasChangedStructure || prevChild.index !== index;
98
111
  }
99
112
  else {
100
113
  // Incompatible types - replace completely
101
- newChild.mount(this);
114
+ const newElm = newChild.mount(this);
102
115
  prevChild.vnode.unmount();
103
116
  result.push(newChild);
117
+ isNewNode.push(false); // Replacement, not an insertion
104
118
  delete oldKeys[key];
105
- hasChangedStructure = true;
119
+ const oldElm = prevChild.vnode.getElements();
120
+ // We need to fall back to structural change when the old node does
121
+ // not have any elements. This can happen when a component returns null,
122
+ // throws an error etc.
123
+ if (!oldElm.length) {
124
+ forceStructuralChange = true;
125
+ return;
126
+ }
127
+ operations.push({
128
+ type: "replace",
129
+ oldElm,
130
+ newElm,
131
+ });
106
132
  }
107
133
  });
108
134
  // Unmount any old children that weren't reused
109
135
  for (const key in oldKeys) {
110
136
  oldKeys[key].vnode.unmount();
111
- hasChangedStructure = true;
137
+ operations.push({
138
+ type: "remove",
139
+ elm: oldKeys[key].vnode.getElements(),
140
+ });
141
+ }
142
+ // Detect structural changes:
143
+ // 1. Reordering: reused nodes are not in their original relative order
144
+ // 2. Insertion in middle: new nodes inserted before existing nodes
145
+ let hasReordering = false;
146
+ let hasInsertionInMiddle = false;
147
+ if (!forceStructuralChange) {
148
+ for (let i = 1; i < reusedOldIndices.length; i++) {
149
+ if (reusedOldIndices[i] < reusedOldIndices[i - 1]) {
150
+ hasReordering = true;
151
+ break;
152
+ }
153
+ }
154
+ }
155
+ if (!hasReordering) {
156
+ // Find the last position that contains a reused/replaced node
157
+ let lastReusedResultIndex = -1;
158
+ for (let i = result.length - 1; i >= 0; i--) {
159
+ if (!isNewNode[i]) {
160
+ lastReusedResultIndex = i;
161
+ break;
162
+ }
163
+ }
164
+ // Check if any new nodes were inserted before the last reused/replaced node
165
+ if (lastReusedResultIndex >= 0) {
166
+ for (let i = 0; i < lastReusedResultIndex; i++) {
167
+ if (isNewNode[i]) {
168
+ hasInsertionInMiddle = true;
169
+ break;
170
+ }
171
+ }
172
+ }
173
+ }
174
+ const hasChangedStructure = forceStructuralChange || hasReordering || hasInsertionInMiddle;
175
+ if (hasChangedStructure) {
176
+ operations.length = 0;
177
+ }
178
+ return { children: result, hasChangedStructure, operations };
179
+ }
180
+ applyPatchOperations(target, operations) {
181
+ operations.forEach((operation) => {
182
+ switch (operation.type) {
183
+ case "add": {
184
+ target.appendChild(elementsToFragment(operation.elm));
185
+ break;
186
+ }
187
+ case "remove": {
188
+ if (Array.isArray(operation.elm)) {
189
+ const range = new Range();
190
+ range.setStartBefore(operation.elm[0]);
191
+ range.setEndAfter(operation.elm[operation.elm.length - 1]);
192
+ range.deleteContents();
193
+ }
194
+ else {
195
+ target.removeChild(operation.elm);
196
+ }
197
+ break;
198
+ }
199
+ case "replace": {
200
+ if (Array.isArray(operation.oldElm)) {
201
+ const range = new Range();
202
+ range.setStartBefore(operation.oldElm[0]);
203
+ range.setEndAfter(operation.oldElm[operation.oldElm.length - 1]);
204
+ range.deleteContents();
205
+ range.insertNode(elementsToFragment(operation.newElm));
206
+ }
207
+ else {
208
+ target.replaceChild(elementsToFragment(operation.newElm), operation.oldElm);
209
+ }
210
+ break;
211
+ }
212
+ }
213
+ });
214
+ }
215
+ /**
216
+ * Intelligently sync DOM to match children VNode order.
217
+ * Only performs DOM operations when elements are out of position.
218
+ * This is used by both patch() and rerender() to efficiently update children.
219
+ */
220
+ syncDOMChildren() {
221
+ if (!this.children) {
222
+ return;
223
+ }
224
+ const elm = this.elm;
225
+ let currentDomChild = elm.firstChild;
226
+ for (const child of this.children) {
227
+ const childNodes = child.getElements();
228
+ for (const node of childNodes) {
229
+ if (currentDomChild === node) {
230
+ // Already in correct position, advance pointer
231
+ currentDomChild = currentDomChild.nextSibling;
232
+ }
233
+ else {
234
+ // Insert (or move if it exists elsewhere in DOM)
235
+ elm.insertBefore(node, currentDomChild);
236
+ }
237
+ }
238
+ }
239
+ // Remove any leftover nodes (shouldn't happen if unmount works correctly)
240
+ while (currentDomChild) {
241
+ const next = currentDomChild.nextSibling;
242
+ elm.removeChild(currentDomChild);
243
+ currentDomChild = next;
112
244
  }
113
- return { children: result, hasChangedStructure };
114
245
  }
115
246
  }
@@ -1,5 +1,5 @@
1
1
  import { Observer } from "../observation";
2
- import { AbstractVNode } from "./AbstractVNode";
2
+ import { AbstractVNode, PatchOperation } from "./AbstractVNode";
3
3
  import { Props, VNode } from "./types";
4
4
  export type ComponentChild = VNode | string | null | number | undefined | boolean;
5
5
  export type ComponentChildren = ComponentChild | ComponentChild[];
@@ -40,7 +40,7 @@ export declare class ComponentVNode extends AbstractVNode {
40
40
  children: VNode[];
41
41
  instance?: ComponentInstance;
42
42
  constructor(component: Component<any>, props: Props, children: VNode[], key?: string);
43
- rerender(): void;
43
+ rerender(operations?: PatchOperation[]): void;
44
44
  mount(parent?: VNode): Node[];
45
45
  patch(newNode: ComponentVNode): void;
46
46
  unmount(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"ComponentVNode.d.ts","sourceRoot":"","sources":["../../src/vdom/ComponentVNode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,QAAQ,EAAU,MAAM,gBAAgB,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAGvC,MAAM,MAAM,cAAc,GACtB,KAAK,GACL,MAAM,GACN,IAAI,GACJ,MAAM,GACN,SAAS,GACT,OAAO,CAAC;AACZ,MAAM,MAAM,iBAAiB,GAAG,cAAc,GAAG,cAAc,EAAE,CAAC;AAElE;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,KAAK,IACjC,CAAC,CAAC,KAAK,EAAE,CAAC,KAAK,MAAM,iBAAiB,CAAC,GACvC,CAAC,MAAM,MAAM,iBAAiB,CAAC,CAAC;AAEpC,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACtC,QAAQ,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC;IAC5B,UAAU,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC;IAC9B,QAAQ,EAAE,QAAQ,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;CACnC,CAAC;AAKF,wBAAgB,mBAAmB,sBAYlC;AAED,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,IAAI,QAYrC;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,IAAI,QAYvC;AAED,qBAAa,cAAe,SAAQ,aAAa;IAC/C,SAAS,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC;IAC1B,KAAK,EAAE,KAAK,CAAC;IAEb,QAAQ,EAAE,KAAK,EAAE,CAAM;IACvB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;gBAE3B,SAAS,EAAE,SAAS,CAAC,GAAG,CAAC,EACzB,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,KAAK,EAAE,EACjB,GAAG,CAAC,EAAE,MAAM;IAWd,QAAQ,IAAI,IAAI;IAGhB,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,GAAG,IAAI,EAAE;IAmI7B,KAAK,CAAC,OAAO,EAAE,cAAc;IAW7B,OAAO;CAcR"}
1
+ {"version":3,"file":"ComponentVNode.d.ts","sourceRoot":"","sources":["../../src/vdom/ComponentVNode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,QAAQ,EAAU,MAAM,gBAAgB,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGhE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAGvC,MAAM,MAAM,cAAc,GACtB,KAAK,GACL,MAAM,GACN,IAAI,GACJ,MAAM,GACN,SAAS,GACT,OAAO,CAAC;AACZ,MAAM,MAAM,iBAAiB,GAAG,cAAc,GAAG,cAAc,EAAE,CAAC;AAElE;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,KAAK,IACjC,CAAC,CAAC,KAAK,EAAE,CAAC,KAAK,MAAM,iBAAiB,CAAC,GACvC,CAAC,MAAM,MAAM,iBAAiB,CAAC,CAAC;AAEpC,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACtC,QAAQ,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC;IAC5B,UAAU,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC;IAC9B,QAAQ,EAAE,QAAQ,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;CACnC,CAAC;AAKF,wBAAgB,mBAAmB,sBAYlC;AAED,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,IAAI,QAYrC;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,IAAI,QAYvC;AAED,qBAAa,cAAe,SAAQ,aAAa;IAC/C,SAAS,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC;IAC1B,KAAK,EAAE,KAAK,CAAC;IAEb,QAAQ,EAAE,KAAK,EAAE,CAAM;IACvB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;gBAE3B,SAAS,EAAE,SAAS,CAAC,GAAG,CAAC,EACzB,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,KAAK,EAAE,EACjB,GAAG,CAAC,EAAE,MAAM;IAWd,QAAQ,CAAC,UAAU,CAAC,EAAE,cAAc,EAAE,GAAG,IAAI;IAG7C,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,GAAG,IAAI,EAAE;IA0I7B,KAAK,CAAC,OAAO,EAAE,cAAc;IAW7B,OAAO;CAcR"}
@@ -50,8 +50,8 @@ export class ComponentVNode extends AbstractVNode {
50
50
  this.children = [];
51
51
  this.key = key;
52
52
  }
53
- rerender() {
54
- this.parent?.rerender();
53
+ rerender(operations) {
54
+ this.parent?.rerender(operations);
55
55
  }
56
56
  mount(parent) {
57
57
  this.parent = parent;
@@ -95,12 +95,17 @@ export class ComponentVNode extends AbstractVNode {
95
95
  isObserverQueued = false;
96
96
  this.root?.setAsCurrent();
97
97
  const newChildren = executeRender();
98
- const prevChildren = this.children;
99
- const { children, hasChangedStructure } = this.patchChildren(newChildren);
98
+ const { children, hasChangedStructure, operations } = this.patchChildren(newChildren);
100
99
  this.children = children;
101
- if (hasChangedStructure) {
100
+ // So if a fragment is returned where we add new elements we can not safely
101
+ // add them yet, check Fragment for a potential later optimization
102
+ const hasAddOperation = operations.some((operation) => operation.type === "add");
103
+ if (hasChangedStructure || hasAddOperation) {
102
104
  this.parent?.rerender();
103
105
  }
106
+ else if (operations.length) {
107
+ this.parent?.rerender(operations);
108
+ }
104
109
  this.root?.clearCurrent();
105
110
  });
106
111
  }),
@@ -1,4 +1,4 @@
1
- import { AbstractVNode } from "./AbstractVNode";
1
+ import { AbstractVNode, PatchOperation } from "./AbstractVNode";
2
2
  import { Props, VNode } from "./types";
3
3
  export declare class ElementVNode extends AbstractVNode {
4
4
  tag: string;
@@ -8,7 +8,7 @@ export declare class ElementVNode extends AbstractVNode {
8
8
  private ref?;
9
9
  private eventListeners?;
10
10
  constructor(tag: string, { ref, ...props }: Props, children: VNode[], key?: string);
11
- rerender(): void;
11
+ rerender(operations?: PatchOperation[]): void;
12
12
  mount(parent?: VNode): Node;
13
13
  /**
14
14
  * An ELEMENT patch goes through three operations
@@ -20,11 +20,5 @@ export declare class ElementVNode extends AbstractVNode {
20
20
  private setProp;
21
21
  private patchProps;
22
22
  private addEventListener;
23
- /**
24
- * Intelligently sync DOM to match children VNode order.
25
- * Only performs DOM operations when elements are out of position.
26
- * This is used by both patch() and rerender() to efficiently update children.
27
- */
28
- private syncDOMChildren;
29
23
  }
30
24
  //# sourceMappingURL=ElementVNode.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ElementVNode.d.ts","sourceRoot":"","sources":["../../src/vdom/ElementVNode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAUvC,qBAAa,YAAa,SAAQ,aAAa;IAC7C,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,KAAK,EAAE,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,GAAG,CAAC,CAA0D;IACtE,OAAO,CAAC,cAAc,CAAC,CAA6B;gBAElD,GAAG,EAAE,MAAM,EACX,EAAE,GAAG,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,EACxB,QAAQ,EAAE,KAAK,EAAE,EACjB,GAAG,CAAC,EAAE,MAAM;IASd,QAAQ,IAAI,IAAI;IAGhB,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,GAAG,IAAI;IAkC3B;;;;OAIG;IACH,KAAK,CAAC,OAAO,EAAE,YAAY;IAY3B,OAAO;IAYP,OAAO,CAAC,OAAO,CAoCb;IACF,OAAO,CAAC,UAAU;IAGlB,OAAO,CAAC,gBAAgB;IAgBxB;;;;OAIG;IACH,OAAO,CAAC,eAAe;CAyBxB"}
1
+ {"version":3,"file":"ElementVNode.d.ts","sourceRoot":"","sources":["../../src/vdom/ElementVNode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGhE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAUvC,qBAAa,YAAa,SAAQ,aAAa;IAC7C,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,KAAK,EAAE,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,GAAG,CAAC,CAA0D;IACtE,OAAO,CAAC,cAAc,CAAC,CAA6B;gBAElD,GAAG,EAAE,MAAM,EACX,EAAE,GAAG,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,EACxB,QAAQ,EAAE,KAAK,EAAE,EACjB,GAAG,CAAC,EAAE,MAAM;IASd,QAAQ,CAAC,UAAU,CAAC,EAAE,cAAc,EAAE,GAAG,IAAI;IAO7C,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,GAAG,IAAI;IAkC3B;;;;OAIG;IACH,KAAK,CAAC,OAAO,EAAE,YAAY;IAc3B,OAAO;IAYP,OAAO,CAAC,OAAO,CAoCb;IACF,OAAO,CAAC,UAAU;IAGlB,OAAO,CAAC,gBAAgB;CAgBzB"}
@@ -17,8 +17,13 @@ export class ElementVNode extends AbstractVNode {
17
17
  this.key = key;
18
18
  this.ref = ref;
19
19
  }
20
- rerender() {
21
- this.syncDOMChildren();
20
+ rerender(operations) {
21
+ if (operations) {
22
+ this.applyPatchOperations(this.getHTMLElement(), operations);
23
+ }
24
+ else {
25
+ this.syncDOMChildren();
26
+ }
22
27
  }
23
28
  mount(parent) {
24
29
  this.parent = parent;
@@ -57,11 +62,14 @@ export class ElementVNode extends AbstractVNode {
57
62
  patch(newNode) {
58
63
  this.patchProps(newNode.props);
59
64
  this.props = newNode.props;
60
- const { children, hasChangedStructure } = this.patchChildren(newNode.children);
65
+ const { children, hasChangedStructure, operations } = this.patchChildren(newNode.children);
61
66
  this.children = children;
62
67
  if (hasChangedStructure) {
63
68
  this.syncDOMChildren();
64
69
  }
70
+ else {
71
+ this.applyPatchOperations(this.getHTMLElement(), operations);
72
+ }
65
73
  }
66
74
  unmount() {
67
75
  this.children.forEach((child) => child.unmount());
@@ -120,32 +128,4 @@ export class ElementVNode extends AbstractVNode {
120
128
  delete this.eventListeners[type];
121
129
  }
122
130
  }
123
- /**
124
- * Intelligently sync DOM to match children VNode order.
125
- * Only performs DOM operations when elements are out of position.
126
- * This is used by both patch() and rerender() to efficiently update children.
127
- */
128
- syncDOMChildren() {
129
- const elm = this.elm;
130
- let currentDomChild = elm.firstChild;
131
- for (const child of this.children) {
132
- const childNodes = child.getElements();
133
- for (const node of childNodes) {
134
- if (currentDomChild === node) {
135
- // Already in correct position, advance pointer
136
- currentDomChild = currentDomChild.nextSibling;
137
- }
138
- else {
139
- // Insert (or move if it exists elsewhere in DOM)
140
- elm.insertBefore(node, currentDomChild);
141
- }
142
- }
143
- }
144
- // Remove any leftover nodes (shouldn't happen if unmount works correctly)
145
- while (currentDomChild) {
146
- const next = currentDomChild.nextSibling;
147
- elm.removeChild(currentDomChild);
148
- currentDomChild = next;
149
- }
150
- }
151
131
  }
@@ -1,4 +1,4 @@
1
- import { AbstractVNode } from "./AbstractVNode";
1
+ import { AbstractVNode, PatchOperation } from "./AbstractVNode";
2
2
  import { VNode } from "./types";
3
3
  export declare const Fragment: unique symbol;
4
4
  export declare class FragmentVNode extends AbstractVNode {
@@ -6,7 +6,7 @@ export declare class FragmentVNode extends AbstractVNode {
6
6
  key?: string;
7
7
  constructor(children: VNode[], key?: string);
8
8
  mount(parent?: VNode): Node[];
9
- rerender(): void;
9
+ rerender(operations?: PatchOperation[]): void;
10
10
  patch(newNode: FragmentVNode): void;
11
11
  unmount(): void;
12
12
  }
@@ -1 +1 @@
1
- {"version":3,"file":"FragmentVNode.d.ts","sourceRoot":"","sources":["../../src/vdom/FragmentVNode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAKhD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC,eAAO,MAAM,QAAQ,eAAqB,CAAC;AAE3C,qBAAa,aAAc,SAAQ,aAAa;IAC9C,QAAQ,EAAE,KAAK,EAAE,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;gBAED,QAAQ,EAAE,KAAK,EAAE,EAAE,GAAG,CAAC,EAAE,MAAM;IAK3C,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,GAAG,IAAI,EAAE;IAW7B,QAAQ,IAAI,IAAI;IAGhB,KAAK,CAAC,OAAO,EAAE,aAAa;IAS5B,OAAO;CAMR"}
1
+ {"version":3,"file":"FragmentVNode.d.ts","sourceRoot":"","sources":["../../src/vdom/FragmentVNode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAKhE,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC,eAAO,MAAM,QAAQ,eAAqB,CAAC;AAE3C,qBAAa,aAAc,SAAQ,aAAa;IAC9C,QAAQ,EAAE,KAAK,EAAE,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;gBAED,QAAQ,EAAE,KAAK,EAAE,EAAE,GAAG,CAAC,EAAE,MAAM;IAK3C,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,GAAG,IAAI,EAAE;IAW7B,QAAQ,CAAC,UAAU,CAAC,EAAE,cAAc,EAAE,GAAG,IAAI;IAG7C,KAAK,CAAC,OAAO,EAAE,aAAa;IAiB5B,OAAO;CAMR"}
@@ -19,15 +19,20 @@ export class FragmentVNode extends AbstractVNode {
19
19
  }
20
20
  return this.children.map((child) => child.mount(this)).flat();
21
21
  }
22
- rerender() {
23
- this.parent?.rerender();
22
+ rerender(operations) {
23
+ this.parent?.rerender(operations);
24
24
  }
25
25
  patch(newNode) {
26
- const { children, hasChangedStructure } = this.patchChildren(newNode.children);
26
+ const { children, hasChangedStructure, operations } = this.patchChildren(newNode.children);
27
27
  this.children = children;
28
- if (hasChangedStructure) {
29
- this.rerender();
30
- }
28
+ // So we can safely pass remove/replace operations up to the parent, but add
29
+ // is very tricky as parent has potentially other children as well. This can be
30
+ // handled with some additional detection, changing it to insertBefore. This can be
31
+ // done by passing this vnode up to the parent
32
+ this.rerender(hasChangedStructure ||
33
+ operations.some((operation) => operation.type === "add")
34
+ ? undefined
35
+ : operations);
31
36
  }
32
37
  unmount() {
33
38
  this.children.forEach((child) => child.unmount());
@@ -1,4 +1,4 @@
1
- import { AbstractVNode } from "./AbstractVNode";
1
+ import { AbstractVNode, PatchOperation } from "./AbstractVNode";
2
2
  import { VNode } from "./types";
3
3
  import { ComponentInstance } from "./ComponentVNode";
4
4
  export declare let currentRoot: RootVNode | undefined;
@@ -19,7 +19,7 @@ export declare class RootVNode extends AbstractVNode {
19
19
  clearCurrent(): void;
20
20
  mount(): Node | Node[];
21
21
  patch(): void;
22
- rerender(): void;
22
+ rerender(operations?: PatchOperation[]): void;
23
23
  unmount(): void;
24
24
  }
25
25
  //# sourceMappingURL=RootVNode.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"RootVNode.d.ts","sourceRoot":"","sources":["../../src/vdom/RootVNode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAIrD,eAAO,IAAI,WAAW,EAAE,SAAS,GAAG,SAAS,CAAC;AAE9C,qBAAa,SAAU,SAAQ,aAAa;IAC1C,QAAQ,EAAE,KAAK,EAAE,CAAC;IAClB,cAAc,EAAE,iBAAiB,EAAE,CAAM;IACzC,OAAO,CAAC,cAAc,CAGpB;IACF,OAAO,CAAC,mBAAmB,CAAkB;IAC7C,OAAO,CAAC,gBAAgB,CAAyB;gBAErC,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW;IAMnD,UAAU,CAAC,EAAE,EAAE,MAAM,IAAI;IAIzB,YAAY,CAAC,EAAE,EAAE,MAAM,IAAI;IAG3B,aAAa,CAAC,EAAE,EAAE,MAAM,IAAI;IAa5B,cAAc;IAOd,aAAa,CAAC,QAAQ,EAAE,iBAAiB;IAIzC,YAAY;IAIZ,YAAY;IAIZ,YAAY;IAMZ,KAAK,IAAI,IAAI,GAAG,IAAI,EAAE;IAGtB,KAAK,IAAI,IAAI;IACb,QAAQ,IAAI,IAAI;IAShB,OAAO,IAAI,IAAI;CAChB"}
1
+ {"version":3,"file":"RootVNode.d.ts","sourceRoot":"","sources":["../../src/vdom/RootVNode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAIrD,eAAO,IAAI,WAAW,EAAE,SAAS,GAAG,SAAS,CAAC;AAE9C,qBAAa,SAAU,SAAQ,aAAa;IAC1C,QAAQ,EAAE,KAAK,EAAE,CAAC;IAClB,cAAc,EAAE,iBAAiB,EAAE,CAAM;IACzC,OAAO,CAAC,cAAc,CAGpB;IACF,OAAO,CAAC,mBAAmB,CAAkB;IAC7C,OAAO,CAAC,gBAAgB,CAAyB;gBAErC,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW;IAMnD,UAAU,CAAC,EAAE,EAAE,MAAM,IAAI;IAIzB,YAAY,CAAC,EAAE,EAAE,MAAM,IAAI;IAG3B,aAAa,CAAC,EAAE,EAAE,MAAM,IAAI;IAa5B,cAAc;IAOd,aAAa,CAAC,QAAQ,EAAE,iBAAiB;IAIzC,YAAY;IAIZ,YAAY;IAIZ,YAAY;IAMZ,KAAK,IAAI,IAAI,GAAG,IAAI,EAAE;IAGtB,KAAK,IAAI,IAAI;IACb,QAAQ,CAAC,UAAU,CAAC,EAAE,cAAc,EAAE,GAAG,IAAI;IAS7C,OAAO,IAAI,IAAI;CAChB"}
@@ -59,11 +59,13 @@ export class RootVNode extends AbstractVNode {
59
59
  return this.children.map((childNode) => childNode.mount(this)).flat();
60
60
  }
61
61
  patch() { }
62
- rerender() {
63
- const childrenElms = this.children
64
- .map((child) => child.getElements())
65
- .flat();
66
- this.elm.replaceChildren(...childrenElms);
62
+ rerender(operations) {
63
+ if (operations) {
64
+ this.applyPatchOperations(this.getHTMLElement(), operations);
65
+ }
66
+ else {
67
+ this.syncDOMChildren();
68
+ }
67
69
  this.flushLifecycle();
68
70
  }
69
71
  unmount() { }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rask-ui",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -1,38 +0,0 @@
1
- import { type VNode } from "snabbdom";
2
- import { Observer } from "./observation";
3
- import { ChildNode } from "./render";
4
- /**
5
- * Component function type. Components receive reactive props that should not be destructured.
6
- *
7
- * @warning **Do not destructure props!** Props are wrapped in a reactive proxy, and destructuring
8
- * breaks reactivity. This is the same rule as Solid.js.
9
- *
10
- * @example
11
- * // ❌ Bad - destructuring props loses reactivity
12
- * function MyComponent({ count, name }) {
13
- * return () => <div>{count} {name}</div>; // Won't update!
14
- * }
15
- *
16
- * // ✅ Good - access props directly in render
17
- * function MyComponent(props) {
18
- * return () => <div>{props.count} {props.name}</div>; // Reactive!
19
- * }
20
- */
21
- export type Component<P> = ((props: P) => () => VNode) | (() => () => VNode);
22
- export type ComponentInstance = {
23
- parent: ComponentInstance | null;
24
- component: Component<any>;
25
- contexts: Map<object, object> | null;
26
- onMounts: Array<() => void>;
27
- onCleanups: Array<() => void>;
28
- hostNode?: VNode;
29
- observer: Observer;
30
- reactiveProps: object;
31
- error: unknown;
32
- notifyError(error: unknown): void;
33
- };
34
- export declare function getCurrentComponent(): ComponentInstance;
35
- export declare function onMount(cb: () => void): void;
36
- export declare function onCleanup(cb: () => void): void;
37
- export declare function createComponent(component: Component<any>, props: Record<string, unknown>, children: ChildNode[] | ChildNode): import("snabbdom").Thunk;
38
- //# sourceMappingURL=component.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../src/component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,KAAK,EAAkB,MAAM,UAAU,CAAC;AAE7D,OAAO,EAAsB,QAAQ,EAAU,MAAM,eAAe,CAAC;AACrE,OAAO,EAAc,SAAS,EAAE,MAAM,UAAU,CAAC;AAGjD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC,KAAK,MAAM,KAAK,CAAC,GAAG,CAAC,MAAM,MAAM,KAAK,CAAC,CAAC;AAE7E,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACjC,SAAS,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC;IAC1B,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IACrC,QAAQ,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC;IAC5B,UAAU,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC;IAC9B,QAAQ,CAAC,EAAE,KAAK,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;CACnC,CAAC;AAIF,wBAAgB,mBAAmB,sBAElC;AAED,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,IAAI,QAQrC;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,IAAI,QAQvC;AAuGD,wBAAgB,eAAe,CAC7B,SAAS,EAAE,SAAS,CAAC,GAAG,CAAC,EACzB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,QAAQ,EAAE,SAAS,EAAE,GAAG,SAAS,4BAWlC"}