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.
- package/README.md +1 -1
- package/package.json +4 -4
- 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/
|
|
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.
|
|
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.
|
|
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/
|
|
32
|
+
"url": "https://github.com/CelsianJs/what-framework"
|
|
33
33
|
},
|
|
34
34
|
"bugs": {
|
|
35
|
-
"url": "https://github.com/CelsianJs/
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
404
|
-
const
|
|
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
|
-
|
|
410
|
-
|
|
411
|
-
|
|
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
|
-
|
|
478
|
+
const unsubscribe = subscribe(handleChange);
|
|
479
|
+
return unsubscribe;
|
|
416
480
|
}, [subscribe, getSnapshot]);
|
|
417
481
|
|
|
418
|
-
|
|
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;
|