Skip to content

Commit

Permalink
feat: add scroll to the selected option (#25)
Browse files Browse the repository at this point in the history
* feat: selected option on the top

* feat: add scrollToSelectedOption prop; add example

* feat: add dynamically height value

* fix: docs
  • Loading branch information
irekrog authored Nov 30, 2021
1 parent 226c94f commit d145768
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 7 deletions.
4 changes: 4 additions & 0 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { ModalExample } from './examples/ModalExample';
import { Overflow } from './examples/Overflow';
import { Ref } from './examples/Ref';
import { RHF } from './examples/RHF';
import { ScrollToSelectedOption } from './examples/ScrollToSelectedOption';
import { Selects } from './examples/Selects';

export const DATA = [
Expand Down Expand Up @@ -50,6 +51,7 @@ const examples = [
'Ref',
'Callbacks',
'Custom Component',
'Scroll To Selected Option',
];

export default function App() {
Expand Down Expand Up @@ -84,6 +86,8 @@ export default function App() {
return <Callbacks />;
case 'Custom Component':
return <CustomComponent />;
case 'Scroll To Selected Option':
return <ScrollToSelectedOption />;
default:
return null;
}
Expand Down
2 changes: 1 addition & 1 deletion example/src/examples/CustomStyles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const CustomStyles = () => {
<SafeAreaView style={{ margin: 20, marginTop: 500 }}>
<Select
optionSelectedStyle={{ backgroundColor: 'lightgreen' }}
optionStyle={{ backgroundColor: 'lightcoral', borderBottomWidth: 1 }}
optionStyle={{ backgroundColor: 'lightcoral', borderBottomWidth: 1, height: 40 }}
optionTextStyle={{ fontSize: 20 }}
options={DATA}
optionsListStyle={{ maxHeight: 150 }}
Expand Down
30 changes: 30 additions & 0 deletions example/src/examples/ScrollToSelectedOption.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import { SafeAreaView, Text } from 'react-native';
import { Select } from '@mobile-reality/react-native-select-pro';

import { DATA } from '../App';

export const ScrollToSelectedOption = () => {
return (
<SafeAreaView>
<Text>Scroll to selected option</Text>
<Select options={DATA} selectControlStyle={{ width: 150 }} />
<Text>Scroll to selected option with default option</Text>
<Select defaultOption={DATA[4]} options={DATA} selectControlStyle={{ width: 150 }} />
<Text>Scroll to selected option is disabled</Text>
<Select
options={DATA}
scrollToSelectedOption={false}
selectControlStyle={{ width: 150 }}
/>
<Text>Scroll to selected option with changed height of the option</Text>
<Select
optionStyle={{
height: 60,
}}
options={DATA}
selectControlStyle={{ width: 150 }}
/>
</SafeAreaView>
);
};
6 changes: 4 additions & 2 deletions src/components/option/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { ComponentProps } from 'react';
import { StyleSheet, Text, TextStyle, TouchableOpacity, ViewStyle } from 'react-native';

import { COLORS, FONT_SIZE, PADDING } from '../../constants/styles';
import { COLORS, FONT_SIZE, ITEM_HEIGHT, PADDING } from '../../constants/styles';
import type { OptionalToRequired } from '../../helpers';
import type { OptionType } from '../../index';
import type { OptionsList } from '../options-list';
Expand Down Expand Up @@ -76,7 +76,9 @@ type Styles = {

const styles = StyleSheet.create<Styles>({
option: {
padding: PADDING,
height: ITEM_HEIGHT,
justifyContent: 'center',
paddingHorizontal: PADDING,
},
text: {
fontSize: FONT_SIZE,
Expand Down
32 changes: 28 additions & 4 deletions src/components/options-list/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React, { ComponentProps } from 'react';
import React, { ComponentProps, useRef } from 'react';
import { FlatList, StyleSheet, TouchableWithoutFeedback, View, ViewStyle } from 'react-native';
import { Portal } from '@gorhom/portal';

import { Portals } from '../../constants/portals';
import { BORDER_WIDTH, COLORS, MAX_HEIGHT_LIST, SHAPE } from '../../constants/styles';
import { BORDER_WIDTH, COLORS, ITEM_HEIGHT, MAX_HEIGHT_LIST, SHAPE } from '../../constants/styles';
import type { OptionalToRequired } from '../../helpers';
import type { Position, State } from '../../state/types';
import type { OnOutsidePress, OnPressOptionType } from '../../types';
Expand All @@ -17,6 +17,7 @@ type FromSelectComponentProps = Pick<
| 'optionSelectedStyle'
| 'optionStyle'
| 'optionTextStyle'
| 'scrollToSelectedOption'
| 'noOptionsText'
| 'onSelect'
| 'optionsListStyle'
Expand Down Expand Up @@ -45,11 +46,13 @@ export const OptionsList = ({
optionStyle,
optionTextStyle,
noOptionsText,
scrollToSelectedOption,
onSelect,
optionsListStyle,
NoOptionsComponent,
OptionComponent,
}: OptionsListProps) => {
const ref = useRef<FlatList>(null);
return (
<>
{isOpened && (
Expand All @@ -73,15 +76,36 @@ export const OptionsList = ({
accessibilityLabel={'Options list'}
bounces={false}
data={optionsData}
getItemLayout={(_data, index) => {
const height = StyleSheet.flatten(optionStyle)?.height;
const isNumber = typeof height === 'number';
return {
length: isNumber ? height : ITEM_HEIGHT,
offset: isNumber ? height * index : ITEM_HEIGHT * index,
index,
};
}}
keyExtractor={({ value }) => value}
keyboardShouldPersistTaps="handled"
persistentScrollbar={true}
renderItem={({ item }) => {
ref={ref}
renderItem={({ item, index }) => {
const { value } = item;
const isSelected = value === selectedOption?.value;
const isScrollToSelectedOption =
isSelected && ref.current && scrollToSelectedOption;

if (isScrollToSelectedOption) {
ref.current.scrollToIndex({
index,
animated: false,
});
}

return (
<Option
OptionComponent={OptionComponent}
isSelected={value === selectedOption?.value}
isSelected={isSelected}
key={value}
onPressOption={onPressOption}
onSelect={onSelect}
Expand Down
2 changes: 2 additions & 0 deletions src/components/select/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export const Select = forwardRef((props: SelectProps, ref: ForwardedRef<SelectRe
optionStyle,
optionTextStyle,
placeholderText = 'Select...',
scrollToSelectedOption = true,
selectContainerStyle,
selectControlButtonsContainerStyle,
selectControlClearOptionButtonStyle,
Expand Down Expand Up @@ -201,6 +202,7 @@ export const Select = forwardRef((props: SelectProps, ref: ForwardedRef<SelectRe
optionTextStyle={optionTextStyle}
optionsData={optionsData}
optionsListStyle={optionsListStyle}
scrollToSelectedOption={scrollToSelectedOption}
selectedOption={selectedOption}
/>
</View>
Expand Down
1 change: 1 addition & 0 deletions src/constants/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export const FONT_SIZE = 12;
export const BORDER_WIDTH = 1;
export const PADDING = 12;
export const MAX_HEIGHT_LIST = 120;
export const ITEM_HEIGHT = 40;

export const COLORS = {
WHITE: '#ffffff',
Expand Down
7 changes: 7 additions & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,13 @@ export interface SelectProps {
* @default "Select..."
*/
placeholderText?: string;
/**
* If `true` options list is scrolled to the selected option
*
* @category Common
* @default true
*/
scrollToSelectedOption?: boolean;
/**
* No options text
*
Expand Down

0 comments on commit d145768

Please sign in to comment.