what-core 0.4.0 → 0.4.1

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": "what-core",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "What Framework - The closest framework to vanilla JS",
5
5
  "type": "module",
6
6
  "main": "dist/what.js",
@@ -12,6 +12,12 @@
12
12
  "import": "./src/index.js",
13
13
  "require": "./dist/what.cjs"
14
14
  },
15
+ "./jsx-runtime": {
16
+ "import": "./src/jsx-runtime.js"
17
+ },
18
+ "./jsx-dev-runtime": {
19
+ "import": "./src/jsx-dev-runtime.js"
20
+ },
15
21
  "./render": {
16
22
  "import": "./src/render.js"
17
23
  },
package/src/dom.js CHANGED
@@ -101,6 +101,18 @@ function createDOM(vnode, parent, isSvg) {
101
101
  return document.createTextNode(String(vnode));
102
102
  }
103
103
 
104
+ // Reactive function child — creates a text node that updates fine-grained
105
+ if (typeof vnode === 'function') {
106
+ const textNode = document.createTextNode('');
107
+ effect(() => {
108
+ const val = vnode();
109
+ // If the function returns a vnode, we can't upgrade a text node to an element.
110
+ // For now, stringify the result. Component-level re-render handles complex cases.
111
+ textNode.textContent = (val == null || val === false || val === true) ? '' : String(val);
112
+ });
113
+ return textNode;
114
+ }
115
+
104
116
  // Array (fragment)
105
117
  if (Array.isArray(vnode)) {
106
118
  const frag = document.createDocumentFragment();
@@ -615,6 +627,20 @@ function patchNode(parent, domNode, vnode) {
615
627
  return placeholder;
616
628
  }
617
629
 
630
+ // Reactive function child — replace whatever's there with a reactive text node
631
+ if (typeof vnode === 'function') {
632
+ const textNode = document.createTextNode('');
633
+ effect(() => {
634
+ const val = vnode();
635
+ textNode.textContent = (val == null || val === false || val === true) ? '' : String(val);
636
+ });
637
+ if (domNode && domNode.parentNode) {
638
+ disposeTree(domNode);
639
+ parent.replaceChild(textNode, domNode);
640
+ }
641
+ return textNode;
642
+ }
643
+
618
644
  // Text
619
645
  if (typeof vnode === 'string' || typeof vnode === 'number') {
620
646
  const text = String(vnode);
package/src/h.js CHANGED
@@ -36,6 +36,9 @@ function flattenChildren(children) {
36
36
  out.push(...flattenChildren(child));
37
37
  } else if (typeof child === 'object' && child._vnode) {
38
38
  out.push(child);
39
+ } else if (typeof child === 'function') {
40
+ // Reactive child — preserve function for fine-grained DOM updates
41
+ out.push(child);
39
42
  } else {
40
43
  // Text node
41
44
  out.push(String(child));
@@ -0,0 +1,19 @@
1
+ // What Framework — JSX Dev Runtime
2
+ // Same as jsx-runtime but used in development mode by Vite.
3
+
4
+ import { h, Fragment } from './h.js';
5
+
6
+ export { Fragment };
7
+
8
+ export function jsxDEV(type, props, key) {
9
+ if (props == null) return h(type, null);
10
+ const { children, ...rest } = props;
11
+ if (key !== undefined) rest.key = key;
12
+ if (children === undefined) return h(type, rest);
13
+ if (Array.isArray(children)) return h(type, rest, ...children);
14
+ return h(type, rest, children);
15
+ }
16
+
17
+ // Also export jsx/jsxs for compatibility — some bundlers use these even in dev
18
+ export const jsx = jsxDEV;
19
+ export const jsxs = jsxDEV;
@@ -0,0 +1,21 @@
1
+ // What Framework — JSX Automatic Runtime
2
+ // Used by: jsxImportSource: "what-framework" (or "what-core")
3
+ // Vite/esbuild import this automatically when using the "react-jsx" transform.
4
+
5
+ import { h, Fragment } from './h.js';
6
+
7
+ export { Fragment };
8
+
9
+ // Automatic JSX transform signature: jsx(type, { children, ...props }, key)
10
+ // What's h() signature: h(type, props, ...children)
11
+ export function jsx(type, props, key) {
12
+ if (props == null) return h(type, null);
13
+ const { children, ...rest } = props;
14
+ if (key !== undefined) rest.key = key;
15
+ if (children === undefined) return h(type, rest);
16
+ if (Array.isArray(children)) return h(type, rest, ...children);
17
+ return h(type, rest, children);
18
+ }
19
+
20
+ // jsxs = jsx for static children (multiple). Same behavior for What.
21
+ export const jsxs = jsx;
package/src/reactive.js CHANGED
@@ -17,29 +17,38 @@ export function signal(initial) {
17
17
  let value = initial;
18
18
  const subs = new Set();
19
19
 
20
- function read() {
21
- if (currentEffect) {
22
- subs.add(currentEffect);
23
- currentEffect.deps.push(subs); // Track reverse dep for cleanup
20
+ // Unified getter/setter: sig() reads, sig(newVal) writes
21
+ function sig(...args) {
22
+ if (args.length === 0) {
23
+ // Read
24
+ if (currentEffect) {
25
+ subs.add(currentEffect);
26
+ currentEffect.deps.push(subs);
27
+ }
28
+ return value;
24
29
  }
25
- return value;
30
+ // Write
31
+ const nextVal = typeof args[0] === 'function' ? args[0](value) : args[0];
32
+ if (Object.is(value, nextVal)) return;
33
+ value = nextVal;
34
+ notify(subs);
26
35
  }
27
36
 
28
- read.set = (next) => {
37
+ sig.set = (next) => {
29
38
  const nextVal = typeof next === 'function' ? next(value) : next;
30
39
  if (Object.is(value, nextVal)) return;
31
40
  value = nextVal;
32
41
  notify(subs);
33
42
  };
34
43
 
35
- read.peek = () => value;
44
+ sig.peek = () => value;
36
45
 
37
- read.subscribe = (fn) => {
38
- return effect(() => fn(read()));
46
+ sig.subscribe = (fn) => {
47
+ return effect(() => fn(sig()));
39
48
  };
40
49
 
41
- read._signal = true;
42
- return read;
50
+ sig._signal = true;
51
+ return sig;
43
52
  }
44
53
 
45
54
  // --- Computed ---