@react-native-ohos/react-native-unistyles
Version:
Level up your React Native StyleSheet
99 lines (81 loc) • 3.16 kB
text/typescript
import type { Optional, RNStyle, RNValue } from '../types'
import { getValueForBreakpoint } from './breakpoints'
import { isAndroid, isIOS } from '../common'
import { withPlugins } from './withPlugins'
export const proxifyFunction = (
key: string,
fn: Function,
variant?: Record<string, Optional<string>>
): Function => new Proxy(fn, {
apply: (target, thisArg, argumentsList) => withPlugins(key, parseStyle(target.apply(thisArg, argumentsList), variant))
})
export const isPlatformColor = <T extends {}>(value: T): boolean => {
if (isIOS) {
return 'semantic' in value && typeof value.semantic === 'object'
}
return isAndroid && 'resource_paths' in value && typeof value.resource_paths === 'object'
}
export const parseStyle = <T extends RNStyle>(
style: T,
variant: Record<string, Optional<string>> = {},
parseMediaQueries = true
): T => Object
.entries(style || {})
.reduce((acc, [key, value]) => {
// nested objects
if (key === 'shadowOffset' || key === 'textShadowOffset') {
acc[key] = parseStyle(value, variant)
return acc
}
// transforms
if (key === 'transform' && Array.isArray(value)) {
acc[key] = value
.map(value => parseStyle(value, variant))
.filter(value => {
// remove undefined values
if (typeof value === 'object') {
return Object.values(value).at(0) !== undefined
}
return true
})
return acc
}
if ((key === 'boxShadow' || key === 'filter') && Array.isArray(value)) {
acc[key] = value
.map(value => parseStyle(value, variant, false))
.filter(value => Object.keys(value).length === 1)
return acc
}
if (key === 'fontVariant' && Array.isArray(value)) {
acc[key] = value
return acc
}
// values or platform colors
if (typeof value !== 'object' || isPlatformColor(value)) {
acc[key as keyof T] = value
return acc
}
if (key === 'variants') {
return {
...acc,
...(Object
.keys(value) as Array<keyof typeof value>)
.reduce((acc, key) => ({
...acc,
// this will parse the styles of the selected variant (or default if it is undefined), if selected variant has no styles then it will fallback to default styles
...parseStyle((value)[key][variant[key as keyof typeof variant]?.toString() || 'default'] ?? (value)[key].default ?? {})
}), {})
}
}
// don't parse media queries and breakpoints
if (!parseMediaQueries) {
return {
...acc,
[key]: value
}
}
return {
...acc,
[key]: getValueForBreakpoint(value as Record<string, RNValue>)
}
}, {} as T)