@@ -242,7 +242,7 @@ export const nodeOps: (context: TresContext) => RendererOptions<TresObject, Tres
242
242
function patchProp ( node : TresObject , prop : string , prevValue : any , nextValue : any ) {
243
243
if ( ! node ) { return }
244
244
245
- let root = node
245
+ let root : Record < string , unknown > = node
246
246
let key = prop
247
247
248
248
// NOTE: Update memoizedProps with the new value
@@ -277,7 +277,7 @@ export const nodeOps: (context: TresContext) => RendererOptions<TresObject, Tres
277
277
node . __tres . eventCount += 1
278
278
}
279
279
let finalKey = kebabToCamel ( key )
280
- let target = root ?. [ finalKey ]
280
+ let target = root ?. [ finalKey ] as Record < string , unknown >
281
281
282
282
if ( key === 'args' ) {
283
283
const prevNode = node as TresObject3D
@@ -300,7 +300,7 @@ export const nodeOps: (context: TresContext) => RendererOptions<TresObject, Tres
300
300
301
301
if ( root . type === 'BufferGeometry' ) {
302
302
if ( key === 'args' ) { return }
303
- root . setAttribute (
303
+ ( root as TresObject ) . setAttribute (
304
304
kebabToCamel ( key ) ,
305
305
new BufferAttribute ( ...( nextValue as ConstructorParameters < typeof BufferAttribute > ) ) ,
306
306
)
@@ -312,11 +312,12 @@ export const nodeOps: (context: TresContext) => RendererOptions<TresObject, Tres
312
312
// TODO: A standalone function called `resolve` is
313
313
// available in /src/utils/index.ts. It's covered by tests.
314
314
// Refactor below to DRY.
315
- const chain = key . split ( '-' )
316
- target = chain . reduce ( ( acc , key ) => acc [ kebabToCamel ( key ) ] , root )
317
- key = chain . pop ( ) as string
318
- finalKey = key
319
- if ( ! target ?. set ) { root = chain . reduce ( ( acc , key ) => acc [ kebabToCamel ( key ) ] , root ) }
315
+ target = root
316
+ for ( const part of key . split ( '-' ) ) {
317
+ finalKey = key = kebabToCamel ( part )
318
+ root = target
319
+ target = target ?. [ key ] as Record < string , unknown >
320
+ }
320
321
}
321
322
let value = nextValue
322
323
if ( value === '' ) { value = true }
@@ -335,11 +336,45 @@ export const nodeOps: (context: TresContext) => RendererOptions<TresObject, Tres
335
336
}
336
337
return
337
338
}
338
- if ( ! target ?. set && ! is . fun ( target ) ) { root [ finalKey ] = value }
339
- else if ( target . constructor === value . constructor && target ?. copy ) { target ?. copy ( value ) }
340
- else if ( is . arr ( value ) ) { target . set ( ...value ) }
341
- else if ( ! target . isColor && target . setScalar ) { target . setScalar ( value ) }
342
- else { target . set ( value ) }
339
+
340
+ // Layers must be written to the mask property
341
+ if ( is . layers ( target ) && is . layers ( value ) ) {
342
+ target . mask = value . mask
343
+ }
344
+ // Set colors if valid color representation for automatic conversion (copy)
345
+ else if ( is . color ( target ) && is . colorRepresentation ( value ) ) {
346
+ target . set ( value )
347
+ }
348
+ // Copy if properties match signatures and implement math interface (likely read-only)
349
+ else if (
350
+ is . copyable ( target ) && is . classInstance ( value ) && target . constructor === value . constructor
351
+ ) {
352
+ target . copy ( value )
353
+ }
354
+ // Set array types
355
+ else if ( is . vectorLike ( target ) && Array . isArray ( value ) ) {
356
+ if ( 'fromArray' in target && typeof target . fromArray === 'function' ) {
357
+ target . fromArray ( value )
358
+ }
359
+ else {
360
+ target . set ( ...value )
361
+ }
362
+ }
363
+ // Set literal types
364
+ else if ( is . vectorLike ( target ) && typeof value === 'number' ) {
365
+ // Allow setting array scalars
366
+ if ( 'setScalar' in target && typeof target . setScalar === 'function' ) {
367
+ target . setScalar ( value )
368
+ }
369
+ // Otherwise just set single value
370
+ else {
371
+ target . set ( value )
372
+ }
373
+ }
374
+ // Else, just overwrite the value
375
+ else {
376
+ root [ key ] = value
377
+ }
343
378
344
379
invalidateInstance ( node as TresObject )
345
380
}
0 commit comments