@praxisjs/runtime 0.2.16 → 0.2.18

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # @praxisjs/runtime
2
2
 
3
+ ## 0.2.18
4
+
5
+ ### Patch Changes
6
+
7
+ - b9411cb: `innerHTML` prop support and JSX type fixes.
8
+ - `@praxisjs/runtime` — `innerHTML` now correctly assigns `element.innerHTML` (DOM property) instead of calling `setAttribute`. Supports reactive values: `innerHTML={() => this.html}`.
9
+ - `@praxisjs/jsx` — `innerHTML?: Reactive<string>` added to `HTMLAttributes`. `LibraryManagedAttributes` now includes `children?: Children` for all component types, so components using `@Slot` or receiving JSX children no longer produce a TypeScript error at the call site.
10
+
11
+ - Updated dependencies [cfb0de2]
12
+ - @praxisjs/decorators@1.0.2
13
+
14
+ ## 0.2.17
15
+
16
+ ### Patch Changes
17
+
18
+ - 9aeec6a: Optimize DOM patching in the runtime for lower allocation and fewer reflows.
19
+
20
+ **element.ts** — prop iteration now uses `for...in` instead of `Object.entries()`, avoiding the intermediate key-value array allocation per element mount.
21
+
22
+ **reactive.ts** — `normalizeToNodes` (returned a new array on every call) is replaced by `collectNodes` (accumulates into a caller-supplied array), removing one allocation per reactive update. Node insertion is batched through `nodesToFragment`: when multiple nodes are produced, they are appended to a `DocumentFragment` and inserted in a single `insertBefore` call. Bulk removal of existing nodes uses `Range.deleteContents()` instead of individual `removeChild` calls, reducing the number of reflow-triggering operations to one.
23
+
24
+ No changes to the public API.
25
+
26
+ - Updated dependencies [74d414a]
27
+ - @praxisjs/core@1.6.0
28
+ - @praxisjs/decorators@1.0.1
29
+
3
30
  ## 0.2.16
4
31
 
5
32
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/dom/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,+BAA+B,CAAC;AAE1D,eAAO,MAAM,QAAQ,aA2BnB,CAAC;AAEH,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA6B5C,CAAC;AAEF,eAAO,MAAM,WAAW,aAAwD,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/dom/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,+BAA+B,CAAC;AAE1D,eAAO,MAAM,QAAQ,aA2BnB,CAAC;AAEH,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA6B5C,CAAC;AAEF,eAAO,MAAM,WAAW,aAAqE,CAAC"}
@@ -57,5 +57,5 @@ export const EVENT_MAP = {
57
57
  onAnimationEnd: "animationend",
58
58
  onTransitionEnd: "transitionend",
59
59
  };
