react-native-unistyles
Version:
Level up your React Native StyleSheet
82 lines (63 loc) • 2.59 kB
text/typescript
import { useCallback, useEffect, useLayoutEffect, useMemo, useState } from 'react'
import { runOnUI, useSharedValue } from 'react-native-reanimated'
import type { UnistylesValues } from '../../types'
import type { UseUpdateVariantColorConfig } from './types'
import { UnistyleDependency } from '../../specs'
import { services } from '../../web/services'
import { getClosestBreakpointValue } from '../../web/utils'
export const useUpdateVariantColor = <T extends Record<string, any>>({
animateCallback,
colorKey,
style,
}: UseUpdateVariantColorConfig<T>) => {
const [dummyDiv] = useState(() => {
const div = document.createElement('div')
div.style.display = 'none'
document.body.appendChild(div)
return div
})
const parsedStyles = useMemo(() => {
return services.shadowRegistry.addStyles([style]).parsedStyles
}, [style])
const getCurrentColor = useCallback(() => {
if (!parsedStyles) {
return 'rgb(0, 0, 0)'
}
const currentColor = parsedStyles[colorKey as keyof UnistylesValues] as string | Record<string, string>
const currentColorVar =
typeof currentColor === 'string'
? currentColor
: (getClosestBreakpointValue<string>(services.runtime, currentColor) ?? 'rgb(0, 0, 0)')
if (currentColorVar.startsWith('var(--')) {
dummyDiv.style.color = currentColorVar
return getComputedStyle(dummyDiv).color
}
return currentColorVar
}, [style, colorKey])
const fromValue = useSharedValue<string>(getCurrentColor())
const toValue = useSharedValue<string>(getCurrentColor())
useEffect(() => {
const dispose = services.listener.addListeners([UnistyleDependency.Theme], () => {
runOnUI(() => {
animateCallback?.(toValue.get(), getCurrentColor())
})()
})
return () => dispose()
}, [style, colorKey])
useLayoutEffect(() => {
animateCallback?.(toValue.get(), getCurrentColor())
const colorStyle = parsedStyles?.[colorKey as keyof UnistylesValues]
if (typeof colorStyle !== 'object' || colorStyle === null) {
return
}
const dispose = services.listener.addListeners([UnistyleDependency.Breakpoints], () => {
animateCallback?.(toValue.get(), getCurrentColor())
})
return () => dispose()
}, [style, colorKey])
useEffect(() => () => dummyDiv.remove(), [])
return {
fromValue,
toValue,
}
}