Skip to content

Feat/picker use dialog 2 #2804

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
e2d9917
Picker support useDialog
adids1221 Aug 7, 2023
296b239
Merge branch 'master' into feat/Picker_useDialog
adids1221 Sep 6, 2023
eb5b26c
don't render status bar when useDialog passed
adids1221 Sep 6, 2023
cd519d7
wrapped the expandableOverly with ts-expect-error
adids1221 Sep 6, 2023
88a9a74
Merge branch 'master' into feat/Picker_useDialog
adids1221 Sep 13, 2023
7a3fa0a
Merge branch 'master' into feat/Picker_useDialog
adids1221 Sep 19, 2023
4bf7d54
PickerItemList flex is defined by useDialog prop
adids1221 Sep 21, 2023
401288b
Merge branch 'master' into feat/Picker_useDialog
adids1221 Sep 27, 2023
c70b954
flex fixes, ModalTopBar won't show up when useDialog is set to true
adids1221 Sep 27, 2023
f164096
fix for web
adids1221 Sep 28, 2023
8c3bd0d
Merge branch 'master' into feat/Picker_useDialog
adids1221 Oct 3, 2023
60eb6bc
Merge branch 'master' into feat/Picker_useDialog
ethanshar Nov 6, 2023
4c10972
Merge branch 'master' into feat/Picker_useDialog
ethanshar Nov 7, 2023
f92b364
Export Picker context and add done button for multi mode + useDialog
ethanshar Nov 13, 2023
7308ad2
Merge branch 'master' into feat/Picker_useDialog_2
ethanshar Nov 13, 2023
c9b3d62
Support passing custom render for the picker dialog header
ethanshar Nov 13, 2023
8d75d8d
Merge branch 'master' into feat/Picker_useDialog_2
ethanshar Nov 16, 2023
61c2050
Remove redundant useDialog prop
ethanshar Nov 19, 2023
e11af69
Fix issue with FlatList not being flexed correctly inside a dialog
ethanshar Nov 19, 2023
044e19a
Remove redundant line
ethanshar Nov 19, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion demo/src/screens/componentScreens/PickerScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const options = [
{label: 'C++', value: 'c++', disabled: true},
{label: 'Perl', value: 'perl'}
];

