├── .gitignore ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── index.js ├── package.json ├── utils ├── filterText.js └── fuzzySearch.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | yarn-error.log 2 | 3 | node_modules 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "nuxt.isNuxtApp": false 3 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 fattahmuhyiddeen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-complete-flatlist 2 | 3 | Extended version of react native flat list with many built in function such as search, pull to refresh, no data available message if empty row 4 | 5 | ![ezgif-3-734272a58f](https://user-images.githubusercontent.com/24792201/35842001-724e51be-0b3a-11e8-8a4b-77eb8b4ed17f.gif) 6 | 7 | Caution: 8 | 9 | `renderItem` props return `item` and `index` parameters 10 | `item` parameter returns a single element in `item` array. But if search text is not empty dan `highlightColor` props is set to any color, `item` parameter will return new structure of JSON object (in order to render highlighted text in jsx). This might break your logic. Therefore, if you want to access original structure of your data, it will be under `item.cleanData`. Remember, `item.cleanData` only exist if `highlightColor` props and search textfield is not empty (user is searching) 11 | 12 | Usage : 13 | 14 | ``` 15 | import React, {useRef} from 'react'; 16 | import { Text, SafeAreaView, TouchableOpacity } from 'react-native'; 17 | import CompleteFlatList from 'react-native-complete-flatlist'; 18 | 19 | const list = [ 20 | { name: 'Fattah', status: 'Active', time: '8:10 PM', date: '1 Jan 2018' }, 21 | { name: 'Syah', status: 'Active', time: '9:14 PM', date: '1 Dec 2018' }, 22 | { name: 'Izzat', status: 'Active', time: '8:15 PM', date: '1 Jan 2018' }, 23 | { name: 'Ali', status: 'Active', time: '8:10 PM', date: '1 Jan 2018' }, 24 | { name: 'Abu', status: 'Active', time: '8:11 PM', date: '1 Jan 2018' }, 25 | { name: 'Fitri', status: 'Active', time: '8:20 PM', date: '1 Jan 2018' }, 26 | { name: 'Armi', status: 'Active', time: '8:33 PM', date: '1 Jan 2018' }, 27 | { name: 'Eidit', status: 'Active', time: '9:10 PM', date: '1 Jan 2018' }, 28 | { name: 'Hamdan', status: 'Active', time: '10:10 PM', date: '1 Jan 2018' }, 29 | { 30 | name: 'Muhyiddeen', 31 | status: 'Blocked', 32 | time: '10:10 PM', 33 | date: '9 Feb 2018', 34 | }, 35 | ]; 36 | 37 | const App = () => { 38 | const ref = useRef(); 39 | const renderItem = ({item, index}) => { 40 | const data = item.cleanData ? item.cleanData : item; 41 | 42 | console.log('item (if search bar is not empty and prop highlightColor is not empty, item will contains extra data to enable highlight feature)', item); 43 | console.log('cleanData (if search bar is not empty and prop highlightColor is not empty, cleanData will contain original data structure without extra data)', item.cleanData); 44 | 45 | 46 | console.log('this is index number : ' + index); 47 | 48 | console.log(data + ' this is original data'); 49 | 50 | return {item.name}; 51 | }; 52 | 53 | return ( 54 | 55 | console.log('refreshing')} 58 | data={list} 59 | // renderSeparator={null} 60 | ref={ref} 61 | highlightColor="yellow" 62 | renderItem={renderItem} 63 | /> 64 | ref.current.clearSearch()} style={{ padding: 5 }}> 65 | Clear Search 66 | 67 | 68 | ); 69 | }; 70 | 71 | export default App; 72 | 73 | 74 | 75 | ``` 76 | 77 | ### Upgrading from V 1.x.x to V 2.x.x 78 | 79 | Change from `renderItem={(data, index) => {} }` to `renderItem={({item, index, separators}) => {} }` (similar like the on in Original Flatlist) 80 | 81 | ### Properties 82 | 83 | All FlatList props should work plus props mentioned below 84 | 85 | | Prop | Type | Description | Default | Required | 86 | | ----------------------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | ----------------------------------------------------------------------- | 87 | | `showSearch` | boolean | If `true` (and `searchKey` prop is defined), search bar will be shown. | true | Optional | 88 | | `isJelly` | boolean | If `true`, when user scroll, the list will expand a lil bit, and when user stop drag, the list will back to original size (iMessage on iPhone style) | false | Optional | 89 | | `slide` | string | Animation how every items come into the list. Can be "none", "left" or "right" | `none` | Optional | 90 | | `data` | array of objects | Data to be rendered in the list | [] | Required (come on, ofcourse u need data for this) | 91 | | `backgroundStyles` | style object | Style of the flatlist background | null | Optional | 92 | | `searchBarBackgroundStyles` | style object | Style of the searchbar background | null | Optional | 93 | | `pullToRefreshCallback` | function | Callback function when user pull to refresh | null | Optional (Pull to refresh will not be available if this is not supplied | 94 | | `isLoading` | boolean | if true, the loading will be shown on top of the list. | false | Optional | 95 | | `renderItem` | function that return a JSX element (Just like RN's ListView and FlatList) | Template of a row in the Flat List | null (open for PR if anyone wish to make default template for this) | Required (since I dont do default template yet) | 96 | | `renderSeparator` | function that return a JSX element to be rendered between rows(Just like RN's ListView and FlatList) | Template of separator in the Flat List | `() => ` | Optional | 97 | | `placeholder` | string | Placeholder of search field | "Search ..." | Optional | 98 | | `searchTextInputStyle` | object (style for React Native's TextInput component) | style for search field | null | Optional | 99 | | `highlightColor` | color | color of higlighted words background when match search keyword. Please read the pre caution if using this prop on top of the readme | yellow | Optional | 100 | | `searchKey` | array of string | This should be name of keys available in data which will be use to search. If this prop is not supplied, search text input will not be rendered. `**Warning: nested key not yet supported` | [] | Optional (if not supplied, search field will not appear) | 101 | | `elementBetweenSearchAndList` | JSX element | What to render between searchbar and the list | null | Optional | 102 | | `refreshOnLoad` | boolean | If `true`, prop `pullToRefreshCallback` will be called if available | true | Optional | 103 | | `onSearch` | function that will replace `pullToRefreshCallback` | If exist, `pullToRefreshCallback` will be overrided. This will not triggered on key press, but on return key pressed. This props is introduced if search trigger result from API. If you just want local search (search from existing array), this props is not needed. `onSearch` will automatic get `keyword` parameter | ()=>null | Optional 104 | | `loadNext` | function | If defined, this function will be called when user scroll FlatList to the bottom. The usecase is to call next pagination of your API. If defined, loading icon will be shown at the bottom of the list. To hide the loading icon, make sure this prop is undefined | undefined | Optional | 105 | | `refreshControlProps` | object | props for RefreshControl | undefined | Optional | 106 | 107 | ### Methods 108 | 109 | If you have `ref` to the component, 110 | ``` 111 | const completeFlatList = useRef(); 112 | ... 113 | 118 | 119 | ``` 120 | 121 | or in component based 122 | 123 | ``` 124 | 125 | this.completeFlatList = c} 128 | ... 129 | /> 130 | ``` 131 | 132 | you can use any method(s) below: 133 | ```completeFlatList.current.methodName()``` 134 | 135 | or in component based 136 | 137 | ```this.completeFlatList.methodName()``` 138 | 139 | | Method | Description | 140 | | ----------- | ----------------------------------- | 141 | | clearSearch | Clear search input programmatically | 142 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { 3 | StyleSheet, 4 | Text, 5 | View, 6 | FlatList, 7 | TextInput, 8 | RefreshControl, 9 | Animated, 10 | ActivityIndicator, 11 | } from "react-native"; 12 | 13 | import filterText from "./utils/filterText"; 14 | import fuzziedText from "./utils/fuzzySearch"; 15 | 16 | class CompleteFlatList extends React.Component { 17 | rowScale = new Animated.Value(0); 18 | 19 | slide = new Animated.Value(0); 20 | 21 | state = { 22 | refreshing: false, 23 | searchText: "", 24 | }; 25 | 26 | static defaultProps = { 27 | searchKey: [], 28 | placeholder: "Search ...", 29 | data: [], 30 | isRefreshing: false, 31 | renderItem: null, 32 | renderSeparator: () => , 33 | backgroundStyles: {}, 34 | searchTextInputStyle: {}, 35 | searchBarBackgroundStyles: {}, 36 | showSearch: true, 37 | isJelly: false, 38 | slide: "none", 39 | elementBetweenSearchAndList: null, 40 | refreshOnLoad: true, 41 | }; 42 | 43 | componentDidMount() { 44 | if (this.props.refreshOnLoad) this.props.pullToRefreshCallback?.(); 45 | 46 | if (this.props.slide != "none") { 47 | Animated.spring(this.slide, { 48 | toValue: 1, 49 | tension: 20, 50 | useNativeDriver: true, 51 | }).start(); 52 | } 53 | } 54 | 55 | clearSearch = () => this.setState({ searchText: "" }, this.searchInput.clear); 56 | 57 | onRefresh = () => { 58 | this.props.pullToRefreshCallback?.(); 59 | this.setState({ refreshing: true }); 60 | setTimeout(() => this.setState({ refreshing: false }), 7000); 61 | }; 62 | 63 | refresh = () => this.setState({ refreshing: false, data: this.props.data }); 64 | 65 | onScrollBeginDrag = () => { 66 | Animated.spring(this.rowScale, { 67 | toValue: 5, 68 | tension: 20, 69 | useNativeDriver: true, 70 | }).start(); 71 | }; 72 | 73 | onScrollEndDrag = () => { 74 | Animated.spring(this.rowScale, { 75 | toValue: 1, 76 | tension: 20, 77 | useNativeDriver: true, 78 | }).start(); 79 | }; 80 | 81 | render() { 82 | const { 83 | renderItem, 84 | renderSeparator, 85 | pullToRefreshCallback, 86 | isRefreshing, 87 | isLoading, 88 | backgroundStyles, 89 | searchBarBackgroundStyles, 90 | onSearch, 91 | placeholder, 92 | searchTextInputStyle, 93 | showSearch, 94 | searchKey, 95 | isJelly, 96 | slide, 97 | useFuzzy, 98 | loadNext, 99 | refreshControlProps = {}, 100 | } = this.props; 101 | const { searchText } = this.state; 102 | const filteredData = useFuzzy 103 | ? fuzziedText({ ...this.props, searchText }) 104 | : filterText({ ...this.props, searchText }); 105 | 106 | const scaleY = !isJelly 107 | ? 1 108 | : this.rowScale.interpolate({ 109 | inputRange: [0, 5], 110 | outputRange: [1, 0.9], 111 | }); 112 | 113 | const jellyProps = isJelly 114 | ? { 115 | onScrollBeginDrag: this.onScrollBeginDrag, 116 | onScrollEndDrag: this.onScrollEndDrag, 117 | } 118 | : {}; 119 | 120 | const searchbar = ( 121 | 122 | (this.searchInput = c)} 124 | style={[styles.searchBar, searchTextInputStyle]} 125 | placeholder={placeholder} 126 | clearButtonMode="while-editing" 127 | placeholderTextColor="#919188" 128 | underlineColorAndroid="transparent" 129 | autoCapitalize="none" 130 | keyboardType="email-address" 131 | onChangeText={(t) => this.setState({ searchText: t })} 132 | value={searchText} 133 | maxLength={100} 134 | returnKeyType="search" 135 | onSubmitEditing={() => onSearch?.(this.state.searchText)} 136 | /> 137 | 138 | ); 139 | 140 | return ( 141 | 142 | {showSearch && !!searchKey.length && searchbar} 143 | {this.props.elementBetweenSearchAndList} 144 | No data available 148 | } 149 | scrollEventThrottle={16} 150 | {...this.props} 151 | onEndReached={() => { 152 | this.props.onEndReached?.(); 153 | loadNext?.(); 154 | }} 155 | {...jellyProps} 156 | refreshControl={ 157 | onSearch(searchText) : pullToRefreshCallback 162 | } 163 | /> 164 | } 165 | data={ 166 | loadNext ? [...filteredData, "loading-component"] : filteredData 167 | } 168 | renderItem={({ item, index, separators }) => { 169 | const translateX = 170 | slide == "none" 171 | ? 0 172 | : this.slide.interpolate({ 173 | inputRange: [0, 1], 174 | outputRange: [ 175 | (slide == "right" ? 1 : -1) * ((index + 1) * 500), 176 | 0, 177 | ], 178 | }); 179 | return ( 180 | 183 | {item === "loading-component" ? ( 184 | 185 | ) : ( 186 | renderItem({ item, index, separators }) 187 | )} 188 | 189 | ); 190 | }} 191 | style={styles.flatList} 192 | /> 193 | 194 | ); 195 | } 196 | } 197 | 198 | const styles = StyleSheet.create({ 199 | noData: { alignSelf: "center", textAlign: "center", marginTop: 20 }, 200 | searchBarContainer: { 201 | justifyContent: "center", 202 | padding: 10, 203 | backgroundColor: "#f2f2f2", 204 | width: "100%", 205 | }, 206 | searchBar: { 207 | borderRadius: 5, 208 | backgroundColor: "white", 209 | height: 38, 210 | fontSize: 15, 211 | width: "100%", 212 | paddingHorizontal: 10, 213 | }, 214 | container: { 215 | flex: 1, 216 | height: "100%", 217 | justifyContent: "center", 218 | alignItems: "center", 219 | width: "100%", 220 | }, 221 | defaultSeparator: { 222 | height: 1, 223 | width: "80%", 224 | alignSelf: "center", 225 | backgroundColor: "#f2f2f2", 226 | }, 227 | flatList: { height: "100%", width: "100%", backgroundColor: "transparent" }, 228 | }); 229 | 230 | export default CompleteFlatList; 231 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-complete-flatlist", 3 | "version": "2.0.19", 4 | "description": "An extension of React Native's Flatlist with search bar, highlighted search, pull to refresh, and etc is ready to use", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "pub": "npm publish --access=public" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/fattahmuhyiddeen/react-native-complete-flatlist.git" 13 | }, 14 | "keywords": [ 15 | "flatlist", 16 | "search", 17 | "bar", 18 | "searchbar", 19 | "list", 20 | "listview", 21 | "scroll", 22 | "listview with search bar", 23 | "flatlist with search bar", 24 | "listview with pull to refresh", 25 | "flatlist with pull to refresh", 26 | "highlight", 27 | "jelly", 28 | "pull to refresh" 29 | ], 30 | "author": "Fattah Muhyiddeen ", 31 | "license": "MIT", 32 | "bugs": { 33 | "url": "https://github.com/fattahmuhyiddeen/react-native-complete-flatlist/issues" 34 | }, 35 | "homepage": "https://github.com/fattahmuhyiddeen/react-native-complete-flatlist#readme", 36 | "devDependencies": { 37 | "mocha": "^5.0.0" 38 | }, 39 | "dependencies": { 40 | "fuse.js": "^6.6.2", 41 | "react-native-highlight-words": "git+https://github.com/fattahmuhyiddeen/react-native-highlight-words.git#master" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /utils/filterText.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Highlighter from 'react-native-highlight-words'; 3 | 4 | const filterText = ({data, searchKey, highlightColor, onSearch, searchText}) => { 5 | if (!searchText || !!onSearch) return data; 6 | 7 | const filteredData = []; 8 | for (const dt of data) { 9 | for (let s = 0; s < searchKey.length; s++) { 10 | const sk = searchKey[s]; 11 | const target = dt[sk]; 12 | if (!target) continue; 13 | 14 | if (target.toLowerCase().indexOf(searchText.toLowerCase()) !== -1) { 15 | if (!highlightColor) { 16 | filteredData.push(dt); 17 | break; 18 | } 19 | const row = {}; 20 | row.cleanData = dt; 21 | const keys = Object.keys(dt); 22 | for (const key of keys) { 23 | if (typeof dt[key] === 'string') { 24 | row[key] = ( 25 | 30 | ); 31 | } 32 | } 33 | filteredData.push(row); 34 | break; 35 | } 36 | } 37 | } 38 | return filteredData; 39 | }; 40 | 41 | export default filterText; 42 | -------------------------------------------------------------------------------- /utils/fuzzySearch.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Fuse from 'fuse.js'; 3 | import Highlighter from 'react-native-highlight-words'; 4 | 5 | const mapTurkishCharacters = str => { 6 | const charMap = { 7 | ş: 's', 8 | Ş: 'S', 9 | ğ: 'g', 10 | Ğ: 'G', 11 | ü: 'u', 12 | Ü: 'U', 13 | ö: 'o', 14 | Ö: 'O', 15 | ı: 'i', 16 | İ: 'I', 17 | ç: 'c', 18 | Ç: 'C', 19 | }; 20 | 21 | return str 22 | .split('') 23 | .map(char => charMap[char] || char) 24 | .join(''); 25 | }; 26 | 27 | const filterText = ({data, searchKey, highlightColor, onSearch, searchText}) => { 28 | if (!searchText || !!onSearch) return data; 29 | 30 | const processedSearchText = mapTurkishCharacters(searchText); 31 | 32 | const processedData = data.map(item => ({ 33 | ...item, 34 | _fuzzyData: mapTurkishCharacters(item[searchKey[0]]), // Assuming searchKey[0] is the primary field you're searching. 35 | })); 36 | 37 | // Setup Fuse.js options 38 | const fuseOptions = { 39 | shouldSort: true, 40 | threshold: 0.6, 41 | location: 0, 42 | distance: 100, 43 | maxPatternLength: 32, 44 | minMatchCharLength: 1, 45 | keys: ['_fuzzyData'], 46 | includeScore: true, 47 | }; 48 | 49 | // Create an instance of Fuse with the processed data and the defined options 50 | const fuse = new Fuse(processedData, fuseOptions); 51 | 52 | // Perform the search 53 | const results = fuse.search(processedSearchText); 54 | 55 | // Process the results for highlighting and other needs 56 | const filteredData = results.map(resultItem => { 57 | if (!highlightColor) return resultItem.item; 58 | 59 | const row = {}; 60 | row.cleanData = resultItem.item; 61 | const keys = Object.keys(resultItem.item); 62 | for (const key of keys) { 63 | if (typeof resultItem.item[key] === 'string') { 64 | row[key] = ( 65 | 70 | ); 71 | } 72 | } 73 | return row; 74 | }); 75 | 76 | return filteredData; 77 | }; 78 | 79 | export default filterText; 80 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | balanced-match@^1.0.0: 6 | version "1.0.2" 7 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" 8 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 9 | 10 | brace-expansion@^1.1.7: 11 | version "1.1.11" 12 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 13 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 14 | dependencies: 15 | balanced-match "^1.0.0" 16 | concat-map "0.0.1" 17 | 18 | browser-stdout@1.3.1: 19 | version "1.3.1" 20 | resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" 21 | integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== 22 | 23 | commander@2.15.1: 24 | version "2.15.1" 25 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" 26 | integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag== 27 | 28 | concat-map@0.0.1: 29 | version "0.0.1" 30 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 31 | integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== 32 | 33 | debug@3.1.0: 34 | version "3.1.0" 35 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" 36 | integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== 37 | dependencies: 38 | ms "2.0.0" 39 | 40 | diff@3.5.0: 41 | version "3.5.0" 42 | resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" 43 | integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== 44 | 45 | escape-string-regexp@1.0.5: 46 | version "1.0.5" 47 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 48 | integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== 49 | 50 | fs.realpath@^1.0.0: 51 | version "1.0.0" 52 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 53 | integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== 54 | 55 | fuse.js@^6.6.2: 56 | version "6.6.2" 57 | resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-6.6.2.tgz#fe463fed4b98c0226ac3da2856a415576dc9a111" 58 | integrity sha512-cJaJkxCCxC8qIIcPBF9yGxY0W/tVZS3uEISDxhYIdtk8OL93pe+6Zj7LjCqVV4dzbqcriOZ+kQ/NE4RXZHsIGA== 59 | 60 | glob@7.1.2: 61 | version "7.1.2" 62 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" 63 | integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== 64 | dependencies: 65 | fs.realpath "^1.0.0" 66 | inflight "^1.0.4" 67 | inherits "2" 68 | minimatch "^3.0.4" 69 | once "^1.3.0" 70 | path-is-absolute "^1.0.0" 71 | 72 | growl@1.10.5: 73 | version "1.10.5" 74 | resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" 75 | integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== 76 | 77 | has-flag@^3.0.0: 78 | version "3.0.0" 79 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 80 | integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== 81 | 82 | he@1.1.1: 83 | version "1.1.1" 84 | resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" 85 | integrity sha512-z/GDPjlRMNOa2XJiB4em8wJpuuBfrFOlYKTZxtpkdr1uPdibHI8rYA3MY0KDObpVyaes0e/aunid/t88ZI2EKA== 86 | 87 | highlight-words-core@^1.0.3: 88 | version "1.2.2" 89 | resolved "https://registry.yarnpkg.com/highlight-words-core/-/highlight-words-core-1.2.2.tgz#1eff6d7d9f0a22f155042a00791237791b1eeaaa" 90 | integrity sha512-BXUKIkUuh6cmmxzi5OIbUJxrG8OAk2MqoL1DtO3Wo9D2faJg2ph5ntyuQeLqaHJmzER6H5tllCDA9ZnNe9BVGg== 91 | 92 | inflight@^1.0.4: 93 | version "1.0.6" 94 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 95 | integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== 96 | dependencies: 97 | once "^1.3.0" 98 | wrappy "1" 99 | 100 | inherits@2: 101 | version "2.0.4" 102 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 103 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 104 | 105 | "js-tokens@^3.0.0 || ^4.0.0": 106 | version "4.0.0" 107 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 108 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== 109 | 110 | loose-envify@^1.4.0: 111 | version "1.4.0" 112 | resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" 113 | integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== 114 | dependencies: 115 | js-tokens "^3.0.0 || ^4.0.0" 116 | 117 | minimatch@3.0.4: 118 | version "3.0.4" 119 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 120 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 121 | dependencies: 122 | brace-expansion "^1.1.7" 123 | 124 | minimatch@^3.0.4: 125 | version "3.1.2" 126 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" 127 | integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== 128 | dependencies: 129 | brace-expansion "^1.1.7" 130 | 131 | minimist@0.0.8: 132 | version "0.0.8" 133 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 134 | integrity sha512-miQKw5Hv4NS1Psg2517mV4e4dYNaO3++hjAvLOAzKqZ61rH8NS1SK+vbfBWZ5PY/Me/bEWhUwqMghEW5Fb9T7Q== 135 | 136 | mkdirp@0.5.1: 137 | version "0.5.1" 138 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 139 | integrity sha512-SknJC52obPfGQPnjIkXbmA6+5H15E+fR+E4iR2oQ3zzCLbd7/ONua69R/Gw7AgkTLsRG+r5fzksYwWe1AgTyWA== 140 | dependencies: 141 | minimist "0.0.8" 142 | 143 | mocha@^5.0.0: 144 | version "5.2.0" 145 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.2.0.tgz#6d8ae508f59167f940f2b5b3c4a612ae50c90ae6" 146 | integrity sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ== 147 | dependencies: 148 | browser-stdout "1.3.1" 149 | commander "2.15.1" 150 | debug "3.1.0" 151 | diff "3.5.0" 152 | escape-string-regexp "1.0.5" 153 | glob "7.1.2" 154 | growl "1.10.5" 155 | he "1.1.1" 156 | minimatch "3.0.4" 157 | mkdirp "0.5.1" 158 | supports-color "5.4.0" 159 | 160 | ms@2.0.0: 161 | version "2.0.0" 162 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 163 | integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== 164 | 165 | object-assign@^4.1.1: 166 | version "4.1.1" 167 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 168 | integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== 169 | 170 | once@^1.3.0: 171 | version "1.4.0" 172 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 173 | integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== 174 | dependencies: 175 | wrappy "1" 176 | 177 | path-is-absolute@^1.0.0: 178 | version "1.0.1" 179 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 180 | integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== 181 | 182 | prop-types@^15.5.7: 183 | version "15.8.1" 184 | resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" 185 | integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== 186 | dependencies: 187 | loose-envify "^1.4.0" 188 | object-assign "^4.1.1" 189 | react-is "^16.13.1" 190 | 191 | react-is@^16.13.1: 192 | version "16.13.1" 193 | resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" 194 | integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== 195 | 196 | react-native-highlight-words@^1.0.1: 197 | version "1.0.1" 198 | resolved "https://registry.yarnpkg.com/react-native-highlight-words/-/react-native-highlight-words-1.0.1.tgz#d998f8eb88765820367c6e8a12e1392df7fd58c7" 199 | integrity sha512-cza6kbXeX2bWIwog6iatcMoWX6xogWvSKK1esCA7EQnQ/2hmqvdYGdGjvzTwLXyLmcBRySgreARNNKuDrKh7dg== 200 | dependencies: 201 | highlight-words-core "^1.0.3" 202 | prop-types "^15.5.7" 203 | 204 | supports-color@5.4.0: 205 | version "5.4.0" 206 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" 207 | integrity sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w== 208 | dependencies: 209 | has-flag "^3.0.0" 210 | 211 | wrappy@1: 212 | version "1.0.2" 213 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 214 | integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== 215 | --------------------------------------------------------------------------------