react-native-ui-lib
Version:
[](https://stand-with-ukraine.pp.ua)
117 lines • 4.63 kB
JavaScript
import _invoke from "lodash/invoke";
import _isPlainObject from "lodash/isPlainObject";
import _isArray from "lodash/isArray";
import React, { useCallback, useEffect, useMemo, useContext } from 'react';
import { StyleSheet } from 'react-native';
import { LogService } from "../../services";
import { Colors, Typography } from "../../style";
import * as Modifiers from "../../commons/modifiers";
import Assets from "../../assets";
import View from "../view";
import TouchableOpacity from "../touchableOpacity";
import Image from "../image";
import Text from "../text";
import { getItemLabel, isItemSelected } from "./PickerPresenter";
import PickerContext from "./PickerContext";
/**
* @description: Picker.Item, for configuring the Picker's selectable options
* @example: https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/componentScreens/PickerScreen.tsx
*/
const PickerItem = props => {
const {
value,
label,
labelStyle,
disabled,
selectedIcon = Assets.internal.icons.check,
selectedIconColor = Colors.$iconPrimary,
onPress,
testID
} = props;
const context = useContext(PickerContext);
const {
migrate
} = context;
const customRenderItem = props.renderItem || context.renderItem;
// @ts-expect-error TODO: fix after removing migrate prop completely
const itemValue = !migrate && typeof value === 'object' ? value?.value : value;
const isSelected = isItemSelected(itemValue, context.value);
const itemLabel = getItemLabel(label, value, props.getItemLabel || context.getItemLabel);
const selectedCounter = context.selectionLimit && _isArray(context.value) && context.value?.length;
const accessibilityProps = {
accessibilityState: isSelected ? {
selected: true
} : undefined,
accessibilityHint: 'Double click to select this suggestion',
...Modifiers.extractAccessibilityProps(props)
};
const isItemDisabled = useMemo(() => {
return !!(disabled || !isSelected && context.selectionLimit && context.selectionLimit === selectedCounter);
}, [selectedCounter, disabled]);
useEffect(() => {
if (_isPlainObject(value)) {
LogService.warn('UILib Picker.Item will stop supporting passing object as value & label (e.g {value, label}) in the next major version. Please pass separate label and value props');
}
}, [value]);
const selectedIndicator = useMemo(() => {
if (isSelected) {
return <Image source={selectedIcon} tintColor={isItemDisabled ? Colors.$iconDisabled : selectedIconColor} />;
}
}, [isSelected, isItemDisabled, selectedIcon, selectedIconColor]);
const itemLabelStyle = useMemo(() => {
return [styles.labelText, isItemDisabled ? styles.labelTextDisabled : undefined, labelStyle];
}, [isItemDisabled, labelStyle]);
const _onPress = useCallback(async props => {
// Using !(await onPress?.(item)) does not work properly when onPress is not sent
// We have to explicitly state `false` so a synchronous void (undefined) will still work as expected
if (onPress && (await onPress(context.isMultiMode ? !isSelected : undefined, props)) === false) {
return;
}
if (migrate) {
context.onPress(value);
} else {
// @ts-expect-error TODO: fix after removing migrate prop completely
context.onPress(typeof value === 'object' || context.isMultiMode ? value : {
value,
label: itemLabel
});
}
}, [migrate, value, context.onPress, onPress]);
const onSelectedLayout = useCallback((...args) => {
_invoke(context, 'onSelectedLayout', ...args);
}, []);
const _renderItem = () => {
return <View style={styles.container} flex row spread centerV>
<Text numberOfLines={1} style={itemLabelStyle}>
{itemLabel}
</Text>
{selectedIndicator}
</View>;
};
return <TouchableOpacity activeOpacity={0.5} onPress={_onPress} onLayout={isSelected ? onSelectedLayout : undefined} disabled={isItemDisabled} testID={testID} throttleTime={0} customValue={props.customValue} {...accessibilityProps}>
{customRenderItem ? customRenderItem(value, {
...props,
isSelected,
isItemDisabled
}, itemLabel) : _renderItem()}
</TouchableOpacity>;
};
const styles = StyleSheet.create({
container: {
height: 56.5,
paddingHorizontal: 23,
borderColor: Colors.$outlineDefault,
borderBottomWidth: 1
},
labelText: {
...Typography.text70,
color: Colors.$textDefault,
flex: 1,
textAlign: 'left'
},
labelTextDisabled: {
color: Colors.$textDisabled
}
});
PickerItem.displayName = 'Picker.Item';
export default PickerItem;