native-base
Version:
Essential cross-platform UI components for React Native
242 lines (211 loc) • 10.9 kB
JavaScript
import get from 'lodash.get';
import merge from 'lodash.merge';
import { Platform } from 'react-native';
import { useNativeBase } from '../useNativeBase';
import { useColorMode } from '../../core/color-mode';
import { omitUndefined, extractInObject } from '../../theme/tools';
import { useContrastText } from '../useContrastText';
import { useBreakpointResolvedProps } from '../useBreakpointResolvedProps';
import { propsFlattener, compareSpecificity } from './propsFlattenerTest';
const SPREAD_PROP_SPECIFICITY_ORDER = ['p', 'padding', 'px', 'py', 'pt', 'pb', 'pl', 'pr', 'paddingTop', 'paddingBottom', 'paddingLeft', 'paddingRight', 'm', 'margin', 'mx', 'my', 'mt', 'mb', 'ml', 'mr', 'marginTop', 'marginBottom', 'marginLeft', 'marginRight'];
const FINAL_SPREAD_PROPS = ['paddingTop', 'paddingBottom', 'paddingLeft', 'paddingRight', 'marginTop', 'marginBottom', 'marginLeft', 'marginRight'];
const MARGIN_MAP = {
mx: ['marginRight', 'marginLeft'],
my: ['marginTop', 'marginBottom'],
mt: ['marginTop'],
mb: ['marginBottom'],
mr: ['marginRight'],
ml: ['marginLeft']
};
MARGIN_MAP.margin = [...MARGIN_MAP.mx, ...MARGIN_MAP.my];
MARGIN_MAP.m = MARGIN_MAP.margin;
MARGIN_MAP.marginTop = MARGIN_MAP.mt;
MARGIN_MAP.marginBottom = MARGIN_MAP.mb;
MARGIN_MAP.marginLeft = MARGIN_MAP.ml;
MARGIN_MAP.marginRight = MARGIN_MAP.mr;
const PADDING_MAP = {
px: ['paddingRight', 'paddingLeft'],
py: ['paddingTop', 'paddingBottom'],
pt: ['paddingTop'],
pb: ['paddingBottom'],
pr: ['paddingRight'],
pl: ['paddingLeft']
};
PADDING_MAP.padding = [...PADDING_MAP.px, ...PADDING_MAP.py];
PADDING_MAP.p = PADDING_MAP.padding;
PADDING_MAP.paddingTop = PADDING_MAP.pt;
PADDING_MAP.paddingBottom = PADDING_MAP.pb;
PADDING_MAP.paddingLeft = PADDING_MAP.pl;
PADDING_MAP.paddingRight = PADDING_MAP.pr;
const SPREAD_PROP_SPECIFICITY_MAP = { ...PADDING_MAP,
...MARGIN_MAP
};
function propsSpreader(incomingProps, incomingSpecifity) {
const flattenedDefaultProps = { ...incomingProps
};
const specificity = {};
SPREAD_PROP_SPECIFICITY_ORDER.forEach(prop => {
if (prop in flattenedDefaultProps) {
const val = incomingProps[prop] || flattenedDefaultProps[prop];
if (!FINAL_SPREAD_PROPS.includes(prop)) {
delete flattenedDefaultProps[prop];
specificity[prop] = incomingSpecifity[prop];
}
SPREAD_PROP_SPECIFICITY_MAP[prop].forEach(newProp => {
if (compareSpecificity(specificity[newProp], specificity[prop])) {
specificity[newProp] = incomingSpecifity[prop];
flattenedDefaultProps[newProp] = val;
}
});
}
});
return merge({}, flattenedDefaultProps);
}
/**
* @summary Combines provided porps with component's theme props and resloves them.
* @arg {string} component - Name of the component.
* @arg {object} incomingProps - Props passed by the user.
* @arg {object} state - dependent states.
* @arg {object} config - configuration for resolution. Accepts key like ignoreProps, resolveResponsively.
* @returns {object} Resolved and flattened props.
*/
export function usePropsResolutionTest(component, incomingProps, state, config) {
var _flattenProps$bg, _flattenProps$backgro, _flattenProps$bgColor, _flattenProps$backgro2, _ref, _flattenProps$bg2, _flattenProps, _flattenProps$_text, _flattenProps2, _flattenProps2$_text;
const [ignoredProps, cleanIncomingProps] = extractInObject(incomingProps, ['children', 'onPress', 'icon', 'onOpen', 'onClose'].concat((config === null || config === void 0 ? void 0 : config.ignoreProps) || []));
const resolveResponsively = ['colorScheme', 'size', 'variant', ...((config === null || config === void 0 ? void 0 : config.resolveResponsively) || [])];
const {
theme
} = useNativeBase();
const colorModeProps = useColorMode();
const componentTheme = get(theme, "components.".concat(component), {}); // STEP 1: combine default props and incoming props
const incomingWithDefaultProps = merge({}, componentTheme.defaultProps || {}, cleanIncomingProps); // STEP 2: flatten them
let [flattenProps, specificityMap] = propsFlattener({
props: incomingWithDefaultProps,
platform: Platform.OS,
colormode: colorModeProps.colorMode,
state: state || {},
previouslyFlattenProps: {}
}, 2); // STEP 2.5: resolving responsive props
const responsiveProps = {};
resolveResponsively.map(propsName => {
if (flattenProps[propsName]) {
// @ts-ignore
responsiveProps[propsName] = flattenProps[propsName];
}
});
const responsivelyResolvedProps = useBreakpointResolvedProps(responsiveProps);
flattenProps = { ...flattenProps,
...responsivelyResolvedProps
}; // STEP 3: Pass it to baseStyle, then variant and then size and resolve them.
// NOTE: Resoloving baseStyle
let componentBaseStyle = {},
flattenBaseStyle,
baseSpecificityMap;
if (componentTheme.baseStyle) {
componentBaseStyle = typeof componentTheme.baseStyle !== 'function' ? componentTheme.baseStyle : componentTheme.baseStyle({
theme,
...flattenProps,
...colorModeProps
});
[flattenBaseStyle, baseSpecificityMap] = propsFlattener({
props: componentBaseStyle,
platform: Platform.OS,
colormode: colorModeProps.colorMode,
state: state || {},
currentSpecificityMap: specificityMap,
previouslyFlattenProps: flattenProps
}, 1);
} // NOTE: Resolving variants
const variant = flattenProps.variant;
let componentVariantProps = {},
flattenVariantStyle,
variantSpecificityMap; // Extracting props from variant
if (variant && componentTheme.variants && componentTheme.variants[variant]) {
componentVariantProps = typeof componentTheme.variants[variant] !== 'function' ? componentTheme.variants[variant] : componentTheme.variants[variant]({
theme,
...flattenProps,
...colorModeProps
});
[flattenVariantStyle, variantSpecificityMap] = propsFlattener({
props: componentVariantProps,
platform: Platform.OS,
colormode: colorModeProps.colorMode,
state: state || {},
currentSpecificityMap: baseSpecificityMap || specificityMap,
// NOTE: Ideally flattenBaseStyle and flattenProps should be deeply merged to create previouslyFlattenProps.
previouslyFlattenProps: flattenProps
}, 1); // We remove variant from original props if we found it in the componentTheme
//@ts-ignore
flattenProps.variant = undefined;
} // NOTE: Resolving size
const size = flattenProps.size;
let componentSizeProps = {},
flattenSizeStyle,
sizeSpecificityMap; // Extracting props from size
if (size && componentTheme.sizes && componentTheme.sizes[size]) {
// Type - sizes: {lg: 1}. Refer icon theme
if (typeof componentTheme.sizes[size] === 'string' || typeof componentTheme.sizes[size] === 'number') {
flattenProps.size = componentTheme.sizes[size]; //@ts-ignore
// componentSizeProps.size = componentTheme.sizes[size];
} // Type - sizes: (props) => ({lg: {px: 1}}). Refer heading theme
else if (typeof componentTheme.sizes[size] === 'function') {
flattenProps.size = undefined;
componentSizeProps = componentTheme.sizes[size]({
theme,
...flattenProps,
...colorModeProps
});
} // Type - sizes: {lg: {px: 1}}. Refer button theme
else {
flattenProps.size = undefined;
componentSizeProps = componentTheme.sizes[size];
}
[flattenSizeStyle, sizeSpecificityMap] = propsFlattener({
props: componentSizeProps,
platform: Platform.OS,
colormode: colorModeProps.colorMode,
state: state || {},
currentSpecificityMap: variantSpecificityMap || baseSpecificityMap || specificityMap,
previouslyFlattenProps: flattenProps
}, 1);
} // // STEP 4: merge
const defaultStyles = merge({}, flattenBaseStyle, flattenVariantStyle, flattenSizeStyle);
for (const prop in defaultStyles) {
delete flattenProps[prop];
}
const defaultSpecificity = merge({}, specificityMap, baseSpecificityMap, variantSpecificityMap, sizeSpecificityMap);
flattenProps = propsSpreader({ ...defaultStyles,
...flattenProps
}, defaultSpecificity); // // STEP 5: linear Grad and contrastText
let ignore = [];
if ((_flattenProps$bg = flattenProps.bg) !== null && _flattenProps$bg !== void 0 && _flattenProps$bg.linearGradient || (_flattenProps$backgro = flattenProps.background) !== null && _flattenProps$backgro !== void 0 && _flattenProps$backgro.linearGradient || (_flattenProps$bgColor = flattenProps.bgColor) !== null && _flattenProps$bgColor !== void 0 && _flattenProps$bgColor.linearGradient || (_flattenProps$backgro2 = flattenProps.backgroundColor) !== null && _flattenProps$backgro2 !== void 0 && _flattenProps$backgro2.linearGradient) {
var _flattenProps$backgro3, _flattenProps$bgColor2, _flattenProps$backgro4;
let bgProp = 'bg';
if ((_flattenProps$backgro3 = flattenProps.background) !== null && _flattenProps$backgro3 !== void 0 && _flattenProps$backgro3.linearGradient) {
bgProp = 'background';
} else if ((_flattenProps$bgColor2 = flattenProps.bgColor) !== null && _flattenProps$bgColor2 !== void 0 && _flattenProps$bgColor2.linearGradient) {
bgProp = 'bgColor';
} else if ((_flattenProps$backgro4 = flattenProps.backgroundColor) !== null && _flattenProps$backgro4 !== void 0 && _flattenProps$backgro4.linearGradient) {
bgProp = 'backgroundColor';
}
flattenProps[bgProp].linearGradient.colors = flattenProps[bgProp].linearGradient.colors.map(color => {
return get(theme.colors, color, color);
});
ignore = ['bg', 'background', 'backgroundColor', 'bgColor'];
} // // NOTE: seprating bg props when linearGardiant is available
const [gradientProps] = extractInObject(flattenProps, ignore);
const bgColor = (_ref = (_flattenProps$bg2 = flattenProps.bg) !== null && _flattenProps$bg2 !== void 0 ? _flattenProps$bg2 : flattenProps.backgroundColor) !== null && _ref !== void 0 ? _ref : flattenProps.bgColor;
const contrastTextColor = useContrastText(bgColor, (_flattenProps = flattenProps) === null || _flattenProps === void 0 ? void 0 : (_flattenProps$_text = _flattenProps._text) === null || _flattenProps$_text === void 0 ? void 0 : _flattenProps$_text.color);
flattenProps._text = contrastTextColor && ((_flattenProps2 = flattenProps) === null || _flattenProps2 === void 0 ? void 0 : (_flattenProps2$_text = _flattenProps2._text) === null || _flattenProps2$_text === void 0 ? void 0 : _flattenProps2$_text.color) === undefined ? {
color: contrastTextColor,
...flattenProps._text
} : flattenProps._text;
const resolvedProps = omitUndefined({ ...flattenProps,
...ignoredProps,
...gradientProps
}); // STEP 6: Return
// flattenProps = {};
// propertyDepth = {};
return resolvedProps;
}
//# sourceMappingURL=usePropsResolutionTest.js.map