rask-ui 0.2.5 → 0.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. package/dist/vdom/AbstractVNode.d.ts +20 -1
  2. package/dist/vdom/AbstractVNode.d.ts.map +1 -1
  3. package/dist/vdom/AbstractVNode.js +151 -12
  4. package/dist/vdom/ComponentVNode.d.ts +2 -2
  5. package/dist/vdom/ComponentVNode.d.ts.map +1 -1
  6. package/dist/vdom/ComponentVNode.js +17 -8
  7. package/dist/vdom/ElementVNode.d.ts +6 -9
  8. package/dist/vdom/ElementVNode.d.ts.map +1 -1
  9. package/dist/vdom/ElementVNode.js +103 -34
  10. package/dist/vdom/FragmentVNode.d.ts +2 -2
  11. package/dist/vdom/FragmentVNode.d.ts.map +1 -1
  12. package/dist/vdom/FragmentVNode.js +18 -7
  13. package/dist/vdom/RootVNode.d.ts +2 -2
  14. package/dist/vdom/RootVNode.d.ts.map +1 -1
  15. package/dist/vdom/RootVNode.js +15 -6
  16. package/dist/vdom/dom-utils.d.ts +6 -1
  17. package/dist/vdom/dom-utils.d.ts.map +1 -1
  18. package/dist/vdom/dom-utils.js +20 -1
  19. package/dist/vdom/types.d.ts +12 -0
  20. package/dist/vdom/types.d.ts.map +1 -1
  21. package/package.json +1 -1
  22. package/dist/component.d.ts +0 -38
  23. package/dist/component.d.ts.map +0 -1
  24. package/dist/component.js +0 -130
  25. package/dist/context.d.ts +0 -5
  26. package/dist/context.d.ts.map +0 -1
  27. package/dist/context.js +0 -29
  28. package/dist/createAsync.test.d.ts +0 -2
  29. package/dist/createAsync.test.d.ts.map +0 -1
  30. package/dist/createAsync.test.js +0 -110
  31. package/dist/createAsyncState.d.ts +0 -16
  32. package/dist/createAsyncState.d.ts.map +0 -1
  33. package/dist/createAsyncState.js +0 -24
  34. package/dist/createContext.test.d.ts +0 -2
  35. package/dist/createContext.test.d.ts.map +0 -1
  36. package/dist/createContext.test.js +0 -136
  37. package/dist/createMutation.test.d.ts +0 -2
  38. package/dist/createMutation.test.d.ts.map +0 -1
  39. package/dist/createMutation.test.js +0 -168
  40. package/dist/createQuery.test.d.ts +0 -2
  41. package/dist/createQuery.test.d.ts.map +0 -1
  42. package/dist/createQuery.test.js +0 -156
  43. package/dist/createRef.test.d.ts +0 -2
  44. package/dist/createRef.test.d.ts.map +0 -1
  45. package/dist/createRef.test.js +0 -80
  46. package/dist/createState.test.d.ts +0 -2
  47. package/dist/createState.test.d.ts.map +0 -1
  48. package/dist/createState.test.js +0 -111
  49. package/dist/createView.test.d.ts +0 -2
  50. package/dist/createView.test.d.ts.map +0 -1
  51. package/dist/createView.test.js +0 -203
  52. package/dist/error.test.d.ts +0 -2
  53. package/dist/error.test.d.ts.map +0 -1
  54. package/dist/error.test.js +0 -144
  55. package/dist/integration.test.d.ts +0 -2
  56. package/dist/integration.test.d.ts.map +0 -1
  57. package/dist/integration.test.js +0 -155
  58. package/dist/jsx.d.ts.map +0 -1
  59. package/dist/jsx.js +0 -42
  60. package/dist/observation.test.d.ts +0 -2
  61. package/dist/observation.test.d.ts.map +0 -1
  62. package/dist/observation.test.js +0 -113
  63. package/dist/render-test.d.ts +0 -2
  64. package/dist/render-test.d.ts.map +0 -1
  65. package/dist/render-test.js +0 -21
  66. package/dist/render.d.ts +0 -7
  67. package/dist/render.d.ts.map +0 -1
  68. package/dist/render.js +0 -77
  69. package/dist/suspense.d.ts +0 -25
  70. package/dist/suspense.d.ts.map +0 -1
  71. package/dist/suspense.js +0 -97
  72. package/dist/tests/class.test.d.ts +0 -2
  73. package/dist/tests/class.test.d.ts.map +0 -1
  74. package/dist/tests/class.test.js +0 -185
  75. package/dist/tests/complex-rendering.test.d.ts +0 -2
  76. package/dist/tests/complex-rendering.test.d.ts.map +0 -1
  77. package/dist/tests/complex-rendering.test.js +0 -400
  78. package/dist/tests/component.cleanup.test.d.ts +0 -2
  79. package/dist/tests/component.cleanup.test.d.ts.map +0 -1
  80. package/dist/tests/component.cleanup.test.js +0 -325
  81. package/dist/tests/component.counter.test.d.ts +0 -2
  82. package/dist/tests/component.counter.test.d.ts.map +0 -1
  83. package/dist/tests/component.counter.test.js +0 -124
  84. package/dist/tests/component.interaction.test.d.ts +0 -2
  85. package/dist/tests/component.interaction.test.d.ts.map +0 -1
  86. package/dist/tests/component.interaction.test.js +0 -73
  87. package/dist/tests/component.props.test.d.ts +0 -2
  88. package/dist/tests/component.props.test.d.ts.map +0 -1
  89. package/dist/tests/component.props.test.js +0 -334
  90. package/dist/tests/component.return-types.test.d.ts +0 -2
  91. package/dist/tests/component.return-types.test.d.ts.map +0 -1
  92. package/dist/tests/component.return-types.test.js +0 -357
  93. package/dist/tests/component.state.test.d.ts +0 -2
  94. package/dist/tests/component.state.test.d.ts.map +0 -1
  95. package/dist/tests/component.state.test.js +0 -135
  96. package/dist/tests/component.test.d.ts +0 -2
  97. package/dist/tests/component.test.d.ts.map +0 -1
  98. package/dist/tests/component.test.js +0 -63
  99. package/dist/tests/createAsync.test.d.ts +0 -2
  100. package/dist/tests/createAsync.test.d.ts.map +0 -1
  101. package/dist/tests/createAsync.test.js +0 -110
  102. package/dist/tests/createContext.test.d.ts +0 -2
  103. package/dist/tests/createContext.test.d.ts.map +0 -1
  104. package/dist/tests/createContext.test.js +0 -141
  105. package/dist/tests/createMutation.test.d.ts +0 -2
  106. package/dist/tests/createMutation.test.d.ts.map +0 -1
  107. package/dist/tests/createMutation.test.js +0 -168
  108. package/dist/tests/createQuery.test.d.ts +0 -2
  109. package/dist/tests/createQuery.test.d.ts.map +0 -1
  110. package/dist/tests/createQuery.test.js +0 -156
  111. package/dist/tests/createRef.test.d.ts +0 -2
  112. package/dist/tests/createRef.test.d.ts.map +0 -1
  113. package/dist/tests/createRef.test.js +0 -84
  114. package/dist/tests/createState.test.d.ts +0 -2
  115. package/dist/tests/createState.test.d.ts.map +0 -1
  116. package/dist/tests/createState.test.js +0 -103
  117. package/dist/tests/createView.test.d.ts +0 -2
  118. package/dist/tests/createView.test.d.ts.map +0 -1
  119. package/dist/tests/createView.test.js +0 -203
  120. package/dist/tests/edge-cases.test.d.ts +0 -2
  121. package/dist/tests/edge-cases.test.d.ts.map +0 -1
  122. package/dist/tests/edge-cases.test.js +0 -637
  123. package/dist/tests/error-no-boundary.test.d.ts +0 -2
  124. package/dist/tests/error-no-boundary.test.d.ts.map +0 -1
  125. package/dist/tests/error-no-boundary.test.js +0 -174
  126. package/dist/tests/error.test.d.ts +0 -2
  127. package/dist/tests/error.test.d.ts.map +0 -1
  128. package/dist/tests/error.test.js +0 -199
  129. package/dist/tests/fragment.test.d.ts +0 -2
  130. package/dist/tests/fragment.test.d.ts.map +0 -1
  131. package/dist/tests/fragment.test.js +0 -618
  132. package/dist/tests/integration.test.d.ts +0 -2
  133. package/dist/tests/integration.test.d.ts.map +0 -1
  134. package/dist/tests/integration.test.js +0 -192
  135. package/dist/tests/keys.test.d.ts +0 -2
  136. package/dist/tests/keys.test.d.ts.map +0 -1
  137. package/dist/tests/keys.test.js +0 -293
  138. package/dist/tests/mount.test.d.ts +0 -2
  139. package/dist/tests/mount.test.d.ts.map +0 -1
  140. package/dist/tests/mount.test.js +0 -91
  141. package/dist/tests/observation.test.d.ts +0 -2
  142. package/dist/tests/observation.test.d.ts.map +0 -1
  143. package/dist/tests/observation.test.js +0 -113
  144. package/dist/tests/patch.test.d.ts +0 -2
  145. package/dist/tests/patch.test.d.ts.map +0 -1
  146. package/dist/tests/patch.test.js +0 -498
  147. package/dist/tests/patchChildren.test.d.ts +0 -2
  148. package/dist/tests/patchChildren.test.d.ts.map +0 -1
  149. package/dist/tests/patchChildren.test.js +0 -405
  150. package/dist/tests/primitives.test.d.ts +0 -2
  151. package/dist/tests/primitives.test.d.ts.map +0 -1
  152. package/dist/tests/primitives.test.js +0 -132
  153. package/dist/vdom/class.test.d.ts +0 -2
  154. package/dist/vdom/class.test.d.ts.map +0 -1
  155. package/dist/vdom/class.test.js +0 -143
  156. package/dist/vdom/complex-rendering.test.d.ts +0 -2
  157. package/dist/vdom/complex-rendering.test.d.ts.map +0 -1
  158. package/dist/vdom/complex-rendering.test.js +0 -400
  159. package/dist/vdom/component.cleanup.test.d.ts +0 -2
  160. package/dist/vdom/component.cleanup.test.d.ts.map +0 -1
  161. package/dist/vdom/component.cleanup.test.js +0 -323
  162. package/dist/vdom/component.counter.test.d.ts +0 -2
  163. package/dist/vdom/component.counter.test.d.ts.map +0 -1
  164. package/dist/vdom/component.counter.test.js +0 -124
  165. package/dist/vdom/component.interaction.test.d.ts +0 -2
  166. package/dist/vdom/component.interaction.test.d.ts.map +0 -1
  167. package/dist/vdom/component.interaction.test.js +0 -73
  168. package/dist/vdom/component.props.test.d.ts +0 -2
  169. package/dist/vdom/component.props.test.d.ts.map +0 -1
  170. package/dist/vdom/component.props.test.js +0 -88
  171. package/dist/vdom/component.return-types.test.d.ts +0 -2
  172. package/dist/vdom/component.return-types.test.d.ts.map +0 -1
  173. package/dist/vdom/component.return-types.test.js +0 -357
  174. package/dist/vdom/component.state.test.d.ts +0 -2
  175. package/dist/vdom/component.state.test.d.ts.map +0 -1
  176. package/dist/vdom/component.state.test.js +0 -129
  177. package/dist/vdom/component.test.d.ts +0 -2
  178. package/dist/vdom/component.test.d.ts.map +0 -1
  179. package/dist/vdom/component.test.js +0 -63
  180. package/dist/vdom/edge-cases.test.d.ts +0 -2
  181. package/dist/vdom/edge-cases.test.d.ts.map +0 -1
  182. package/dist/vdom/edge-cases.test.js +0 -637
  183. package/dist/vdom/fragment.test.d.ts +0 -2
  184. package/dist/vdom/fragment.test.d.ts.map +0 -1
  185. package/dist/vdom/fragment.test.js +0 -618
  186. package/dist/vdom/keys.test.d.ts +0 -2
  187. package/dist/vdom/keys.test.d.ts.map +0 -1
  188. package/dist/vdom/keys.test.js +0 -293
  189. package/dist/vdom/mount.test.d.ts +0 -2
  190. package/dist/vdom/mount.test.d.ts.map +0 -1
  191. package/dist/vdom/mount.test.js +0 -91
  192. package/dist/vdom/patch.test.d.ts +0 -2
  193. package/dist/vdom/patch.test.d.ts.map +0 -1
  194. package/dist/vdom/patch.test.js +0 -498
  195. package/dist/vdom/patchChildren.test.d.ts +0 -2
  196. package/dist/vdom/patchChildren.test.d.ts.map +0 -1
  197. package/dist/vdom/patchChildren.test.js +0 -392
  198. package/dist/vdom/primitives.test.d.ts +0 -2
  199. package/dist/vdom/primitives.test.d.ts.map +0 -1
  200. package/dist/vdom/primitives.test.js +0 -132
