diff --git a/package.json b/package.json index 29d2b079..7c4d63d3 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,12 @@ { - "name": "react-native-material-dropdown", - "version": "0.11.1", + "name": "react-native-material-dropdown-v3", + "version": "0.11.2", "license": "BSD-3-Clause", - "author": "Alexander Nazarov ", + "contributors": [ + {"name": "Alexander Nazarov", "email": "n4kz@n4kz.com"}, + {"name": "Jimmy Wei", "email": "ijimmywei@gmail.com"}, + {"name": "Mike Dizon", "email": "mdizon@gmail.com"} + ], "description": "Material dropdown", "keywords": [ @@ -21,12 +25,13 @@ "repository": { "type": "git", - "url": "git://github.com/n4kz/react-native-material-dropdown.git" + "url": "git://github.com/mikedizon/react-native-material-dropdown.git" }, "peerDependencies": { "react": "*", - "react-native": "*" + "react-native": "*", + "react-native-paper": "*" }, "devDependencies": { @@ -41,8 +46,6 @@ "dependencies": { "prop-types": "^15.5.9", - "react-native-material-buttons": "^0.5.0", - "react-native-material-ripple": "^0.8.0", - "react-native-material-textfield": "^0.12.0" + "react-native-material-ripple": "^0.8.0" } } diff --git a/src/components/dropdown/index.js b/src/components/dropdown/index.js index b1e65a1f..08987b3b 100644 --- a/src/components/dropdown/index.js +++ b/src/components/dropdown/index.js @@ -1,766 +1,773 @@ import PropTypes from 'prop-types'; import React, { PureComponent } from 'react'; import { - Text, - View, - FlatList, - Animated, - Modal, - TouchableWithoutFeedback, - Dimensions, - Platform, - ViewPropTypes, - I18nManager, + Text, + View, + FlatList, + Animated, + Modal, + TouchableWithoutFeedback, + Dimensions, + Platform, + ViewPropTypes, + I18nManager, } from 'react-native'; import Ripple from 'react-native-material-ripple'; -import { TextField } from 'react-native-material-textfield'; +import { TextInput } from 'react-native-paper'; import DropdownItem from '../item'; import styles from './styles'; export default class Dropdown extends PureComponent { - static defaultProps = { - hitSlop: { top: 6, right: 4, bottom: 6, left: 4 }, + static defaultProps = { + hitSlop: { top: 6, right: 4, bottom: 6, left: 4 }, - disabled: false, + disabled: false, - data: [], + data: [], - valueExtractor: ({ value } = {}, index) => value, - labelExtractor: ({ label } = {}, index) => label, - propsExtractor: () => null, + valueExtractor: ({ value } = {}, index) => value, + labelExtractor: ({ label } = {}, index) => label, + propsExtractor: () => null, - absoluteRTLLayout: false, + absoluteRTLLayout: false, - dropdownOffset: { - top: 32, - left: 0, - }, + dropdownOffset: { + top: 32, + left: 0, + }, - dropdownMargins: { - min: 8, - max: 16, - }, + dropdownMargins: { + min: 8, + max: 16, + }, - rippleCentered: false, - rippleSequential: true, + rippleCentered: false, + rippleSequential: true, - rippleInsets: { - top: 16, - right: 0, - bottom: -8, - left: 0, - }, + rippleInsets: { + top: 16, + right: 0, + bottom: -8, + left: 0, + }, - rippleOpacity: 0.54, - shadeOpacity: 0.12, + rippleOpacity: 0.54, + shadeOpacity: 0.12, - rippleDuration: 400, - animationDuration: 225, + rippleDuration: 400, + animationDuration: 225, - fontSize: 16, + fontSize: 16, - textColor: 'rgba(0, 0, 0, .87)', - itemColor: 'rgba(0, 0, 0, .54)', - baseColor: 'rgba(0, 0, 0, .38)', + textColor: 'rgba(0, 0, 0, .87)', + itemColor: 'rgba(0, 0, 0, .54)', + baseColor: 'rgba(0, 0, 0, .38)', - itemCount: 4, - itemPadding: 8, + itemCount: 4, + itemPadding: 8, - supportedOrientations: [ - 'portrait', - 'portrait-upside-down', - 'landscape', - 'landscape-left', - 'landscape-right', - ], + supportedOrientations: [ + 'portrait', + 'portrait-upside-down', + 'landscape', + 'landscape-left', + 'landscape-right', + ], - useNativeDriver: false, - }; - - static propTypes = { - ...TouchableWithoutFeedback.propTypes, + useNativeDriver: false, + }; - disabled: PropTypes.bool, + static propTypes = { + ...TouchableWithoutFeedback.propTypes, - value: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.number, - ]), + disabled: PropTypes.bool, - data: PropTypes.arrayOf(PropTypes.object), + value: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number, + ]), - valueExtractor: PropTypes.func, - labelExtractor: PropTypes.func, - propsExtractor: PropTypes.func, + data: PropTypes.arrayOf(PropTypes.object), - absoluteRTLLayout: PropTypes.bool, + valueExtractor: PropTypes.func, + labelExtractor: PropTypes.func, + propsExtractor: PropTypes.func, - dropdownOffset: PropTypes.shape({ - top: PropTypes.number.isRequired, - left: PropTypes.number.isRequired, - }), + absoluteRTLLayout: PropTypes.bool, - dropdownMargins: PropTypes.shape({ - min: PropTypes.number.isRequired, - max: PropTypes.number.isRequired, - }), + dropdownOffset: PropTypes.shape({ + top: PropTypes.number.isRequired, + left: PropTypes.number.isRequired, + }), - dropdownPosition: PropTypes.number, + dropdownMargins: PropTypes.shape({ + min: PropTypes.number.isRequired, + max: PropTypes.number.isRequired, + }), - rippleColor: PropTypes.string, - rippleCentered: PropTypes.bool, - rippleSequential: PropTypes.bool, + dropdownPosition: PropTypes.number, - rippleInsets: PropTypes.shape({ - top: PropTypes.number, - right: PropTypes.number, - bottom: PropTypes.number, - left: PropTypes.number, - }), + rippleColor: PropTypes.string, + rippleCentered: PropTypes.bool, + rippleSequential: PropTypes.bool, - rippleOpacity: PropTypes.number, - shadeOpacity: PropTypes.number, + rippleInsets: PropTypes.shape({ + top: PropTypes.number, + right: PropTypes.number, + bottom: PropTypes.number, + left: PropTypes.number, + }), - rippleDuration: PropTypes.number, - animationDuration: PropTypes.number, + rippleOpacity: PropTypes.number, + shadeOpacity: PropTypes.number, - fontSize: PropTypes.number, + rippleDuration: PropTypes.number, + animationDuration: PropTypes.number, - textColor: PropTypes.string, - itemColor: PropTypes.string, - selectedItemColor: PropTypes.string, - disabledItemColor: PropTypes.string, - baseColor: PropTypes.string, + fontSize: PropTypes.number, - itemTextStyle: Text.propTypes.style, + textColor: PropTypes.string, + itemColor: PropTypes.string, + selectedItemColor: PropTypes.string, + disabledItemColor: PropTypes.string, + baseColor: PropTypes.string, - itemCount: PropTypes.number, - itemPadding: PropTypes.number, + itemTextStyle: Text.propTypes.style, - onLayout: PropTypes.func, - onFocus: PropTypes.func, - onBlur: PropTypes.func, - onChangeText: PropTypes.func, + itemCount: PropTypes.number, + itemPadding: PropTypes.number, - renderBase: PropTypes.func, - renderAccessory: PropTypes.func, + onLayout: PropTypes.func, + onFocus: PropTypes.func, + onBlur: PropTypes.func, + onChangeText: PropTypes.func, - containerStyle: (ViewPropTypes || View.propTypes).style, - overlayStyle: (ViewPropTypes || View.propTypes).style, - pickerStyle: (ViewPropTypes || View.propTypes).style, + renderBase: PropTypes.func, + renderAccessory: PropTypes.func, - supportedOrientations: PropTypes.arrayOf(PropTypes.string), + labelContainerStyle: (ViewPropTypes || View.propTypes).style, + containerStyle: (ViewPropTypes || View.propTypes).style, + overlayStyle: (ViewPropTypes || View.propTypes).style, + pickerStyle: (ViewPropTypes || View.propTypes).style, - useNativeDriver: PropTypes.bool, - }; + supportedOrientations: PropTypes.arrayOf(PropTypes.string), - constructor(props) { - super(props); + useNativeDriver: PropTypes.bool, + }; - this.onPress = this.onPress.bind(this); - this.onClose = this.onClose.bind(this); - this.onSelect = this.onSelect.bind(this); - this.onLayout = this.onLayout.bind(this); + constructor(props) { + super(props); - this.updateRippleRef = this.updateRef.bind(this, 'ripple'); - this.updateContainerRef = this.updateRef.bind(this, 'container'); - this.updateScrollRef = this.updateRef.bind(this, 'scroll'); + this.onPress = this.onPress.bind(this); + this.onClose = this.onClose.bind(this); + this.onSelect = this.onSelect.bind(this); + this.onLayout = this.onLayout.bind(this); - this.renderAccessory = this.renderAccessory.bind(this); - this.renderItem = this.renderItem.bind(this); + this.updateRippleRef = this.updateRef.bind(this, 'ripple'); + this.updateContainerRef = this.updateRef.bind(this, 'container'); + this.updateScrollRef = this.updateRef.bind(this, 'scroll'); - this.keyExtractor = this.keyExtractor.bind(this); + this.renderAccessory = this.renderAccessory.bind(this); + this.renderItem = this.renderItem.bind(this); - this.blur = () => this.onClose(); - this.focus = this.onPress; + this.keyExtractor = this.keyExtractor.bind(this); - let { value } = this.props; + this.blur = () => this.onClose(); + this.focus = this.onPress; - this.mounted = false; - this.focused = false; + let { value } = this.props; - this.state = { - opacity: new Animated.Value(0), - selected: -1, - modal: false, - value, - }; - } + this.mounted = false; + this.focused = false; - componentWillReceiveProps({ value }) { - if (value !== this.props.value) { - this.setState({ value }); - } - } - - componentDidMount() { - this.mounted = true; - } - - componentWillUnmount() { - this.mounted = false; - } - - onPress(event) { - let { - data, - disabled, - onFocus, - itemPadding, - rippleDuration, - dropdownOffset, - dropdownMargins: { min: minMargin, max: maxMargin }, - animationDuration, - absoluteRTLLayout, - useNativeDriver, - } = this.props; - - if (disabled) { - return; + this.state = { + opacity: new Animated.Value(0), + selected: -1, + modal: false, + value, + }; } - let itemCount = data.length; - let timestamp = Date.now(); + componentDidUpdate(prevProps, prevState) { + if (prevProps.value !== this.props.value) { + this.txRef.current.value = this.props.value; + } else if (prevState.value !== this.state.value) { + this.txRef.current.value = this.state.value; + } + } - if (null != event) { - /* Adjust event location */ - event.nativeEvent.locationY -= this.rippleInsets().top; - event.nativeEvent.locationX -= this.rippleInsets().left; + - /* Start ripple directly from event */ - this.ripple.startRipple(event); + componentDidMount() { + this.mounted = true; } - if (!itemCount) { - return; + componentWillUnmount() { + this.mounted = false; } - this.focused = true; + onPress(event) { + let { + data, + disabled, + onFocus, + itemPadding, + rippleDuration, + dropdownOffset, + dropdownMargins: { min: minMargin, max: maxMargin }, + animationDuration, + absoluteRTLLayout, + useNativeDriver, + } = this.props; + + if (disabled) { + return; + } + + let itemCount = data.length; + let timestamp = Date.now(); + + if (null != event) { + /* Adjust event location */ + event.nativeEvent.locationY -= this.rippleInsets().top; + event.nativeEvent.locationX -= this.rippleInsets().left; + + /* Start ripple directly from event */ + this.ripple.startRipple(event); + } + + if (!itemCount) { + return; + } + + this.focused = true; + + if ('function' === typeof onFocus) { + onFocus(); + } + + let dimensions = Dimensions.get('window'); + + this.container.measureInWindow((x, y, containerWidth, containerHeight) => { + let { opacity } = this.state; - if ('function' === typeof onFocus) { - onFocus(); + /* Adjust coordinates for relative layout in RTL locale */ + if (I18nManager.isRTL && !absoluteRTLLayout) { + x = dimensions.width - (x + containerWidth); + } + + let delay = Math.max(0, rippleDuration - animationDuration - (Date.now() - timestamp)); + let selected = this.selectedIndex(); + + let leftInset; + let left = x + + dropdownOffset.left + - maxMargin; + + if (left > minMargin) { + leftInset = maxMargin; + } else { + left = minMargin; + leftInset = minMargin; + } + + let right = x + containerWidth + maxMargin; + let rightInset; + + if (dimensions.width - right > minMargin) { + rightInset = maxMargin; + } else { + right = dimensions.width - minMargin; + rightInset = minMargin; + } + + let top = y + + dropdownOffset.top + - itemPadding; + + this.setState({ + modal: true, + width: right - left, + top, + left, + leftInset, + rightInset, + selected, + }); + + setTimeout((() => { + if (this.mounted) { + this.resetScrollOffset(); + + Animated + .timing(opacity, { + duration: animationDuration, + toValue: 1, + useNativeDriver, + }) + .start(() => { + if (this.mounted && 'ios' === Platform.OS) { + let { flashScrollIndicators } = this.scroll || {}; + + if ('function' === typeof flashScrollIndicators) { + flashScrollIndicators.call(this.scroll); + } + } + }); + } + }), delay); + }); } - let dimensions = Dimensions.get('window'); - - this.container.measureInWindow((x, y, containerWidth, containerHeight) => { - let { opacity } = this.state; - - /* Adjust coordinates for relative layout in RTL locale */ - if (I18nManager.isRTL && !absoluteRTLLayout) { - x = dimensions.width - (x + containerWidth); - } - - let delay = Math.max(0, rippleDuration - animationDuration - (Date.now() - timestamp)); - let selected = this.selectedIndex(); - - let leftInset; - let left = x - + dropdownOffset.left - - maxMargin; - - if (left > minMargin) { - leftInset = maxMargin; - } else { - left = minMargin; - leftInset = minMargin; - } - - let right = x + containerWidth + maxMargin; - let rightInset; - - if (dimensions.width - right > minMargin) { - rightInset = maxMargin; - } else { - right = dimensions.width - minMargin; - rightInset = minMargin; - } - - let top = y - + dropdownOffset.top - - itemPadding; - - this.setState({ - modal: true, - width: right - left, - top, - left, - leftInset, - rightInset, - selected, - }); - - setTimeout((() => { - if (this.mounted) { - this.resetScrollOffset(); - - Animated + onClose(value = this.state.value) { + let { onBlur, animationDuration, useNativeDriver } = this.props; + let { opacity } = this.state; + + Animated .timing(opacity, { - duration: animationDuration, - toValue: 1, - useNativeDriver, + duration: animationDuration, + toValue: 0, + useNativeDriver, }) .start(() => { - if (this.mounted && 'ios' === Platform.OS) { - let { flashScrollIndicators } = this.scroll || {}; + this.focused = false; - if ('function' === typeof flashScrollIndicators) { - flashScrollIndicators.call(this.scroll); + if ('function' === typeof onBlur) { + onBlur(); + } + + if (this.mounted) { + this.setState({ value, modal: false }); } - } }); - } - }), delay); - }); - } - - onClose(value = this.state.value) { - let { onBlur, animationDuration, useNativeDriver } = this.props; - let { opacity } = this.state; - - Animated - .timing(opacity, { - duration: animationDuration, - toValue: 0, - useNativeDriver, - }) - .start(() => { - this.focused = false; + } - if ('function' === typeof onBlur) { - onBlur(); - } + onSelect(index) { + let { + data, + valueExtractor, + onChangeText, + animationDuration, + rippleDuration, + } = this.props; + + let value = valueExtractor(data[index], index); + let delay = Math.max(0, rippleDuration - animationDuration); - if (this.mounted) { - this.setState({ value, modal: false }); + if ('function' === typeof onChangeText) { + onChangeText(value, index, data); } - }); - } - - onSelect(index) { - let { - data, - valueExtractor, - onChangeText, - animationDuration, - rippleDuration, - } = this.props; - - let value = valueExtractor(data[index], index); - let delay = Math.max(0, rippleDuration - animationDuration); - - if ('function' === typeof onChangeText) { - onChangeText(value, index, data); - } - setTimeout(() => this.onClose(value), delay); - } + setTimeout(() => this.onClose(value), delay); + } - onLayout(event) { - let { onLayout } = this.props; + onLayout(event) { + let { onLayout } = this.props; - if ('function' === typeof onLayout) { - onLayout(event); + if ('function' === typeof onLayout) { + onLayout(event); + } } - } - value() { - let { value } = this.state; + value() { + let { value } = this.state; - return value; - } - - selectedIndex() { - let { value } = this.state; - let { data, valueExtractor } = this.props; + return value; + } - return data - .findIndex((item, index) => null != item && value === valueExtractor(item, index)); - } + selectedIndex() { + let { value } = this.state; + let { data, valueExtractor } = this.props; - selectedItem() { - let { data } = this.props; + return data + .findIndex((item, index) => null != item && value === valueExtractor(item, index)); + } - return data[this.selectedIndex()]; - } + selectedItem() { + let { data } = this.props; - isFocused() { - return this.focused; - } + return data[this.selectedIndex()]; + } - itemSize() { - let { fontSize, itemPadding } = this.props; + isFocused() { + return this.focused; + } - return Math.ceil(fontSize * 1.5 + itemPadding * 2); - } + itemSize() { + let { fontSize, itemPadding } = this.props; - visibleItemCount() { - let { data, itemCount } = this.props; + return Math.ceil(fontSize * 1.5 + itemPadding * 2); + } - return Math.min(data.length, itemCount); - } + visibleItemCount() { + let { data, itemCount } = this.props; - tailItemCount() { - return Math.max(this.visibleItemCount() - 2, 0); - } + return Math.min(data.length, itemCount); + } - rippleInsets() { - let { - top = 16, - right = 0, - bottom = -8, - left = 0, - } = this.props.rippleInsets || {}; + tailItemCount() { + return Math.max(this.visibleItemCount() - 2, 0); + } - return { top, right, bottom, left }; - } + rippleInsets() { + let { + top = 16, + right = 0, + bottom = -8, + left = 0, + } = this.props.rippleInsets || {}; - resetScrollOffset() { - let { selected } = this.state; - let { data, dropdownPosition } = this.props; + return { top, right, bottom, left }; + } - let offset = 0; - let itemCount = data.length; - let itemSize = this.itemSize(); - let tailItemCount = this.tailItemCount(); - let visibleItemCount = this.visibleItemCount(); + resetScrollOffset() { + let { selected } = this.state; + let { data, dropdownPosition } = this.props; + + let offset = 0; + let itemCount = data.length; + let itemSize = this.itemSize(); + let tailItemCount = this.tailItemCount(); + let visibleItemCount = this.visibleItemCount(); + + if (itemCount > visibleItemCount) { + if (null == dropdownPosition) { + switch (selected) { + case -1: + break; + + case 0: + case 1: + break; + + default: + if (selected >= itemCount - tailItemCount) { + offset = itemSize * (itemCount - visibleItemCount); + } else { + offset = itemSize * (selected - 1); + } + } + } else { + let index = selected - dropdownPosition; - if (itemCount > visibleItemCount) { - if (null == dropdownPosition) { - switch (selected) { - case -1: - break; + if (dropdownPosition < 0) { + index -= visibleItemCount; + } - case 0: - case 1: - break; + index = Math.max(0, index); + index = Math.min(index, itemCount - visibleItemCount); - default: - if (selected >= itemCount - tailItemCount) { - offset = itemSize * (itemCount - visibleItemCount); - } else { - offset = itemSize * (selected - 1); + if (~selected) { + offset = itemSize * index; + } } } - } else { - let index = selected - dropdownPosition; - if (dropdownPosition < 0) { - index -= visibleItemCount; + if (this.scroll) { + this.scroll.scrollToOffset({ offset, animated: false }); } + } - index = Math.max(0, index); - index = Math.min(index, itemCount - visibleItemCount); - - if (~selected) { - offset = itemSize * index; - } - } + updateRef(name, ref) { + this[name] = ref; } - if (this.scroll) { - this.scroll.scrollToOffset({ offset, animated: false }); + keyExtractor(item, index) { + let { valueExtractor } = this.props; + + return `${index}-${valueExtractor(item, index)}`; } - } - updateRef(name, ref) { - this[name] = ref; - } + txRef = React.createRef(); - keyExtractor(item, index) { - let { valueExtractor } = this.props; + renderBase(props) { + let { value } = this.state; + let { + data, + renderBase, + labelExtractor, + dropdownOffset, + renderAccessory = this.renderAccessory, + } = this.props; - return `${index}-${valueExtractor(item, index)}`; - } + let index = this.selectedIndex(); + let title; - renderBase(props) { - let { value } = this.state; - let { - data, - renderBase, - labelExtractor, - dropdownOffset, - renderAccessory = this.renderAccessory, - } = this.props; + if (~index) { + title = labelExtractor(data[index], index); + } - let index = this.selectedIndex(); - let title; + if (null == title) { + title = value; + } - if (~index) { - title = labelExtractor(data[index], index); - } + if ('function' === typeof renderBase) { + return renderBase({ ...props, title, value, renderAccessory }); + } - if (null == title) { - title = value; + title = null == title || 'string' === typeof title ? + title : + String(title); + + return ( + + ); } - if ('function' === typeof renderBase) { - return renderBase({ ...props, title, value, renderAccessory }); + renderRipple() { + let { + baseColor, + rippleColor = baseColor, + rippleOpacity, + rippleDuration, + rippleCentered, + rippleSequential, + } = this.props; + + let { bottom, ...insets } = this.rippleInsets(); + let style = { + ...insets, + + height: this.itemSize() - bottom, + position: 'absolute', + }; + + return ( + + ); } - title = null == title || 'string' === typeof title? - title: - String(title); - - return ( - - ); - } - - renderRipple() { - let { - baseColor, - rippleColor = baseColor, - rippleOpacity, - rippleDuration, - rippleCentered, - rippleSequential, - } = this.props; - - let { bottom, ...insets } = this.rippleInsets(); - let style = { - ...insets, - - height: this.itemSize() - bottom, - position: 'absolute', - }; - - return ( - - ); - } - - renderAccessory() { - let { baseColor: backgroundColor } = this.props; - let triangleStyle = { backgroundColor }; - - return ( - - - - - - ); - } - - renderItem({ item, index }) { - if (null == item) { - return null; - } + renderAccessory() { + let { baseColor: backgroundColor } = this.props; + let triangleStyle = { backgroundColor }; - let { selected, leftInset, rightInset } = this.state; - - let { - valueExtractor, - labelExtractor, - propsExtractor, - textColor, - itemColor, - baseColor, - selectedItemColor = textColor, - disabledItemColor = baseColor, - fontSize, - itemTextStyle, - rippleOpacity, - rippleDuration, - shadeOpacity, - } = this.props; - - let props = propsExtractor(item, index); - - let { style, disabled } - = props - = { - rippleDuration, - rippleOpacity, - rippleColor: baseColor, - - shadeColor: baseColor, - shadeOpacity, - - ...props, - - onPress: this.onSelect, - }; - - let value = valueExtractor(item, index); - let label = labelExtractor(item, index); - - let title = null == label? - value: - label; - - let color = disabled? - disabledItemColor: - ~selected? - index === selected? - selectedItemColor: - itemColor: - selectedItemColor; - - let textStyle = { color, fontSize }; - - props.style = [ - style, - { - height: this.itemSize(), - paddingLeft: leftInset, - paddingRight: rightInset, - }, - ]; - - return ( - - - {title} - - - ); - } - - render() { - let { - renderBase, - renderAccessory, - containerStyle, - overlayStyle: overlayStyleOverrides, - pickerStyle: pickerStyleOverrides, - - rippleInsets, - rippleOpacity, - rippleCentered, - rippleSequential, - - hitSlop, - pressRetentionOffset, - testID, - nativeID, - accessible, - accessibilityLabel, - - supportedOrientations, - - ...props - } = this.props; - - let { - data, - disabled, - itemPadding, - dropdownPosition, - } = props; - - let { left, top, width, opacity, selected, modal } = this.state; - - let itemCount = data.length; - let visibleItemCount = this.visibleItemCount(); - let tailItemCount = this.tailItemCount(); - let itemSize = this.itemSize(); - - let height = 2 * itemPadding + itemSize * visibleItemCount; - let translateY = -itemPadding; - - if (null == dropdownPosition) { - switch (selected) { - case -1: - translateY -= 1 === itemCount? 0 : itemSize; - break; - - case 0: - break; - - default: - if (selected >= itemCount - tailItemCount) { - translateY -= itemSize * (visibleItemCount - (itemCount - selected)); - } else { - translateY -= itemSize; - } - } - } else { - if (dropdownPosition < 0) { - translateY -= itemSize * (visibleItemCount + dropdownPosition); - } else { - translateY -= itemSize * dropdownPosition; - } + return ( + + + + + + ); } - let overlayStyle = { opacity }; + renderItem({ item, index }) { + if (null == item) { + return null; + } - let pickerStyle = { - width, - height, - top, - left, - transform: [{ translateY }], - }; + let { selected, leftInset, rightInset } = this.state; + + let { + valueExtractor, + labelExtractor, + propsExtractor, + textColor, + itemColor, + baseColor, + selectedItemColor = textColor, + disabledItemColor = baseColor, + fontSize, + itemTextStyle, + rippleOpacity, + rippleDuration, + shadeOpacity, + } = this.props; + + let props = propsExtractor(item, index); + + let { style, disabled } + = props + = { + rippleDuration, + rippleOpacity, + rippleColor: baseColor, + + shadeColor: baseColor, + shadeOpacity, + + ...props, + + onPress: this.onSelect, + }; + + let value = valueExtractor(item, index); + let label = labelExtractor(item, index); + + let title = null == label ? + value : + label; + + let color = disabled ? + disabledItemColor : + ~selected ? + index === selected ? + selectedItemColor : + itemColor : + selectedItemColor; + + let textStyle = { color, fontSize }; + + props.style = [ + style, + { + height: this.itemSize(), + paddingLeft: leftInset, + paddingRight: rightInset, + }, + ]; + + return ( + + + {title} + + + ); + } - let touchableProps = { - disabled, - hitSlop, - pressRetentionOffset, - onPress: this.onPress, - testID, - nativeID, - accessible, - accessibilityLabel, - }; + render() { + let { + renderBase, + renderAccessory, + containerStyle, + labelContainerStyle, + overlayStyle: overlayStyleOverrides, + pickerStyle: pickerStyleOverrides, + + rippleInsets, + rippleOpacity, + rippleCentered, + rippleSequential, + + hitSlop, + pressRetentionOffset, + testID, + nativeID, + accessible, + accessibilityLabel, + + supportedOrientations, + + ...props + } = this.props; + + let { + data, + disabled, + itemPadding, + dropdownPosition, + } = props; + + let { left, top, width, opacity, selected, modal } = this.state; + + let itemCount = data.length; + let visibleItemCount = this.visibleItemCount(); + let tailItemCount = this.tailItemCount(); + let itemSize = this.itemSize(); + + let height = 2 * itemPadding + itemSize * visibleItemCount; + let translateY = -itemPadding; + + if (null == dropdownPosition) { + switch (selected) { + case -1: + translateY -= 1 === itemCount ? 0 : itemSize; + break; + + case 0: + break; + + default: + if (selected >= itemCount - tailItemCount) { + translateY -= itemSize * (visibleItemCount - (itemCount - selected)); + } else { + translateY -= itemSize; + } + } + } else { + if (dropdownPosition < 0) { + translateY -= itemSize * (visibleItemCount + dropdownPosition); + } else { + translateY -= itemSize * dropdownPosition; + } + } - return ( - - - - {this.renderBase(props)} - {this.renderRipple()} - - - - - true} - onResponderRelease={this.blur} - > - true} - > - + let overlayStyle = { opacity }; + + let pickerStyle = { + width, + height, + top, + left, + transform: [{ translateY }], + }; + + let touchableProps = { + disabled, + hitSlop, + pressRetentionOffset, + onPress: this.onPress, + testID, + nativeID, + accessible, + accessibilityLabel, + }; + + return ( + + + + {this.renderBase(props)} + {this.renderRipple()} + + + + + true} + onResponderRelease={this.blur} + > + true} + > + + + + - - - - ); - } + ); + } } diff --git a/src/components/item/index.js b/src/components/item/index.js index 22e36354..31a27196 100644 --- a/src/components/item/index.js +++ b/src/components/item/index.js @@ -1,6 +1,6 @@ import PropTypes from 'prop-types'; import React, { PureComponent } from 'react'; -import { Button } from 'react-native-material-buttons'; +import { Button } from 'react-native-paper'; import styles from './styles'; @@ -33,12 +33,13 @@ export default class DropdownItem extends PureComponent { } render() { - let { children, style, index, ...props } = this.props; + let { children, style, index, ...props } = this.props; return (