@@ -11,6 +11,7 @@ import {
1111 type ModelConstructor ,
1212 type ModelFactory ,
1313 Signal ,
14+ Effect as CoreEffect ,
1415 type ReadonlySignal ,
1516 untracked ,
1617 SignalOptions ,
@@ -312,47 +313,83 @@ hook(OptionsTypes.DIFFED, (old, vnode) => {
312313 old ( vnode ) ;
313314} ) ;
314315
315- function createPropUpdater (
316+ interface PropUpdater extends CoreEffect , PropertyUpdater {
317+ _dom : Element ;
318+ _prop : string ;
319+ _propSignal : Signal < Signal > ;
320+ _props : Record < string , any > ;
321+ _setAsProperty : boolean ;
322+ }
323+
324+ function updateProp ( this : PropUpdater ) {
325+ this . _notify = notifyDomUpdates ;
326+ const value = this . _propSignal . value . value ;
327+ // If Preact just rendered this value, don't render it again:
328+ if ( this . _props [ this . _prop ] === value ) return ;
329+ // Write the value back into the rendered props so that Preact's next
330+ // diff compares against what is actually in the DOM. The Signal
331+ // reference itself lives in vnode.__np and is restored into props by
332+ // the UNMOUNT hook, so this never clobbers it.
333+ this . _props [ this . _prop ] = value ;
334+ if ( this . _setAsProperty ) {
335+ // @ts -ignore-next-line silly
336+ this . _dom [ this . _prop ] = value ;
337+ // Match Preact's attribute handling: data-* and aria-* attributes
338+ // https://github.com/preactjs/preact/blob/main/src/diff/props.js#L132
339+ } else if ( value != null && ( value !== false || this . _prop [ 4 ] === "-" ) ) {
340+ this . _dom . setAttribute ( this . _prop , value ) ;
341+ } else {
342+ this . _dom . removeAttribute ( this . _prop ) ;
343+ }
344+ }
345+
346+ const PropUpdater = function (
347+ this : PropUpdater ,
316348 dom : Element ,
317349 prop : string ,
318350 propSignal : Signal ,
319351 props : Record < string , any >
320- ) : PropertyUpdater {
321- const setAsProperty =
352+ ) {
353+ CoreEffect . call ( this , updateProp ) ;
354+ this . _dom = dom ;
355+ this . _prop = prop ;
356+ this . _propSignal = signal ( propSignal ) ;
357+ this . _props = props ;
358+ this . _setAsProperty =
322359 prop in dom &&
323360 // SVG elements need to go through `setAttribute` because they
324361 // expect things like SVGAnimatedTransformList instead of strings.
325362 // @ts -ignore
326363 dom . ownerSVGElement === undefined ;
364+ try {
365+ this . _callback ( ) ;
366+ } catch ( err ) {
367+ this . _dispose ( ) ;
368+ throw err ;
369+ }
370+ } as unknown as {
371+ new (
372+ dom : Element ,
373+ prop : string ,
374+ propSignal : Signal ,
375+ props : Record < string , any >
376+ ) : PropUpdater ;
377+ prototype : PropUpdater ;
378+ } ;
327379
328- const changeSignal = signal ( propSignal ) ;
329- return {
330- _update : ( newSignal : Signal , newProps : typeof props ) => {
331- changeSignal . value = newSignal ;
332- props = newProps ;
333- } ,
334- _dispose : effect ( function ( this : Effect ) {
335- this . _notify = notifyDomUpdates ;
336- const value = changeSignal . value . value ;
337- // If Preact just rendered this value, don't render it again:
338- if ( props [ prop ] === value ) return ;
339- // Write the value back into the rendered props so that Preact's next
340- // diff compares against what is actually in the DOM. The Signal
341- // reference itself lives in vnode.__np and is restored into props by
342- // the UNMOUNT hook, so this never clobbers it.
343- props [ prop ] = value ;
344- if ( setAsProperty ) {
345- // @ts -ignore-next-line silly
346- dom [ prop ] = value ;
347- // Match Preact's attribute handling: data-* and aria-* attributes
348- // https://github.com/preactjs/preact/blob/main/src/diff/props.js#L132
349- } else if ( value != null && ( value !== false || prop [ 4 ] === "-" ) ) {
350- dom . setAttribute ( prop , value ) ;
351- } else {
352- dom . removeAttribute ( prop ) ;
353- }
354- } ) ,
355- } ;
380+ PropUpdater . prototype = new CoreEffect ( updateProp ) as PropUpdater ;
381+ PropUpdater . prototype . _update = function ( newSignal , newProps ) {
382+ this . _propSignal . value = newSignal ;
383+ this . _props = newProps ;
384+ } ;
385+
386+ function createPropUpdater (
387+ dom : Element ,
388+ prop : string ,
389+ propSignal : Signal ,
390+ props : Record < string , any >
391+ ) : PropertyUpdater {
392+ return new PropUpdater ( dom , prop , propSignal , props ) ;
356393}
357394
358395/** Unsubscribe from Signals when unmounting components/vnodes */
0 commit comments