@@ -1,4 +1,5 @@
1
1
  import { AbstractVNode } from "./AbstractVNode";
2
+ import { flattenNodes } from "./dom-utils";
2
3
  // Global reference to the currently executing root
3
4
  // Safe because JS is single-threaded - only one render executes at a time
4
5
  export let currentRoot;
@@ -56,14 +57,22 @@ export class RootVNode extends AbstractVNode {
56
57
  }
57
58
  }
58
59
  mount() {
59
- return this.children.map((childNode) => childNode.mount(this)).flat();
60
+ // Optimized: avoid intermediate arrays from map+flat
61
+ const childResults = [];
62
+ for (let i = 0; i < this.children.length; i++) {
63
+ childResults.push(this.children[i].mount(this));
64
+ }
65
+ const result = flattenNodes(childResults);
66
+ return result.length === 1 ? result[0] : result;
60
67
  }
61
68
  patch() { }
62
- rerender() {
63
- const childrenElms = this.children
64
- .map((child) => child.getElements())
65
- .flat();
66
- this.elm.replaceChildren(...childrenElms);
69
+ rerender(operations) {
70
+ if (operations) {
71
+ this.applyPatchOperations(this.getHTMLElement(), operations);
72
+ }
73
+ else {
74
+ this.syncDOMChildren();
75
+ }
67
76
  this.flushLifecycle();
68
77
  }
69
78
  unmount() { }
@@ -1,9 +1,14 @@
1
+ /**
2
+ * Efficiently flatten a Node or Node[] result without creating intermediate arrays.
3
+ * Used to optimize mount operations that return either Node or Node[].
4
+ */
5
+ export declare function flattenNodes(items: (Node | Node[])[]): Node[];
1
6
  export declare function replaceElementsOf(parent: HTMLElement, newChildren: Node | Node[]): void;
2
7
  export declare function elementsToFragment(elm: Node | Node[]): Node;
3
8
  export declare function removeElementRange(parent: Node, start: Node, end: Node): void;
4
9
  export declare function setElementProp(elm: HTMLElement, key: string, value: unknown): void;
5
10
  export declare function setElementAttr(elm: HTMLElement, key: string, value: string | null): void;
6
- export declare function setElementStyle(elm: HTMLElement, value: string | Record<string, unknown> | null): void;
11
+ export declare function setElementStyle(elm: HTMLElement, value?: string | Record<string, unknown> | null): void;
7
12
  export declare function isEventProp(name: string): boolean;
8
13
  export declare function setElementClass(elm: HTMLElement, value: string | Record<string, boolean> | null | undefined): void;
9
14
  //# sourceMappingURL=dom-utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dom-utils.d.ts","sourceRoot":"","sources":["../../src/vdom/dom-utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,WAAW,EACnB,WAAW,EAAE,IAAI,GAAG,IAAI,EAAE,QAO3B;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,IAAI,GAAG,IAAI,EAAE,GAAG,IAAI,CAc3D;AAGD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,QAQtE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,QAE3E;AAED,wBAAgB,cAAc,CAC5B,GAAG,EAAE,WAAW,EAChB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GAAG,IAAI,QAOrB;AAED,wBAAgB,eAAe,CAC7B,GAAG,EAAE,WAAW,EAChB,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,QAe/C;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED,wBAAgB,eAAe,CAC7B,GAAG,EAAE,WAAW,EAChB,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,QA0B3D"}
1
+ {"version":3,"file":"dom-utils.d.ts","sourceRoot":"","sources":["../../src/vdom/dom-utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,CAAC,IAAI,GAAG,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,CAa7D;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,WAAW,EACnB,WAAW,EAAE,IAAI,GAAG,IAAI,EAAE,QAO3B;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,IAAI,GAAG,IAAI,EAAE,GAAG,IAAI,CAc3D;AAGD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,QAQtE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,QAE3E;AAED,wBAAgB,cAAc,CAC5B,GAAG,EAAE,WAAW,EAChB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GAAG,IAAI,QAOrB;AAED,wBAAgB,eAAe,CAC7B,GAAG,EAAE,WAAW,EAChB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,QAehD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED,wBAAgB,eAAe,CAC7B,GAAG,EAAE,WAAW,EAChB,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,QA0B3D"}
@@ -1,3 +1,22 @@
1
+ /**
2
+ * Efficiently flatten a Node or Node[] result without creating intermediate arrays.
3
+ * Used to optimize mount operations that return either Node or Node[].
4
+ */
5
+ export function flattenNodes(items) {
6
+ const result = [];
7
+ for (let i = 0; i < items.length; i++) {
8
+ const item = items[i];
9
+ if (Array.isArray(item)) {
10
+ for (let j = 0; j < item.length; j++) {
11
+ result.push(item[j]);
12
+ }
13
+ }
14
+ else {
15
+ result.push(item);
16
+ }
17
+ }
18
+ return result;
19
+ }
1
20
  export function replaceElementsOf(parent, newChildren) {
2
21
  if (Array.isArray(newChildren)) {
3
22
  parent.replaceChildren(...newChildren);
@@ -42,7 +61,7 @@ export function setElementAttr(elm, key, value) {
42
61
  }
43
62
  }
44
63
  export function setElementStyle(elm, value) {
45
- if (value === null) {
64
+ if (value === null || value === undefined) {
46
65
  elm.removeAttribute("style");
47
66
  return;
48
67
  }
@@ -5,4 +5,16 @@ import { RootVNode } from "./RootVNode";
5
5
  import { TextVNode } from "./TextVNode";
6
6
  export type VNode = ElementVNode | FragmentVNode | ComponentVNode | TextVNode | RootVNode;
7
7
  export type Props = Record<string, unknown>;
8
+ /**
9
+ * Bit flags to optimize VNode property checks.
10
+ * Pre-computed during VNode creation to avoid repeated conditional checks.
11
+ */
12
+ export declare const enum VFlags {
13
+ None = 0,
14
+ HasProps = 1,// Has any props at all
15
+ HasClass = 2,// Has class or className prop
16
+ HasStyle = 4,// Has style prop
17
+ HasEvents = 8,// Has event listeners (onXxx props)
18
+ HasDataAttrs = 16
19
+ }
8
20
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/vdom/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,MAAM,MAAM,KAAK,GACb,YAAY,GACZ,aAAa,GACb,cAAc,GACd,SAAS,GACT,SAAS,CAAC;AAEd,MAAM,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/vdom/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,MAAM,MAAM,KAAK,GACb,YAAY,GACZ,aAAa,GACb,cAAc,GACd,SAAS,GACT,SAAS,CAAC;AAEd,MAAM,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE5C;;;GAGG;AACH,0BAAkB,MAAM;IACtB,IAAI,IAAI;IACR,QAAQ,IAAS,CAAQ,uBAAuB;IAChD,QAAQ,IAAS,CAAQ,8BAA8B;IACvD,QAAQ,IAAS,CAAQ,iBAAiB;IAC1C,SAAS,IAAS,CAAO,oCAAoC;IAC7D,YAAY,KAAS;CACtB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rask-ui",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
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"}
package/dist/component.js DELETED
@@ -1,130 +0,0 @@
1
- import { thunk } from "snabbdom";
2
- import { getCurrentObserver, Observer, Signal } from "./observation";
3
- import { jsx, patch } from "./render";
4
- import { createState } from "./createState";
5
- const componentStack = [];
6
- export function getCurrentComponent() {
7
- return componentStack[0] || null;
8
- }
9
- export function onMount(cb) {
10
- const current = componentStack[0];
11
- if (!current) {
12
- throw new Error("Only use onMount in component setup");
13
- }
14
- current.onMounts.push(cb);
15
- }
16
- export function onCleanup(cb) {
17
- const current = componentStack[0];
18
- if (!current) {
19
- throw new Error("Only use onCleanup in component setup");
20
- }
21
- current.onCleanups.push(cb);
22
- }
23
- const hook = {
24
- insert(vnode) {
25
- componentStack.shift();
26
- vnode.data.componentInstance.onMounts.forEach((cb) => cb());
27
- },
28
- destroy(vnode) {
29
- vnode.data.componentInstance.onCleanups.forEach((cb) => cb());
30
- },
31
- prepatch(oldVnode, thunk) {
32
- copyToThunk(oldVnode, thunk);
33
- componentStack.unshift(thunk.data.componentInstance);
34
- },
35
- postpatch(_, newNode) {
36
- const componentInstance = newNode.data.componentInstance;
37
- componentStack.shift();
38
- const props = newNode.data.args[0];
39
- const children = newNode.data.args[1];
40
- for (const key in props) {
41
- componentInstance.reactiveProps[key] = props[key];
42
- }
43
- componentInstance.reactiveProps.children = children;
44
- },
45
- init(thunk) {
46
- const component = thunk.data.fn;
47
- const args = thunk.data.args;
48
- let errorSignal;
49
- let error;
50
- const executeRender = () => {
51
- const stopObserving = instance.observer.observe();
52
- let renderResult = null;
53
- try {
54
- renderResult = render();
55
- }
56
- catch (error) {
57
- instance.notifyError(error);
58
- }
59
- finally {
60
- stopObserving();
61
- }
62
- return jsx("component", {
63
- hook: {
64
- insert: hook.insert,
65
- destroy: hook.destroy,
66
- },
67
- "data-name": component.name,
68
- }, Array.isArray(renderResult) ? renderResult : [renderResult]);
69
- };
70
- const instance = {
71
- parent: thunk.data.parentComponent || null,
72
- component,
73
- contexts: null,
74
- onMounts: [],
75
- onCleanups: [],
76
- observer: new Observer(() => {
77
- const renderResult = executeRender();
78
- instance.hostNode = patch(instance.hostNode, renderResult);
79
- }),
80
- reactiveProps: createState({
81
- ...args[0],
82
- children: args[1],
83
- }),
84
- get error() {
85
- if (!errorSignal) {
86
- errorSignal = new Signal();
87
- }
88
- const observer = getCurrentObserver();
89
- if (observer) {
90
- observer.subscribeSignal(errorSignal);
91
- }
92
- return error;
93
- },
94
- notifyError(childError) {
95
- if (errorSignal) {
96
- error = childError;
97
- errorSignal.notify();
98
- }
99
- else if (instance.parent) {
100
- instance.parent.notifyError(childError);
101
- }
102
- else {
103
- throw childError;
104
- }
105
- },
106
- };
107
- componentStack.unshift(instance);
108
- const render = component(instance.reactiveProps);
109
- const renderResult = executeRender();
110
- renderResult.data.componentInstance = instance;
111
- copyToThunk(renderResult, thunk);
112
- instance.hostNode = thunk;
113
- },
114
- };
115
- export function createComponent(component, props, children) {
116
- const thunkNode = thunk("component", props.key, component, [props, children]);
117
- Object.assign(thunkNode.data.hook, hook);
118
- // Capture the parent component at vnode creation time (during render)
119
- // rather than at init time, to ensure correct parent relationships
120
- thunkNode.data.parentComponent = getCurrentComponent();
121
- return thunkNode;
122
- }
123
- function copyToThunk(vnode, thunk) {
124
- vnode.data.fn = thunk.data.fn;
125
- vnode.data.args = thunk.data.args;
126
- thunk.data = vnode.data;
127
- thunk.children = vnode.children;
128
- thunk.text = vnode.text;
129
- thunk.elm = vnode.elm;
130
- }
package/dist/context.d.ts DELETED
@@ -1,5 +0,0 @@
1
- export declare function createContext<T extends object>(): {
2
- set(value: T): void;
3
- get(): T;
4
- };
5
- //# sourceMappingURL=context.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAEA,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM;eAE/B,CAAC;WAaL,CAAC;EAmBX"}
package/dist/context.js DELETED
@@ -1,29 +0,0 @@
1
- import { getCurrentComponent } from "./component";
2
- export function createContext() {
3
- const context = {
4
- set(value) {
5
- const currentComponent = getCurrentComponent();
6
- if (!currentComponent) {
7
- throw new Error("You can not set context out component setup");
8
- }
9
- if (!currentComponent.contexts) {
10
- currentComponent.contexts = new Map();
11
- }
12
- currentComponent.contexts.set(context, value);
13
- },
14
- get() {
15
- let currentComponent = getCurrentComponent();
16
- if (!currentComponent) {
17
- throw new Error("You can not set context out component setup");
18
- }
19
- while (currentComponent) {
20
- if (currentComponent.contexts?.has(context)) {
21
- return currentComponent.contexts.get(context);
22
- }
23
- currentComponent = currentComponent.parent;
24
- }
25
- throw new Error("Could not find context in parent components");
26
- },
27
- };
28
- return context;
29
- }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=createAsync.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"createAsync.test.d.ts","sourceRoot":"","sources":["../src/createAsync.test.ts"],"names":[],"mappings":""}
@@ -1,110 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { createAsync } from './createAsync';
3
- describe('createAsync', () => {
4
- it('should start in pending state', () => {
5
- const promise = new Promise(() => { });
6
- const async = createAsync(promise);
7
- expect(async.isPending).toBe(true);
8
- expect(async.value).toBeNull();
9
- expect(async.error).toBeNull();
10
- });
11
- it('should resolve to value state on success', async () => {
12
- const promise = Promise.resolve('success');
13
- const async = createAsync(promise);
14
- expect(async.isPending).toBe(true);
15
- await promise;
16
- // Wait for state update
17
- await new Promise((resolve) => setTimeout(resolve, 0));
18
- expect(async.isPending).toBe(false);
19
- expect(async.value).toBe('success');
20
- expect(async.error).toBeNull();
21
- });
22
- it('should resolve to error state on rejection', async () => {
23
- const promise = Promise.reject(new Error('failed'));
24
- const async = createAsync(promise);
25
- expect(async.isPending).toBe(true);
26
- try {
27
- await promise;
28
- }
29
- catch {
30
- // Ignore
31
- }
32
- // Wait for state update
33
- await new Promise((resolve) => setTimeout(resolve, 0));
34
- expect(async.isPending).toBe(false);
35
- expect(async.value).toBeNull();
36
- expect(async.error).toContain('failed');
37
- });
38
- it('should handle numeric values', async () => {
39
- const promise = Promise.resolve(42);
40
- const async = createAsync(promise);
41
- await promise;
42
- await new Promise((resolve) => setTimeout(resolve, 0));
43
- expect(async.value).toBe(42);
44
- });
45
- it('should handle object values', async () => {
46
- const data = { id: 1, name: 'Test' };
47
- const promise = Promise.resolve(data);
48
- const async = createAsync(promise);
49
- await promise;
50
- await new Promise((resolve) => setTimeout(resolve, 0));
51
- expect(async.value).toEqual(data);
52
- });
53
- it('should handle array values', async () => {
54
- const data = [1, 2, 3, 4, 5];
55
- const promise = Promise.resolve(data);
56
- const async = createAsync(promise);
57
- await promise;
58
- await new Promise((resolve) => setTimeout(resolve, 0));
59
- expect(async.value).toEqual(data);
60
- });
61
- it('should convert error to string', async () => {
62
- const promise = Promise.reject('string error');
63
- const async = createAsync(promise);
64
- try {
65
- await promise;
66
- }
67
- catch {
68
- // Ignore
69
- }
70
- await new Promise((resolve) => setTimeout(resolve, 0));
71
- expect(typeof async.error).toBe('string');
72
- expect(async.error).toBe('string error');
73
- });
74
- it('should handle error objects', async () => {
75
- const error = new Error('Something went wrong');
76
- const promise = Promise.reject(error);
77
- const async = createAsync(promise);
78
- try {
79
- await promise;
80
- }
81
- catch {
82
- // Ignore
83
- }
84
- await new Promise((resolve) => setTimeout(resolve, 0));
85
- expect(async.error).toContain('Something went wrong');
86
- });
87
- it('should create reactive state', async () => {
88
- const promise = new Promise((resolve) => {
89
- setTimeout(() => resolve('delayed'), 10);
90
- });
91
- const async = createAsync(promise);
92
- expect(async.isPending).toBe(true);
93
- await promise;
94
- await new Promise((resolve) => setTimeout(resolve, 20));
95
- expect(async.isPending).toBe(false);
96
- expect(async.value).toBe('delayed');
97
- });
98
- it('should handle immediate resolution', async () => {
99
- const async = createAsync(Promise.resolve('immediate'));
100
- await new Promise((resolve) => setTimeout(resolve, 0));
101
- expect(async.isPending).toBe(false);
102
- expect(async.value).toBe('immediate');
103
- });
104
- it('should handle immediate rejection', async () => {
105
- const async = createAsync(Promise.reject('immediate error'));
106
- await new Promise((resolve) => setTimeout(resolve, 0));
107
- expect(async.isPending).toBe(false);
108
- expect(async.error).toBe('immediate error');
109
- });
110
- });
@@ -1,16 +0,0 @@
1
- type AsyncState<T> = {
2
- isPending: true;
3
- value: null;
4
- error: null;
5
- } | {
6
- isPending: false;
7
- value: T;
8
- error: null;
9
- } | {
10
- isPending: false;
11
- value: null;
12
- error: string;
13
- };
14
- export declare function createAsyncState<T>(promise: Promise<T>): AsyncState<T>;
15
- export {};
16
- //# sourceMappingURL=createAsyncState.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"createAsyncState.d.ts","sourceRoot":"","sources":["../src/createAsyncState.ts"],"names":[],"mappings":"AAEA,KAAK,UAAU,CAAC,CAAC,IACb;IACE,SAAS,EAAE,IAAI,CAAC;IAChB,KAAK,EAAE,IAAI,CAAC;IACZ,KAAK,EAAE,IAAI,CAAC;CACb,GACD;IACE,SAAS,EAAE,KAAK,CAAC;IACjB,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,IAAI,CAAC;CACb,GACD;IACE,SAAS,EAAE,KAAK,CAAC;IACjB,KAAK,EAAE,IAAI,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEN,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,iBAwBtD"}
@@ -1,24 +0,0 @@
1
- import { createState } from "./createState";
2
- export function createAsyncState(promise) {
3
- const state = createState({
4
- isPending: true,
5
- error: null,
6
- value: null,
7
- });
8
- promise
9
- .then((value) => {
10
- Object.assign(state, {
11
- value,
12
- error: null,
13
- isPending: false,
14
- });
15
- })
16
- .catch((error) => {
17
- Object.assign(state, {
18
- value: null,
19
- error: String(error),
20
- isPending: false,
21
- });
22
- });
23
- return state;
24
- }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=createContext.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"createContext.test.d.ts","sourceRoot":"","sources":["../src/createContext.test.tsx"],"names":[],"mappings":""}
@@ -1,136 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "./jsx-runtime";
2
- import { describe, it, expect } from "vitest";
3
- import { createContext } from "./createContext";
4
- import { render } from "./vdom";
5
- describe("createContext", () => {
6
- it("should create a context object", () => {
7
- const context = createContext();
8
- expect(context).toHaveProperty("inject");
9
- expect(context).toHaveProperty("get");
10
- });
11
- it("should allow setting and getting context values", () => {
12
- const ThemeContext = createContext();
13
- function Parent() {
14
- ThemeContext.inject({ theme: "dark" });
15
- return () => _jsx(Child, {});
16
- }
17
- function Child() {
18
- const theme = ThemeContext.get();
19
- return () => _jsx("div", { children: theme.theme });
20
- }
21
- const container = document.createElement("div");
22
- document.body.appendChild(container);
23
- const vnode = render(_jsx(Parent, {}), container);
24
- expect(vnode.elm.textContent).toContain("dark");
25
- document.body.removeChild(vnode.elm);
26
- });
27
- it("should traverse parent components to find context", () => {
28
- const ThemeContext = createContext();
29
- function GrandParent() {
30
- ThemeContext.inject({ theme: "light" });
31
- return () => _jsx(Parent, {});
32
- }
33
- function Parent() {
34
- return () => _jsx(Child, {});
35
- }
36
- function Child() {
37
- const theme = ThemeContext.get();
38
- return () => _jsx("div", { children: theme.theme });
39
- }
40
- const container = document.createElement("div");
41
- document.body.appendChild(container);
42
- const vnode = render(_jsx(GrandParent, {}), container);
43
- expect(vnode.elm.textContent).toContain("light");
44
- document.body.removeChild(vnode.elm);
45
- });
46
- it("should throw error when context is not found", () => {
47
- const ThemeContext = createContext();
48
- function Child() {
49
- expect(() => {
50
- ThemeContext.get();
51
- }).toThrow("Could not find context in parent components");
52
- return () => _jsx("div", { children: "Child" });
53
- }
54
- const container = document.createElement("div");
55
- document.body.appendChild(container);
56
- const vnode = render(_jsx(Child, {}), container);
57
- document.body.removeChild(vnode.elm);
58
- });
59
- it("should throw error when setting context outside component", () => {
60
- const ThemeContext = createContext();
61
- expect(() => {
62
- ThemeContext.inject({ theme: "dark" });
63
- }).toThrow("No current root");
64
- });
65
- it("should throw error when getting context outside component", () => {
66
- const ThemeContext = createContext();
67
- expect(() => {
68
- ThemeContext.get();
69
- }).toThrow("No current root");
70
- });
71
- it("should allow overriding context in nested components", () => {
72
- const ThemeContext = createContext();
73
- function GrandParent() {
74
- ThemeContext.inject({ theme: "light" });
75
- return () => (_jsxs("div", { children: [_jsx(Parent, {}), _jsx(ChildOfGrandParent, {})] }));
76
- }
77
- function Parent() {
78
- ThemeContext.inject({ theme: "dark" });
79
- return () => _jsx(ChildOfParent, {});
80
- }
81
- function ChildOfParent() {
82
- const theme = ThemeContext.get();
83
- return () => _jsx("div", { class: "child-of-parent", children: theme.theme });
84
- }
85
- function ChildOfGrandParent() {
86
- const theme = ThemeContext.get();
87
- return () => _jsx("div", { class: "child-of-grandparent", children: theme.theme });
88
- }
89
- const container = document.createElement("div");
90
- document.body.appendChild(container);
91
- const vnode = render(_jsx(GrandParent, {}), container);
92
- const childOfParent = document.querySelector(".child-of-parent");
93
- const childOfGrandParent = document.querySelector(".child-of-grandparent");
94
- expect(childOfParent?.textContent).toBe("dark");
95
- expect(childOfGrandParent?.textContent).toBe("light");
96
- document.body.removeChild(vnode.elm);
97
- });
98
- it("should support multiple different contexts", () => {
99
- const ThemeContext = createContext();
100
- const UserContext = createContext();
101
- function Parent() {
102
- ThemeContext.inject({ theme: "dark" });
103
- UserContext.inject({ name: "Alice" });
104
- return () => _jsx(Child, {});
105
- }
106
- function Child() {
107
- const theme = ThemeContext.get();
108
- const user = UserContext.get();
109
- return () => (_jsxs("div", { children: [theme.theme, " - ", user.name] }));
110
- }
111
- const container = document.createElement("div");
112
- document.body.appendChild(container);
113
- const vnode = render(_jsx(Parent, {}), container);
114
- expect(vnode.elm.textContent).toContain("dark - Alice");
115
- document.body.removeChild(vnode.elm);
116
- });
117
- it("should handle context values of different types", () => {
118
- const NumberContext = createContext();
119
- const ArrayContext = createContext();
120
- function Parent() {
121
- NumberContext.inject(42);
122
- ArrayContext.inject(["a", "b", "c"]);
123
- return () => _jsx(Child, {});
124
- }
125
- function Child() {
126
- const num = NumberContext.get();
127
- const arr = ArrayContext.get();
128
- return () => (_jsxs("div", { children: [num, " - ", arr.join(",")] }));
129
- }
130
- const container = document.createElement("div");
131
- document.body.appendChild(container);
132
- const vnode = render(_jsx(Parent, {}), container);
133
- expect(vnode.elm.textContent).toContain("42 - a,b,c");
134
- document.body.removeChild(vnode.elm);
135
- });
136
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=createMutation.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"createMutation.test.d.ts","sourceRoot":"","sources":["../src/createMutation.test.ts"],"names":[],"mappings":""}