Skip to content

Commit c47ff67

Browse files
authored
Migrate Picker implementation to TS and use Function component (#1870)
* Migrate Picker implementation to TS and use Function component * Move picker business logic to hooks * Convert PickerItem to TS * Convert Picker context and presenter to TS * Fix TS errors * Rename PickerModal to PickerItemsList * Refactor PickerItemsList to a function componet * Add typings exports and comment redudant tests * Use memo for Picker Item label style * Remove resolved TODO * Remove old comments * Remove old comment * Remove old PICKER_MODES const * Remove comments * Update generatedTypes
1 parent f1b1c70 commit c47ff67

28 files changed

+1121
-265
lines changed

generatedTypes/index.d.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export {default as ColorPalette, ColorPaletteProps} from './src/components/color
4444
export {default as ColorSwatch, ColorSwatchProps} from './src/components/colorPicker/ColorSwatch';
4545
export {default as DateTimePicker, DateTimePickerProps} from './src/components/dateTimePicker';
4646
export {default as Drawer, DrawerProps, DrawerItemProps} from './src/components/drawer';
47+
export {default as Picker, PickerProps, PickerValue, PickerModes, PickerSearchStyle} from './src/components/picker/new';
4748
export {default as ProgressBar, ProgressBarProps} from './src/components/progressBar';
4849
export {default as FeatureHighlight, FeatureHighlightProps} from './src/components/featureHighlight';
4950
export {default as FloatingButton, FloatingButtonProps} from './src/components/floatingButton';
@@ -103,10 +104,7 @@ export {
103104
PureBaseComponent,
104105
UIComponent,
105106
forwardRef,
106-
AvatarHelper,
107-
Picker,
108-
PickerItemValue,
109-
PickerProps
107+
AvatarHelper
110108
} from '../typings';
111109

112110
/* All components that are missing either manual or auto generated typings */
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import React from 'react';
2+
import { PickerContextProps } from './types';
3+
declare const _default: React.Context<PickerContextProps>;
4+
export default _default;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/// <reference types="react" />
2+
import { PickerItemProps } from './types';
3+
/**
4+
* @description: Picker.Item, for configuring the Picker's selectable options
5+
* @example: https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/componentScreens/PickerScreen.js
6+
*/
7+
declare const PickerItem: {
8+
(props: PickerItemProps): JSX.Element;
9+
displayName: string;
10+
};
11+
export default PickerItem;
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/// <reference types="react" />
2+
import { PickerItemsListProps } from './types';
3+
declare const PickerItemsList: (props: PickerItemsListProps) => JSX.Element;
4+
export default PickerItemsList;
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { PickerProps, PickerSingleValue, PickerValue } from './types';
2+
export declare function isItemSelected(childValue: PickerSingleValue, selectedValue?: PickerValue): boolean;
3+
export declare function getItemLabel(label: string, value: PickerValue, getItemLabel: PickerProps['getItemLabel']): any;
4+
export declare function shouldFilterOut(searchValue: string, itemLabel: string): boolean;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { PickerProps, PickerValue } from '../types';
2+
interface UsePickerLabelProps extends Pick<PickerProps, 'value' | 'getLabel' | 'getItemLabel' | 'placeholder'> {
3+
items: {
4+
value: string | number;
5+
label: string;
6+
}[] | null | undefined;
7+
}
8+
declare const usePickerLabel: (props: UsePickerLabelProps) => {
9+
getLabelsFromArray: (value: PickerValue) => string;
10+
getLabel: (value: PickerValue) => string | undefined;
11+
accessibilityInfo: {
12+
accessibilityLabel: string;
13+
accessibilityHint: string;
14+
};
15+
label: string | undefined;
16+
};
17+
export default usePickerLabel;
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { PickerProps } from '../types';
2+
declare type UsePickerMigrationWarnings = Pick<PickerProps, 'value' | 'mode'>;
3+
declare const usePickerMigrationWarnings: (props: UsePickerMigrationWarnings) => void;
4+
export default usePickerMigrationWarnings;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/// <reference types="react" />
2+
import { PickerProps } from '../types';
3+
declare type UsePickerSearchProps = Pick<PickerProps, 'showSearch' | 'onSearchChange' | 'children' | 'getItemLabel'>;
4+
declare const usePickerSearch: (props: UsePickerSearchProps) => {
5+
setSearchValue: import("react").Dispatch<import("react").SetStateAction<string>>;
6+
onSearchChange: (searchValue: string) => void;
7+
filteredChildren: import("react").ReactNode;
8+
};
9+
export default usePickerSearch;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { RefObject } from 'react';
2+
import { PickerProps, PickerValue, PickerSingleValue, PickerMultiValue } from '../types';
3+
interface UsePickerSelectionProps extends Pick<PickerProps, 'migrate' | 'value' | 'onChange' | 'getItemValue' | 'topBarProps'> {
4+
pickerExpandableRef: RefObject<any>;
5+
setSearchValue: (searchValue: string) => void;
6+
}
7+
declare const usePickerSelection: (props: UsePickerSelectionProps) => {
8+
multiDraftValue: PickerMultiValue;
9+
onDoneSelecting: (item: PickerValue) => void;
10+
toggleItemSelection: (item: PickerSingleValue) => void;
11+
cancelSelect: () => void;
12+
};
13+
export default usePickerSelection;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import React, { PropsWithChildren } from 'react';
2+
import { ForwardRefInjectedProps, BaseComponentInjectedProps } from '../../commons/new';
3+
import { PickerProps, PickerValue, PickerModes, PickerSearchStyle } from './types';
4+
declare const Picker: {
5+
(props: PropsWithChildren<PickerProps> & ForwardRefInjectedProps & BaseComponentInjectedProps): JSX.Element;
6+
Item: {
7+
(props: import("./types").PickerItemProps): JSX.Element;
8+
displayName: string;
9+
};
10+
defaultProps: any;
11+
modes: {
12+
SINGLE: string;
13+
MULTI: string;
14+
};
15+
extractPickerItems(props: PropsWithChildren<PickerProps>): {
16+
value: any;
17+
label: any;
18+
}[] | null | undefined;
19+
};
20+
export { PickerProps, PickerValue, PickerModes, PickerSearchStyle };
21+
export { Picker };
22+
declare const _default: React.ComponentClass<{
23+
useCustomTheme?: boolean | undefined;
24+
}, any>;
25+
export default _default;
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
import React, { PropsWithChildren } from 'react';
2+
import { FlatListProps, StyleProp, ViewStyle, TextInputProps, TextStyle } from 'react-native';
3+
import { ExpandableOverlayProps } from '../../incubator/expandableOverlay';
4+
import { ModalTopBarProps } from '../modal/TopBar';
5+
export declare enum PickerModes {
6+
SINGLE = "SINGLE",
7+
MULTI = "MULTI"
8+
}
9+
declare type PickerValueDeprecated = {
10+
value: string | number;
11+
label: string;
12+
};
13+
export declare type PickerSingleValue = string | number | PickerValueDeprecated;
14+
export declare type PickerMultiValue = PickerSingleValue[];
15+
export declare type PickerValue = PickerSingleValue | PickerMultiValue;
16+
export interface PickerSearchStyle {
17+
icon?: number;
18+
color?: string;
19+
placeholderTextColor?: string;
20+
selectionColor?: string;
21+
}
22+
export interface PickerBaseProps extends Omit<TextInputProps, 'value' | 'onChange'> {
23+
/**
24+
* Temporary prop required for migration to Picker's new API
25+
*/
26+
migrate?: boolean;
27+
/**
28+
* Temporary prop required for inner text field migration
29+
*/
30+
migrateTextField?: boolean;
31+
/**
32+
* Picker current value in the shape of {value: ..., label: ...}, for custom shape use 'getItemValue' prop
33+
*/
34+
value?: PickerValue;
35+
/**
36+
* Callback for when picker value change
37+
*/
38+
onChange?: (value: PickerValue) => void;
39+
/**
40+
* SINGLE mode or MULTI mode
41+
*/
42+
mode?: PickerModes;
43+
/**
44+
* Limit the number of selected items
45+
*/
46+
selectionLimit?: number;
47+
/**
48+
* Adds blur effect to picker modal (iOS only)
49+
*/
50+
enableModalBlur?: boolean;
51+
/**
52+
* Render custom picker - input will be value (see above)
53+
* Example:
54+
* renderPicker = (selectedItem) => {...}
55+
*/
56+
renderPicker?: (value?: PickerValue, label?: string) => React.ReactElement;
57+
/**
58+
* Render custom picker item
59+
*/
60+
renderItem?: (value: PickerValue, itemProps: PickerItemProps & {
61+
isSelected: boolean;
62+
}, label: string) => React.ReactElement;
63+
/**
64+
* Render custom picker modal (e.g ({visible, children, toggleModal}) => {...})
65+
*/
66+
renderCustomModal?: (modalProps: ExpandableOverlayProps['modalProps']) => React.ReactElement;
67+
/**
68+
* Custom picker props (when using renderPicker, will apply on the button wrapper)
69+
*/
70+
customPickerProps?: ExpandableOverlayProps;
71+
/**
72+
* Add onPress callback for when pressing the picker
73+
*/
74+
onPress?: () => void;
75+
/**
76+
* @deprecated
77+
* A function that extract the unique value out of the value prop in case value has a custom structure (e.g. {myValue, myLabel})
78+
*/
79+
getItemValue?: (value: PickerValue) => any;
80+
/**
81+
* @deprecated
82+
* A function that extract the label out of the value prop in case value has a custom structure (e.g. {myValue, myLabel})
83+
*/
84+
getItemLabel?: (value: PickerValue) => string;
85+
/**
86+
* A function that returns the label to show for the selected Picker value
87+
*/
88+
getLabel?: (value: PickerValue) => string;
89+
/**
90+
* The picker modal top bar props
91+
*/
92+
topBarProps?: ModalTopBarProps;
93+
/**
94+
* Show search input to filter picker items by label
95+
*/
96+
showSearch?: boolean;
97+
/**
98+
* Style object for the search input (only when passing showSearch)
99+
*/
100+
searchStyle?: PickerSearchStyle;
101+
/**
102+
* Placeholder text for the search input (only when passing showSearch)
103+
*/
104+
searchPlaceholder?: string;
105+
/**
106+
* callback for picker modal search input text change (only when passing showSearch)
107+
*/
108+
onSearchChange?: (searchValue: string) => void;
109+
/**
110+
* Render custom search input (only when passing showSearch)
111+
*/
112+
renderCustomSearch?: (props: PickerItemsListProps) => React.ReactElement;
113+
/**
114+
* Allow to use the native picker solution (different style for iOS and Android)
115+
*/
116+
useNativePicker?: boolean;
117+
/**
118+
* Callback for rendering a custom native picker inside the dialog (relevant to native picker only)
119+
*/
120+
renderNativePicker?: () => React.ReactElement;
121+
/**
122+
* Pass props to the list component that wraps the picker options (allows to control FlatList behavior)
123+
*/
124+
listProps?: FlatListProps<any>;
125+
/**
126+
* Pass props to the picker modal
127+
*/
128+
pickerModalProps?: object;
129+
/**
130+
* Custom container style
131+
*/
132+
containerStyle?: StyleProp<ViewStyle>;
133+
/**
134+
* Callback for modal onShow event
135+
*/
136+
onShow?: () => void;
137+
/**
138+
* Component test id
139+
*/
140+
testID?: string;
141+
}
142+
export interface PickerPropsWithSingle extends PickerBaseProps {
143+
mode: PickerModes.SINGLE;
144+
value: PickerSingleValue;
145+
}
146+
export interface PickerPropsWithMulti extends PickerBaseProps {
147+
mode: PickerModes.MULTI;
148+
value: PickerMultiValue;
149+
}
150+
export declare type PickerProps = PickerPropsWithSingle | PickerPropsWithMulti;
151+
export interface PickerItemProps {
152+
/**
153+
* Item's value
154+
*/
155+
value: PickerSingleValue;
156+
/**
157+
* Item's label
158+
*/
159+
label: string;
160+
/**
161+
* Item's label style
162+
*/
163+
labelStyle?: StyleProp<TextStyle>;
164+
/**
165+
* Custom function for the item label (e.g (value) => customLabel)
166+
*/
167+
getItemLabel: PickerProps['getItemLabel'];
168+
/**
169+
* @deprecated Function to return the value out of the item value prop when value is custom shaped.
170+
*/
171+
getItemValue: PickerProps['getItemValue'];
172+
/**
173+
* Render custom item
174+
*/
175+
renderItem?: PickerProps['renderItem'];
176+
/**
177+
* Pass to change the selected icon
178+
*/
179+
selectedIcon?: number;
180+
/**
181+
* Pass to change the selected icon color
182+
*/
183+
selectedIconColor?: string;
184+
/**
185+
* Is the item disabled
186+
*/
187+
disabled?: boolean;
188+
/**
189+
* Callback for onPress action
190+
*/
191+
onPress: () => void;
192+
/**
193+
* Component test id
194+
*/
195+
testID?: string;
196+
}
197+
export interface PickerContextProps extends Pick<PickerProps, 'migrate' | 'value' | 'getItemValue' | 'getItemLabel' | 'renderItem' | 'selectionLimit'> {
198+
onPress: (value: PickerSingleValue) => void;
199+
isMultiMode: boolean;
200+
onSelectedLayout: (event: any) => any;
201+
selectionLimit: PickerProps['selectionLimit'];
202+
}
203+
export declare type PickerItemsListProps = Pick<PropsWithChildren<PickerProps>, 'topBarProps' | 'listProps' | 'children' | 'showSearch' | 'searchStyle' | 'searchPlaceholder' | 'onSearchChange' | 'renderCustomSearch' | 'testID'>;
204+
export {};

src/components/picker/PickerContext.js

Lines changed: 0 additions & 3 deletions
This file was deleted.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import React from 'react';
2+
import {PickerContextProps} from './types';
3+
4+
// @ts-expect-error
5+
export default React.createContext<PickerContextProps>({});

0 commit comments

Comments
 (0)