Skip to content

Commit 286c00c

Browse files
committed
feat(package): Add withPickerValues hoc
1 parent 6a5d74a commit 286c00c

9 files changed

Lines changed: 266 additions & 17 deletions

File tree

index.js

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,24 @@
1-
import { compose } from "recompose";
2-
import setFormikInitialValue from "./src/setFormikInitialValue";
3-
import withError from "./src/withError";
4-
import withFocus from "./src/withFocus";
5-
import withFormik from "./src/withFormik";
6-
import withInputTypeProps from "./src/withInputTypeProps";
7-
import withTouched from "./src/withTouched";
8-
import makeReactNativeField from "./src/makeReactNativeField";
9-
import { withNextInputAutoFocusForm, withNextInputAutoFocusInput } from "./src/withNextInputAutoFocus";
1+
import { compose } from 'recompose';
2+
import setFormikInitialValue from './src/setFormikInitialValue';
3+
import withError from './src/withError';
4+
import withFocus from './src/withFocus';
5+
import withFormik from './src/withFormik';
6+
import withInputTypeProps from './src/withInputTypeProps';
7+
import withTouched from './src/withTouched';
8+
import withPickerValues from './src/withPickerValues';
9+
import makeReactNativeField from './src/makeReactNativeField';
10+
import {
11+
withNextInputAutoFocusForm,
12+
withNextInputAutoFocusInput,
13+
} from './src/withNextInputAutoFocus';
1014

11-
const makeInputsGreatAgain = compose(withInputTypeProps, setFormikInitialValue, withError, withTouched, makeReactNativeField);
15+
const makeInputsGreatAgain = compose(
16+
withInputTypeProps,
17+
setFormikInitialValue,
18+
withError,
19+
withTouched,
20+
makeReactNativeField
21+
);
1222

1323
export default makeInputsGreatAgain;
1424

@@ -22,5 +32,6 @@ export {
2232
withInputTypeProps,
2333
withTouched,
2434
withNextInputAutoFocusForm,
25-
withNextInputAutoFocusInput
35+
withNextInputAutoFocusInput,
36+
withPickerValues,
2637
};

jest.config.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
const path = require("path");
1+
const path = require('path');
22

