UNPKG

native-base

Version:

Essential cross-platform UI components for React Native

209 lines (180 loc) 7.96 kB
import get from 'lodash.get'; import isNil from 'lodash.isnil'; import mergeWith from 'lodash.mergewith'; import cloneDeep from 'lodash.clonedeep'; import { themePropertyMap } from './../../theme/base'; import { getClosestBreakpoint, findLastValidBreakpoint, hasValidBreakpointFormat, extractInObject } from './../../theme/tools'; import { useContrastText } from '../useContrastText'; /* Extract props from theme props and omit those from props */ /** * * @param props Props passed by the user * @param theme Theme object * @param colorModeProps `colorMode` object * @param componentTheme Theme for specific components * @param currentBreakpoint Current breakpoint values * @returns Extracting props from defaultProps while overriding the props that are already present */ export function extractProps(props, theme, {}, componentTheme, currentBreakpoint) { let newProps = {}; for (let property in props) { // If the property exists in themePropertyMap then get its value if (themePropertyMap[property]) { let propValues = extractPropertyFromFunction(property, props, theme, componentTheme); if (typeof propValues === 'string' || typeof propValues === 'number') { newProps[property] = propValues; } else if (!isNil(propValues)) { for (let nestedProp in propValues) { newProps[nestedProp] = get(theme, "".concat(themePropertyMap[nestedProp], ".").concat(propValues[nestedProp]), propValues[nestedProp]); } } else if (property === 'shadow') { let shadowProps = theme[themePropertyMap[property]][props[property]]; if (!isNil(shadowProps)) { newProps = { ...newProps, ...shadowProps }; } } else { newProps[property] = resolveValueWithBreakpoint(props[property], theme.breakpoints, currentBreakpoint, property); } } else { newProps[property] = resolveValueWithBreakpoint(props[property], theme.breakpoints, currentBreakpoint, property); } } return cloneDeep(newProps); } /* Remove props from defaultProps that are already present in props */ function filterDefaultProps(props, defaultProps) { let [, resultProps] = extractInObject(defaultProps, Object.keys(props)); return resultProps; } /** * If property is functional in componentTheme, get its returned object * * @param property : name of the prop * @param props : all props * @param theme : provided theme without components * @param componentTheme : component specific theme * @returns */ export const extractPropertyFromFunction = (property, props, theme, componentTheme) => { let propValues; // Check if the entry in the theme is a function then calling it with all theme and props as params if (componentTheme && typeof componentTheme[themePropertyMap[property]] === 'function') { let funcProps = componentTheme[themePropertyMap[property]]({ theme, ...props }); // Check if returned object from componentTheme is a nested object let isNested = Object.keys(funcProps).some(function (key) { return funcProps[key] && typeof funcProps[key] === 'object'; }); // If the returned value is nested object then find the property value in it, otherwise return the whole object propValues = isNested ? { ...get(funcProps, "".concat(props[property])) } : { ...funcProps }; } else { // If the entry is any value other than function then return the whole object or value propValues = get(componentTheme, "".concat(themePropertyMap[property], ".").concat(props[property])); } return propValues; }; /* Merge _props and apply contrastText color if not passed by theme or user */ export function mergeUnderscoreProps(newProps, props) { const _props = Object.keys(newProps).filter(propName => propName.startsWith('_')); _props.forEach(propName => { var _newProps$bg, _newProps$propName$co, _newProps$propName, _props$propName; // Adding color based on bg contrast if no color is given const bg = (_newProps$bg = newProps.bg) !== null && _newProps$bg !== void 0 ? _newProps$bg : newProps.backgroundColor; const textColor = bg ? { color: useContrastText(bg, (_newProps$propName$co = (_newProps$propName = newProps[propName]) === null || _newProps$propName === void 0 ? void 0 : _newProps$propName.color) !== null && _newProps$propName$co !== void 0 ? _newProps$propName$co : (_props$propName = props[propName]) === null || _props$propName === void 0 ? void 0 : _props$propName.color) } : {}; // Overriding calculated props with user added props newProps[propName] = { ...textColor, ...newProps[propName], ...props[propName] }; }); return newProps; } /** * * Checks the property and resolves it if it has breakpoints * @param values : value from props * @param currentBreakpoint : current value for which breakpoint will be calculated * @param property : property name * @returns */ export const resolveValueWithBreakpoint = (values, breakpointTheme, currentBreakpoint, property) => { if (hasValidBreakpointFormat(values, breakpointTheme, property)) { // Check the last valid breakpoint value from all values // If current breakpoint is `md` and we have `base` then `lg`, then last value will be taken(`base` in this case) return findLastValidBreakpoint(values, breakpointTheme, currentBreakpoint); } else { return values; } }; /** * Takes all prop related data and returns the props that needs to be applied to the component * * @param theme Theme object * @param colorModeProps Color mode information * @param componentTheme Theme object for the specific component * @param props Props passed by the user * @param windowWidth Width of the current window * @returns props to be applied */ export function calculateProps(theme, colorModeProps, componentTheme, props, windowWidth) { let currentBreakpoint = getClosestBreakpoint(theme.breakpoints, windowWidth); if (!props) { props = {}; } let newProps; if (componentTheme) { // Extracting props from defaultProps newProps = extractProps(filterDefaultProps(props, componentTheme.defaultProps), theme, colorModeProps, componentTheme, currentBreakpoint); // Extracting props from base style let componentBaseStyle = typeof componentTheme.baseStyle !== 'function' ? componentTheme.baseStyle : componentTheme.baseStyle({ theme, ...newProps, ...props, ...colorModeProps }); newProps = mergeWith(newProps, componentBaseStyle, // @ts-ignore (objValue, srcValue, key) => { if (!isNil(objValue)) { delete newProps[key]; } }); const variant = props.variant || get(componentTheme, 'defaultProps.variant'); // Extracting props from variant if (variant && componentTheme.variants && componentTheme.variants[variant]) { const colorScheme = props.colorScheme || get(componentTheme, 'defaultProps.colorScheme'); let variantProps = componentTheme.variants[variant]({ ...props, ...newProps, colorScheme, theme, ...colorModeProps }); variantProps = extractProps(variantProps, theme, colorModeProps, componentTheme, currentBreakpoint); // added this to handle order of props newProps = mergeWith(newProps, variantProps, // @ts-ignore (objValue, srcValue, key) => { if (!isNil(objValue)) { delete newProps[key]; } }); delete newProps.variant; delete newProps.colorScheme; } } // Extracting props from normal props let extractedProps = extractProps(props, theme, colorModeProps, componentTheme, currentBreakpoint); // added this to handle order of props // @ts-ignore newProps = mergeWith(newProps, extractedProps, (objValue, srcValue, key) => { if (!isNil(objValue)) { delete newProps[key]; } }); newProps = mergeUnderscoreProps(newProps, props); return newProps; } //# sourceMappingURL=utils.js.map