const filters = [
{label: 'All', value: 0},
{label: 'Draft', value: 1},
Expand All @@ -45,6 +46,16 @@ const schemes = [
{label: 'Dark', value: 3}
];

const dialogOptions = [
{label: 'Option 1', value: 0},
{label: 'Option 2', value: 1},
{label: 'Option 3', value: 2},
{label: 'Option 4', value: 3, disabled: true},
{label: 'Option 5', value: 4},
{label: 'Option 6', value: 5},
{label: 'Option 7', value: 6},
{label: 'Option 8', value: 6}
];
export default class PickerScreen extends Component {
picker = React.createRef<PickerMethods>();
state = {
Expand All @@ -53,7 +64,9 @@ export default class PickerScreen extends Component {
language: undefined,
language2: options[2].value,
languages: [],
option: undefined,
nativePickerValue: 'java',
dialogPickerValue: 'java',
customModalValues: [],
filter: filters[0].value,
scheme: schemes[0].value,
Expand Down Expand Up @@ -125,7 +138,6 @@ export default class PickerScreen extends Component {
label="Wheel Picker"
placeholder="Pick a Language"
useWheelPicker
// useWheelPicker
value={this.state.nativePickerValue}
onChange={nativePickerValue => this.setState({nativePickerValue})}
trailingAccessory={<Icon source={dropdown}/>}
Expand Down Expand Up @@ -164,6 +176,30 @@ export default class PickerScreen extends Component {
))}
</Picker>

<Picker
label="Dialog Picker"
placeholder="Favorite Language"
mode={Picker.modes.MULTI}
value={this.state.option}
enableModalBlur={false}
onChange={item => this.setState({option: item})}
topBarProps={{title: 'Languages'}}
useDialog
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure it's related to the PR, but passing useSafeArea does not work together with useDialog

  • It can be passed via customPickerProps.dialogProps

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix the flexness issue of the FlatList inside the dialog

renderCustomDialogHeader={({onDone, onCancel}) => (
<View padding-s5 row spread>
<Button link label="Cancel" onPress={onCancel}/>
<Button link label="Done" onPress={onDone}/>
</View>
)}
customPickerProps={{migrateDialog: true, dialogProps: {bottom: true, width: '100%', height: '45%'}}}
showSearch
searchPlaceholder={'Search a language'}
>
{_.map(dialogOptions, option => (
<Picker.Item key={option.value} value={option.value} label={option.label} disabled={option.disabled}/>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last items are not properly scrollable \ visible

))}
</Picker>

<Text marginB-10 text70 $textDefault>
Custom Picker:
</Text>
Expand Down
27 changes: 23 additions & 4 deletions src/components/picker/PickerItemsList.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import _ from 'lodash';
import React, {useCallback, useContext, useState} from 'react';
import React, {useCallback, useContext, useState, useMemo} from 'react';
import {StyleSheet, FlatList, TextInput, ListRenderItemInfo} from 'react-native';
import {Typography, Colors} from '../../style';
import Assets from '../../assets';
Expand All @@ -9,9 +9,10 @@ import Text from '../text';
import Icon from '../icon';
import Button from '../button';
import WheelPicker from '../WheelPicker';
import {PickerItemProps, PickerItemsListProps, PickerSingleValue} from './types';
import {PickerItemProps, PickerItemsListProps, PickerSingleValue, PickerModes} from './types';
import PickerContext from './PickerContext';
import PickerItem from './PickerItem';
import {Constants} from '../../commons/new';

const keyExtractor = (_item: string, index: number) => index.toString();

Expand All @@ -27,11 +28,21 @@ const PickerItemsList = (props: PickerItemsListProps) => {
searchPlaceholder = 'Search...',
onSearchChange,
renderCustomSearch,
renderCustomDialogHeader,
useSafeArea,
useDialog,
mode,
testID
} = props;
const context = useContext(PickerContext);
const [wheelPickerValue, setWheelPickerValue] = useState<PickerSingleValue>(context.value ?? items?.[0].value);
// TODO: Might not need this memoized style, instead we can move it to a stylesheet
const wrapperContainerStyle = useMemo(() => {
// const shouldFlex = Constants.isWeb ? 1 : useDialog ? 1 : 1;
const shouldFlex = true;
const style = {flex: shouldFlex ? 1 : 0, maxHeight: Constants.isWeb ? Constants.windowHeight * 0.75 : undefined};
Comment on lines +42 to +43
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const shouldFlex = true;
const style = {flex: shouldFlex ? 1 : 0, maxHeight: Constants.isWeb ? Constants.windowHeight * 0.75 : undefined};
const style = {flex: 1, maxHeight: Constants.isWeb ? Constants.windowHeight * 0.75 : undefined};

return style;
}, [/* useDialog */]);

const renderSearchInput = () => {
if (showSearch) {
Expand Down Expand Up @@ -135,11 +146,19 @@ const PickerItemsList = (props: PickerItemsListProps) => {
);
};

const renderPickerHeader = () => {
if (renderCustomDialogHeader) {
return renderCustomDialogHeader?.({onDone: topBarProps?.onDone, onCancel: topBarProps?.onCancel});
} else if (!useDialog || mode === PickerModes.MULTI) {
return <Modal.TopBar {...topBarProps}/>;
}
};

return (
<View bg-$backgroundDefault flex useSafeArea={useSafeArea}>
<View bg-$backgroundDefault style={wrapperContainerStyle} useSafeArea={useSafeArea}>
{!useWheelPicker && (
<>
{<Modal.TopBar {...topBarProps}/>}
{renderPickerHeader()}
{renderSearchInput()}
{renderList()}
</>
Expand Down
82 changes: 45 additions & 37 deletions src/components/picker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,10 @@ const Picker = React.forwardRef((props: PickerProps, ref) => {
searchStyle,
searchPlaceholder,
renderCustomSearch,
renderCustomDialogHeader,
// useNativePicker,
useWheelPicker,
useDialog,
renderPicker,
customPickerProps,
containerStyle,
Expand Down Expand Up @@ -218,6 +220,8 @@ const Picker = React.forwardRef((props: PickerProps, ref) => {
<PickerItemsList
testID={`${testID}.modal`}
useWheelPicker={useWheelPicker}
mode={mode}
useDialog={useDialog}
items={useItems ? items : undefined}
topBarProps={{
...topBarProps,
Expand All @@ -229,6 +233,7 @@ const Picker = React.forwardRef((props: PickerProps, ref) => {
searchPlaceholder={searchPlaceholder}
onSearchChange={_onSearchChange}
renderCustomSearch={renderCustomSearch}
renderCustomDialogHeader={renderCustomDialogHeader}
listProps={listProps}
useSafeArea={useSafeArea}
>
Expand All @@ -238,6 +243,7 @@ const Picker = React.forwardRef((props: PickerProps, ref) => {
}, [
testID,
mode,
useDialog,
selectedItemPosition,
topBarProps,
cancelSelect,
Expand All @@ -248,6 +254,7 @@ const Picker = React.forwardRef((props: PickerProps, ref) => {
searchPlaceholder,
_onSearchChange,
renderCustomSearch,
renderCustomDialogHeader,
listProps,
filteredChildren,
useSafeArea,
Expand Down Expand Up @@ -281,44 +288,45 @@ const Picker = React.forwardRef((props: PickerProps, ref) => {
// }

return (
//TODO : fix the ExpandableOverlay ts error
<PickerContext.Provider value={contextValue}>
<ExpandableOverlay
ref={pickerExpandable}
useDialog={useWheelPicker}
modalProps={modalProps}
dialogProps={DIALOG_PROPS}
expandableContent={expandableModalContent}
renderCustomOverlay={renderCustomModal ? _renderCustomModal : undefined}
onPress={onPress}
testID={testID}
{...customPickerProps}
disabled={themeProps.editable === false}
>
{renderPicker ? (
// @ts-expect-error - hopefully will be solved after the picker migration ends
renderPicker(value, label)
) : (
<TextField
// @ts-expect-error
ref={pickerRef}
// {...textInputProps}
{...others}
{...propsByFieldType}
testID={`${testID}.input`}
// @ts-expect-error
containerStyle={[containerStyle, propsByFieldType?.containerStyle]}
labelStyle={[propsByFieldType?.labelStyle, labelStyle]}
{...accessibilityInfo}
importantForAccessibility={'no-hide-descendants'}
value={label}
selection={Constants.isAndroid ? {start: 0} : undefined}
/* Note: Disable TextField expandable feature */
// topBarProps={undefined}
>
{renderPickerInnerInput()}
</TextField>
)}
</ExpandableOverlay>
{
/* @ts-expect-error */
<ExpandableOverlay
ref={pickerExpandable}
useDialog={useDialog || useWheelPicker}
modalProps={modalProps}
dialogProps={customPickerProps?.dialogProps || DIALOG_PROPS}
expandableContent={expandableModalContent}
renderCustomOverlay={renderCustomModal ? _renderCustomModal : undefined}
onPress={onPress}
testID={testID}
{...customPickerProps}
disabled={themeProps.editable === false}
>
{renderPicker ? (
// @ts-expect-error - hopefully will be solved after the picker migration ends
renderPicker(value, label)
) : (
<TextField
// @ts-expect-error
ref={pickerRef}
{...others}
{...propsByFieldType}
testID={`${testID}.input`}
// @ts-expect-error
containerStyle={[containerStyle, propsByFieldType?.containerStyle]}
labelStyle={[propsByFieldType?.labelStyle, labelStyle]}
{...accessibilityInfo}
importantForAccessibility={'no-hide-descendants'}
value={label}
selection={Constants.isAndroid ? {start: 0} : undefined}
>
{renderPickerInnerInput()}
</TextField>
)}
</ExpandableOverlay>
}
</PickerContext.Provider>
);
});
Expand Down
11 changes: 11 additions & 0 deletions src/components/picker/types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ export interface PickerSearchStyle {

export type PickerBaseProps = Omit<NewTextFieldProps, 'value' | 'onChange'> & {
/* ...TextField.propTypes, */
/**
* Use dialog instead of modal picker
*/
useDialog?: boolean;
/**
* Temporary prop required for migration to Picker's new API
*/
Expand Down Expand Up @@ -142,6 +146,10 @@ export type PickerBaseProps = Omit<NewTextFieldProps, 'value' | 'onChange'> & {
* Render custom search input (only when passing showSearch)
*/
renderCustomSearch?: (props: PickerItemsListProps) => React.ReactElement;
/**
* Render a custom header for Picker's dialog
*/
renderCustomDialogHeader?: (callbacks: {onDone?: () => void, onCancel?: ()=> void}) => React.ReactElement;
// /**
// * @deprecated pass useWheelPicker prop instead
// * Allow to use the native picker solution (different style for iOS and Android)
Expand Down Expand Up @@ -261,8 +269,11 @@ export type PickerItemsListProps = Pick<
| 'searchPlaceholder'
| 'onSearchChange'
| 'renderCustomSearch'
| 'renderCustomDialogHeader'
| 'useSafeArea'
| 'useWheelPicker'
| 'useDialog'
| 'mode'
| 'testID'
> & {
items?: {value: any; label: any}[];
Expand Down