33
module.exports = {
4-
preset: "react-native",
5-
setupFiles: [path.join(__dirname, "./jest/preamble.js")]
4+
preset: 'react-native',
5+
transformIgnorePatterns: [
6+
'node_modules/(?!(react-native|react-native-button|react-native-core-library|@bam.tech/[w-]*|static-container|react-native-tab-view)|react-native-iphone-x-helper/)',
7+
],
8+
setupFiles: [path.join(__dirname, './jest/preamble.js')],
69
};

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
"forms"
2222
],
2323
"dependencies": {
24+
"@bam.tech/react-native-modalbox": "^1.4.2",
25+
"@bam.tech/react-native-root-siblings": "^2.0.3",
2426
"lodash": "4.17.5",
2527
"recompose": "^0.26.0"
2628
},
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// @flow
2+
3+
import React, { PureComponent } from 'react';
4+
import { TouchableOpacity, View } from 'react-native';
5+
6+
type _Props = {
7+
children: ?*,
8+
onPress: () => any,
9+
children: any,
10+
};
11+
12+
export default class DisableInputKeyboard extends PureComponent {
13+
static defaultProps = {
14+
children: null,
15+
};
16+
17+
props: _Props;
18+
19+
render() {
20+
return (
21+
<TouchableOpacity onPress={this.props.onPress}>
22+
<View pointerEvents={'box-only'}>{this.props.children}</View>
23+
</TouchableOpacity>
24+
);
25+
}
26+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// @flow
2+
3+
import React, { PureComponent } from 'react';
4+
import { Easing, Keyboard } from 'react-native';
5+
import Modal from '@bam.tech/react-native-modalbox';
6+
import RootSiblings from '@bam.tech/react-native-root-siblings';
7+
8+
type _Props = {
9+
style: Object,
10+
easingAnimation: () => void,
11+
children: any,
12+
};
13+
14+
const renderModal = (props: _Props, open: ?boolean) => (
15+
<Modal
16+
backdrop={false}
17+
position="bottom"
18+
moveAboveKeyboard={false}
19+
isOpen={open}
20+
style={[{ height: 216, backgroundColor: 'rgb(200, 203, 211)' }, props.style]}
21+
easing={props.easingAnimation}
22+
>
23+
{props.children}
24+
</Modal>
25+
);
26+
27+
let keyboardModalInstance = null;
28+
let displayedKeyboardComponent = null;
29+
let keyboardModalCount = 0;
30+
let keyboardDidShowListener = null;
31+
let currentProps;
32+
33+
const updateKeyboardModalComponent = (props: _Props, open: ?boolean) => {
34+
if (open) currentProps = props;
35+
if (keyboardModalInstance) keyboardModalInstance.update(renderModal(props, open));
36+
};
37+
38+
const open = (keyboardComponent: any) => {
39+
if (displayedKeyboardComponent) displayedKeyboardComponent.displayed = false;
40+
41+
displayedKeyboardComponent = keyboardComponent;
42+
displayedKeyboardComponent.displayed = true;
43+
44+
updateKeyboardModalComponent(keyboardComponent.props, true);
45+
};
46+
47+
const keyboardDidShow = () => updateKeyboardModalComponent(currentProps, false);
48+
49+
const createKeyboardModalComponent = (props: _Props) => {
50+
keyboardModalCount += 1;
51+
52+
if (keyboardModalCount > 1) return;
53+
54+
currentProps = props;
55+
56+
keyboardModalInstance = new RootSiblings(renderModal(props));
57+
debugger;
58+
keyboardDidShowListener = Keyboard.addListener('keyboardWillShow', keyboardDidShow);
59+
};
60+
61+
const removeKeyboardModalComponent = () => {
62+
keyboardModalCount -= 1;
63+
64+
if (keyboardModalCount === 0) {
65+
if (keyboardDidShowListener) keyboardDidShowListener.remove();
66+
if (keyboardModalInstance) keyboardModalInstance.remove();
67+
}
68+
};
69+
70+
export default class KeyboardModal extends PureComponent {
71+
static dismiss() {
72+
if (keyboardModalCount > 0) {
73+
updateKeyboardModalComponent(currentProps, false);
74+
}
75+
}
76+
77+
static defaultProps = {
78+
easingAnimation: Easing.ease,
79+
};
80+
81+
componentWillMount() {
82+
createKeyboardModalComponent(this.props);
83+
}
84+
85+
componentWillReceiveProps(nextProps: _Props) {
86+
if (this.displayed) {
87+
updateKeyboardModalComponent(nextProps);
88+
}
89+
}
90+
91+
componentWillUnmount() {
92+
removeKeyboardModalComponent();
93+
}
94+
95+
displayed: boolean = false;
96+
97+
open() {
98+
this.displayed = true;
99+
Keyboard.dismiss();
100+
open(this);
101+
}
102+
103+
close() {
104+
this.displayed = false;
105+
updateKeyboardModalComponent(this.props, false);
106+
}
107+
108+
render() {
109+
return null;
110+
}
111+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// @flow
2+
import React, { PureComponent } from 'react';
3+
import { View, Platform, Picker } from 'react-native';
4+
5+
import KeyboardModal from './KeyboardModal';
6+
import DisableKeyboard from './DisableKeyboard';
7+
8+
type PropsType = {
9+
values: Array<{ label: string, value: string }>,
10+
};
11+
12+
class PickerModal extends PureComponent<PropsType> {
13+
pickerModal: ?KeyboardModal;
14+
15+
openPicker = () => {
16+
if (this.pickerModal) this.pickerModal.open();
17+
};
18+
19+
onValueChange = (value: any) => {
20+
if (this.props.onChangeText) this.props.onChangeText(value);
21+
};
22+
23+
renderPicker = () => {
24+
const picker = (
25+
<Picker onValueChange={this.onValueChange} selectedValue={this.props.value}>
26+
<Picker.Item value="" label={this.props.placeholder} />
27+
{this.props.values.map(item => <Picker.Item key={item.value} {...item} />)}
28+
</Picker>
29+
);
30+
31+
return Platform.OS === 'ios' ? (
32+
<KeyboardModal
33+
ref={ref => {
34+
this.pickerModal = ref;
35+
}}
36+
>
37+
{picker}
38+
</KeyboardModal>
39+
) : (
40+
picker
41+
);
42+
};
43+
44+
render() {
45+
return (
46+
<View>
47+
<DisableKeyboard onPress={this.openPicker}>{this.props.children}</DisableKeyboard>
48+
{this.renderPicker()}
49+
</View>
50+
);
51+
}
52+
}
53+
54+
export default PickerModal;

src/withPickerValues/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from './withPickerValues';
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// @flow
2+
3+
import React from 'react';
4+
import { compose } from 'recompose';
5+
6+
import PickerModal from './PickerModal';
7+
8+
const withPickerModal = Component => props => {
9+
const selectedItem = props.values.find(item => item.value === props.value);
10+
return (
11+
<PickerModal {...props}>
12+
<Component {...props} value={selectedItem ? selectedItem.label : ''} />
13+
</PickerModal>
14+
);
15+
};
16+
17+
export default compose(withPickerModal);

yarn.lock

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,20 @@
1616
esutils "^2.0.2"
1717
js-tokens "^3.0.0"
1818

19+
"@bam.tech/react-native-modalbox@^1.4.2":
20+
version "1.4.2"
21+
resolved "https://registry.yarnpkg.com/@bam.tech/react-native-modalbox/-/react-native-modalbox-1.4.2.tgz#85d130358354834bccb74f5a8d0384e8b5491e29"
22+
dependencies:
23+
create-react-class "^15.6.0"
24+
prop-types "^15.5.10"
25+
26+
"@bam.tech/react-native-root-siblings@^2.0.3":
27+
version "2.0.3"
28+
resolved "https://registry.yarnpkg.com/@bam.tech/react-native-root-siblings/-/react-native-root-siblings-2.0.3.tgz#ac1dee579874998b2796ad20f6648d7033320c5c"
29+
dependencies:
30+
fbemitter "^2.1.1"
31+
static-container "^1.0.0"
32+
1933
"@mrmlnc/readdir-enhanced@^2.2.1":
2034
version "2.2.1"
2135
resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
@@ -1811,7 +1825,7 @@ create-error-class@^3.0.0:
18111825
dependencies:
18121826
capture-stack-trace "^1.0.0"
18131827

1814-
create-react-class@^15.5.2:
1828+
create-react-class@^15.5.2, create-react-class@^15.6.0:
18151829
version "15.6.3"
18161830
resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.6.3.tgz#2d73237fb3f970ae6ebe011a9e66f46dbca80036"
18171831
dependencies:
@@ -2522,6 +2536,12 @@ fb-watchman@^2.0.0:
25222536
dependencies:
25232537
bser "^2.0.0"
25242538

2539+
fbemitter@^2.1.1:
2540+
version "2.1.1"
2541+
resolved "https://registry.yarnpkg.com/fbemitter/-/fbemitter-2.1.1.tgz#523e14fdaf5248805bb02f62efc33be703f51865"
2542+
dependencies:
2543+
fbjs "^0.8.4"
2544+
25252545
fbjs-scripts@^0.8.1:
25262546
version "0.8.1"
25272547
resolved "https://registry.yarnpkg.com/fbjs-scripts/-/fbjs-scripts-0.8.1.tgz#c1c6efbecb7f008478468976b783880c2f669765"
@@ -2535,7 +2555,7 @@ fbjs-scripts@^0.8.1:
25352555
semver "^5.1.0"
25362556
through2 "^2.0.0"
25372557

2538-
fbjs@^0.8.1, fbjs@^0.8.14, fbjs@^0.8.16, fbjs@^0.8.9:
2558+
fbjs@^0.8.1, fbjs@^0.8.14, fbjs@^0.8.16, fbjs@^0.8.4, fbjs@^0.8.9:
25392559
version "0.8.16"
25402560
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db"
25412561
dependencies:
@@ -5348,7 +5368,7 @@ promise@^7.1.1:
53485368
dependencies:
53495369
asap "~2.0.3"
53505370

5351-
prop-types@^15.5.8, prop-types@^15.6.0:
5371+
prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0:
53525372
version "15.6.1"
53535373
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.1.tgz#36644453564255ddda391191fb3a125cbdf654ca"
53545374
dependencies:
@@ -6342,6 +6362,10 @@ stacktrace-parser@^0.1.3:
63426362
version "0.1.4"
63436363
resolved "https://registry.yarnpkg.com/stacktrace-parser/-/stacktrace-parser-0.1.4.tgz#01397922e5f62ecf30845522c95c4fe1d25e7d4e"
63446364

6365+
static-container@^1.0.0:
6366+
version "1.2.0"
6367+
resolved "https://registry.yarnpkg.com/static-container/-/static-container-1.2.0.tgz#1c6e92b869da47d32abe47f45f50bf39661d9c2f"
6368+
63456369
static-extend@^0.1.1:
63466370
version "0.1.2"
63476371
resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"

0 commit comments

Comments
 (0)