├── .nvmrc ├── .watchmanconfig ├── example ├── App.js ├── assets │ ├── icon.png │ ├── favicon.png │ ├── splash.png │ └── adaptive-icon.png ├── tsconfig.json ├── babel.config.js ├── app.json ├── package.json ├── webpack.config.js ├── metro.config.js └── src │ ├── App.tsx │ └── dropdown │ ├── Menu.tsx │ ├── Dropdown2.tsx │ ├── CountrySelect2.tsx │ ├── CountrySelect1.tsx │ ├── DropdownWithConfirm.tsx │ ├── Dropdown1.tsx │ ├── MultiSelectAll.tsx │ ├── DropdownLazyLoad.tsx │ └── MultiSelectWithConfirm.tsx ├── src ├── __tests__ │ └── index.test.tsx ├── assets │ ├── down.png │ └── close.png ├── toolkits │ ├── model.ts │ └── index.ts ├── components │ ├── SelectCountry │ │ ├── model.ts │ │ ├── styles.ts │ │ └── index.tsx │ ├── TextInput │ │ ├── model.ts │ │ ├── styles.ts │ │ └── index.tsx │ ├── Dropdown │ │ ├── styles.ts │ │ ├── model.ts │ │ └── index.tsx │ └── MultiSelect │ │ ├── styles.ts │ │ ├── model.ts │ │ └── index.tsx ├── index.tsx └── useDeviceOrientation.ts ├── .gitattributes ├── tsconfig.build.json ├── babel.config.js ├── .yarnrc ├── .editorconfig ├── lefthook.yml ├── .github ├── actions │ └── setup │ │ └── action.yml └── workflows │ └── ci.yml ├── tsconfig.json ├── scripts └── bootstrap.js ├── .gitignore ├── LICENSE ├── CONTRIBUTING.md ├── package.json ├── CODE_OF_CONDUCT.md └── README.md /.nvmrc: -------------------------------------------------------------------------------- 1 | 16.18.1 2 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /example/App.js: -------------------------------------------------------------------------------- 1 | export { default } from './src/App'; 2 | -------------------------------------------------------------------------------- /src/__tests__/index.test.tsx: -------------------------------------------------------------------------------- 1 | it.todo('write a test'); 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | # specific for windows script files 3 | *.bat text eol=crlf -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "extends": "./tsconfig", 4 | "exclude": ["example"] 5 | } 6 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:metro-react-native-babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /src/assets/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoaphantn7604/react-native-element-dropdown/HEAD/src/assets/down.png -------------------------------------------------------------------------------- /src/assets/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoaphantn7604/react-native-element-dropdown/HEAD/src/assets/close.png -------------------------------------------------------------------------------- /example/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoaphantn7604/react-native-element-dropdown/HEAD/example/assets/icon.png -------------------------------------------------------------------------------- /example/assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoaphantn7604/react-native-element-dropdown/HEAD/example/assets/favicon.png -------------------------------------------------------------------------------- /example/assets/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoaphantn7604/react-native-element-dropdown/HEAD/example/assets/splash.png -------------------------------------------------------------------------------- /.yarnrc: -------------------------------------------------------------------------------- 1 | # Override Yarn command so we can automatically setup the repo on running `yarn` 2 | 3 | yarn-path "scripts/bootstrap.js" 4 | -------------------------------------------------------------------------------- /example/assets/adaptive-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoaphantn7604/react-native-element-dropdown/HEAD/example/assets/adaptive-icon.png -------------------------------------------------------------------------------- /src/toolkits/model.ts: -------------------------------------------------------------------------------- 1 | export interface IUseDetectDevice { 2 | isAndroid: boolean; 3 | isIOS: boolean; 4 | isTablet: boolean; 5 | } 6 | -------------------------------------------------------------------------------- /example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig", 3 | "compilerOptions": { 4 | // Avoid expo-cli auto-generating a tsconfig 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | 9 | indent_style = space 10 | indent_size = 2 11 | 12 | end_of_line = lf 13 | charset = utf-8 14 | trim_trailing_whitespace = true 15 | insert_final_newline = true 16 | -------------------------------------------------------------------------------- /src/components/SelectCountry/model.ts: -------------------------------------------------------------------------------- 1 | import type { ImageStyle } from 'react-native'; 2 | import type { DropdownProps } from '../Dropdown/model'; 3 | 4 | export type ISelectCountryRef = { 5 | open: () => void; 6 | close: () => void; 7 | }; 8 | 9 | export interface SelectCountryProps extends DropdownProps { 10 | imageField: string; 11 | imageStyle?: ImageStyle; 12 | } 13 | -------------------------------------------------------------------------------- /lefthook.yml: -------------------------------------------------------------------------------- 1 | pre-commit: 2 | parallel: true 3 | commands: 4 | lint: 5 | files: git diff --name-only @{push} 6 | glob: "*.{js,ts,jsx,tsx}" 7 | run: npx eslint {files} 8 | types: 9 | files: git diff --name-only @{push} 10 | glob: "*.{js,ts, jsx, tsx}" 11 | run: npx tsc --noEmit 12 | commit-msg: 13 | parallel: true 14 | commands: 15 | commitlint: 16 | run: npx commitlint --edit 17 | -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | import Dropdown from './components/Dropdown'; 2 | import MultiSelect from './components/MultiSelect'; 3 | import SelectCountry from './components/SelectCountry'; 4 | import { IDropdownRef } from './components/Dropdown/model'; 5 | import { IMultiSelectRef } from './components/MultiSelect/model'; 6 | import { ISelectCountryRef } from './components/SelectCountry/model'; 7 | 8 | export { 9 | Dropdown, 10 | MultiSelect, 11 | SelectCountry, 12 | IDropdownRef, 13 | IMultiSelectRef, 14 | ISelectCountryRef, 15 | }; 16 | -------------------------------------------------------------------------------- /src/components/TextInput/model.ts: -------------------------------------------------------------------------------- 1 | import type React from 'react'; 2 | import type { 3 | ImageStyle, 4 | StyleProp, 5 | TextInputProps, 6 | TextStyle, 7 | ViewStyle, 8 | } from 'react-native'; 9 | 10 | interface Props extends TextInputProps { 11 | fontFamily?: string; 12 | style?: StyleProp; 13 | inputStyle?: StyleProp; 14 | iconStyle?: StyleProp; 15 | showIcon?: boolean; 16 | renderRightIcon?: () => React.ReactElement | null; 17 | renderLeftIcon?: () => React.ReactElement | null; 18 | } 19 | 20 | export type CTextInput = React.FC; 21 | -------------------------------------------------------------------------------- /example/babel.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const pak = require('../package.json'); 3 | 4 | module.exports = function (api) { 5 | api.cache(true); 6 | 7 | return { 8 | presets: ['babel-preset-expo'], 9 | plugins: [ 10 | [ 11 | 'module-resolver', 12 | { 13 | extensions: ['.tsx', '.ts', '.js', '.json'], 14 | alias: { 15 | // For development, we want to alias the library to the source 16 | [pak.name]: path.join(__dirname, '..', pak.source), 17 | }, 18 | }, 19 | ], 20 | ], 21 | }; 22 | }; 23 | -------------------------------------------------------------------------------- /src/components/SelectCountry/styles.ts: -------------------------------------------------------------------------------- 1 | import { I18nManager, StyleSheet } from 'react-native'; 2 | 3 | export const styles = StyleSheet.create({ 4 | dropdown: { 5 | width: 58, 6 | paddingHorizontal: 6, 7 | height: 26, 8 | }, 9 | container: { 10 | width: 60, 11 | }, 12 | item: { 13 | flexDirection: I18nManager.isRTL ? 'row-reverse' : 'row', 14 | padding: 6, 15 | alignItems: 'center', 16 | }, 17 | image: { 18 | width: 20, 19 | height: 20, 20 | marginRight: 3, 21 | marginVertical: 4, 22 | }, 23 | selectedTextStyle: { 24 | flex: 1, 25 | fontSize: 12, 26 | writingDirection: I18nManager.isRTL ? 'rtl' : 'ltr', 27 | }, 28 | }); 29 | -------------------------------------------------------------------------------- /example/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "example", 4 | "slug": "example", 5 | "version": "1.0.0", 6 | "orientation": "portrait", 7 | "icon": "./assets/icon.png", 8 | "userInterfaceStyle": "light", 9 | "splash": { 10 | "image": "./assets/splash.png", 11 | "resizeMode": "contain", 12 | "backgroundColor": "#ffffff" 13 | }, 14 | "assetBundlePatterns": [ 15 | "**/*" 16 | ], 17 | "ios": { 18 | "supportsTablet": true 19 | }, 20 | "android": { 21 | "adaptiveIcon": { 22 | "foregroundImage": "./assets/adaptive-icon.png", 23 | "backgroundColor": "#ffffff" 24 | } 25 | }, 26 | "web": { 27 | "favicon": "./assets/favicon.png" 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/components/TextInput/styles.ts: -------------------------------------------------------------------------------- 1 | import { I18nManager, StyleSheet } from 'react-native'; 2 | 3 | export const styles = StyleSheet.create({ 4 | container: { 5 | backgroundColor: 'white', 6 | borderRadius: 8, 7 | padding: 12, 8 | justifyContent: 'center', 9 | }, 10 | textInput: { 11 | flexDirection: I18nManager.isRTL ? 'row-reverse' : 'row', 12 | alignItems: 'center', 13 | flex: 1, 14 | }, 15 | input: { 16 | fontSize: 16, 17 | flex: 1, 18 | textAlign: I18nManager.isRTL ? 'right' : 'left', 19 | }, 20 | label: { 21 | marginBottom: 4, 22 | fontSize: 16, 23 | }, 24 | row: { 25 | flexDirection: I18nManager.isRTL ? 'row-reverse' : 'row', 26 | }, 27 | icon: { 28 | width: 20, 29 | height: 20, 30 | }, 31 | }); 32 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "version": "1.0.0", 4 | "main": "node_modules/expo/AppEntry.js", 5 | "scripts": { 6 | "start": "expo start", 7 | "android": "expo start --android", 8 | "ios": "expo start --ios", 9 | "web": "expo start --web" 10 | }, 11 | "dependencies": { 12 | "@expo/vector-icons": "^13.0.0", 13 | "expo": "~48.0.6", 14 | "expo-status-bar": "~1.4.4", 15 | "react": "18.2.0", 16 | "react-dom": "18.2.0", 17 | "react-native": "0.71.3", 18 | "react-native-web": "~0.18.10" 19 | }, 20 | "devDependencies": { 21 | "@babel/core": "^7.20.0", 22 | "@expo/webpack-config": "^0.17.2", 23 | "babel-loader": "^8.1.0", 24 | "babel-plugin-module-resolver": "^4.1.0" 25 | }, 26 | "private": true 27 | } 28 | -------------------------------------------------------------------------------- /.github/actions/setup/action.yml: -------------------------------------------------------------------------------- 1 | name: Setup 2 | description: Setup Node.js and install dependencies 3 | 4 | runs: 5 | using: composite 6 | steps: 7 | - name: Setup Node.js 8 | uses: actions/setup-node@v3 9 | with: 10 | node-version-file: .nvmrc 11 | 12 | - name: Cache dependencies 13 | id: yarn-cache 14 | uses: actions/cache@v3 15 | with: 16 | path: | 17 | **/node_modules 18 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 19 | restore-keys: | 20 | ${{ runner.os }}-yarn- 21 | 22 | - name: Install dependencies 23 | if: steps.yarn-cache.outputs.cache-hit != 'true' 24 | run: | 25 | yarn install --cwd example --frozen-lockfile 26 | yarn install --frozen-lockfile 27 | shell: bash 28 | -------------------------------------------------------------------------------- /src/toolkits/index.ts: -------------------------------------------------------------------------------- 1 | import { Platform, PixelRatio, Dimensions } from 'react-native'; 2 | import type { IUseDetectDevice } from './model'; 3 | 4 | const { width, height } = Dimensions.get('window'); 5 | 6 | const isTablet = () => { 7 | let pixelDensity = PixelRatio.get(); 8 | const adjustedWidth = width * pixelDensity; 9 | const adjustedHeight = height * pixelDensity; 10 | if (pixelDensity < 2 && (adjustedWidth >= 1000 || adjustedHeight >= 1000)) { 11 | return true; 12 | } else { 13 | return ( 14 | pixelDensity === 2 && (adjustedWidth >= 1824 || adjustedHeight >= 1824) 15 | ); 16 | } 17 | }; 18 | 19 | const useDetectDevice: IUseDetectDevice = { 20 | isAndroid: Platform.OS === 'android', 21 | isIOS: Platform.OS === 'ios', 22 | isTablet: isTablet(), 23 | }; 24 | 25 | export { useDetectDevice }; 26 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./", 4 | "paths": { 5 | "react-native-element-dropdown": ["./src/index"] 6 | }, 7 | "allowUnreachableCode": false, 8 | "allowUnusedLabels": false, 9 | "esModuleInterop": true, 10 | "importsNotUsedAsValues": "remove", 11 | "forceConsistentCasingInFileNames": true, 12 | "jsx": "react", 13 | "lib": ["esnext"], 14 | "module": "esnext", 15 | "moduleResolution": "node", 16 | "noFallthroughCasesInSwitch": true, 17 | "noImplicitReturns": true, 18 | "noImplicitUseStrict": false, 19 | "noStrictGenericChecks": false, 20 | "noUncheckedIndexedAccess": true, 21 | "noUnusedLocals": true, 22 | "noUnusedParameters": true, 23 | "resolveJsonModule": true, 24 | "skipLibCheck": true, 25 | "strict": true, 26 | "target": "esnext" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /scripts/bootstrap.js: -------------------------------------------------------------------------------- 1 | const os = require('os'); 2 | const path = require('path'); 3 | const child_process = require('child_process'); 4 | 5 | const root = path.resolve(__dirname, '..'); 6 | const args = process.argv.slice(2); 7 | const options = { 8 | cwd: process.cwd(), 9 | env: process.env, 10 | stdio: 'inherit', 11 | encoding: 'utf-8', 12 | }; 13 | 14 | if (os.type() === 'Windows_NT') { 15 | options.shell = true; 16 | } 17 | 18 | let result; 19 | 20 | if (process.cwd() !== root || args.length) { 21 | // We're not in the root of the project, or additional arguments were passed 22 | // In this case, forward the command to `yarn` 23 | result = child_process.spawnSync('yarn', args, options); 24 | } else { 25 | // If `yarn` is run without arguments, perform bootstrap 26 | result = child_process.spawnSync('yarn', ['bootstrap'], options); 27 | } 28 | 29 | process.exitCode = result.status; 30 | -------------------------------------------------------------------------------- /example/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const createExpoWebpackConfigAsync = require('@expo/webpack-config'); 3 | const { resolver } = require('./metro.config'); 4 | 5 | const root = path.resolve(__dirname, '..'); 6 | const node_modules = path.join(__dirname, 'node_modules'); 7 | 8 | module.exports = async function (env, argv) { 9 | const config = await createExpoWebpackConfigAsync(env, argv); 10 | 11 | config.module.rules.push({ 12 | test: /\.(js|jsx|ts|tsx)$/, 13 | include: path.resolve(root, 'src'), 14 | use: 'babel-loader', 15 | }); 16 | 17 | // We need to make sure that only one version is loaded for peerDependencies 18 | // So we alias them to the versions in example's node_modules 19 | Object.assign(config.resolve.alias, { 20 | ...resolver.extraNodeModules, 21 | 'react-native-web': path.join(node_modules, 'react-native-web'), 22 | }); 23 | 24 | return config; 25 | }; 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # XDE 6 | .expo/ 7 | 8 | # VSCode 9 | .vscode/ 10 | jsconfig.json 11 | 12 | # Xcode 13 | # 14 | build/ 15 | *.pbxuser 16 | !default.pbxuser 17 | *.mode1v3 18 | !default.mode1v3 19 | *.mode2v3 20 | !default.mode2v3 21 | *.perspectivev3 22 | !default.perspectivev3 23 | xcuserdata 24 | *.xccheckout 25 | *.moved-aside 26 | DerivedData 27 | *.hmap 28 | *.ipa 29 | *.xcuserstate 30 | project.xcworkspace 31 | 32 | # Android/IJ 33 | # 34 | .classpath 35 | .cxx 36 | .gradle 37 | .idea 38 | .project 39 | .settings 40 | local.properties 41 | android.iml 42 | 43 | # Cocoapods 44 | # 45 | example/ios/Pods 46 | 47 | # Ruby 48 | example/vendor/ 49 | 50 | # node.js 51 | # 52 | node_modules/ 53 | npm-debug.log 54 | yarn-debug.log 55 | yarn-error.log 56 | 57 | # BUCK 58 | buck-out/ 59 | \.buckd/ 60 | android/app/libs 61 | android/keystores/debug.keystore 62 | 63 | # Expo 64 | .expo/ 65 | 66 | # Turborepo 67 | .turbo/ 68 | 69 | # generated by bob 70 | lib/ 71 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | branches: 8 | - main 9 | 10 | jobs: 11 | lint: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v3 16 | 17 | - name: Setup 18 | uses: ./.github/actions/setup 19 | 20 | - name: Lint files 21 | run: yarn lint 22 | 23 | - name: Typecheck files 24 | run: yarn typecheck 25 | 26 | test: 27 | runs-on: ubuntu-latest 28 | steps: 29 | - name: Checkout 30 | uses: actions/checkout@v3 31 | 32 | - name: Setup 33 | uses: ./.github/actions/setup 34 | 35 | - name: Run unit tests 36 | run: yarn test --maxWorkers=2 --coverage 37 | 38 | build: 39 | runs-on: ubuntu-latest 40 | steps: 41 | - name: Checkout 42 | uses: actions/checkout@v3 43 | 44 | - name: Setup 45 | uses: ./.github/actions/setup 46 | 47 | - name: Build package 48 | run: yarn prepack 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Hoa Phan 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | -------------------------------------------------------------------------------- /example/metro.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const escape = require('escape-string-regexp'); 3 | const { getDefaultConfig } = require('@expo/metro-config'); 4 | const exclusionList = require('metro-config/src/defaults/exclusionList'); 5 | const pak = require('../package.json'); 6 | 7 | const root = path.resolve(__dirname, '..'); 8 | 9 | const modules = Object.keys({ 10 | ...pak.peerDependencies, 11 | }); 12 | 13 | const defaultConfig = getDefaultConfig(__dirname); 14 | 15 | module.exports = { 16 | ...defaultConfig, 17 | 18 | projectRoot: __dirname, 19 | watchFolders: [root], 20 | 21 | // We need to make sure that only one version is loaded for peerDependencies 22 | // So we block them at the root, and alias them to the versions in example's node_modules 23 | resolver: { 24 | ...defaultConfig.resolver, 25 | 26 | blacklistRE: exclusionList( 27 | modules.map( 28 | (m) => 29 | new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`) 30 | ) 31 | ), 32 | 33 | extraNodeModules: modules.reduce((acc, name) => { 34 | acc[name] = path.join(__dirname, 'node_modules', name); 35 | return acc; 36 | }, {}), 37 | }, 38 | }; 39 | -------------------------------------------------------------------------------- /src/useDeviceOrientation.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-shadow */ 2 | import { useEffect, useState } from 'react'; 3 | import { Dimensions, ScaledSize } from 'react-native'; 4 | 5 | const isOrientationPortrait = ({ width, height }: ScaledSize) => 6 | height >= width; 7 | const isOrientationLandscape = ({ width, height }: ScaledSize) => 8 | width >= height; 9 | 10 | export function useDeviceOrientation() { 11 | const screen = Dimensions.get('screen'); 12 | const initialState = { 13 | portrait: isOrientationPortrait(screen), 14 | landscape: isOrientationLandscape(screen), 15 | }; 16 | 17 | const [orientation, setOrientation] = useState(initialState); 18 | 19 | useEffect(() => { 20 | const onChange = ({ screen }: { screen: ScaledSize }) => { 21 | setOrientation({ 22 | portrait: isOrientationPortrait(screen), 23 | landscape: isOrientationLandscape(screen), 24 | }); 25 | }; 26 | 27 | const subscription = Dimensions.addEventListener('change', onChange); 28 | 29 | return () => { 30 | if (typeof subscription?.remove === 'function') { 31 | subscription.remove(); 32 | } 33 | }; 34 | }, []); 35 | 36 | return orientation.portrait ? 'PORTRAIT' : 'LANDSCAPE'; 37 | } 38 | -------------------------------------------------------------------------------- /example/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StyleSheet, View, ScrollView } from 'react-native'; 3 | import DropdownExample1 from './dropdown/Dropdown1'; 4 | import DropdownExample2 from './dropdown/Dropdown2'; 5 | import Menu from './dropdown/Menu'; 6 | import DropdownWithConfirm from './dropdown/DropdownWithConfirm'; 7 | import CountrySelect1 from './dropdown/CountrySelect1'; 8 | import CountrySelect2 from './dropdown/CountrySelect2'; 9 | import MultiSelectAll from './dropdown/MultiSelectAll'; 10 | import MultiSelectWithConfirm from './dropdown/MultiSelectWithConfirm'; 11 | import DropdownLazyLoad from './dropdown/DropdownLazyLoad'; 12 | 13 | const DropdownScreen = (_props: any) => { 14 | return ( 15 | 16 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | ); 32 | }; 33 | 34 | export default DropdownScreen; 35 | 36 | const styles = StyleSheet.create({ 37 | container: { 38 | flex: 1, 39 | backgroundColor: 'white', 40 | paddingVertical: 50, 41 | }, 42 | }); 43 | -------------------------------------------------------------------------------- /src/components/Dropdown/styles.ts: -------------------------------------------------------------------------------- 1 | import { I18nManager, StyleSheet } from 'react-native'; 2 | 3 | export const styles = StyleSheet.create({ 4 | mainWrap: { 5 | justifyContent: 'center', 6 | }, 7 | container: { 8 | flexShrink: 1, 9 | borderWidth: 0.5, 10 | borderColor: '#EEEEEE', 11 | backgroundColor: 'white', 12 | shadowColor: '#000', 13 | shadowOffset: { 14 | width: 0, 15 | height: 1, 16 | }, 17 | shadowOpacity: 0.2, 18 | shadowRadius: 1.41, 19 | elevation: 2, 20 | }, 21 | flex1: { 22 | flex: 1, 23 | }, 24 | flexShrink: { 25 | flexShrink: 1, 26 | }, 27 | wrapTop: { 28 | justifyContent: 'flex-end', 29 | }, 30 | dropdown: { 31 | flexDirection: I18nManager.isRTL ? 'row-reverse' : 'row', 32 | justifyContent: 'space-between', 33 | alignItems: 'center', 34 | }, 35 | title: { 36 | marginVertical: 5, 37 | fontSize: 16, 38 | writingDirection: I18nManager.isRTL ? 'rtl' : 'ltr', 39 | }, 40 | item: { 41 | padding: 17, 42 | flexDirection: I18nManager.isRTL ? 'row-reverse' : 'row', 43 | justifyContent: 'space-between', 44 | alignItems: 'center', 45 | }, 46 | textItem: { 47 | flex: 1, 48 | fontSize: 16, 49 | writingDirection: I18nManager.isRTL ? 'rtl' : 'ltr', 50 | }, 51 | icon: { 52 | width: 20, 53 | height: 20, 54 | }, 55 | input: { 56 | borderWidth: 0.5, 57 | borderColor: '#DDDDDD', 58 | paddingHorizontal: 8, 59 | marginBottom: 8, 60 | margin: 6, 61 | height: 45, 62 | }, 63 | fullScreen: { 64 | alignItems: 'center', 65 | justifyContent: 'center', 66 | }, 67 | }); 68 | -------------------------------------------------------------------------------- /src/components/SelectCountry/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useImperativeHandle, useMemo, useRef } from 'react'; 2 | import { Image, Text, View } from 'react-native'; 3 | import Dropdown from '../Dropdown'; 4 | import { ISelectCountryRef, SelectCountryProps } from './model'; 5 | import { styles } from './styles'; 6 | 7 | const SelectCountryComponent = React.forwardRef< 8 | ISelectCountryRef, 9 | SelectCountryProps 10 | >((props, currentRef) => { 11 | const { 12 | data, 13 | value, 14 | valueField, 15 | labelField, 16 | imageField, 17 | selectedTextStyle, 18 | imageStyle, 19 | } = props; 20 | const ref: any = useRef(null); 21 | 22 | useImperativeHandle(currentRef, () => { 23 | return { open: eventOpen, close: eventClose }; 24 | }); 25 | 26 | const eventOpen = () => { 27 | ref.current.open(); 28 | }; 29 | 30 | const eventClose = () => { 31 | ref.current.close(); 32 | }; 33 | 34 | const _renderItem = (item: any) => { 35 | return ( 36 | 37 | 38 | 39 | {item[labelField]} 40 | 41 | 42 | ); 43 | }; 44 | 45 | const selectItem: any = useMemo(() => { 46 | const index = data.findIndex((e: any) => e[valueField] === value); 47 | return data[index]; 48 | }, [data, valueField, value]); 49 | 50 | return ( 51 | { 56 | if (selectItem?.image) { 57 | return ( 58 | 62 | ); 63 | } else { 64 | return null; 65 | } 66 | }} 67 | /> 68 | ); 69 | }); 70 | 71 | export default SelectCountryComponent; 72 | -------------------------------------------------------------------------------- /example/src/dropdown/Menu.tsx: -------------------------------------------------------------------------------- 1 | import React, { useRef, useState } from 'react'; 2 | import { StyleSheet, Dimensions, View } from 'react-native'; 3 | import { Dropdown, IDropdownRef } from 'react-native-element-dropdown'; 4 | import AntDesign from '@expo/vector-icons/AntDesign'; 5 | 6 | const data = [ 7 | { label: 'Item 1', value: '1' }, 8 | { label: 'Item 2', value: '2' }, 9 | { label: 'Item 3', value: '3' }, 10 | { label: 'Item 4', value: '4' }, 11 | { label: 'Item 5', value: '5' }, 12 | { label: 'Item 6', value: '6' }, 13 | { label: 'Item 7', value: '7' }, 14 | { label: 'Item 8', value: '8' }, 15 | ]; 16 | 17 | const { width } = Dimensions.get('window'); 18 | 19 | const DropdownComponent = () => { 20 | const [value, setValue] = useState(); 21 | const ref = useRef(null); 22 | 23 | const renderIcon = () => { 24 | return ( 25 | 26 | 27 | 28 | ); 29 | }; 30 | 31 | return ( 32 | { 43 | setValue(item.value); 44 | }} 45 | onChangeText={() => {}} // Keep search keyword 46 | renderRightIcon={renderIcon} 47 | /> 48 | ); 49 | }; 50 | 51 | export default DropdownComponent; 52 | 53 | const styles = StyleSheet.create({ 54 | dropdown: { 55 | margin: 16, 56 | width: 50, 57 | marginLeft: width - 80, 58 | height: 50, 59 | borderColor: 'gray', 60 | borderWidth: 0.5, 61 | borderRadius: 8, 62 | paddingRight: 14, 63 | }, 64 | containerStyle: { 65 | width: 200, 66 | marginLeft: -150, 67 | marginTop: 5, 68 | }, 69 | iconStyle: { 70 | width: 50, 71 | height: 50, 72 | alignItems: 'center', 73 | justifyContent: 'center', 74 | }, 75 | }); 76 | -------------------------------------------------------------------------------- /example/src/dropdown/Dropdown2.tsx: -------------------------------------------------------------------------------- 1 | import React, { useRef, useState } from 'react'; 2 | import { Button, StyleSheet, View } from 'react-native'; 3 | import { Dropdown, IDropdownRef } from 'react-native-element-dropdown'; 4 | 5 | const data = [ 6 | { label: 'Item 1', value: '1' }, 7 | { label: 'Item 2', value: '2' }, 8 | { label: 'Item 3', value: '3' }, 9 | { label: 'Item 4', value: '4' }, 10 | { label: 'Item 5', value: '5' }, 11 | { label: 'Item 6', value: '6' }, 12 | { label: 'Item 7', value: '7' }, 13 | { label: 'Item 8', value: '8' }, 14 | ]; 15 | 16 | const DropdownComponent = () => { 17 | const [value, setValue] = useState(); 18 | const ref = useRef(null); 19 | 20 | return ( 21 | 22 | { 39 | setValue(item.value); 40 | }} 41 | onChangeText={() => {}} // Keep search keyword 42 | /> 43 | 44 |