react-native-reanimated
Version:
More powerful alternative to Animated library for React Native.
94 lines (79 loc) • 2.83 kB
text/typescript
;
import { createPropsBuilder } from '../../style';
import type { PlainStyle, UnknownRecord } from '../../types';
import {
hasValueProcessor,
isConfigPropertyAlias,
isDefined,
kebabizeCamelCase,
maybeAddSuffix,
} from '../../utils';
import { isRuleBuilder } from '../utils';
import { PROPERTIES_CONFIG } from './config';
import type { PropsBuilderConfig, RuleBuilder } from './types';
type WebPropsBuilderConfig<P extends UnknownRecord = UnknownRecord> =
PropsBuilderConfig<P>;
export function createWebPropsBuilder<TProps extends UnknownRecord>(
config: WebPropsBuilderConfig<TProps>
) {
const usedRuleBuilders = new Set<RuleBuilder<TProps>>();
const propsBuilder = createPropsBuilder({
config,
processConfigValue(configValue, propertyKey) {
// Handle true - include unchanged
if (configValue === true) {
return true;
}
// Handle false - exclude property
if (configValue === false) {
return;
}
// Handle suffix (e.g., 'px')
if (typeof configValue === 'string') {
return (value) => maybeAddSuffix(value, configValue);
}
// Handle property alias
if (isConfigPropertyAlias<TProps>(configValue)) {
return config[configValue.as];
}
// Handle rule builders - store reference and return marker
if (isRuleBuilder<TProps>(configValue)) {
// Return a processor that feeds values to the rule builder and returns undefined
// so the property doesn't appear in the regular processed props (only the result
// of the rule builder will appear in the final style)
return (value) => {
usedRuleBuilders.add(configValue);
configValue.add(propertyKey, value as TProps[keyof TProps]);
return;
};
}
// Handle value processor
if (hasValueProcessor(configValue)) {
return configValue.process;
}
},
});
return {
build(props: Partial<TProps>): string | null {
usedRuleBuilders.clear();
// Build props - rule builders are fed during processing
const processedProps = propsBuilder.build(props);
// Build only used rule builders and merge their results
for (const builder of usedRuleBuilders) {
Object.assign(processedProps, builder.build());
}
// Convert to CSS string
const cssString = Object.entries(processedProps)
.reduce<string[]>((acc, [key, value]) => {
if (isDefined(value)) {
acc.push(`${kebabizeCamelCase(key)}: ${value as string}`);
}
return acc;
}, [])
.join('; ');
return cssString || null; // Return null if cssString is empty
},
};
}
export const webPropsBuilder =
createWebPropsBuilder<PlainStyle>(PROPERTIES_CONFIG);