11import type { RendererConfig } from "./renderer" ;
22import type { ObjPath } from "../renderer" ;
33import type { PreactBindings , SharedVNode } from "./bindings" ;
4+ import type { Signal } from "@preact/signals" ;
45
56export interface SerializedVNode {
67 type : "vnode" ;
@@ -22,6 +23,19 @@ export function serializeVNode<T extends SharedVNode>(
2223 return null ;
2324}
2425
26+ export function isSignal ( x : any ) : x is Signal {
27+ return (
28+ x !== null &&
29+ typeof x === "object" &&
30+ typeof x . peek === "function" &&
31+ "value" in x
32+ ) ;
33+ }
34+
35+ export function isReadOnlySignal ( signal : Signal ) : boolean {
36+ return ( signal as any ) . _r === true ;
37+ }
38+
2539export function jsonify (
2640 data : any ,
2741 getVNode : ( x : any ) => SerializedVNode | null ,
@@ -46,6 +60,14 @@ export function jsonify(
4660 const vnode = getVNode ( data ) ;
4761 if ( vnode != null ) return vnode ;
4862
63+ if ( isSignal ( data ) ) {
64+ return {
65+ type : "signal" ,
66+ name : isReadOnlySignal ( data ) ? "computed Signal" : "Signal" ,
67+ value : jsonify ( data . peek ( ) , getVNode , seen ) ,
68+ } ;
69+ }
70+
4971 if ( Array . isArray ( data ) ) {
5072 return data . map ( x => jsonify ( x , getVNode , seen ) ) ;
5173 }
@@ -134,6 +156,11 @@ export function setInCopy<T = any>(
134156) : T {
135157 if ( idx >= path . length ) return value ;
136158
159+ // Signals bypass everything
160+ if ( path [ path . length - 1 ] === "value" && maybeSetSignal ( obj , path , value ) ) {
161+ return obj ;
162+ }
163+
137164 const updated = clone ( obj ) ;
138165 if ( obj instanceof Set ) {
139166 const oldValue = Array . from ( obj ) [ + path [ idx ] ] ;
@@ -179,6 +206,24 @@ export function setIn(obj: Record<string, any>, path: ObjPath, value: any) {
179206 }
180207}
181208
209+ export function maybeSetSignal (
210+ obj : Record < string , any > ,
211+ path : ObjPath ,
212+ value : any ,
213+ ) {
214+ let current : any = obj ;
215+ for ( let i = 0 ; i < path . length ; i ++ ) {
216+ if ( isSignal ( current ) ) {
217+ current . value = value ;
218+ return true ;
219+ }
220+
221+ current = current [ path [ i ] ] ;
222+ }
223+
224+ return false ;
225+ }
226+
182227export function hasIn ( obj : Record < string , any > , path : ObjPath ) {
183228 let item = obj ;
184229 for ( let i = 0 ; i < path . length ; i ++ ) {
0 commit comments