@torpor/view 0.1.1 → 0.1.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@torpor/view",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Torpor's view library, for writing and mounting components",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -35,15 +35,15 @@
35
35
  "@testing-library/user-event": "^14.6.1",
36
36
  "@trivago/prettier-plugin-sort-imports": "^5.2.2",
37
37
  "@types/jsdom": "^21.1.7",
38
- "@types/node": "^22.15.29",
38
+ "@types/node": "^24.0.3",
39
39
  "fast-glob": "^3.3.3",
40
40
  "jsdom": "^26.1.0",
41
41
  "sucrase": "^3.35.0",
42
42
  "tinybench": "^4.0.1",
43
43
  "tsup": "^8.5.0",
44
- "tsx": "^4.19.4",
44
+ "tsx": "^4.20.3",
45
45
  "typescript": "^5.8.3",
46
- "vitest": "^3.2.1"
46
+ "vitest": "^3.2.3"
47
47
  },
48
48
  "scripts": {
49
49
  "build": "tsc --noEmit && tsup && tsx ./scripts/copyToRepl.ts",
@@ -52,6 +52,17 @@ export default function buildComponentNode(
52
52
  value = value.substring(1, value.length - 1);
53
53
  buildRun("setProp", `${propsName}["${name}"] = ${value};`, status, b);
54
54
  buildRun("setBinding", `${value} = ${propsName}["${name}"];`, status, b);
55
+ } else if (name === ":class" && value != null && isFullyReactive(value)) {
56
+ status.imports.add("t_class");
57
+ value = value.substring(1, value.length - 1);
58
+ if (node.scopeStyles) {
59
+ value += `, "torp-${status.styleHash}"`;
60
+ }
61
+ buildRun("setClasses", `${propsName}["class"] = t_class(${value});`, status, b);
62
+ } else if (name === ":style" && value != null && isFullyReactive(value)) {
63
+ status.imports.add("t_style");
64
+ value = value.substring(1, value.length - 1);
65
+ buildRun("setStyles", `${propsName}["style"] = t_style(${value});`, status, b);
55
66
  } else if (value != null) {
56
67
  let fullyReactive = isFullyReactive(value);
57
68
  let partlyReactive = isReactive(value);
@@ -6,6 +6,7 @@ import { type BuildStatus } from "./BuildStatus";
6
6
  import buildAddFragment from "./buildAddFragment";
7
7
  import buildFragment from "./buildFragment";
8
8
  import buildNode from "./buildNode";
9
+ import replaceForVarNames from "./replaceForVarNames";
9
10
 
10
11
  // TODO: Are there too many branches for ifs etc?
11
12
 
@@ -55,7 +56,7 @@ function buildIfBranch(
55
56
  ) {
56
57
  status.imports.add("t_run_branch");
57
58
 
58
- b.append(`${node.statement} {`);
59
+ b.append(`${replaceForVarNames(node.statement, status)} {`);
59
60
  b.append(`t_run_branch(${rangeName}, ${index}, () => {`);
60
61
 
61
62
  buildFragment(node, status, b, parentName, "t_before");
@@ -5,6 +5,7 @@ import { type BuildStatus } from "./BuildStatus";
5
5
  import buildAddFragment from "./buildAddFragment";
6
6
  import buildFragment from "./buildFragment";
7
7
  import buildNode from "./buildNode";
8
+ import replaceForVarNames from "./replaceForVarNames";
8
9
 
9
10
  export default function buildReplaceNode(node: ControlNode, status: BuildStatus, b: Builder): void {
10
11
  const replaceAnchorName = node.varName!;
@@ -38,7 +39,7 @@ function buildReplaceBranch(
38
39
  ) {
39
40
  status.imports.add("t_run_branch");
40
41
 
41
- b.append(`${node.statement};`);
42
+ b.append(`${replaceForVarNames(node.statement, status)};`);
42
43
  b.append(`t_run_branch(${rangeName}, -1, () => {`);
43
44
 
44
45
  buildFragment(node, status, b, parentName, "t_before");
@@ -6,6 +6,7 @@ import { type BuildStatus } from "./BuildStatus";
6
6
  import buildAddFragment from "./buildAddFragment";
7
7
  import buildFragment from "./buildFragment";
8
8
  import buildNode from "./buildNode";
9
+ import replaceForVarNames from "./replaceForVarNames";
9
10
 
10
11
  export default function buildSwitchNode(node: ControlNode, status: BuildStatus, b: Builder): void {
11
12
  const switchParentName = node.parentName!;
@@ -55,7 +56,7 @@ function buildSwitchBranch(
55
56
  ) {
56
57
  status.imports.add("t_run_branch");
57
58
 
58
- b.append(`${node.statement} {`);
59
+ b.append(`${replaceForVarNames(node.statement, status)} {`);
59
60
  b.append(`t_run_branch(${rangeName}, ${index}, () => {`);
60
61
 
61
62
  buildFragment(node, status, b, parentName, "t_before");
@@ -34,6 +34,17 @@ export default function buildServerComponentNode(
34
34
  name = name.substring(1, name.length - 1);
35
35
  const propName = name.split(".").at(-1);
36
36
  b.append(`${propsName}["${propName}"] = ${name};`);
37
+ } else if (name === ":class" && value != null && isFullyReactive(value)) {
38
+ status.imports.add("t_class");
39
+ value = value.substring(1, value.length - 1);
40
+ if (node.scopeStyles) {
41
+ value += `, "torp-${status.styleHash}"`;
42
+ }
43
+ b.append(`${propsName}["class"] = t_class(${value});`);
44
+ } else if (name === ":style" && value != null && isFullyReactive(value)) {
45
+ status.imports.add("t_style");
46
+ value = value.substring(1, value.length - 1);
47
+ b.append(`${propsName}["style"] = t_style(${value});`);
37
48
  } else if (value != null) {
38
49
  let fullyReactive = isFullyReactive(value);
39
50
  let partlyReactive = isReactive(value);
@@ -28,7 +28,7 @@ function moveChildEffects(
28
28
  newData.propData.set(key, props);
29
29
 
30
30
  let oldPropValue = oldValue[key];
31
- let oldPropData = oldPropValue[proxyDataSymbol];
31
+ let oldPropData = oldPropValue != null ? oldPropValue[proxyDataSymbol] : undefined;
32
32
 
33
33
  // If the old value was a proxy, make the new value one too
34
34
  // TODO: Make sure we aren't accidentally creating proxies for
@@ -94,4 +94,10 @@ function check(container: HTMLElement, state: State) {
94
94
  expect(queryByText(container, "From state")).toHaveClass("hello red green torp-1ljxz83", {
95
95
  exact: true,
96
96
  });
97
+
98
+ // Components
99
+ expect(queryByText(container, "Child class")).not.toBeNull();
100
+ expect(queryByText(container, "Child class")).toHaveClass("child-class", {
101
+ exact: true,
102
+ });
97
103
  }
@@ -28,7 +28,9 @@ export default function Class() {
28
28
  <div :class={[ "foo", 0, { bar: true }, "", [1 && "baz", ["qux"]] ]}>
29
29
  Class nested
30
30
  </div>
31
- </div>
31
+
32
+ <Child :class={{ "child-class": true }} />
33
+ </div>
32
34
  }
33
35
 
34
36
  @style {
@@ -37,3 +39,11 @@ export default function Class() {
37
39
  }
38
40
  }
39
41
  }
42
+
43
+ function Child() {
44
+ @render {
45
+ <div class={$props.class}>
46
+ Child class
47
+ </div>
48
+ }
49
+ }
@@ -2,6 +2,7 @@ import $run from "../../../../src/render/$run";
2
2
  import $watch from "../../../../src/render/$watch";
3
3
  import { type SlotRender } from "../../../../src/types/SlotRender";
4
4
  import t_add_fragment from "../../../../src/render/addFragment";
5
+ import t_anchor from "../../../../src/render/nodeAnchor";
5
6
  import t_child from "../../../../src/render/nodeChild";
6
7
  import t_class from "../../../../src/render/getClasses";
7
8
  import t_fragment from "../../../../src/render/getFragment";
@@ -22,7 +23,7 @@ export default function Class(
22
23
  /* User interface */
23
24
  const t_fragments: DocumentFragment[] = [];
24
25
 
25
- const t_fragment_0 = t_fragment($parent.ownerDocument!, t_fragments, 0, `<div class="torp-1ljxz83"> <div id="divid" class="torp-1ljxz83"> From id </div> <div class="divclass torp-1ljxz83"> From string </div> <a class="torp-1ljxz83"> From state </a> <div class="torp-1ljxz83"> From state with scope </div> <div class="torp-1ljxz83"> Class object </div> <div class="torp-1ljxz83"> Class array </div> <div class="torp-1ljxz83"> Class nested </div> </div>`);
26
+ const t_fragment_0 = t_fragment($parent.ownerDocument!, t_fragments, 0, `<div class="torp-1ljxz83"> <div id="divid" class="torp-1ljxz83"> From id </div> <div class="divclass torp-1ljxz83"> From string </div> <a class="torp-1ljxz83"> From state </a> <div class="torp-1ljxz83"> From state with scope </div> <div class="torp-1ljxz83"> Class object </div> <div class="torp-1ljxz83"> Class array </div> <div class="torp-1ljxz83"> Class nested </div> <!> </div>`);
26
27
  // @ts-ignore
27
28
  const t_div_1 = t_root(t_fragment_0) as HTMLDivElement;
28
29
  const t_a_1 = t_next(t_child(t_div_1), 5) as HTMLElement;
@@ -30,6 +31,14 @@ export default function Class(
30
31
  const t_div_3 = t_next(t_div_2, 2) as HTMLDivElement;
31
32
  const t_div_4 = t_next(t_div_3, 2) as HTMLDivElement;
32
33
  const t_div_5 = t_next(t_div_4, 2) as HTMLDivElement;
34
+ const t_comp_anchor_1 = t_anchor(t_next(t_div_5, 2)) as HTMLElement;
35
+
36
+ /* @component */
37
+ const t_props_1: any = $watch({});
38
+ $run(function setClasses() {
39
+ t_props_1["class"] = t_class({ "child-class": true });
40
+ });
41
+ Child(t_div_1, t_comp_anchor_1, t_props_1, $context);
33
42
  $run(function setClasses() {
34
43
  t_a_1.className = t_class({ hello: true, red: $props.red, green: $props.green, blue: $props.blue }, "torp-1ljxz83");
35
44
  });
@@ -49,3 +58,28 @@ export default function Class(
49
58
  t_next(t_div_1);
50
59
 
51
60
  }
61
+
62
+ function Child(
63
+ $parent: ParentNode,
64
+ $anchor: Node | null,
65
+ $props: Record<PropertyKey, any>,
66
+ // @ts-ignore
67
+ $context?: Record<PropertyKey, any>,
68
+ // @ts-ignore
69
+ $slots?: Record<string, SlotRender>
70
+ ) {
71
+ $props ??= $watch({});
72
+
73
+ /* User interface */
74
+ const t_fragments: DocumentFragment[] = [];
75
+
76
+ const t_fragment_0 = t_fragment($parent.ownerDocument!, t_fragments, 0, `<div> Child class </div>`);
77
+ // @ts-ignore
78
+ const t_div_1 = t_root(t_fragment_0) as HTMLDivElement;
79
+ $run(function setClassName() {
80
+ t_div_1.className = $props.class;
81
+ });
82
+ t_add_fragment(t_fragment_0, $parent, $anchor);
83
+ t_next(t_div_1);
84
+
85
+ }
@@ -1,4 +1,5 @@
1
1
  import { type ServerSlotRender } from "../../../../src/types/ServerSlotRender";
2
+ import t_attr from "../../../../src/render/formatAttributeText";
2
3
  import t_class from "../../../../src/render/getClasses";
3
4
 
4
5
  export default function Class(
@@ -12,7 +13,28 @@ export default function Class(
12
13
 
13
14
  /* User interface */
14
15
  let $output = "";
15
- $output += `<div class="torp-1ljxz83"> <div id="divid" class="torp-1ljxz83"> From id </div> <div class="divclass torp-1ljxz83"> From string </div> <a class="${t_class({ hello: true, red: $props.red, green: $props.green, blue: $props.blue }, "torp-1ljxz83")}"> From state </a> <div class="${t_class({ hello: true, red: $props.red, green: $props.green, blue: $props.blue }, "torp-1ljxz83")}"> From state with scope </div> <div class="${t_class({ foo: true, bar: false, baz: 5, qux: null }, "torp-1ljxz83")}"> Class object </div> <div class="${t_class([ "foo", false, true && "baz", undefined ], "torp-1ljxz83")}"> Class array </div> <div class="${t_class([ "foo", 0, { bar: true }, "", [1 && "baz", ["qux"]] ], "torp-1ljxz83")}"> Class nested </div> </div>`;
16
+ $output += `<div class="torp-1ljxz83"> <div id="divid" class="torp-1ljxz83"> From id </div> <div class="divclass torp-1ljxz83"> From string </div> <a class="${t_class({ hello: true, red: $props.red, green: $props.green, blue: $props.blue }, "torp-1ljxz83")}"> From state </a> <div class="${t_class({ hello: true, red: $props.red, green: $props.green, blue: $props.blue }, "torp-1ljxz83")}"> From state with scope </div> <div class="${t_class({ foo: true, bar: false, baz: 5, qux: null }, "torp-1ljxz83")}"> Class object </div> <div class="${t_class([ "foo", false, true && "baz", undefined ], "torp-1ljxz83")}"> Class array </div> <div class="${t_class([ "foo", 0, { bar: true }, "", [1 && "baz", ["qux"]] ], "torp-1ljxz83")}"> Class nested </div> `;
17
+ const t_props_1: any = {};
18
+ t_props_1["class"] = t_class({ "child-class": true });
19
+
20
+ $output += Child(t_props_1, $context)
21
+ $output += ` </div>`;
22
+
23
+ return $output;
24
+ }
25
+
26
+ function Child(
27
+ $props: Record<PropertyKey, any>,
28
+ // @ts-ignore
29
+ $context?: Record<PropertyKey, any>,
30
+ // @ts-ignore
31
+ $slots?: Record<string, ServerSlotRender>
32
+ ) {
33
+ $props ??= {};
34
+
35
+ /* User interface */
36
+ let $output = "";
37
+ $output += `<div ${$props.class ? `class="${t_attr($props.class)}"` : ''}> Child class </div>`;
16
38
 
17
39
  return $output;
18
40
  }
@@ -2,6 +2,7 @@ import $run from "../../../../src/render/$run";
2
2
  import $watch from "../../../../src/render/$watch";
3
3
  import { type SlotRender } from "../../../../src/types/SlotRender";
4
4
  import t_add_fragment from "../../../../src/render/addFragment";
5
+ import t_anchor from "../../../../src/render/nodeAnchor";
5
6
  import t_child from "../../../../src/render/nodeChild";
6
7
  import t_class from "../../../../src/render/getClasses";
7
8
  import t_fragment from "../../../../src/render/getFragment";
@@ -22,7 +23,7 @@ export default function Class(
22
23
  /* User interface */
23
24
  const t_fragments: DocumentFragment[] = [];
24
25
 
25
- const t_fragment_0 = t_fragment($parent.ownerDocument!, t_fragments, 0, `<div class="torp-1ljxz83"> <div id="divid" class="torp-1ljxz83"> From id </div> <div class="divclass torp-1ljxz83"> From string </div> <a class="torp-1ljxz83"> From state </a> <div class="torp-1ljxz83"> From state with scope </div> <div class="torp-1ljxz83"> Class object </div> <div class="torp-1ljxz83"> Class array </div> <div class="torp-1ljxz83"> Class nested </div> </div>`);
26
+ const t_fragment_0 = t_fragment($parent.ownerDocument!, t_fragments, 0, `<div class="torp-1ljxz83"> <div id="divid" class="torp-1ljxz83"> From id </div> <div class="divclass torp-1ljxz83"> From string </div> <a class="torp-1ljxz83"> From state </a> <div class="torp-1ljxz83"> From state with scope </div> <div class="torp-1ljxz83"> Class object </div> <div class="torp-1ljxz83"> Class array </div> <div class="torp-1ljxz83"> Class nested </div> <!> </div>`);
26
27
  // @ts-ignore
27
28
  const t_div_1 = t_root(t_fragment_0) as HTMLDivElement;
28
29
  const t_a_1 = t_next(t_child(t_div_1), 5) as HTMLElement;
@@ -30,6 +31,14 @@ export default function Class(
30
31
  const t_div_3 = t_next(t_div_2, 2) as HTMLDivElement;
31
32
  const t_div_4 = t_next(t_div_3, 2) as HTMLDivElement;
32
33
  const t_div_5 = t_next(t_div_4, 2) as HTMLDivElement;
34
+ const t_comp_anchor_1 = t_anchor(t_next(t_div_5, 2)) as HTMLElement;
35
+
36
+ /* @component */
37
+ const t_props_1: any = $watch({});
38
+ $run(function setClasses() {
39
+ t_props_1["class"] = t_class({ "child-class": true });
40
+ });
41
+ Child(t_div_1, t_comp_anchor_1, t_props_1, $context);
33
42
  $run(function setClasses() {
34
43
  t_a_1.className = t_class({ hello: true, red: $props.red, green: $props.green, blue: $props.blue }, "torp-1ljxz83");
35
44
  });
@@ -49,3 +58,28 @@ export default function Class(
49
58
  t_next(t_div_1);
50
59
 
51
60
  }
61
+
62
+ function Child(
63
+ $parent: ParentNode,
64
+ $anchor: Node | null,
65
+ $props: Record<PropertyKey, any>,
66
+ // @ts-ignore
67
+ $context?: Record<PropertyKey, any>,
68
+ // @ts-ignore
69
+ $slots?: Record<string, SlotRender>
70
+ ) {
71
+ $props ??= $watch({});
72
+
73
+ /* User interface */
74
+ const t_fragments: DocumentFragment[] = [];
75
+
76
+ const t_fragment_0 = t_fragment($parent.ownerDocument!, t_fragments, 0, `<div> Child class </div>`);
77
+ // @ts-ignore
78
+ const t_div_1 = t_root(t_fragment_0) as HTMLDivElement;
79
+ $run(function setClassName() {
80
+ t_div_1.className = $props.class;
81
+ });
82
+ t_add_fragment(t_fragment_0, $parent, $anchor);
83
+ t_next(t_div_1);
84
+
85
+ }
@@ -1,4 +1,5 @@
1
1
  import { type ServerSlotRender } from "../../../../src/types/ServerSlotRender";
2
+ import t_attr from "../../../../src/render/formatAttributeText";
2
3
  import t_class from "../../../../src/render/getClasses";
3
4
 
4
5
  export default function Class(
@@ -12,7 +13,28 @@ export default function Class(
12
13
 
13
14
  /* User interface */
14
15
  let $output = "";
15
- $output += `<div class="torp-1ljxz83"> <div id="divid" class="torp-1ljxz83"> From id </div> <div class="divclass torp-1ljxz83"> From string </div> <a class="${t_class({ hello: true, red: $props.red, green: $props.green, blue: $props.blue }, "torp-1ljxz83")}"> From state </a> <div class="${t_class({ hello: true, red: $props.red, green: $props.green, blue: $props.blue }, "torp-1ljxz83")}"> From state with scope </div> <div class="${t_class({ foo: true, bar: false, baz: 5, qux: null }, "torp-1ljxz83")}"> Class object </div> <div class="${t_class([ "foo", false, true && "baz", undefined ], "torp-1ljxz83")}"> Class array </div> <div class="${t_class([ "foo", 0, { bar: true }, "", [1 && "baz", ["qux"]] ], "torp-1ljxz83")}"> Class nested </div> </div>`;
16
+ $output += `<div class="torp-1ljxz83"> <div id="divid" class="torp-1ljxz83"> From id </div> <div class="divclass torp-1ljxz83"> From string </div> <a class="${t_class({ hello: true, red: $props.red, green: $props.green, blue: $props.blue }, "torp-1ljxz83")}"> From state </a> <div class="${t_class({ hello: true, red: $props.red, green: $props.green, blue: $props.blue }, "torp-1ljxz83")}"> From state with scope </div> <div class="${t_class({ foo: true, bar: false, baz: 5, qux: null }, "torp-1ljxz83")}"> Class object </div> <div class="${t_class([ "foo", false, true && "baz", undefined ], "torp-1ljxz83")}"> Class array </div> <div class="${t_class([ "foo", 0, { bar: true }, "", [1 && "baz", ["qux"]] ], "torp-1ljxz83")}"> Class nested </div> `;
17
+ const t_props_1: any = {};
18
+ t_props_1["class"] = t_class({ "child-class": true });
19
+
20
+ $output += Child(t_props_1, $context)
21
+ $output += ` </div>`;
22
+
23
+ return $output;
24
+ }
25
+
26
+ function Child(
27
+ $props: Record<PropertyKey, any>,
28
+ // @ts-ignore
29
+ $context?: Record<PropertyKey, any>,
30
+ // @ts-ignore
31
+ $slots?: Record<string, ServerSlotRender>
32
+ ) {
33
+ $props ??= {};
34
+
35
+ /* User interface */
36
+ let $output = "";
37
+ $output += `<div ${$props.class ? `class="${t_attr($props.class)}"` : ''}> Child class </div>`;
16
38
 
17
39
  return $output;
18
40
  }