react-native-unistyles
Version:
Level up your React Native StyleSheet
126 lines (100 loc) • 4.64 kB
text/typescript
import type { UnistylesTheme, UnistylesValues } from '../types'
import type { UniGeneratedStyle, UnistylesServices } from './types'
import { UnistyleDependency } from '../specs/NativePlatform/NativePlatform.nitro'
import { deepMergeObjects } from '../utils'
import { extractSecrets, extractUnistyleDependencies, isGeneratedUnistyle, isServer } from './utils'
import { getVariants } from './variants'
export class UnistylesShadowRegistry {
// MOCKS
name = 'UnistylesShadowRegistry'
__type = 'web'
equals = () => true
toString = () => 'UnistylesShadowRegistry'
dispose = () => {}
// END MOCKS
private scopedTheme: UnistylesTheme | undefined = undefined
private disposeMap = new Map<string, VoidFunction>()
constructor(private services: UnistylesServices) {}
add = (ref: any, hash?: string) => {
if (isServer() || !(ref instanceof HTMLElement) || !hash) {
return
}
this.services.registry.connect(ref, hash)
}
addStyles = (unistyles: Array<UnistylesValues>, forChild?: boolean) => {
const [firstStyle] = unistyles
// If it is already a generated style, return it
if (firstStyle && isGeneratedUnistyle(firstStyle)) {
return firstStyle as UniGeneratedStyle
}
const getParsedStyles = () => {
const allStyles = unistyles.map((unistyle) => {
const secrets = extractSecrets(unistyle)
// Regular style
if (!secrets) {
return unistyle
}
// Animated styles - shouldn't be processed
if (Object.keys(secrets).length === 0) {
return {}
}
const { __uni__key, __uni__stylesheet, __uni__args = [], __stylesheetVariants: variants } = secrets
const newComputedStylesheet = this.services.registry.getComputedStylesheet(
__uni__stylesheet,
scopedTheme,
)
const style = newComputedStylesheet[__uni__key] as UnistylesValues | ((...args: any) => UnistylesValues)
const result = typeof style === 'function' ? style(...__uni__args) : style
const variantsResult = getVariants(result, variants)
const resultWithVariants = deepMergeObjects(result, variantsResult)
const dependencies = extractUnistyleDependencies(resultWithVariants)
if (typeof __uni__stylesheet === 'function') {
// Add dependencies from dynamic styles to stylesheet
this.services.registry.addDependenciesToStylesheet(__uni__stylesheet, dependencies)
}
return {
...resultWithVariants,
...resultWithVariants._web,
} as UnistylesValues
})
return deepMergeObjects(...allStyles)
}
// Copy scoped theme to not use referenced value
const scopedTheme = this.scopedTheme
const parsedStyles = getParsedStyles()
const { hash, existingHash } = this.services.registry.add(parsedStyles, forChild)
const injectedClassNames = parsedStyles?._web?._classNames ?? []
const injectedClassName = Array.isArray(injectedClassNames) ? injectedClassNames.join(' ') : injectedClassNames
const dependencies = extractUnistyleDependencies(parsedStyles)
const filteredDependencies = this.services.state.CSSVars
? dependencies.filter((dependency) => dependency !== UnistyleDependency.Theme)
: dependencies
if (!existingHash) {
this.disposeMap.set(
hash,
this.services.listener.addListeners(filteredDependencies, () => {
this.services.registry.applyStyles(hash, getParsedStyles())
}),
)
}
const hashClassname = forChild ? hash.replace(' > *', '') : hash
return { injectedClassName, hash: hashClassname, parsedStyles }
}
setScopedTheme = (theme?: UnistylesTheme) => {
this.scopedTheme = theme
}
getScopedTheme = () => this.scopedTheme
remove = (ref: any, hash?: string) => {
if (isServer() || !(ref instanceof HTMLElement) || !hash) {
return
}
this.services.registry.remove(ref, hash).then((removed) => {
if (!removed) {
return
}
this.disposeMap.get(hash)?.()
this.disposeMap.delete(hash)
})
}
flush = () => {}
}