60
- export const VALUE_PROPS = new Set(["checked", "value", "disabled", "selected"]);
60
+ export const VALUE_PROPS = new Set(["checked", "value", "disabled", "selected", "innerHTML"]);
61
61
  //# sourceMappingURL=constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/dom/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG,4BAA4B,CAAC;AAE1D,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC;IAC9B,KAAK;IACL,MAAM;IACN,QAAQ;IACR,MAAM;IACN,MAAM;IACN,UAAU;IACV,SAAS;IACT,SAAS;IACT,MAAM;IACN,GAAG;IACH,MAAM;IACN,KAAK;IACL,QAAQ;IACR,QAAQ;IACR,UAAU;IACV,MAAM;IACN,SAAS;IACT,OAAO;IACP,gBAAgB;IAChB,gBAAgB;IAChB,MAAM;IACN,QAAQ;IACR,gBAAgB;IAChB,OAAO;IACP,UAAU;IACV,eAAe;CAChB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,SAAS,GAA2B;IAC/C,OAAO,EAAE,OAAO;IAChB,UAAU,EAAE,UAAU;IACtB,QAAQ,EAAE,QAAQ;IAClB,OAAO,EAAE,OAAO;IAChB,QAAQ,EAAE,QAAQ;IAClB,OAAO,EAAE,OAAO;IAChB,SAAS,EAAE,SAAS;IACpB,OAAO,EAAE,OAAO;IAChB,UAAU,EAAE,UAAU;IACtB,OAAO,EAAE,OAAO;IAChB,MAAM,EAAE,MAAM;IACd,WAAW,EAAE,WAAW;IACxB,SAAS,EAAE,SAAS;IACpB,YAAY,EAAE,YAAY;IAC1B,YAAY,EAAE,YAAY;IAC1B,WAAW,EAAE,WAAW;IACxB,aAAa,EAAE,aAAa;IAC5B,QAAQ,EAAE,QAAQ;IAClB,OAAO,EAAE,OAAO;IAChB,WAAW,EAAE,WAAW;IACxB,SAAS,EAAE,SAAS;IACpB,UAAU,EAAE,UAAU;IACtB,MAAM,EAAE,MAAM;IACd,YAAY,EAAE,YAAY;IAC1B,UAAU,EAAE,UAAU;IACtB,WAAW,EAAE,WAAW;IACxB,cAAc,EAAE,cAAc;IAC9B,eAAe,EAAE,eAAe;CACjC,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/dom/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG,4BAA4B,CAAC;AAE1D,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC;IAC9B,KAAK;IACL,MAAM;IACN,QAAQ;IACR,MAAM;IACN,MAAM;IACN,UAAU;IACV,SAAS;IACT,SAAS;IACT,MAAM;IACN,GAAG;IACH,MAAM;IACN,KAAK;IACL,QAAQ;IACR,QAAQ;IACR,UAAU;IACV,MAAM;IACN,SAAS;IACT,OAAO;IACP,gBAAgB;IAChB,gBAAgB;IAChB,MAAM;IACN,QAAQ;IACR,gBAAgB;IAChB,OAAO;IACP,UAAU;IACV,eAAe;CAChB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,SAAS,GAA2B;IAC/C,OAAO,EAAE,OAAO;IAChB,UAAU,EAAE,UAAU;IACtB,QAAQ,EAAE,QAAQ;IAClB,OAAO,EAAE,OAAO;IAChB,QAAQ,EAAE,QAAQ;IAClB,OAAO,EAAE,OAAO;IAChB,SAAS,EAAE,SAAS;IACpB,OAAO,EAAE,OAAO;IAChB,UAAU,EAAE,UAAU;IACtB,OAAO,EAAE,OAAO;IAChB,MAAM,EAAE,MAAM;IACd,WAAW,EAAE,WAAW;IACxB,SAAS,EAAE,SAAS;IACpB,YAAY,EAAE,YAAY;IAC1B,YAAY,EAAE,YAAY;IAC1B,WAAW,EAAE,WAAW;IACxB,aAAa,EAAE,aAAa;IAC5B,QAAQ,EAAE,QAAQ;IAClB,OAAO,EAAE,OAAO;IAChB,WAAW,EAAE,WAAW;IACxB,SAAS,EAAE,SAAS;IACpB,UAAU,EAAE,UAAU;IACtB,MAAM,EAAE,MAAM;IACd,YAAY,EAAE,YAAY;IAC1B,UAAU,EAAE,UAAU;IACtB,WAAW,EAAE,WAAW;IACxB,cAAc,EAAE,cAAc;IAC9B,eAAe,EAAE,eAAe;CACjC,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC"}
package/dist/element.js CHANGED
@@ -3,10 +3,10 @@ import { createElement } from "./dom/create";
3
3
  import { applyProp } from "./dom/props";
