diff --git a/README.md b/README.md
index aff68802..a60397e2 100644
--- a/README.md
+++ b/README.md
@@ -6,6 +6,8 @@
+The example in the screenshots: https://snack.expo.dev/8mHmLfcZf
+
# Documentation
**The documentation has been moved to https://hossein-zare.github.io/react-native-dropdown-picker-website/**
diff --git a/index.d.ts b/index.d.ts
index 7b648984..9beba118 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -1,5 +1,5 @@
declare module 'react-native-dropdown-picker' {
- import type { ComponentType, SetStateAction, Dispatch } from 'react';
+ import type { Dispatch, PropsWithoutRef } from 'react';
import type {
FlatListProps,
LayoutChangeEvent,
@@ -14,13 +14,16 @@ declare module 'react-native-dropdown-picker' {
ViewStyle,
} from 'react-native';
+ type SetStateCallback = ((prevState: S) => S);
+ type SetStateValue = ((prevState: S) => S);
+
export type ValueType = string | number | boolean;
- export type ItemType = {
+ export type ItemType = {
label?: string;
- value?: ValueType;
+ value?: T;
icon?: () => void;
- parent?: ValueType;
+ parent?: T;
selectable?: boolean;
disabled?: boolean;
testID?: string;
@@ -65,18 +68,23 @@ declare module 'react-native-dropdown-picker' {
| 'FA'
| 'TR'
| 'RU'
- | 'ES';
+ | 'ES'
+ | 'ID'
+ | 'IT';
export interface TranslationInterface {
PLACEHOLDER: string;
SEARCH_PLACEHOLDER: string;
- SELECTED_ITEMS_COUNT_TEXT: string;
+ SELECTED_ITEMS_COUNT_TEXT: string | {
+ [key in (number | "n")]: string;
+ };
NOTHING_TO_SHOW: string;
}
- export interface RenderBadgeItemPropsInterface {
+ export interface RenderBadgeItemPropsInterface {
label: string;
- value: ValueType;
+ value: T;
+ props: TouchableOpacityProps;
IconComponent: () => JSX.Element;
textStyle: StyleProp;
badgeStyle: StyleProp;
@@ -85,17 +93,17 @@ declare module 'react-native-dropdown-picker' {
getBadgeColor: (value: string) => string;
getBadgeDotColor: (value: string) => string;
showBadgeDot: boolean;
- onPress: (value: ValueType) => void;
+ onPress: (value: T) => void;
rtl: boolean;
THEME: ThemeType;
}
- export interface RenderListItemPropsInterface {
+ export interface RenderListItemPropsInterface {
rtl: boolean;
- item: ItemType;
+ item: ItemType;
label: string;
- value: ValueType;
- parent: ValueType;
+ value: T;
+ parent: T;
selectable: boolean;
disabled: boolean;
props: ViewProps;
@@ -118,8 +126,8 @@ declare module 'react-native-dropdown-picker' {
containerStyle: StyleProp;
labelStyle: StyleProp;
categorySelectable: boolean;
- onPress: () => void;
- setPosition: (value: ValueType, y: number) => void;
+ onPress: (value: T) => void;
+ setPosition: (value: T, y: number) => void;
theme: ThemeNameType;
THEME: ThemeType;
}
@@ -143,8 +151,8 @@ declare module 'react-native-dropdown-picker' {
export type ThemeNameType = 'DEFAULT' | 'LIGHT' | 'DARK';
export type ThemeType = object;
- interface DropDownPickerBaseProps {
- items: ItemType[];
+ interface DropDownPickerBaseProps {
+ items: ItemType[];
open: boolean;
placeholder?: string;
closeAfterSelecting?: boolean;
@@ -198,8 +206,8 @@ declare module 'react-native-dropdown-picker' {
mode?: ModeType;
itemKey?: string;
maxHeight?: number;
- renderBadgeItem?: (props: RenderBadgeItemPropsInterface) => JSX.Element;
- renderListItem?: (props: RenderListItemPropsInterface) => JSX.Element;
+ renderBadgeItem?: (props: RenderBadgeItemPropsInterface) => JSX.Element;
+ renderListItem?: (props: RenderListItemPropsInterface) => JSX.Element;
itemSeparator?: boolean;
bottomOffset?: number;
badgeColors?: string[] | string;
@@ -229,8 +237,9 @@ declare module 'react-native-dropdown-picker' {
activityIndicatorColor?: string;
props?: TouchableOpacityProps;
itemProps?: TouchableOpacityProps;
+ badgeProps?: TouchableOpacityProps;
modalProps?: ModalProps;
- flatListProps?: Partial>;
+ flatListProps?: Partial>>;
scrollViewProps?: ScrollViewProps;
searchTextInputProps?: TextInputProps;
modalTitle?: string;
@@ -239,8 +248,8 @@ declare module 'react-native-dropdown-picker' {
min?: number;
max?: number;
addCustomItem?: boolean;
- setOpen: Dispatch>;
- setItems?: Dispatch>;
+ setOpen: Dispatch>;
+ setItems?: Dispatch>;
disableBorderRadius?: boolean;
containerProps?: ViewProps;
onLayout?: (e: LayoutChangeEvent) => void;
@@ -248,6 +257,7 @@ declare module 'react-native-dropdown-picker' {
onOpen?: () => void;
onClose?: () => void;
onChangeSearchText?: (text: string) => void;
+ onDirectionChanged?: (direction: DropDownDirectionType) => void;
zIndex?: number;
zIndexInverse?: number;
disableLocalSearch?: boolean;
@@ -256,22 +266,24 @@ declare module 'react-native-dropdown-picker' {
rtl?: boolean;
testID?: string;
closeOnBackPressed?: boolean;
+ hideSelectedItemIcon?: boolean;
+ extendableBadgeContainer?: boolean;
}
- interface DropDownPickerSingleProps {
+ interface DropDownPickerSingleProps {
multiple?: false;
- onChangeValue?: (value: ValueType | null) => void;
- onSelectItem?: (item: ItemType) => void;
- setValue: Dispatch>;
- value: ValueType | null;
+ onChangeValue?: (value: T | null) => void;
+ onSelectItem?: (item: ItemType) => void;
+ setValue: Dispatch>;
+ value: T | null;
}
- interface DropDownPickerMultipleProps {
+ interface DropDownPickerMultipleProps {
multiple: true;
- onChangeValue?: (value: ValueType[] | null) => void;
- onSelectItem?: (items: ItemType[]) => void;
- setValue: Dispatch>;
- value: ValueType[] | null;
+ onChangeValue?: (value: T[] | null) => void;
+ onSelectItem?: (items: ItemType[]) => void;
+ setValue: Dispatch>;
+ value: T[] | null;
}
interface DropDownPickerInterface {
@@ -297,13 +309,16 @@ declare module 'react-native-dropdown-picker' {
) => void;
}
- export type DropDownPickerProps = (
- | DropDownPickerSingleProps
- | DropDownPickerMultipleProps
+ export type DropDownPickerProps = (
+ | DropDownPickerSingleProps
+ | DropDownPickerMultipleProps
) &
- DropDownPickerBaseProps;
+ DropDownPickerBaseProps;
- const DropDownPicker: ComponentType &
+ const DropDownPicker: ((
+ props: PropsWithoutRef>,
+ ) => React.ReactElement) &
DropDownPickerInterface;
+
export default DropDownPicker;
}
diff --git a/package.json b/package.json
index 1846f418..a03b8238 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "react-native-dropdown-picker",
- "version": "5.3.0",
+ "version": "5.4.0",
"description": "A single / multiple, categorizable, customizable, localizable and searchable item picker (drop-down) component for react native which supports both Android & iOS.",
"keywords": [
"picker",
diff --git a/src/components/Picker.js b/src/components/Picker.js
index a154d882..6ddf29b6 100644
--- a/src/components/Picker.js
+++ b/src/components/Picker.js
@@ -65,6 +65,7 @@ function Picker({
arrowIconStyle = {},
tickIconStyle = {},
closeIconStyle = {},
+ hideSelectedItemIcon = false,
badgeStyle = {},
badgeTextStyle = {},
badgeDotStyle = {},
@@ -128,6 +129,7 @@ function Picker({
activityIndicatorColor = Colors.GREY,
props = {},
itemProps = {},
+ badgeProps= {},
modalProps = {},
flatListProps = {},
scrollViewProps = {},
@@ -147,6 +149,7 @@ function Picker({
setValue = (callback) => {},
onChangeValue = (value) => {},
onChangeSearchText = (text) => {},
+ onDirectionChanged = (direction) => {},
zIndex = 5000,
zIndexInverse = 6000,
rtl = false,
@@ -155,6 +158,7 @@ function Picker({
theme = THEMES.DEFAULT,
testID,
closeOnBackPressed = false,
+ extendableBadgeContainer = false,
onSelectItem = (item) => {}
}) {
const [necessaryItems, setNecessaryItems] = useState([]);
@@ -586,9 +590,15 @@ function Picker({
const item = getSelectedItem();
if (multiple)
- if (item.length > 0)
- return _multipleText.replace('{count}', item.length);
- else
+ if (item.length > 0) {
+ let mtext = _multipleText;
+
+ if (typeof mtext !== 'string') {
+ mtext = mtext[item.length] ?? mtext.n;
+ }
+
+ return mtext.replace('{count}', item.length);
+ } else
return fallback;
try {
@@ -634,7 +644,10 @@ function Picker({
);
const size = y + maxHeight + pickerHeight + bottomOffset;
- setDirection(size < WINDOW_HEIGHT ? 'top' : 'bottom');
+ const direction = size < WINDOW_HEIGHT ? 'top' : 'bottom';
+
+ onDirectionChanged(direction);
+ setDirection(direction);
}
onPressToggle();
@@ -642,6 +655,7 @@ function Picker({
open,
onPressToggle,
onPress,
+ onDirectionChanged,
maxHeight,
pickerHeight,
bottomOffset,
@@ -864,12 +878,15 @@ function Picker({
const SelectedItemIconComponent = useMemo(() => {
const Component = _selectedItemIcon();
+ if (hideSelectedItemIcon)
+ return null;
+
return Component !== null && (
);
- }, [_selectedItemIcon, _iconContainerStyle]);
+ }, [_selectedItemIcon, hideSelectedItemIcon, _iconContainerStyle]);
/**
* The simple body component.
@@ -957,6 +974,7 @@ function Picker({
*/
const __renderBadge = useCallback(({item}) => (
([
+ const labelContainerStyle = useMemo(() => ([
THEME.labelContainer, rtl && {
transform: [
{scaleX: -1}
@@ -1038,12 +1056,12 @@ function Picker({
* @returns {JSX.Element}
*/
const BadgeListEmptyComponent = useCallback(() => (
-
+
{_placeholder}
- ), [_labelStyle, labelContainer, labelProps, _placeholder]);
+ ), [_labelStyle, labelContainerStyle, labelProps, _placeholder]);
/**
* Set ref.
@@ -1052,26 +1070,73 @@ function Picker({
badgeFlatListRef.current = ref;
}, []);
+ /**
+ * The extendable badge container style.
+ * @returns {object}
+ */
+ const extendableBadgeContainerStyle = useMemo(() => ([
+ RTL_DIRECTION(rtl, THEME.extendableBadgeContainer)
+ ]), [rtl, THEME]);
+
+ /**
+ * The extendable badge item container style.
+ * @returns {object}
+ */
+ const extendableBadgeItemContainerStyle = useMemo(() => ([
+ THEME.extendableBadgeItemContainer, rtl && {
+ marginEnd: 0,
+ marginStart: THEME.extendableBadgeItemContainer.marginEnd
+ }
+ ]), [rtl, THEME]);
+
+ /**
+ * Extendable badge container.
+ * @returns {JSX.Element}
+ */
+ const ExtendableBadgeContainer = useCallback(({selectedItems}) => {
+ if (selectedItems.length > 0) {
+ return (
+
+ {selectedItems.map((item, index) => (
+
+ <__renderBadge item={item} />
+
+ ))}
+
+ );
+ }
+
+ return ;
+ }, [__renderBadge, extendableBadgeContainerStyle, extendableBadgeItemContainerStyle]);
+
/**
* The badge body component.
* @returns {JSX.Element}
*/
- const BadgeBodyComponent = useMemo(() => (
-
- ), [
+ const BadgeBodyComponent = useMemo(() => {
+ if (extendableBadgeContainer) {
+ return
+ }
+
+ return (
+
+ );
+ }, [
rtl,
+ extendableBadgeContainer,
+ ExtendableBadgeContainer,
selectedItems,
__renderBadge,
keyExtractor,
@@ -1186,7 +1251,6 @@ function Picker({
...[textStyle].flat(),
...[listMessageTextStyle].flat()
]), [listMessageTextStyle, THEME]);
-
/**
* onPress item.
@@ -1749,4 +1813,4 @@ const styles = StyleSheet.create({
}
});
-export default memo(Picker);
+export default memo(Picker);
\ No newline at end of file
diff --git a/src/components/RenderBadgeItem.js b/src/components/RenderBadgeItem.js
index 04fc8e74..e6353705 100644
--- a/src/components/RenderBadgeItem.js
+++ b/src/components/RenderBadgeItem.js
@@ -13,6 +13,7 @@ import { RTL_DIRECTION, RTL_STYLE } from '../constants';
function RenderBadge({
rtl,
label,
+ props,
value,
textStyle,
badgeStyle,
@@ -61,7 +62,7 @@ function RenderBadge({
]), [textStyle, badgeTextStyle]);
return (
-
+
{showBadgeDot && }
{label}
diff --git a/src/constants/index.js b/src/constants/index.js
index 5a9c661f..f4e9c768 100644
--- a/src/constants/index.js
+++ b/src/constants/index.js
@@ -46,7 +46,9 @@ export const LANGUAGE = {
FARSI: 'FA',
TURKISH: 'TR',
RUSSIAN: 'RU',
- SPANISH: 'ES'
+ SPANISH: 'ES',
+ INDONESIAN: 'ID',
+ ITALIAN: 'IT'
}
export const GET_DROPDOWN_DIRECTION = (direction) => {
diff --git a/src/themes/dark/index.js b/src/themes/dark/index.js
index 6f3fb4f4..1d778d9a 100644
--- a/src/themes/dark/index.js
+++ b/src/themes/dark/index.js
@@ -20,11 +20,12 @@ export default StyleSheet.create({
alignItems: 'center',
justifyContent: 'space-between',
width: '100%',
- height: 50,
+ minHeight: 50,
borderRadius: 8,
borderWidth: 1,
borderColor: Colors.BLACK,
paddingHorizontal: 10,
+ paddingVertical: 3,
backgroundColor: Colors.EBONY_CLAY,
},
label: {
@@ -159,7 +160,7 @@ export default StyleSheet.create({
padding: 10,
},
listMessageText: {
-
+ color: Colors.HEATHER
},
selectedItemContainer: {
@@ -170,5 +171,14 @@ export default StyleSheet.create({
modalTitle: {
fontSize: 18,
color: Colors.HEATHER
+ },
+ extendableBadgeContainer: {
+ flexDirection: 'row',
+ flexWrap: 'wrap',
+ flex: 1
+ },
+ extendableBadgeItemContainer: {
+ marginVertical: 3,
+ marginEnd: 7
}
-});
\ No newline at end of file
+});
diff --git a/src/themes/light/index.js b/src/themes/light/index.js
index 4186419a..ba38795c 100644
--- a/src/themes/light/index.js
+++ b/src/themes/light/index.js
@@ -20,11 +20,12 @@ export default StyleSheet.create({
alignItems: 'center',
justifyContent: 'space-between',
width: '100%',
- height: 50,
+ minHeight: 50,
borderRadius: 8,
borderWidth: 1,
borderColor: Colors.BLACK,
paddingHorizontal: 10,
+ paddingVertical: 3,
backgroundColor: Colors.WHITE
},
label: {
@@ -169,5 +170,14 @@ export default StyleSheet.create({
modalTitle: {
fontSize: 18,
color: Colors.BLACK
+ },
+ extendableBadgeContainer: {
+ flexDirection: 'row',
+ flexWrap: 'wrap',
+ flex: 1
+ },
+ extendableBadgeItemContainer: {
+ marginVertical: 3,
+ marginEnd: 7
}
});
\ No newline at end of file
diff --git a/src/translations/index.js b/src/translations/index.js
index 903578e8..1b5e05a1 100644
--- a/src/translations/index.js
+++ b/src/translations/index.js
@@ -2,7 +2,10 @@ export default {
EN: {
PLACEHOLDER: 'Select an item',
SEARCH_PLACEHOLDER: 'Type something...',
- SELECTED_ITEMS_COUNT_TEXT: '{count} item(s) have been selected',
+ SELECTED_ITEMS_COUNT_TEXT: {
+ 1: 'An item has been selected',
+ n: '{count} items have been selected'
+ },
NOTHING_TO_SHOW: 'There\'s nothing to show!'
},
AR: {
@@ -14,13 +17,19 @@ export default {
FA: {
PLACEHOLDER: 'آیتمی انتخاب کنید',
SEARCH_PLACEHOLDER: 'چیزی تایپ کنید...',
- SELECTED_ITEMS_COUNT_TEXT: '{count} آیتم انتخاب شده است',
+ SELECTED_ITEMS_COUNT_TEXT: {
+ 1: 'یک آیتم انتخاب شده است',
+ n: '{count} آیتم انتخاب شده است'
+ },
NOTHING_TO_SHOW: 'چیزی برای نمایش وجود ندارد!'
},
TR: {
PLACEHOLDER: 'Bir seçenek seçin',
SEARCH_PLACEHOLDER: 'Arama...',
- SELECTED_ITEMS_COUNT_TEXT: '{count} öğe seçildi',
+ SELECTED_ITEMS_COUNT_TEXT: {
+ 1: 'Bir öğe seçildi',
+ n: '{count} öğe seçildi'
+ },
NOTHING_TO_SHOW: 'Gösterecek hiçbir şey yok!'
},
RU: {
@@ -34,5 +43,20 @@ export default {
SEARCH_PLACEHOLDER: 'Escribe algo...',
SELECTED_ITEMS_COUNT_TEXT: 'Se han seleccionado {count} elemento(s)',
NOTHING_TO_SHOW: '¡No hay nada que mostrar!'
- }
+ },
+ ID: {
+ PLACEHOLDER: 'Pilih item',
+ SEARCH_PLACEHOLDER: 'Ketik sesuatu...',
+ SELECTED_ITEMS_COUNT_TEXT: '{count} item telah dipilih',
+ NOTHING_TO_SHOW: 'Tidak ada yang bisa ditampilkan!'
+ },
+ IT: {
+ PLACEHOLDER: 'Seleziona un elemento',
+ SEARCH_PLACEHOLDER: 'Digita qualcosa...',
+ SELECTED_ITEMS_COUNT_TEXT: {
+ 1: 'Un elemento è stato selezionato',
+ n: '{count} elementi sono stati selezionati'
+ },
+ NOTHING_TO_SHOW: 'Non c\'è nulla da mostrare!'
+ },
}