import { NitroModules } from 'react-native-nitro-modules' import type { UnistylesShadowRegistry as UnistylesShadowRegistrySpec } from './ShadowRegistry.nitro' import type { ShadowNode, Unistyle, ViewHandle } from './types' interface ShadowRegistry extends UnistylesShadowRegistrySpec { // Babel API add(handle?: ViewHandle, styles?: Array): void remove(handle?: ViewHandle): void // JSI link(node: ShadowNode, styles?: Array): void unlink(node: ShadowNode): void suspend(node: ShadowNode): void flush(): void setScopedTheme(themeName?: string): void getScopedTheme(): string | undefined } const HybridShadowRegistry = NitroModules.createHybridObject('UnistylesShadowRegistry') const SUSPENSE_TAG = 13 const isInsideSuspendedBoundary = (fiber: any): boolean => { let current = fiber?.return while (current) { if (current.tag === SUSPENSE_TAG && current.memoizedState !== null) { return true } current = current.return } return false } const findFiberForHandle = (handle: ViewHandle) => { return ( handle?.__internalInstanceHandle ?? handle?.getScrollResponder?.()?.getNativeScrollRef?.()?.__internalInstanceHandle ?? handle?.getNativeScrollRef?.()?.__internalInstanceHandle ?? handle?._viewRef?.__internalInstanceHandle ?? handle?.viewRef?.current?.__internalInstanceHandle ?? handle?._nativeRef?.__internalInstanceHandle ) } const findShadowNodeForHandle = (handle: ViewHandle) => { const node = handle?.__internalInstanceHandle?.stateNode?.node ?? handle?.getScrollResponder?.()?.getNativeScrollRef?.()?.__internalInstanceHandle?.stateNode?.node ?? handle?.getNativeScrollRef?.()?.__internalInstanceHandle?.stateNode?.node ?? handle?._viewRef?.__internalInstanceHandle?.stateNode?.node ?? handle?.viewRef?.current?.__internalInstanceHandle?.stateNode?.node ?? handle?._nativeRef?.__internalInstanceHandle?.stateNode?.node // @ts-ignore we don't know the type of handle if (!node && handle?.props?.horizontal && handle?.constructor?.name === 'FlatList') { throw new Error( 'Unistyles: detected an unsupported FlatList with the horizontal prop. This will cause crashes on Android due to a bug in React Native core. Read more: https://github.com/facebook/react-native/issues/51601', ) } return node } HybridShadowRegistry.add = (handle, styles) => { // virtualized nodes can be null if (!handle || !styles) { return } const stylesArray = Array.isArray(styles) ? styles.flat() : [styles] // filter styles that are undefined or with no keys const filteredStyles = stylesArray .filter((style) => style && Object.keys(style).length > 0) .flat() .filter(Boolean) if (filteredStyles.length > 0) { const node = findShadowNodeForHandle(handle) if (!node) { throw new Error( `Unistyles: Could not find shadow node for one of your components of type ${handle?.constructor?.name ?? 'unknown'}`, ) } HybridShadowRegistry.link(node, filteredStyles) } } HybridShadowRegistry.remove = (handle) => { if (!handle) { return } const maybeNode = findShadowNodeForHandle(handle) if (maybeNode) { const fiber = findFiberForHandle(handle) if (fiber && isInsideSuspendedBoundary(fiber)) { HybridShadowRegistry.suspend(maybeNode) } else { HybridShadowRegistry.unlink(maybeNode) } } } type PrivateMethods = 'add' | 'remove' | 'link' | 'unlink' | 'suspend' export const UnistylesShadowRegistry = HybridShadowRegistry as Omit