Skip to content

Commit f96c37e

Browse files
authored
Expose new impertive methods on picker (#1988)
* Expose new impertive methods on picker to allow opening expandable picker modal * Remove redundant view * Extend types * Expose PickerMethods type
1 parent dd5b2e8 commit f96c37e

File tree

8 files changed

+71
-18
lines changed

8 files changed

+71
-18
lines changed

demo/src/screens/componentScreens/PickerScreen.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ import {
1313
PanningProvider,
1414
Typography,
1515
PickerProps,
16-
DialogProps
16+
PickerMethods,
17+
DialogProps,
18+
Button
1719
} from 'react-native-ui-lib'; //eslint-disable-line
1820
import contactsData from '../../data/conversations';
1921
import {longOptions} from './PickerScreenLongOptions';
@@ -38,6 +40,7 @@ const filters = [
3840
];
3941

4042
export default class PickerScreen extends Component {
43+
picker = React.createRef<PickerMethods>();
4144
state = {
4245
itemsCount: 1,
4346
// language: {value: 'java', label: 'Java'},
@@ -260,6 +263,8 @@ export default class PickerScreen extends Component {
260263

261264
<Picker
262265
migrate
266+
// @ts-expect-error
267+
ref={this.picker}
263268
migrateTextField
264269
label="Language"
265270
placeholder="Favorite Language"
@@ -270,13 +275,20 @@ export default class PickerScreen extends Component {
270275
searchPlaceholder={'Search a language'}
271276
searchStyle={{color: Colors.blue30, placeholderTextColor: Colors.grey50}}
272277
marginT-s4
278+
enableErrors={false}
273279
// mode={Picker.modes.MULTI}
274280
// useNativePicker
275281
>
276282
{_.map(options, option => (
277283
<Picker.Item key={option.value} value={option.value} label={option.label} disabled={option.disabled}/>
278284
))}
279285
</Picker>
286+
<Button
287+
label="Open Picker Manually"
288+
link
289+
style={{alignSelf: 'flex-start'}}
290+
onPress={() => this.picker.current?.openExpandable?.()}
291+
/>
280292
</View>
281293
</ScrollView>
282294
);
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import React, {useImperativeHandle, useRef} from 'react';
2+
import {ExpandableOverlayMethods} from '../../../incubator/expandableOverlay';
3+
import {TextFieldMethods} from '../../../incubator/TextField';
4+
5+
const useImperativePickerHandle = (ref: React.Ref<any>,
6+
expandableRef: React.MutableRefObject<ExpandableOverlayMethods | null>) => {
7+
const pickerRef = useRef<TextFieldMethods>();
8+
useImperativeHandle(ref, () => {
9+
// @ts-expect-error useRef return type is possible null therefor it throw TS error
10+
const {isFocused, focus, blur, clear, validate} = pickerRef.current;
11+
// @ts-expect-error useRef return type is possible null therefor it throw TS error
12+
const {openExpandable, closeExpandable, toggleExpandable} = expandableRef.current;
13+
14+
return {
15+
isFocused,
16+
focus,
17+
blur,
18+
clear,
19+
validate,
20+
openExpandable,
21+
closeExpandable,
22+
toggleExpandable
23+
};
24+
});
25+
26+
return pickerRef;
27+
};
28+
29+
export default useImperativePickerHandle;

src/components/picker/new.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
ForwardRefInjectedProps,
1515
BaseComponentInjectedProps
1616
} from '../../commons/new';
17-
import ExpandableOverlay, {ExpandableOverlayProps} from '../../incubator/expandableOverlay';
17+
import ExpandableOverlay, {ExpandableOverlayProps, ExpandableOverlayMethods} from '../../incubator/expandableOverlay';
1818
// @ts-expect-error
1919
import {TextField} from '../inputs';
2020
import TextFieldMigrator from '../textField/TextFieldMigrator';
@@ -26,8 +26,9 @@ import PickerContext from './PickerContext';
2626
import usePickerSelection from './helpers/usePickerSelection';
2727
import usePickerLabel from './helpers/usePickerLabel';
2828
import usePickerSearch from './helpers/usePickerSearch';
29+
import useImperativePickerHandle from './helpers/useImperativePickerHandle';
2930
import usePickerMigrationWarnings from './helpers/usePickerMigrationWarnings';
30-
import {PickerProps, PickerItemProps, PickerValue, PickerModes, PickerSearchStyle} from './types';
31+
import {PickerProps, PickerItemProps, PickerValue, PickerModes, PickerSearchStyle, PickerMethods} from './types';
3132

3233
const Picker = (props: PropsWithChildren<PickerProps> & ForwardRefInjectedProps & BaseComponentInjectedProps) => {
3334
const {
@@ -68,9 +69,11 @@ const Picker = (props: PropsWithChildren<PickerProps> & ForwardRefInjectedProps
6869
const [selectedItemPosition, setSelectedItemPosition] = useState(0);
6970
const [items] = useState(Picker.extractPickerItems(props));
7071

71-
const pickerExpandable = useRef<typeof ExpandableOverlay>();
72+
const pickerExpandable = useRef<ExpandableOverlayMethods>(null);
7273

7374
usePickerMigrationWarnings({value, mode});
75+
76+
const pickerRef = useImperativePickerHandle(forwardedRef, pickerExpandable);
7477
const {
7578
filteredChildren,
7679
setSearchValue,
@@ -199,7 +202,6 @@ const Picker = (props: PropsWithChildren<PickerProps> & ForwardRefInjectedProps
199202
return (
200203
<PickerContext.Provider value={contextValue}>
201204
<ExpandableOverlay
202-
// @ts-expect-error
203205
ref={pickerExpandable}
204206
modalProps={modalProps}
205207
expandableContent={expandableModalContent}
@@ -216,7 +218,7 @@ const Picker = (props: PropsWithChildren<PickerProps> & ForwardRefInjectedProps
216218
<TextFieldMigrator
217219
migrate={migrateTextField}
218220
customWarning="RNUILib Picker component's internal TextField will soon be replaced with a new implementation, in order to start the migration - please pass to Picker the 'migrateTextField' prop"
219-
ref={forwardedRef}
221+
ref={pickerRef}
220222
// {...textInputProps}
221223
{...others}
222224
testID={`${testID}.input`}
@@ -251,6 +253,6 @@ Picker.extractPickerItems = (props: PropsWithChildren<PickerProps>) => {
251253
return items;
252254
};
253255

254-
export {PickerProps, PickerItemProps, PickerValue, PickerModes, PickerSearchStyle};
256+
export {PickerProps, PickerItemProps, PickerValue, PickerModes, PickerSearchStyle, PickerMethods};
255257
export {Picker}; // For tests
256258
export default asBaseComponent<PickerProps, typeof Picker>(forwardRef(Picker));

src/components/picker/types.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import React, {PropsWithChildren, ReactNode} from 'react';
22
import {FlatListProps, StyleProp, ViewStyle, TextStyle} from 'react-native';
3-
import {ExpandableOverlayProps} from '../../incubator/expandableOverlay';
3+
import {ExpandableOverlayProps, ExpandableOverlayMethods} from '../../incubator/expandableOverlay';
44
import {ModalTopBarProps} from '../modal/TopBar';
55
// TODO: Replace with new TextField Props after migration to new TextField has completed
66
import {TextFieldProps} from '../../../typings/components/Inputs';
7+
import {TextFieldMethods} from '../../incubator/TextField';
78

89
// Note: enum values are uppercase due to legacy
910
export enum PickerModes {
@@ -248,3 +249,5 @@ export type PickerItemsListProps = Pick<
248249
| 'useSafeArea'
249250
| 'testID'
250251
>;
252+
253+
export type PickerMethods = TextFieldMethods & ExpandableOverlayMethods;

src/incubator/TextField/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {asBaseComponent, forwardRef} from '../../commons/new';
1111
import View from '../../components/view';
1212
import {Colors} from '../../style';
1313
import {useMeasure} from '../../hooks';
14-
import {TextFieldProps, InternalTextFieldProps, ValidationMessagePosition, FieldContextType} from './types';
14+
import {TextFieldProps, InternalTextFieldProps, ValidationMessagePosition, FieldContextType, TextFieldMethods} from './types';
1515
import {shouldHidePlaceholder} from './Presenter';
1616
import Input from './Input';
1717
import ValidationMessage from './ValidationMessage';
@@ -170,5 +170,5 @@ const TextField = (props: InternalTextFieldProps) => {
170170
TextField.displayName = 'Incubator.TextField';
171171
TextField.validationMessagePositions = ValidationMessagePosition;
172172

173-
export {TextFieldProps, FieldContextType, StaticMembers as TextFieldStaticMembers};
173+
export {TextFieldProps, FieldContextType, StaticMembers as TextFieldStaticMembers, TextFieldMethods};
174174
export default asBaseComponent<TextFieldProps, StaticMembers>(forwardRef(TextField as any));

src/incubator/TextField/types.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,3 +227,11 @@ export type FieldContextType = {
227227
disabled: boolean;
228228
validateField: () => void;
229229
};
230+
231+
export interface TextFieldMethods {
232+
isFocused: () => void;
233+
focus: () => void;
234+
blur: () => void;
235+
clear: () => void;
236+
validate: () => boolean;
237+
}

src/incubator/expandableOverlay/index.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@ import View from '../../components/view';
55
import Modal, {ModalProps, ModalTopBarProps} from '../../components/modal';
66
import Dialog, {DialogProps} from '../../components/dialog';
77

8-
export interface RenderCustomOverlayProps {
9-
visible: boolean;
8+
export interface ExpandableOverlayMethods {
109
openExpandable: () => void;
1110
closeExpandable: () => void;
1211
toggleExpandable: () => void;
1312
}
1413

14+
export interface RenderCustomOverlayProps extends ExpandableOverlayMethods {
15+
visible: boolean;
16+
}
17+
1518
export type ExpandableOverlayProps = TouchableOpacityProps &
1619
PropsWithChildren<{
1720
/**
@@ -48,11 +51,6 @@ export type ExpandableOverlayProps = TouchableOpacityProps &
4851
disabled?: boolean;
4952
}>;
5053

51-
interface ExpandableOverlayMethods {
52-
openExpandable: () => void;
53-
closeExpandable: () => void;
54-
}
55-
5654
const ExpandableOverlay = (props: ExpandableOverlayProps, ref: any) => {
5755
const {
5856
children,

src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,8 @@ export {
114114
PickerItemProps,
115115
PickerValue,
116116
PickerModes,
117-
PickerSearchStyle
117+
PickerSearchStyle,
118+
PickerMethods
118119
} from './components/picker/new';
119120
export {default as ProgressBar, ProgressBarProps} from './components/progressBar';
120121
export {default as RadioButton, RadioButtonProps} from './components/radioButton';

0 commit comments

Comments
 (0)