@zoijs/core 1.3.2 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,63 +1,71 @@
1
- {
2
- "name": "@zoijs/core",
3
- "version": "1.3.2",
4
- "description": "Zoijs — a beginner-friendly, no-build, no-Virtual-DOM frontend framework. Plain HTML, CSS, and JavaScript.",
5
- "type": "module",
6
- "main": "src/index.js",
7
- "types": "src/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "types": "./src/index.d.ts",
11
- "default": "./src/index.js"
12
- }
13
- },
14
- "files": [
15
- "src",
16
- "README.md",
17
- "LICENSE",
18
- "CHANGELOG.md"
19
- ],
20
- "sideEffects": false,
21
- "engines": {
22
- "node": ">=18"
23
- },
24
- "author": "Zoijs contributors (https://zoijs.dev)",
25
- "license": "MIT",
26
- "homepage": "https://zoijs.dev",
27
- "repository": {
28
- "type": "git",
29
- "url": "git+https://github.com/Zoijs/zoijs.git",
30
- "directory": "framework"
31
- },
32
- "bugs": {
33
- "url": "https://github.com/Zoijs/zoijs/issues"
34
- },
35
- "keywords": [
36
- "zoijs",
37
- "framework",
38
- "frontend",
39
- "ui",
40
- "reactive",
41
- "reactivity",
42
- "signals",
43
- "no-build",
44
- "no-jsx",
45
- "no-virtual-dom",
46
- "fine-grained",
47
- "beginner-friendly",
48
- "html",
49
- "spa"
50
- ],
51
- "scripts": {
52
- "test": "node --test --import ./tests/setup-dom.js",
53
- "test:unit": "node --test",
54
- "test:types": "tsc --noEmit -p tsconfig.json",
55
- "test:browser": "playwright test",
56
- "dev": "npx serve -l 7310 ."
57
- },
58
- "devDependencies": {
59
- "@playwright/test": "^1.61.1",
60
- "jsdom": "^29.1.1",
61
- "typescript": "^5.9.3"
62
- }
63
- }
1
+ {
2
+ "name": "@zoijs/core",
3
+ "version": "1.5.0",
4
+ "description": "Zoijs — a beginner-friendly, no-build, no-Virtual-DOM frontend framework. Plain HTML, CSS, and JavaScript.",
5
+ "type": "module",
6
+ "main": "src/index.js",
7
+ "types": "src/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./src/index.d.ts",
11
+ "default": "./src/index.js"
12
+ },
13
+ "./devtools": {
14
+ "types": "./src/devtools.d.ts",
15
+ "default": "./src/reactivity/devtools.js"
16
+ },
17
+ "./server": {
18
+ "types": "./src/server.d.ts",
19
+ "default": "./src/server.js"
20
+ }
21
+ },
22
+ "files": [
23
+ "src",
24
+ "README.md",
25
+ "LICENSE",
26
+ "CHANGELOG.md"
27
+ ],
28
+ "sideEffects": false,
29
+ "engines": {
30
+ "node": ">=18"
31
+ },
32
+ "author": "Zoijs contributors (https://zoijs.dev)",
33
+ "license": "MIT",
34
+ "homepage": "https://zoijs.dev",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "git+https://github.com/Zoijs/zoijs.git",
38
+ "directory": "framework"
39
+ },
40
+ "bugs": {
41
+ "url": "https://github.com/Zoijs/zoijs/issues"
42
+ },
43
+ "keywords": [
44
+ "zoijs",
45
+ "framework",
46
+ "frontend",
47
+ "ui",
48
+ "reactive",
49
+ "reactivity",
50
+ "signals",
51
+ "no-build",
52
+ "no-jsx",
53
+ "no-virtual-dom",
54
+ "fine-grained",
55
+ "beginner-friendly",
56
+ "html",
57
+ "spa"
58
+ ],
59
+ "scripts": {
60
+ "test": "node --test --import ./tests/setup-dom.js",
61
+ "test:unit": "node --test",
62
+ "test:types": "tsc --noEmit -p tsconfig.json",
63
+ "test:browser": "playwright test",
64
+ "dev": "npx serve -l 7310 ."
65
+ },
66
+ "devDependencies": {
67
+ "@playwright/test": "^1.61.1",
68
+ "jsdom": "^29.1.1",
69
+ "typescript": "^5.9.3"
70
+ }
71
+ }
package/src/core/each.js CHANGED
@@ -1,24 +1,24 @@
1
- // each() — keyed list rendering (Milestone 3).
2
- //
3
- // Returns a small marker object that the renderer recognizes in a text slot and
4
- // turns into a keyed list binding. Keeping this factory tiny (and separate from
5
- // the renderer) avoids a circular import — the renderer just checks the marker.
6
- //
7
- // ${each(
8
- // () => todos.get(), // items: a reactive function (or a plain array)
9
- // todo => todo.id, // keyFn: a stable unique key per item
10
- // todo => html`<li>...</li>` // renderFn: builds DOM for one item
11
- // )}
12
- //
13
- // When the array changes, items with matching keys reuse their DOM nodes (moved
14
- // if reordered); new keys are inserted; removed keys are disposed and removed.
15
-
16
- /**
17
- * @param {Function|Array} items a function returning the array, or an array
18
- * @param {Function} keyFn item -> unique key
19
- * @param {Function} renderFn item -> html() result
20
- * @returns {{ __zoijsEach: true, items: any, keyFn: Function, renderFn: Function }}
21
- */
22
- export function each(items, keyFn, renderFn) {
23
- return { __zoijsEach: true, items, keyFn, renderFn };
24
- }
1
+ // each() — keyed list rendering (Milestone 3).
2
+ //
3
+ // Returns a small marker object that the renderer recognizes in a text slot and
4
+ // turns into a keyed list binding. Keeping this factory tiny (and separate from
5
+ // the renderer) avoids a circular import — the renderer just checks the marker.
6
+ //
7
+ // ${each(
8
+ // () => todos.get(), // items: a reactive function (or a plain array)
9
+ // todo => todo.id, // keyFn: a stable unique key per item
10
+ // todo => html`<li>...</li>` // renderFn: builds DOM for one item
11
+ // )}
12
+ //
13
+ // When the array changes, items with matching keys reuse their DOM nodes (moved
14
+ // if reordered); new keys are inserted; removed keys are disposed and removed.
15
+
16
+ /**
17
+ * @param {Function|Array} items a function returning the array, or an array
18
+ * @param {Function} keyFn item -> unique key
19
+ * @param {Function} renderFn item -> html() result
20
+ * @returns {{ __zoijsEach: true, items: any, keyFn: Function, renderFn: Function }}
21
+ */
22
+ export function each(items, keyFn, renderFn) {
23
+ return { __zoijsEach: true, items, keyFn, renderFn };
24
+ }
package/src/core/html.js CHANGED
@@ -7,8 +7,10 @@
7
7
  // attribute value, an event, etc. Dynamic values are kept in a separate channel
