import * as OGL from 'ogl' ; import { COLORS , RESERVED_PROPS } from './constants' ; import { Instance , InstanceProps } from './types' ; /**
 * Converts camelCase primitives to PascalCase.
 */ export const toPascalCase = ( str ) => str . charAt ( 0 ) . toUpperCase ( ) + str . substring ( 1 ) ; /**
 * Converts a stringified color name into a Color.
 */ export const toColor = ( name ) => new OGL . Color ( COLORS [ name ] ?? name ) ; /**
 * Converts an array of integers into a Vector.
 */ export const toVector = ( values ) => new OGL [ `Vec${ values . length }` ] ( ... values ) ; /**
 * Filters keys from an object.
 */ export const filterKeys = ( obj , prune = false , ... keys ) => { const keysToSelect = new Set ( keys . flat ( ) ) ; return Object . fromEntries ( Object . entries ( obj ) . filter ( ( [ key ] ) => keysToSelect . has ( key ) === ! prune ) ) ; } ; /**
 * Safely mutates an OGL element, respecting special JSX syntax.
 */ export const applyProps = ( instance , newProps , oldProps = { } ) => { const identical = Object . keys ( newProps ) . filter ( ( key ) => newProps [ key ] === oldProps [ key ] ) ; const handlers = Object . keys ( newProps ) . filter ( ( key ) => typeof newProps [ key ] === 'function' && key . startsWith ( 'on' ) ) ; const props = filterKeys ( newProps , true , ... identical , ... handlers , ... RESERVED_PROPS ) ; if ( Object . keys ( props ) . length ) { Object . entries ( props ) . forEach ( ( [ key , value ] ) => { let root = instance ; let target = root [ key ] ; if ( key . includes ( '-' ) ) { const chain = key . split ( '-' ) ; target = chain . reduce ( ( acc , key ) => acc [ key ] , instance ) ; if ( ! target ?. set ) { key = chain . pop ( ) ; root = chain . reduce ( ( acc , key ) => acc [ key ] , instance ) ; } } if ( target ?. set ) { if ( target . constructor . name === value . constructor . name ) { target . copy ( value ) ; } else if ( Array . isArray ( value ) ) { target . set ( ... value ) ; } else { const scalar = new Array ( target . length ) . fill ( value ) ; target . set ( ... scalar ) ; } } else { if ( key === 'uniforms' ) { value = Object . entries ( value ) . reduce ( ( acc , [ uniform , entry ] ) => { if ( entry . value === undefined ) { let value ; if ( typeof entry === 'string' ) { value = toColor ( entry as keyof typeof COLORS ) ; } else if ( Array . isArray ( entry ) ) { value = toVector ( entry ) ; } else { value = entry ; } entry = { value } ; } acc [ uniform ] = entry ; return acc ; } , { } ) ; } root [ key ] = value ; } } ) ; } if ( handlers . length ) { instance . __handlers = handlers . reduce ( ( acc , key ) => ( { ... acc , [ key ] : newProps [ key ] } ) , { } ) ; } } ; /**
 * Shallow checks objects.
 */ export const checkShallow = ( a , b ) => { if ( Array . isArray ( a ) ) { if ( ! Array . isArray ( b ) ) return false ; if ( a == b ) return true ; if ( a . every ( ( v , i ) => v === b [ i ] ) ) return true ; } if ( a === b ) return true ; return false ; } ; /**
 * Prepares a set of changes to be applied to the instance.
 */ export const diffProps = ( instance , newProps , oldProps = { } ) => { newProps = filterKeys ( newProps , true , ... RESERVED_PROPS ) ; oldProps = filterKeys ( oldProps , true , ... RESERVED_PROPS ) ; const changedProps = { } ; Object . entries ( newProps ) . forEach ( ( [ key , value ] ) => { if ( instance . isPrimitive && key === 'object' ) return ; if ( checkShallow ( value , oldProps [ key ] ) ) return ; changedProps [ key ] = value ; } ) ; return changedProps ; } ;