UNPKG

react-native-unistyles

Version:
177 lines (142 loc) 6.24 kB
import { Animated } from 'react-native' import type { UnistylesBreakpoints } from '../../global' import type { UnistyleDependency } from '../../specs/NativePlatform/NativePlatform.nitro' import { ColorScheme, Orientation } from '../../specs/types' import type { StyleSheet, StyleSheetWithSuperPowers, UnistylesValues } from '../../types/stylesheet' import { isDefined, isUnistylesMq, parseMq } from '../../utils' import type { UnistylesRuntime } from '../runtime' import * as unistyles from '../services' import { UNI_GENERATED_KEYS, type UniGeneratedKey, type UniGeneratedStyle } from '../types' import { hyphenate, keyInObject, reduceObject } from './common' export const schemeToTheme = (scheme: ColorScheme) => { switch (scheme) { case ColorScheme.Dark: return 'dark' case ColorScheme.Light: default: return 'light' } } export type UnistyleSecrets = { __uni__stylesheet: StyleSheetWithSuperPowers<StyleSheet>, __uni__key: string, __uni__args?: Array<any>, __stylesheetVariants: Record<string, string | boolean | undefined> } export const assignSecrets = <T>(object: T, secrets: UnistyleSecrets) => { const secretsId = Math.random().toString(36).slice(8) // @ts-expect-error assign hidden secrets object[`unistyles_${secretsId}`] = {} // @ts-expect-error assign hidden secrets Object.defineProperties(object[`unistyles_${secretsId}`], reduceObject(secrets, secret => ({ value: secret, enumerable: false, configurable: true }))) return object } export const extractSecrets = (object: any) => { if (!object) { return undefined } const [, secrets] = Object.entries(object).find(([key]) => key.startsWith('unistyles_')) ?? [] if (!secrets) { return undefined } return reduceObject(Object.getOwnPropertyDescriptors(secrets), secret => secret.value) } export const removeInlineStyles = (values: UnistylesValues) => { const returnValue = {} Object.defineProperties(returnValue, reduceObject(values, value => ({ value, enumerable: false, configurable: true }))) return returnValue } export const getMediaQuery = (query: string, allBreakpoints: Array<string>) => { if (Object.values(Orientation).includes(query as Orientation)) { return `@media (orientation: ${query})` } if (isUnistylesMq(query)) { const { minWidth, maxWidth, minHeight, maxHeight } = parseMq(query) const queries = [ minWidth ? `(min-width: ${minWidth}px)` : undefined, maxWidth ? `(max-width: ${maxWidth}px)` : undefined, minHeight ? `(min-height: ${minHeight}px)` : undefined, maxHeight ? `(max-height: ${maxHeight}px)` : undefined ].filter(Boolean).join(' and ') return `@media ${queries}` } const breakpointValue = unistyles.services.runtime.breakpoints[query as keyof UnistylesBreakpoints] ?? 0 const nextBreakpoint = allBreakpoints .filter((b): b is keyof UnistylesBreakpoints => b in unistyles.services.runtime.breakpoints) .map(b => unistyles.services.runtime.breakpoints[b] as number) .sort((a, b) => a - b) .find(b => b > breakpointValue) const queries = [ `(min-width: ${breakpointValue}px)`, nextBreakpoint ? `(max-width: ${nextBreakpoint - 1}px)` : undefined, ].filter(Boolean).join(' and ') return `@media ${queries}` } export const extractUnistyleDependencies = (value: any) => { if (!value) { return [] } const dependencies: Array<UnistyleDependency> = keyInObject(value, 'uni__dependencies') ? value.uni__dependencies : [] return Array.isArray(dependencies) ? dependencies : [] } export const checkForProp = (value: any, prop: string): boolean => { if (Array.isArray(value)) { return value.some(nestedValue => checkForProp(nestedValue, prop)) } if (typeof value === 'object' && value !== null) { return keyInObject(value, prop) ? true : keyInObject(value, '_web') ? checkForProp(value._web, prop) : false } return false } export const checkForAnimated = (value: any): boolean => { if (Array.isArray(value)) { return value.some(checkForAnimated) } if (typeof value === 'object' && value !== null) { const objectValues = Object.values(value) const secrets = extractSecrets(value) // @ts-expect-error React Native Web exports Animated.AnimatedNode as Animated.Node return value instanceof Animated.Node || objectValues.length > 0 && objectValues.some(checkForAnimated) || secrets && Object.keys(secrets).length === 0 } return false } export const isGeneratedUnistyle = (value: Record<string, any>): value is UniGeneratedStyle => { const keys = Object.keys(value) return keys.length > 0 && keys.every(key => UNI_GENERATED_KEYS.includes(key as UniGeneratedKey)) } export const convertTheme = (key: string, value: any, prev = '-'): [string, any] => { if (typeof value === 'object' && value !== null) { return [key, Object.fromEntries(Object.entries(value).map(([nestedKey, nestedValue]) => convertTheme(nestedKey, nestedValue, `${prev}-${key}`)))] } if (typeof value === 'string') { return [key, `var(${prev}-${hyphenate(key)})`] } return [key, value] } export const getClosestBreakpointValue = <T>(runtime: UnistylesRuntime, values: Partial<Record<keyof UnistylesBreakpoints, T>>) => { const breakpoints = runtime.breakpoints const breakpointValues = Object.entries(values) // Filter out non-breakpoint values .filter((pair): pair is [keyof UnistylesBreakpoints, T] => pair[0] in breakpoints) // Sort in descending order .sort(([a], [b]) => (breakpoints[b] ?? 0) - (breakpoints[a] ?? 0)) // Get breakpoint value with highest priority const [_, currentBreakpointValue] = breakpointValues.find( ([key]) => isDefined(runtime.breakpoint) && (breakpoints[key] ?? 0) <= (breakpoints[runtime.breakpoint] ?? 0) ) ?? [] return currentBreakpointValue }