import { useContext, useEffect, useLayoutEffect, useState, type FC, type Ref } from 'react' import type { ExpandNestedProps } from '@takram/three-geospatial/r3f' import { CloudLayer as CloudLayerImpl, type CloudLayerLike } from '../CloudLayer' import { CloudLayers } from '../CloudLayers' import { CloudLayersContext } from './CloudLayers' export interface CloudLayerProps extends CloudLayerLike, ExpandNestedProps { ref?: Ref index?: number } export const CloudLayer: FC = ({ ref: forwardedRef, index: indexProp, ...props }) => { const context = useContext(CloudLayersContext) if (context == null) { throw new Error('CloudLayer can only be used within the Clouds component!') } const { layers, indexPool, disableDefault } = context const [index, setIndex] = useState() useLayoutEffect(() => { if (indexProp != null) { const poolIndex = indexPool.indexOf(indexProp) if (poolIndex !== -1) { indexPool.splice(poolIndex, 1) setIndex(indexProp) return () => { indexPool.push(indexProp) setIndex(undefined) } } } else { // Sorting is just for predictability. Layer order is still not defined, // but it doesn't matter. const index = indexPool.sort((a, b) => a - b).shift() if (index != null) { setIndex(index) return () => { indexPool.push(index) setIndex(undefined) } } } }, [indexProp, layers, indexPool]) useLayoutEffect(() => { if (index == null) { return } const layer = layers[index] return () => { layer.copy( disableDefault ? CloudLayerImpl.DEFAULT : CloudLayers.DEFAULT[index] ) } }, [layers, index, disableDefault]) useEffect(() => { if (index == null) { return } if (typeof forwardedRef === 'function') { forwardedRef(layers[index]) } else if (forwardedRef != null) { forwardedRef.current = layers[index] } }, [forwardedRef, layers, index]) // Surely this resets any modifications made via forwarded ref. if (index != null) { const layer = layers[index] layer.copy( disableDefault ? CloudLayerImpl.DEFAULT : CloudLayers.DEFAULT[index] ) layer.set(props) } return null }