4
4
  export function mountElement(tag, props, scope) {
5
5
  const el = createElement(tag);
6
- for (const [key, val] of Object.entries(props)) {
6
+ for (const key in props) {
7
7
  if (key === "children")
8
8
  continue;
9
- applyProp(el, key, val, scope);
9
+ applyProp(el, key, props[key], scope);
10
10
  }
11
11
  if (props.children !== undefined) {
12
12
  mountChildren(el, props.children, scope);
@@ -1 +1 @@
1
- {"version":3,"file":"element.js","sourceRoot":"","sources":["../src/element.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAIxC,MAAM,UAAU,YAAY,CAC1B,GAAW,EACX,KAA8B,EAC9B,KAAY;IAEZ,MAAM,EAAE,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IAE9B,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/C,IAAI,GAAG,KAAK,UAAU;YAAE,SAAS;QACjC,SAAS,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IACjC,CAAC;IAED,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACjC,aAAa,CAAC,EAAE,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC3C,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC"}
1
+ {"version":3,"file":"element.js","sourceRoot":"","sources":["../src/element.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAIxC,MAAM,UAAU,YAAY,CAC1B,GAAW,EACX,KAA8B,EAC9B,KAAY;IAEZ,MAAM,EAAE,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IAE9B,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;QACxB,IAAI,GAAG,KAAK,UAAU;YAAE,SAAS;QACjC,SAAS,CAAC,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;IACxC,CAAC;IAED,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACjC,aAAa,CAAC,EAAE,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC3C,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"reactive.d.ts","sourceRoot":"","sources":["../src/reactive.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAYrC,wBAAgB,aAAa,CAC3B,MAAM,EAAE,IAAI,EACZ,EAAE,EAAE,MAAM,OAAO,EACjB,WAAW,EAAE,KAAK,GACjB,IAAI,CA8BN"}
1
+ {"version":3,"file":"reactive.d.ts","sourceRoot":"","sources":["../src/reactive.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAmBrC,wBAAgB,aAAa,CAC3B,MAAM,EAAE,IAAI,EACZ,EAAE,EAAE,MAAM,OAAO,EACjB,WAAW,EAAE,KAAK,GACjB,IAAI,CAoCN"}
package/dist/reactive.js CHANGED
@@ -1,36 +1,54 @@
1
1
  import { runInScope } from "./context";
2
- function normalizeToNodes(value) {
2
+ function collectNodes(value, out) {
3
3
  if (value === null || value === undefined || value === false)
4
- return [];
5
- if (value instanceof Node)
6
- return [value];
7
- if (Array.isArray(value))
8
- return value.flatMap(normalizeToNodes);
4
+ return;
5
+ if (value instanceof Node) {
6
+ out.push(value);
7
+ return;
8
+ }
9
+ if (Array.isArray(value)) {
10
+ for (const v of value)
11
+ collectNodes(v, out);
12
+ return;
13
+ }
9
14
  if (typeof value === "string" || typeof value === "number") {
10
- return [document.createTextNode(String(value))];
15
+ out.push(document.createTextNode(String(value)));
16
+ return;
11
17
  }
12
- return [];
18
+ }
19
+ function nodesToFragment(nodes) {
20
+ if (nodes.length === 1)
21
+ return nodes[0];
22
+ const fragment = document.createDocumentFragment();
23
+ for (const n of nodes)
24
+ fragment.appendChild(n);
25
+ return fragment;
13
26
  }
14
27
  export function mountReactive(parent, fn, parentScope) {
15
- const end = document.createComment("reactive");
28
+ const end = document.createComment("");
16
29
  parent.appendChild(end);
17
30
  let currentNodes = [];
18
31
  let childScope = parentScope.fork();
19
32
  parentScope.effect(() => {
20
33
  childScope.dispose();
21
34
  childScope = parentScope.fork();
22
- for (const n of currentNodes) {
23
- n.parentNode?.removeChild(n);
24
- }
25
- currentNodes = [];
26
35
  const result = runInScope(childScope, fn);
27
- const newNodes = normalizeToNodes(result);
28
- // Use end.parentNode instead of the original `parent` — the parent
29
- // reference may be a DocumentFragment that was emptied after its
30
- // children were transferred to the real DOM by mountComponent.
36
+ const newNodes = [];
37
+ collectNodes(result, newNodes);
31
38
  const anchor = end.parentNode ?? parent;
32
- for (const n of newNodes) {
33
- anchor.insertBefore(n, end);
39
+ if (currentNodes.length > 0) {
40
+ if (currentNodes.length === 1) {
41
+ anchor.removeChild(currentNodes[0]);
42
+ }
43
+ else {
44
+ const range = document.createRange();
45
+ range.setStartBefore(currentNodes[0]);
46
+ range.setEndAfter(currentNodes[currentNodes.length - 1]);
47
+ range.deleteContents();
48
+ }
49
+ }
50
+ if (newNodes.length > 0) {
51
+ anchor.insertBefore(nodesToFragment(newNodes), end);
34
52
  }
35
53
  currentNodes = newNodes;
36
54
  });
@@ -1 +1 @@
1
- {"version":3,"file":"reactive.js","sourceRoot":"","sources":["../src/reactive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAIvC,SAAS,gBAAgB,CAAC,KAAc;IACtC,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,KAAK;QAAE,OAAO,EAAE,CAAC;IACxE,IAAI,KAAK,YAAY,IAAI;QAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAC1C,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACjE,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC3D,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,MAAY,EACZ,EAAiB,EACjB,WAAkB;IAElB,MAAM,GAAG,GAAG,QAAQ,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;IAC/C,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAExB,IAAI,YAAY,GAAW,EAAE,CAAC;IAC9B,IAAI,UAAU,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC;IAEpC,WAAW,CAAC,MAAM,CAAC,GAAG,EAAE;QACtB,UAAU,CAAC,OAAO,EAAE,CAAC;QACrB,UAAU,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC;QAEhC,KAAK,MAAM,CAAC,IAAI,YAAY,EAAE,CAAC;YAC7B,CAAC,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;QAC/B,CAAC;QACD,YAAY,GAAG,EAAE,CAAC;QAElB,MAAM,MAAM,GAAG,UAAU,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;QAC1C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAE1C,mEAAmE;QACnE,iEAAiE;QACjE,+DAA+D;QAC/D,MAAM,MAAM,GAAG,GAAG,CAAC,UAAU,IAAI,MAAM,CAAC;QACxC,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;YACzB,MAAM,CAAC,YAAY,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAC9B,CAAC;QACD,YAAY,GAAG,QAAQ,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,CAAC"}
1
+ {"version":3,"file":"reactive.js","sourceRoot":"","sources":["../src/reactive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAIvC,SAAS,YAAY,CAAC,KAAc,EAAE,GAAW;IAC/C,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,KAAK;QAAE,OAAO;IACrE,IAAI,KAAK,YAAY,IAAI,EAAE,CAAC;QAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAAC,OAAO;IAAC,CAAC;IACvD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAAC,KAAK,MAAM,CAAC,IAAI,KAAK;YAAE,YAAY,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAAC,OAAO;IAAC,CAAC;IAClF,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC3D,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACjD,OAAO;IACT,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,KAAa;IACpC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;IACxC,MAAM,QAAQ,GAAG,QAAQ,CAAC,sBAAsB,EAAE,CAAC;IACnD,KAAK,MAAM,CAAC,IAAI,KAAK;QAAE,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAC/C,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,MAAY,EACZ,EAAiB,EACjB,WAAkB;IAElB,MAAM,GAAG,GAAG,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;IACvC,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAExB,IAAI,YAAY,GAAW,EAAE,CAAC;IAC9B,IAAI,UAAU,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC;IAEpC,WAAW,CAAC,MAAM,CAAC,GAAG,EAAE;QACtB,UAAU,CAAC,OAAO,EAAE,CAAC;QACrB,UAAU,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC;QAEhC,MAAM,MAAM,GAAG,UAAU,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;QAC1C,MAAM,QAAQ,GAAW,EAAE,CAAC;QAC5B,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAE/B,MAAM,MAAM,GAAG,GAAG,CAAC,UAAU,IAAI,MAAM,CAAC;QAExC,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC7B,MAAkB,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;YACnD,CAAC;iBAAM,CAAC;gBACN,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;gBACrC,KAAK,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;gBACtC,KAAK,CAAC,WAAW,CAAC,YAAY,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;gBACzD,KAAK,CAAC,cAAc,EAAE,CAAC;YACzB,CAAC;QACH,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,MAAM,CAAC,YAAY,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC;QACtD,CAAC;QAED,YAAY,GAAG,QAAQ,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@praxisjs/runtime",
3
- "version": "0.2.16",
3
+ "version": "0.2.18",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -14,8 +14,8 @@
14
14
  "typescript": "^5.9.3"
15
15
  },
16
16
  "dependencies": {
17
- "@praxisjs/core": "1.5.0",
18
- "@praxisjs/decorators": "1.0.0",
17
+ "@praxisjs/core": "1.6.0",
18
+ "@praxisjs/decorators": "1.0.2",
19
19
  "@praxisjs/shared": "0.2.0"
20
20
  },
21
21
  "scripts": {
@@ -60,4 +60,4 @@ export const EVENT_MAP: Record<string, string> = {
60
60
  onTransitionEnd: "transitionend",
61
61
  };
62
62
 
63
- export const VALUE_PROPS = new Set(["checked", "value", "disabled", "selected"]);
63
+ export const VALUE_PROPS = new Set(["checked", "value", "disabled", "selected", "innerHTML"]);
package/src/element.ts CHANGED
@@ -11,9 +11,9 @@ export function mountElement(
11
11
  ): HTMLElement | SVGElement {
12
12
  const el = createElement(tag);
13
13
 
14
- for (const [key, val] of Object.entries(props)) {
14
+ for (const key in props) {
15
15
  if (key === "children") continue;
16
- applyProp(el, key, val, scope);
16
+ applyProp(el, key, props[key], scope);
17
17
  }
18
18
 
19
19
  if (props.children !== undefined) {
package/src/reactive.ts CHANGED
@@ -2,14 +2,21 @@ import { runInScope } from "./context";
2
2
 
3
3
  import type { Scope } from "./scope";
4
4
 
5
- function normalizeToNodes(value: unknown): Node[] {
6
- if (value === null || value === undefined || value === false) return [];
7
- if (value instanceof Node) return [value];
8
- if (Array.isArray(value)) return value.flatMap(normalizeToNodes);
5
+ function collectNodes(value: unknown, out: Node[]): void {
6
+ if (value === null || value === undefined || value === false) return;
7
+ if (value instanceof Node) { out.push(value); return; }
8
+ if (Array.isArray(value)) { for (const v of value) collectNodes(v, out); return; }
9
9
  if (typeof value === "string" || typeof value === "number") {
10
- return [document.createTextNode(String(value))];
10
+ out.push(document.createTextNode(String(value)));
11
+ return;
11
12
  }
12
- return [];
13
+ }
14
+
15
+ function nodesToFragment(nodes: Node[]): Node {
16
+ if (nodes.length === 1) return nodes[0];
17
+ const fragment = document.createDocumentFragment();
18
+ for (const n of nodes) fragment.appendChild(n);
19
+ return fragment;
13
20
  }
14
21
 
15
22
  export function mountReactive(
@@ -17,7 +24,7 @@ export function mountReactive(
17
24
  fn: () => unknown,
18
25
  parentScope: Scope,
19
26
  ): void {
20
- const end = document.createComment("reactive");
27
+ const end = document.createComment("");
21
28
  parent.appendChild(end);
22
29
 
23
30
  let currentNodes: Node[] = [];
@@ -27,21 +34,27 @@ export function mountReactive(
27
34
  childScope.dispose();
28
35
  childScope = parentScope.fork();
29
36
 
30
- for (const n of currentNodes) {
31
- n.parentNode?.removeChild(n);
32
- }
33
- currentNodes = [];
34
-
35
37
  const result = runInScope(childScope, fn);
36
- const newNodes = normalizeToNodes(result);
38
+ const newNodes: Node[] = [];
39
+ collectNodes(result, newNodes);
37
40
 
38
- // Use end.parentNode instead of the original `parent` — the parent
39
- // reference may be a DocumentFragment that was emptied after its
40
- // children were transferred to the real DOM by mountComponent.
41
41
  const anchor = end.parentNode ?? parent;
42
- for (const n of newNodes) {
43
- anchor.insertBefore(n, end);
42
+
43
+ if (currentNodes.length > 0) {
44
+ if (currentNodes.length === 1) {
45
+ (anchor as Element).removeChild(currentNodes[0]);
46
+ } else {
47
+ const range = document.createRange();
48
+ range.setStartBefore(currentNodes[0]);
49
+ range.setEndAfter(currentNodes[currentNodes.length - 1]);
50
+ range.deleteContents();
51
+ }
52
+ }
53
+
54
+ if (newNodes.length > 0) {
55
+ anchor.insertBefore(nodesToFragment(newNodes), end);
44
56
  }
57
+
45
58
  currentNodes = newNodes;
46
59
  });
47
60