diff --git a/.eslintrc b/.eslintrc
index c5360064..ff27af56 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -1,6 +1,10 @@
{
'parser': 'babel-eslint',
+ 'globals': {
+ 'setTimeout': true,
+ },
+
'plugins': [
'react',
],
diff --git a/index.js b/index.js
new file mode 100644
index 00000000..d3a0e372
--- /dev/null
+++ b/index.js
@@ -0,0 +1,3 @@
+import Dropdown from './src/components/dropdown';
+
+export { Dropdown };
diff --git a/src/components/dropdown/index.js b/src/components/dropdown/index.js
new file mode 100644
index 00000000..535aa7f7
--- /dev/null
+++ b/src/components/dropdown/index.js
@@ -0,0 +1,206 @@
+import PropTypes from 'prop-types';
+import React, { PureComponent } from 'react';
+import {
+ Text,
+ View,
+ ScrollView,
+ Modal,
+ TouchableWithoutFeedback,
+ Dimensions,
+ Platform,
+} from 'react-native';
+import { Button } from 'react-native-material-buttons';
+import { TextField } from 'react-native-material-textfield';
+
+import styles from './styles';
+
+export default class Dropdown extends PureComponent {
+ static defaultProps = {
+ overlayColor: 'transparent',
+ };
+
+ static propTypes = {
+ overlayColor: PropTypes.string,
+
+ value: PropTypes.string,
+ data: PropTypes.arrayOf(PropTypes.shape({
+ value: PropTypes.string,
+ })),
+
+ onChangeText: PropTypes.func,
+ onFocus: PropTypes.func,
+ onBlur: PropTypes.func,
+ };
+
+ constructor(props) {
+ super(props);
+
+ this.onPress = this.onPress.bind(this);
+ this.onClose = this.onClose.bind(this);
+ this.updateContainerRef = this.updateRef.bind(this, 'container');
+ this.updateScrollRef = this.updateRef.bind(this, 'scroll');
+ this.renderAccessory = this.renderAccessory.bind(this);
+
+ this.state = {
+ value: this.props.value,
+ offset: 0,
+ modal: false,
+ };
+ }
+
+ isFocused() {
+ return this.state.modal;
+ }
+
+ onPress() {
+ let { value } = this.state;
+ let { data, onFocus } = this.props;
+
+ let offset = 0;
+
+ if (value) {
+ let index = data
+ .indexOf(
+ data
+ .filter((item) => value === item.value)
+ .shift()
+ );
+
+ if (~index) {
+ offset = (index - 1) * 36;
+ }
+ }
+
+ this.container.measureInWindow((x, y, width, height) => {
+ this.setState({
+ modal: true,
+ width: width + 16,
+ top: Platform.select({ ios: y + 1, android: y }) + 26,
+ left: x - 8,
+ offset,
+ });
+
+ if ('function' === typeof onFocus) {
+ onFocus();
+ }
+ });
+ }
+
+ onClose() {
+ let { onBlur } = this.props;
+
+ if ('function' === typeof onBlur) {
+ onBlur();
+ }
+
+ this.setState({ modal: false });
+ }
+
+ onSelect(index) {
+ let { data, onChangeText } = this.props;
+ let { value } = data[index];
+
+ if ('function' === typeof onChangeText) {
+ onChangeText(value);
+ }
+
+ this.setState({ value });
+
+ setTimeout(this.onClose, 400);
+ }
+
+ updateRef(name, ref) {
+ this[name] = ref;
+
+ /* XXX: Initial position for ScrollView */
+ /* FIXME: Android */
+ if ('scroll' === name && ref) {
+ let { offset } = this.state;
+
+ ref.scrollTo({ x: 0, y: offset, animated: false });
+ }
+ }
+
+ renderAccessory() {
+ let triangleStyle = {
+ backgroundColor: TextField.defaultProps.baseColor,
+ };
+
+ return (
+
+
+
+
+
+ );
+ }
+
+ renderItems() {
+ let { data } = this.props;
+
+ return data
+ .map(({ value }, index) => (
+
+ ));
+ }
+
+ render() {
+ let { value, left, top, width, modal } = this.state;
+ let { data, onChangeText, overlayColor, ...props } = this.props;
+
+ let dimensions = Dimensions.get('window');
+
+ let modalStyle = {
+ width: dimensions.width,
+ height: dimensions.height,
+ backgroundColor: overlayColor,
+ };
+
+ let pickerStyle = {
+ width,
+ top,
+ left,
+ };
+
+ return (
+ undefined} ref={this.updateContainerRef}>
+
+
+
+
+
+
+
+
+
+
+
+ {this.renderItems()}
+
+
+
+
+
+
+ );
+ }
+}
diff --git a/src/components/dropdown/styles.js b/src/components/dropdown/styles.js
new file mode 100644
index 00000000..3f7cab11
--- /dev/null
+++ b/src/components/dropdown/styles.js
@@ -0,0 +1,68 @@
+import { StyleSheet } from 'react-native';
+
+export default StyleSheet.create({
+ accessory: {
+ width: 24,
+ height: 24,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+
+ triangle: {
+ width: 8,
+ height: 8,
+ transform: [{
+ translateY: -4,
+ }, {
+ rotate: '45deg',
+ }],
+ },
+
+ triangleContainer: {
+ width: 12,
+ height: 6,
+ overflow: 'hidden',
+ alignItems: 'center',
+
+ backgroundColor: 'transparent', /* XXX: Required */
+ },
+
+ picker: {
+ backgroundColor: 'white',
+ borderRadius: 2,
+ minHeight: 36 + 16,
+ maxHeight: (36 * 5) + 16 - 24,
+
+ position: 'absolute',
+
+ shadowColor: 'rgb(0, 0, 0)',
+ shadowOpacity: 0.54,
+ shadowRadius: 2,
+ shadowOffset: { width: 0, height: 2 },
+ elevation: 4,
+
+ transform: [{
+ translateY: -36 - 8,
+ }],
+ },
+
+ scroll: {
+ flex: 1,
+ borderRadius: 2,
+ },
+
+ scrollContainer: {
+ paddingVertical: 8,
+ },
+
+ item: {
+ height: 36,
+ paddingHorizontal: 8,
+ borderRadius: 0,
+ justifyContent: 'center',
+ },
+
+ text: {
+ fontSize: 16,
+ },
+});