what-react 0.1.2 → 0.7.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.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/package.json +4 -4
  3. package/src/index.js +87 -10
package/README.md CHANGED
@@ -123,7 +123,7 @@ reactCompat({
123
123
 
124
124
  - [React Compat Showcase](https://react.whatfw.com)
125
125
  - [Documentation](https://whatfw.com)
126
- - [GitHub](https://github.com/CelsianJs/whatfw)
126
+ - [GitHub](https://github.com/CelsianJs/what-framework)
127
127
  - [Benchmarks](https://benchmarks.whatfw.com)
128
128
 
129
129
  ## License
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "what-react",
3
- "version": "0.1.2",
3
+ "version": "0.7.0",
4
4
  "description": "React compatibility layer for What Framework — use React packages with signals under the hood",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -23,16 +23,16 @@
23
23
  "compatibility"
24
24
  ],
25
25
  "peerDependencies": {
26
- "what-core": "^0.5.3"
26
+ "what-core": "^0.7.0"
27
27
  },
28
28
  "author": "ZVN DEV (https://zvndev.com)",
29
29
  "license": "MIT",
30
30
  "repository": {
31
31
  "type": "git",
32
- "url": "https://github.com/CelsianJs/whatfw"
32
+ "url": "https://github.com/CelsianJs/what-framework"
33
33
  },
34
34
  "bugs": {
35
- "url": "https://github.com/CelsianJs/whatfw/issues"
35
+ "url": "https://github.com/CelsianJs/what-framework/issues"
36
36
  },
37
37
  "homepage": "https://react.whatfw.com"
38
38
  }
package/src/index.js CHANGED
@@ -355,17 +355,68 @@ export function isValidElement(object) {
355
355
  }
356
356
 
357
357
  // ---- useLayoutEffect ----
358
+ // Must run synchronously after DOM mutations but before paint.
359
+ // We use queueMicrotask for layout-level timing (runs before next rAF).
358
360
 
359
361
  export function useLayoutEffect(fn, deps) {
360
- return whatUseEffect(fn, deps);
362
+ const hookRef = whatUseRef({ deps: undefined, cleanup: null });
363
+
364
+ const hook = hookRef.current;
365
+
366
+ if (_depsChanged(hook.deps, deps)) {
367
+ // Run synchronously via microtask — before next paint but after DOM mutations
368
+ queueMicrotask(() => {
369
+ if (hook.cleanup) {
370
+ try { hook.cleanup(); } catch (e) { /* cleanup error */ }
371
+ hook.cleanup = null;
372
+ }
373
+ const result = fn();
374
+ if (typeof result === 'function') {
375
+ hook.cleanup = result;
376
+ }
377
+ });
378
+ hook.deps = deps;
379
+ }
380
+
381
+ // Register cleanup on unmount
382
+ onCleanup(() => {
383
+ if (hook.cleanup) {
384
+ try { hook.cleanup(); } catch (e) { /* cleanup error */ }
385
+ hook.cleanup = null;
386
+ }
387
+ });
361
388
  }
362
389
 
363
390
  // ---- useInsertionEffect ----
364
391
  // React 18 hook for CSS-in-JS libraries. Runs synchronously before layout effects.
365
- // We map it to useEffect since What doesn't have multi-phase commit.
392
+ // We run it immediately (synchronously) during render to ensure it runs before
393
+ // useLayoutEffect's microtask and useEffect's async scheduling.
366
394
 
367
395
  export function useInsertionEffect(fn, deps) {
368
- return whatUseEffect(fn, deps);
396
+ const hookRef = whatUseRef({ deps: undefined, cleanup: null });
397
+
398
+ const hook = hookRef.current;
399
+
400
+ if (_depsChanged(hook.deps, deps)) {
401
+ // Run synchronously — before layout effects
402
+ if (hook.cleanup) {
403
+ try { hook.cleanup(); } catch (e) { /* cleanup error */ }
404
+ hook.cleanup = null;
405
+ }
406
+ const result = fn();
407
+ if (typeof result === 'function') {
408
+ hook.cleanup = result;
409
+ }
410
+ hook.deps = deps;
411
+ }
412
+
413
+ // Register cleanup on unmount
414
+ onCleanup(() => {
415
+ if (hook.cleanup) {
416
+ try { hook.cleanup(); } catch (e) { /* cleanup error */ }
417
+ hook.cleanup = null;
418
+ }
419
+ });
369
420
  }
370
421
 
371
422
  // ---- useImperativeHandle ----
@@ -398,24 +449,40 @@ export function useId() {
398
449
  export function useDebugValue() {}
399
450
 
400
451
  // ---- useSyncExternalStore ----
452
+ // Uses a signal internally so that consumers get reactive updates.
453
+ // The signal is initialized with getSnapshot(), and updated via the store's
454
+ // subscribe callback. The returned signal function integrates with What's
455
+ // fine-grained reactivity — reading it inside an effect auto-tracks the dependency.
401
456
 
402
457
  export function useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) {
403
- const [value, setValue] = whatUseState(() => getSnapshot());
404
- const snapshotRef = whatUseRef(getSnapshot());
458
+ // Create a signal initialized with the current snapshot
459
+ const storeSignal = whatUseRef(null);
460
+ if (storeSignal.current === null) {
461
+ storeSignal.current = signal(getSnapshot());
462
+ }
463
+
464
+ const sig = storeSignal.current;
405
465
 
466
+ // Subscribe to the store, updating the signal when the store changes.
467
+ // onCleanup handles unsubscription on unmount.
406
468
  whatUseEffect(() => {
407
469
  const handleChange = () => {
408
470
  const next = getSnapshot();
409
- if (!Object.is(snapshotRef.current, next)) {
410
- snapshotRef.current = next;
411
- setValue(next);
471
+ const prev = sig.peek();
472
+ if (!Object.is(prev, next)) {
473
+ sig.set(next);
412
474
  }
413
475
  };
476
+ // Sync in case store changed between render and effect
414
477
  handleChange();
415
- return subscribe(handleChange);
478
+ const unsubscribe = subscribe(handleChange);
479
+ return unsubscribe;
416
480
  }, [subscribe, getSnapshot]);
417
481
 
418
- return value;
482
+ // Return the signal function itself. In the run-once model, returning sig()
483
+ // would capture a snapshot that never updates. Returning the signal function
484
+ // lets the fine-grained runtime track it reactively when used in JSX.
485
+ return sig;
419
486
  }
420
487
 
421
488
  // ---- useTransition ----
@@ -519,6 +586,16 @@ PureComponent.prototype.shouldComponentUpdate = function(nextProps, nextState) {
519
586
 
520
587
  // ---- Internal helpers ----
521
588
 
589
+ function _depsChanged(oldDeps, newDeps) {
590
+ if (oldDeps === undefined) return true;
591
+ if (!oldDeps || !newDeps) return true;
592
+ if (oldDeps.length !== newDeps.length) return true;
593
+ for (let i = 0; i < oldDeps.length; i++) {
594
+ if (!Object.is(oldDeps[i], newDeps[i])) return true;
595
+ }
596
+ return false;
597
+ }
598
+
522
599
  function shallowEqual(a, b) {
523
600
  if (Object.is(a, b)) return true;
524
601
  if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) return false;