8
8
  // from the static HTML; a value can never change the template's structure.
9
9
  //
10
- // Output of the parse (cached per `strings`):
11
- // template : a <template> element with unique markers
10
+ // Output of the parse (cached per `strings`) is DOM-free — a static HTML string
11
+ // plus part descriptors. The <template> element is built lazily on first client
12
+ // render; on a server, @zoijs/ssr reads the static HTML + parts directly.
13
+ // html : the static HTML string, with unique markers (no DOM)
12
14
  // parts : ordered list of binding descriptors
13
15
  // { type: "child" } ← a comment-marker anchor
14
16
  // { type: "element", attrs: [AttrPart] } ← element carrying data-zoijs-bind
@@ -29,10 +31,24 @@ const cache = new WeakMap();
29
31
  export function html(strings, ...values) {
30
32
  let compiled = cache.get(strings);
31
33
  if (!compiled) {
32
- compiled = compile(strings);
34
+ compiled = compile(strings); // pure: a static HTML string + parts, NO DOM
33
35
  cache.set(strings, compiled);
34
36
  }
35
- return { template: compiled.template, parts: compiled.parts, hasElements: compiled.hasElements, values };
37
+ // The <template> element is created lazily, on first client render — so html()
38
+ // itself touches no DOM and works on a server (where @zoijs/ssr reads the static
39
+ // HTML + parts instead). The brand lets consumers detect a result without
40
+ // tripping the getter.
41
+ return {
42
+ __zoijsTemplate: true,
43
+ parts: compiled.parts,
44
+ hasElements: compiled.hasElements,
45
+ __staticHTML: compiled.html,
46
+ get template() {
47
+ if (!compiled.template) compiled.template = createTemplate(compiled.html);
48
+ return compiled.template;
49
+ },
50
+ values,
51
+ };
36
52
  }
37
53
 
38
54
  // ---- scanner ----------------------------------------------------------------
@@ -239,5 +255,8 @@ function compile(strings) {
239
255
  }
240
256
 
241
257
  const hasElements = parts.some((p) => p.type === "element");
242
- return { template: createTemplate(out), parts, hasElements };
258
+ // Pure output: the static HTML string and the part descriptors. The DOM
259
+ // <template> is built later, lazily (see html()), so compile() needs no DOM and
260
+ // its result can be serialized on a server.
261
+ return { html: out, parts, hasElements, template: null };
243
262
  }