├── .gitignore ├── .prettierrc ├── .vscode └── settings.json ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── example ├── .buckconfig ├── .bundle │ └── config ├── .eslintrc.js ├── .gitignore ├── .node-version ├── .prettierrc.js ├── .ruby-version ├── .watchmanconfig ├── App.tsx ├── Gemfile ├── Gemfile.lock ├── __tests__ │ └── App-test.tsx ├── android │ ├── app │ │ ├── build.gradle │ │ ├── debug.keystore │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ ├── MainActivity.kt │ │ │ │ └── MainApplication.kt │ │ │ └── res │ │ │ ├── drawable │ │ │ └── rn_edit_text_material.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ └── values │ │ │ ├── strings.xml │ │ │ └── styles.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle ├── app.json ├── babel.config.js ├── index.js ├── ios │ ├── .xcode.env │ ├── Podfile │ ├── Podfile.lock │ ├── example.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── example.xcscheme │ ├── example.xcworkspace │ │ └── contents.xcworkspacedata │ ├── example │ │ ├── AppDelegate.h │ │ ├── AppDelegate.mm │ │ ├── Images.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── Info.plist │ │ ├── LaunchScreen.storyboard │ │ ├── PrivacyInfo.xcprivacy │ │ └── main.m │ └── exampleTests │ │ ├── Info.plist │ │ └── exampleTests.m ├── metro.config.js ├── package-lock.json ├── package.json └── tsconfig.json ├── package-lock.json ├── package.json ├── src ├── DragListContext.tsx └── index.tsx └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | 106 | node_modules/ 107 | lib/ -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 2, 3 | "useTabs": false, 4 | "trailingComma": "es5", 5 | "arrowParens": "avoid" 6 | } 7 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### Changelog 2 | 3 | All notable changes to this project will be documented in this file. Dates are displayed in UTC. 4 | 5 | Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). 6 | 7 | #### [3.9.5](https://github.com/fivecar/react-native-draglist/compare/3.9.4...3.9.5) 8 | 9 | - fix: #95 Re-render on iOS after reordering [`#97`](https://github.com/fivecar/react-native-draglist/pull/97) 10 | - chore: more README tweaks for clarity [`#92`](https://github.com/fivecar/react-native-draglist/pull/92) 11 | - chore: update README to reorder sections [`#91`](https://github.com/fivecar/react-native-draglist/pull/91) 12 | - fix: #95 Re-render on iOS after reordering (#97) [`#76`](https://github.com/fivecar/react-native-draglist/issues/76) 13 | 14 | #### [3.9.4](https://github.com/fivecar/react-native-draglist/compare/3.9.3...3.9.4) 15 | 16 | > 8 March 2025 17 | 18 | - fix: Fool WDYR into not complaining about rerender [`#89`](https://github.com/fivecar/react-native-draglist/pull/89) 19 | - Release 3.9.4 [`1aa44e2`](https://github.com/fivecar/react-native-draglist/commit/1aa44e297c922665a178c03dddb12b73988df5b9) 20 | 21 | #### [3.9.3](https://github.com/fivecar/react-native-draglist/compare/3.9.2...3.9.3) 22 | 23 | > 8 March 2025 24 | 25 | - fix: Need to re-render when data changes [`#88`](https://github.com/fivecar/react-native-draglist/pull/88) 26 | - Release 3.9.3 [`58323ed`](https://github.com/fivecar/react-native-draglist/commit/58323edb68f4384a94ea40222929ce1199046afe) 27 | 28 | #### [3.9.2](https://github.com/fivecar/react-native-draglist/compare/3.9.1...3.9.2) 29 | 30 | > 8 March 2025 31 | 32 | - chore: Update contribution docs [`#87`](https://github.com/fivecar/react-native-draglist/pull/87) 33 | - chore: Refactor pan handlers [`#86`](https://github.com/fivecar/react-native-draglist/pull/86) 34 | - fix: #76 Sync ref state synchronously with render [`#85`](https://github.com/fivecar/react-native-draglist/pull/85) 35 | - fix: #76 Clean up cell rendering to reduce re-renders [`#84`](https://github.com/fivecar/react-native-draglist/pull/84) 36 | - Release 3.9.2 [`70aa28c`](https://github.com/fivecar/react-native-draglist/commit/70aa28c9096a91c0f9785675e52e7b3f6b77cdb4) 37 | 38 | #### [3.9.1](https://github.com/fivecar/react-native-draglist/compare/3.9.0...3.9.1) 39 | 40 | > 8 March 2025 41 | 42 | - fix: #81 Patch Android for disappearing item [`#83`](https://github.com/fivecar/react-native-draglist/pull/83) 43 | - chore: Upgrade Android example app's RN [`#82`](https://github.com/fivecar/react-native-draglist/pull/82) 44 | - fix: #81 Patch Android for disappearing item (#83) [`#81`](https://github.com/fivecar/react-native-draglist/issues/81) 45 | - Release 3.9.1 [`206706c`](https://github.com/fivecar/react-native-draglist/commit/206706cbb841a6ad09c5720ebf2a08bbdc85402a) 46 | 47 | #### [3.9.0](https://github.com/fivecar/react-native-draglist/compare/3.8.2...3.9.0) 48 | 49 | > 6 March 2025 50 | 51 | - fix: #76 Remove flicker on reorder [`#80`](https://github.com/fivecar/react-native-draglist/pull/80) 52 | - feat: #78 Keep `onHoverChanged` up to date [`#79`](https://github.com/fivecar/react-native-draglist/pull/79) 53 | - chore: fix README.md type in example code [`#77`](https://github.com/fivecar/react-native-draglist/pull/77) 54 | - Release 3.9.0 [`97c4f95`](https://github.com/fivecar/react-native-draglist/commit/97c4f95597f069c7bd7f764b74d1fee9883660da) 55 | 56 | #### [3.8.2](https://github.com/fivecar/react-native-draglist/compare/3.8.1...3.8.2) 57 | 58 | > 16 January 2025 59 | 60 | - fix: #70 Timing fix for async measure call [`#73`](https://github.com/fivecar/react-native-draglist/pull/73) 61 | - fix: #70 Timing fix for async measure call (#73) [`#70`](https://github.com/fivecar/react-native-draglist/issues/70) 62 | - Release 3.8.2 [`8c52785`](https://github.com/fivecar/react-native-draglist/commit/8c5278530ac19644e67166a705f20a1f547ba77c) 63 | 64 | #### [3.8.1](https://github.com/fivecar/react-native-draglist/compare/3.8.0...3.8.1) 65 | 66 | > 14 January 2025 67 | 68 | - fix: #68 - forwardRef declaration [`#71`](https://github.com/fivecar/react-native-draglist/pull/71) 69 | - Release 3.8.1 [`155126c`](https://github.com/fivecar/react-native-draglist/commit/155126cefe9f8020f542a4d93ee5de94ad735a45) 70 | 71 | #### [3.8.0](https://github.com/fivecar/react-native-draglist/compare/3.7.0...3.8.0) 72 | 73 | > 1 December 2024 74 | 75 | - feat: #40 Allow custom FlatList prop [`#62`](https://github.com/fivecar/react-native-draglist/pull/62) 76 | - Release 3.8.0 [`a4af02f`](https://github.com/fivecar/react-native-draglist/commit/a4af02fec803b75508a8136e35eca564bbb1d644) 77 | 78 | #### [3.7.0](https://github.com/fivecar/react-native-draglist/compare/3.6.3...3.7.0) 79 | 80 | > 30 November 2024 81 | 82 | - fix: maintain elevation on all active items [`#61`](https://github.com/fivecar/react-native-draglist/pull/61) 83 | - fix: Use center of active item for placement [`#60`](https://github.com/fivecar/react-native-draglist/pull/60) 84 | - feat: Autoscroll without needing additional movement [`#59`](https://github.com/fivecar/react-native-draglist/pull/59) 85 | - fix: #25 - scroll equally fast downward [`#58`](https://github.com/fivecar/react-native-draglist/pull/58) 86 | - fix: #50 - pan correctly relative to touch position [`#57`](https://github.com/fivecar/react-native-draglist/pull/57) 87 | - feat: Include Bart's article for more details [`#56`](https://github.com/fivecar/react-native-draglist/pull/56) 88 | - Release 3.7.0 [`1907410`](https://github.com/fivecar/react-native-draglist/commit/1907410cd9ec77ba0eea8e6df79d4dd4c0e1e6f9) 89 | 90 | #### [3.6.3](https://github.com/fivecar/react-native-draglist/compare/3.6.2...3.6.3) 91 | 92 | > 29 November 2024 93 | 94 | - fix: #53 - Active item animation rendering for RN 0.76.3 [`#54`](https://github.com/fivecar/react-native-draglist/pull/54) 95 | - Release 3.6.3 [`0e33eff`](https://github.com/fivecar/react-native-draglist/commit/0e33eff0942c3ba9680029adc4b780ec54e1ae0f) 96 | 97 | #### [3.6.2](https://github.com/fivecar/react-native-draglist/compare/3.6.1...3.6.2) 98 | 99 | > 17 August 2024 100 | 101 | - fix: #45 - adds index to `keyExtractor` [`#48`](https://github.com/fivecar/react-native-draglist/pull/48) 102 | - fix: #40 - remove LayoutAnimation related code [`#47`](https://github.com/fivecar/react-native-draglist/pull/47) 103 | - Release 3.6.2 [`4925cdb`](https://github.com/fivecar/react-native-draglist/commit/4925cdbdba202cd9d6abe10b95cb3e81685996ba) 104 | 105 | #### [3.6.1](https://github.com/fivecar/react-native-draglist/compare/3.6.0...3.6.1) 106 | 107 | > 10 July 2024 108 | 109 | - fix: Fix position of item being dragged [`#42`](https://github.com/fivecar/react-native-draglist/pull/42) 110 | - fix: Remove old reference to horizontal lists [`#43`](https://github.com/fivecar/react-native-draglist/pull/43) 111 | - Release 3.6.1 [`9d61472`](https://github.com/fivecar/react-native-draglist/commit/9d61472059358cf2d657f6a35f6eee2e12022c34) 112 | 113 | #### [3.6.0](https://github.com/fivecar/react-native-draglist/compare/3.5.1...3.6.0) 114 | 115 | > 17 March 2024 116 | 117 | - Revert "fix: remove typescript bypass on forwardRef (#31)" [`#37`](https://github.com/fivecar/react-native-draglist/pull/37) 118 | - feat: make scrolling axis-generic and update README.md [`#36`](https://github.com/fivecar/react-native-draglist/pull/36) 119 | - feat: Add simple support for horizontal lists [`#33`](https://github.com/fivecar/react-native-draglist/pull/33) 120 | - fix: remove typescript bypass on forwardRef [`#31`](https://github.com/fivecar/react-native-draglist/pull/31) 121 | - fix: Use measure instead of measureInWindow to get screen coordinate [`#32`](https://github.com/fivecar/react-native-draglist/pull/32) 122 | - fix: block rapid reordering from using stale indices [`#35`](https://github.com/fivecar/react-native-draglist/pull/35) 123 | - fix: attempt to export generic types differently [`#21`](https://github.com/fivecar/react-native-draglist/pull/21) 124 | - events can receive a void callback [`#20`](https://github.com/fivecar/react-native-draglist/pull/20) 125 | - Release 3.6.0 [`f124e40`](https://github.com/fivecar/react-native-draglist/commit/f124e4065ddaa830366ed0631ebaae6ac9f3e535) 126 | 127 | #### [3.5.1](https://github.com/fivecar/react-native-draglist/compare/3.5.0...3.5.1) 128 | 129 | > 21 June 2023 130 | 131 | - Release 3.5.1 [`038b630`](https://github.com/fivecar/react-native-draglist/commit/038b630fdc7e302ebb2425d5b99f370a7579a17e) 132 | - fix: update y position upon panResponderGrant to capture list position on screen [`410451b`](https://github.com/fivecar/react-native-draglist/commit/410451b94107add793a033d3943435e95afe3d9a) 133 | - fix: update y position upon panResponderGrant in order to capture new list position [`e582036`](https://github.com/fivecar/react-native-draglist/commit/e5820361d173db5d9da94ec31d0ac88f8094247b) 134 | 135 | #### [3.5.0](https://github.com/fivecar/react-native-draglist/compare/3.4.0...3.5.0) 136 | 137 | > 16 June 2023 138 | 139 | - Release 3.5.0 [`4811d7b`](https://github.com/fivecar/react-native-draglist/commit/4811d7b8b155681af559d9d81dda5e60316a6c41) 140 | - feat: rename onStartDrag to onDragStart and onEndDrag to onDragEnd #17 [`885d6d5`](https://github.com/fivecar/react-native-draglist/commit/885d6d540c90c30513d4b362275d0f84d0ddd3ad) 141 | - feat: rename onStartDrag to onDragStart and onEndDrag to onDragEnd #17 [`4438944`](https://github.com/fivecar/react-native-draglist/commit/4438944f751bf9c8c2d4c071a41b41c50672f3dd) 142 | 143 | #### [3.4.0](https://github.com/fivecar/react-native-draglist/compare/3.3.0...3.4.0) 144 | 145 | > 6 June 2023 146 | 147 | - Release 3.4.0 [`d77ac6a`](https://github.com/fivecar/react-native-draglist/commit/d77ac6aaaf5400ca6b119438c21c49b9e3f40503) 148 | - feat: provide forwardRef for callers to access the underlying FlatList [`3b8f96d`](https://github.com/fivecar/react-native-draglist/commit/3b8f96dce0b8e1d5e3265e18069130f521c07581) 149 | - feat: provide forwardRef for callers to access the underlying FlatList [`5d5db67`](https://github.com/fivecar/react-native-draglist/commit/5d5db67774eb3e0d270c32ae68940d1e09d2b61e) 150 | 151 | #### [3.3.0](https://github.com/fivecar/react-native-draglist/compare/3.2.0...3.3.0) 152 | 153 | > 10 May 2023 154 | 155 | - Release 3.3.0 [`491a44e`](https://github.com/fivecar/react-native-draglist/commit/491a44e7de756589775803ed24c3dc07e3699dd0) 156 | - feat: add onHoverChanged event [`0bc5e86`](https://github.com/fivecar/react-native-draglist/commit/0bc5e86c9d5f5fdd22b336b2a27e895f4937eacc) 157 | - feat: add onHoverChanged event [`66c96d0`](https://github.com/fivecar/react-native-draglist/commit/66c96d0fcebe14724f04c4792244582d48d07f35) 158 | 159 | #### [3.2.0](https://github.com/fivecar/react-native-draglist/compare/3.1.3...3.2.0) 160 | 161 | > 31 March 2023 162 | 163 | - Release 3.2.0 [`0e81828`](https://github.com/fivecar/react-native-draglist/commit/0e818287b3272c16d6ef58ee29552deb67b797f6) 164 | - feat: create GitHub releases for each release [`3fe197b`](https://github.com/fivecar/react-native-draglist/commit/3fe197bba48702ec71794e3912b340c39421a969) 165 | 166 | #### [3.1.3](https://github.com/fivecar/react-native-draglist/compare/3.1.2...3.1.3) 167 | 168 | > 31 March 2023 169 | 170 | - Release 3.1.3 [`8f19261`](https://github.com/fivecar/react-native-draglist/commit/8f19261ccc044b7484fcbe5443223945b94e24d3) 171 | - fix: using github release and auto-changelog [`64fccd6`](https://github.com/fivecar/react-native-draglist/commit/64fccd6196597ccbd08f58302d3a66c6b0c4277c) 172 | 173 | #### [3.1.2](https://github.com/fivecar/react-native-draglist/compare/3.1.1...3.1.2) 174 | 175 | > 31 March 2023 176 | 177 | - fix: another attempt to generate reasonable changelogs [`#9`](https://github.com/fivecar/react-native-draglist/issues/9) 178 | - Release 3.1.2 [`a241351`](https://github.com/fivecar/react-native-draglist/commit/a2413514ee86a8e52db104653b528c32a229f467) 179 | 180 | #### [3.1.1](https://github.com/fivecar/react-native-draglist/compare/3.1.0...3.1.1) 181 | 182 | > 31 March 2023 183 | 184 | - fix (#9): configure release-it to generate changelog [`1c32b88`](https://github.com/fivecar/react-native-draglist/commit/1c32b8877db53f3f6c642554da8f01da80620652) 185 | - Release 3.1.1 [`c758f63`](https://github.com/fivecar/react-native-draglist/commit/c758f63e967c28b3b77ff8e8051de99e4a263074) 186 | 187 | #### [3.1.0](https://github.com/fivecar/react-native-draglist/compare/3.0.5...3.1.0) 188 | 189 | > 31 March 2023 190 | 191 | - fix: attempt to add auto-changelog to track releases [`b12c049`](https://github.com/fivecar/react-native-draglist/commit/b12c04931294d388c261704c7c55b02300095c1d) 192 | - fix: deactivate item when press happens without drag [`c6ad49f`](https://github.com/fivecar/react-native-draglist/commit/c6ad49f3cb86f969740cc2fc9d9d57f94a1490c1) 193 | - Release 3.1.0 [`d15f936`](https://github.com/fivecar/react-native-draglist/commit/d15f936591028cd441b197274b62dc113a6fbc1f) 194 | 195 | #### [3.0.5](https://github.com/fivecar/react-native-draglist/compare/3.0.4...3.0.5) 196 | 197 | > 20 March 2023 198 | 199 | - fix: reduce re-renders by useCallback for callbacks [`#8`](https://github.com/fivecar/react-native-draglist/pull/8) 200 | - Release 3.0.5 [`cbdc127`](https://github.com/fivecar/react-native-draglist/commit/cbdc127f783cc9e4d14b050e7cbb7707cf028551) 201 | - fix: optimize re-renders during drag [`6a9818a`](https://github.com/fivecar/react-native-draglist/commit/6a9818a51d8865ffc43a57ed55af08c6f23f7114) 202 | - Release 3.0.4 [`ff66585`](https://github.com/fivecar/react-native-draglist/commit/ff66585609095713b5965c92e8f769132e6afbe8) 203 | 204 | #### [3.0.4](https://github.com/fivecar/react-native-draglist/compare/3.0.2...3.0.4) 205 | 206 | > 20 March 2023 207 | 208 | - docs: add bling to readme [`#7`](https://github.com/fivecar/react-native-draglist/pull/7) 209 | - fix: reduce re-renders by useCallback for callbacks [`ad9c996`](https://github.com/fivecar/react-native-draglist/commit/ad9c9961c4d8f41c10cc79664ba96ec94ccb2f82) 210 | - Release 3.0.4 [`e1dd3ae`](https://github.com/fivecar/react-native-draglist/commit/e1dd3aea9bbc494f6db9463ba2a1b2a7c4f1eec9) 211 | 212 | #### [3.0.2](https://github.com/fivecar/react-native-draglist/compare/3.0.1...3.0.2) 213 | 214 | > 15 February 2023 215 | 216 | - Disable FlatList scroll while dragging [`#6`](https://github.com/fivecar/react-native-draglist/pull/6) 217 | - docs: update README.md to prefer Android example for speed [`4fdf75a`](https://github.com/fivecar/react-native-draglist/commit/4fdf75ae1436961427cfec319bff5456d81ff019) 218 | - Release 3.0.2 [`1a84b46`](https://github.com/fivecar/react-native-draglist/commit/1a84b468ddc59597b9f864e14b886a89141e5bb2) 219 | 220 | ### [3.0.1](https://github.com/fivecar/react-native-draglist/compare/2.1.0...3.0.1) 221 | 222 | > 23 January 2023 223 | 224 | - fix: Android now works [`#5`](https://github.com/fivecar/react-native-draglist/pull/5) 225 | - Release 3.0.1 [`17f4bd5`](https://github.com/fivecar/react-native-draglist/commit/17f4bd5966cd8d2aebd397f6a0b5a3705eb37f4a) 226 | - docs: recommend onPressIn to call onStartDrag [`723788e`](https://github.com/fivecar/react-native-draglist/commit/723788e542978db5fefab1b896bdc135df30de96) 227 | 228 | #### [2.1.0](https://github.com/fivecar/react-native-draglist/compare/2.0.0...2.1.0) 229 | 230 | > 30 December 2022 231 | 232 | - Release 2.1.0 [`cf27079`](https://github.com/fivecar/react-native-draglist/commit/cf27079de786a85d82de618715c97fef8bf468d4) 233 | - Prevent slide animation after release [`4bbba09`](https://github.com/fivecar/react-native-draglist/commit/4bbba095d33ad67f085e24c7393be1a102e83ff8) 234 | - Prevent slide animation after release [`084be87`](https://github.com/fivecar/react-native-draglist/commit/084be871457da205bc6a5b6cdf8f3319c6c8621d) 235 | 236 | ### [2.0.0](https://github.com/fivecar/react-native-draglist/compare/1.1.0...2.0.0) 237 | 238 | > 15 December 2022 239 | 240 | - fix: corrected use of onReordered with useRef to fix #2 [`#2`](https://github.com/fivecar/react-native-draglist/issues/2) 241 | - Initial example building [`a528f08`](https://github.com/fivecar/react-native-draglist/commit/a528f0813409568478b24d9a2442710234a81d03) 242 | - Fixed inclusion of parent in example project [`e244f39`](https://github.com/fivecar/react-native-draglist/commit/e244f39374f1227726efee93b03ff09b7242ce96) 243 | - Release 2.0.0 [`cab4ccc`](https://github.com/fivecar/react-native-draglist/commit/cab4ccc3e3646c4abd378dea7b055b8d7b60f0f4) 244 | 245 | #### 1.1.0 246 | 247 | > 7 December 2022 248 | 249 | - fix: updated distribution to use release-it and microbundle [`3fd393d`](https://github.com/fivecar/react-native-draglist/commit/3fd393d95b18926e6c9f5f475120c0c681eb9c86) 250 | - Initial commit [`b963f18`](https://github.com/fivecar/react-native-draglist/commit/b963f18f097d5edd7792045198ab50a7ab0ab208) 251 | - Update to package correctly, and also filled out README [`26f2ae7`](https://github.com/fivecar/react-native-draglist/commit/26f2ae7d9b7ffed695cad4bdeedcb37418199bcc) 252 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Welcome 2 | 3 | Thank you for being willing to contribute to this project. To make edits and verify what 4 | you've done is correct/ok, please use the example project (in `/example`) to validate your changes. 5 | 6 | ```console 7 | npm install 8 | cd example 9 | npm install 10 | npm run android # or `npm run ios`, which takes longer to build 11 | ``` 12 | 13 | Note that whenever you make changes to code in the package itself (e.g. `index.tsx`), you'll need to 14 | update the example app to use it: 15 | 16 | ```console 17 | npm run build 18 | cd example 19 | npm i .. # This reinstalls the stuff you just built into `/dist` 20 | npm run android 21 | npm run ios 22 | ``` 23 | 24 | ## Validation 25 | I've unfortunately had no time to write tests for this, nor do I have the expertise to know how to 26 | test panResponder stuff correctly. So if you can believe it, all changes need to be manually tested 27 | in this package. 28 | 29 | ### Test Cases 30 | 31 | **You must test on both Android and iOS!** Annoyingly, the native implementations of lists and 32 | animations are different enough between the platforms that we often find one OS works great while 33 | the other goes janky/wonky. 34 | 35 | When testing in the example app, please consider at least the following: 36 | - Dragging items in the short list. This is the basic case. 37 | - Beginning to drag an item, but then placing it back where you started. 38 | - Dragging items in the long, scrolling list. 39 | - Dragging items in the scrolling list beyond its bottom or top extent to test auto-scrolling. 40 | - Tapping "Scroll to Top" to make sure forwardRefs aren't broken. 41 | - Dragging in the horizontal list. 42 | 43 | ## Thank You! 44 | I will try to be active on PRs and issues to help contributors as much as possible. Thanks! -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 fivecar 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 | 2 | # react-native-draglist 3 | 4 | [![npm package][npm-img]][npm-url] 5 | [![Downloads][downloads-img]][downloads-url] 6 | [![Issues][issues-img]][issues-url] 7 | 8 | FlatList that can be reordered by dragging its items 9 | 10 | ![show_me_reordering](https://user-images.githubusercontent.com/39933441/203197020-eb409b97-e108-4d9b-8ee4-684ae238b65b.gif) 11 | 12 | ## Why Does This Exist At All? 13 | 14 | > Given [react-native-draggable-flatlist](https://github.com/computerjazz/react-native-draggable-flatlist/), 15 | > why is there also this package? 16 | 17 | Great question. `react-native-draggable-flatlist` has silky-smooth animations, contains dozens of code files, and even manipulates internal data structures in [react-native-reanimated](https://github.com/software-mansion/react-native-reanimated) to make the animations work. You should absolutely use, and prefer, `react-native-draggable-flatlist`, if it works for you. 18 | 19 | `react-native-draglist` exists because `react-native-reanimated`, which `react-native-draggable-flatlist` depends on, randomly hangs and crashes apps through a variety of [issues](https://github.com/software-mansion/react-native-reanimated/issues), several of which have not been fixed despite several major "stable" releases. Furthermore, the hangs and crashes are both frequent and hard to reliably reproduce, making their timely resolution unlikely. 20 | 21 | ## What Is `react-native-draglist` 22 | This package is a basic version of `react-native-draggable-flatlist` without dependencies on anything except `react` and `react-native`. Specifically, it is deliberately built to avoid `react-native-reanimated` and its hanging/crashing issues. 23 | 24 | It is limited in that it does not animate as smoothly (though it does `useNativeDriver`). It supports both vertical and horizontal lists. 25 | 26 | # Installation 27 | With no dependencies outside of `react-native` and `react`, this package installs easily: 28 | ``` 29 | npm install react-native-draglist 30 | ``` 31 | or 32 | ``` 33 | yarn add react-native-draglist 34 | ``` 35 | 36 | # Use 37 | 38 | ## Typical Flow 39 | 1. Set up `DragList` much like you do any `FlatList`, except with a `renderItem` that calls `onDragStart` at the appropriate time and `onDragEnd` in `onPressOut`. 40 | 2. When `onReordered` gets called, update the ordering of `data`. 41 | 42 | That's basically it. 43 | 44 | ## Show Me The Code 45 | 46 | ```TSX 47 | import React, {useState} from 'react'; 48 | import {StyleSheet, Text, TouchableOpacity, View} from 'react-native'; 49 | import DragList, {DragListRenderItemInfo} from 'react-native-draglist'; 50 | 51 | const SOUND_OF_SILENCE = ['hello', 'darkness', 'my', 'old', 'friend']; 52 | 53 | export default function DraggableLyrics() { 54 | const [data, setData] = useState(SOUND_OF_SILENCE); 55 | 56 | function keyExtractor(str: string, _index: number) { 57 | return str; 58 | } 59 | 60 | function renderItem(info: DragListRenderItemInfo) { 61 | const {item, onDragStart, onDragEnd, isActive} = info; 62 | 63 | return ( 64 | 68 | {item} 69 | 70 | ); 71 | } 72 | 73 | async function onReordered(fromIndex: number, toIndex: number) { 74 | const copy = [...data]; // Don't modify react data in-place 75 | const removed = copy.splice(fromIndex, 1); 76 | 77 | copy.splice(toIndex, 0, removed[0]); // Now insert at the new pos 78 | setData(copy); 79 | } 80 | 81 | return ( 82 | 88 | ); 89 | } 90 | ``` 91 | 92 | ## API 93 | 94 | All `FlatList` properties are supported, with the following extensions/modifications: 95 | - `renderItem` is now passed a `DragListRenderItemInfo`, which extends `ListRenderItemInfo` with these additional fields: 96 | 97 | |Field|Type|Note| 98 | |--|--|--| 99 | |`onDragStart`|`() => void`|Your item should call this function when you detect a drag starting (i.e. when the user wants to begin reordering the list). A common implementation is to have a drag handle on your item whose `onPressIn` calls `onDragStart`. Alternatively, you could have an `onLongPress` call this, or use any other mechanism that makes most sense for your UI. *DragList* will not start rendering items as being dragged until you call this. 100 | |`onDragEnd`|`() => void`|Your item should call this function when you detect a tap or drag ending. A common implementation is to have a drag handle whose `onPressOut` calls `onDragEnd`. If you don't call this during `onPressOut`, *DragList* will not realize your item is no longer active if the user taps but doesn't drag (because you will have called `onDragStart`, and yet *DragList* couldn't capture the pan responder from you because the user hasn't moved, thus it doesn't know when the user releases). 101 | |`isActive`|`boolean`|This is `true` iff the current item is actively being dragged by the user. This can be used to render the item differently while it's being dragged (e.g. less opacity, different background color, borders, etc). 102 | 103 | - `async onReordered(fromIndex: number, toIndex: number)` is called once the user drops a dragged item in its new position. This is *not called* if the user drops the item back in the spot it started. `DragList` will await this function and not reset its UI until it completes, so you can make modifications to the underlying data before the list resets its state. 104 | - `fromIndex` will be between `[0, data.length)` (that is, any valid index from the items you gave it). 105 | - `toIndex` reflects the position to which the item should be moved in the pre-modified `data`. It will never equal `fromIndex`. So, for instance, if `toIndex` is `0`, you should make `data[fromIndex]` the first element of `data`. **Note**: if the user drags the item to the very end of the list, `toIndex` will equal `data.length` (i.e. it will reference an index that is one beyond the end of the list -- the range of values is `[0, data.length]`). 106 | - `onHoverChanged(index: number)` (optional): called whenever an item being dragged changes its index in the list. Note this is only called when the item hasn't been dropped into its final (potentially new) index yet — it's called as the item hovers around various indices it could be dropped at. 107 | - `ref: React.RefObject>` (optional): You can optionally pass a ref, which DragList will tunnel through to the underlying FlatList (via `forwardRef`). This is useful, for instance, if you want to `scrollToIndex` yourself on the underlying list. 108 | - `CustomFlatList: typeof FlatList` (optional): You can pass any component that implements the same interface as `FlatList`. Note: the component needs to support all sorts of `FlatList` things (e.g. `ref`, `scrollToPos`, etc) — i.e. it needs to implement the whole `FlatList` interface, not be just a `React.ComponentType>`. 109 | 110 | ## Example Included 111 | To play with the list, you can run the example within `example/`: 112 | 113 | ```console 114 | npm install 115 | cd example 116 | npm install 117 | npm run android # or `npm run ios`, which takes longer to build 118 | ``` 119 | 120 | # FAQs 121 | 122 | ## How can I contribute? 123 | Thanks for being willing! Please see 124 | [CONTRIBUTING.md](https://github.com/fivecar/react-native-draglist/blob/main/CONTRIBUTING.md). I'd 125 | love your help. 126 | 127 | ## What about lists with multiple columns? 128 | This package makes no attempt to handle multi-column lists. I'm happy to look at PRs that attempt 129 | such things, but I suspect most attempts will be fraught with issues because the UX for dragging in 130 | a multi-column list isn't immediately obvious, especially when the underlying `FlatList` 131 | implementation can't be controlled from the outside. 132 | 133 | ## Do you have caveats? 134 | This package is implemented with probably 1/10th the files, and 1/20th the advanced concepts, as `react-native-draggable-flatlist`. The latter even directly modifies unpublished internal data structures of `react-native-reanimated`, so it's all sorts of advanced in ways that this package will never be. You should prefer, and default to, using `react-native-draggable-flatlist` unless its random hangs and crashes bother you. 135 | 136 | If you have suggestions, or better yet, PRs for how this package can be improved, [please connect via GitHub](https://github.com/fivecar/react-native-draglist/)! 137 | 138 | [downloads-img]:https://img.shields.io/npm/dt/react-native-draglist 139 | [downloads-url]:https://www.npmtrends.com/react-native-draglist 140 | [npm-img]:https://img.shields.io/npm/v/react-native-draglist 141 | [npm-url]:https://www.npmjs.com/package/react-native-draglist 142 | [issues-img]:https://img.shields.io/github/issues/fivecar/react-native-draglist 143 | [issues-url]:https://github.com/fivecar/ -------------------------------------------------------------------------------- /example/.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /example/.bundle/config: -------------------------------------------------------------------------------- 1 | BUNDLE_PATH: "vendor/bundle" 2 | BUNDLE_FORCE_RUBY_PLATFORM: 1 3 | -------------------------------------------------------------------------------- /example/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: '@react-native', 4 | }; 5 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | **/.xcode.env.local 24 | xcshareddata 25 | *.keystore 26 | !debug.keystore 27 | 28 | # Android/IntelliJ 29 | # 30 | build/ 31 | .idea 32 | .gradle 33 | local.properties 34 | *.iml 35 | *.hprof 36 | .cxx/ 37 | 38 | # node.js 39 | # 40 | node_modules/ 41 | npm-debug.log 42 | yarn-error.log 43 | 44 | # fastlane 45 | # 46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 47 | # screenshots whenever they are needed. 48 | # For more information about the recommended setup visit: 49 | # https://docs.fastlane.tools/best-practices/source-control/ 50 | 51 | **/fastlane/report.xml 52 | **/fastlane/Preview.html 53 | **/fastlane/screenshots 54 | **/fastlane/test_output 55 | 56 | # Bundle artifact 57 | *.jsbundle 58 | 59 | # Ruby / CocoaPods 60 | **/Pods/ 61 | /vendor/bundle/ 62 | 63 | # Temporary files created by Metro to check the health of the file watcher 64 | .metro-health-check* 65 | 66 | # testing 67 | /coverage 68 | 69 | # Yarn 70 | .yarn/* 71 | !.yarn/patches 72 | !.yarn/plugins 73 | !.yarn/releases 74 | !.yarn/sdks 75 | !.yarn/versions -------------------------------------------------------------------------------- /example/.node-version: -------------------------------------------------------------------------------- 1 | 16 2 | -------------------------------------------------------------------------------- /example/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | arrowParens: 'avoid', 3 | bracketSameLine: true, 4 | bracketSpacing: false, 5 | singleQuote: true, 6 | trailingComma: 'all', 7 | }; 8 | -------------------------------------------------------------------------------- /example/.ruby-version: -------------------------------------------------------------------------------- 1 | 2.7.5 2 | -------------------------------------------------------------------------------- /example/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /example/App.tsx: -------------------------------------------------------------------------------- 1 | import React, {useMemo, useState} from 'react'; 2 | import { 3 | Button, 4 | FlatList, 5 | StyleSheet, 6 | Text, 7 | TouchableOpacity, 8 | View, 9 | } from 'react-native'; 10 | import DragList, {DragListRenderItemInfo} from 'react-native-draglist'; 11 | 12 | const SOUND_OF_SILENCE = ['hello', 'darkness', 'my', 'old', 'friend']; 13 | 14 | export default function DraggableLyrics() { 15 | const [data, setData] = useState(SOUND_OF_SILENCE); 16 | const [scrollData, setScrollData] = useState( 17 | [8, 6, 7, 5, 3, 0, 9] 18 | .map(num => SOUND_OF_SILENCE.map(word => `${word}${num}`)) 19 | .flat(), 20 | ); 21 | const [horzData, setHorzData] = useState(['a', 'b', 'c', 'd', 'e', 'f', 'g']); 22 | const listRef = React.useRef | null>(null); 23 | const header = useMemo(() => { 24 | return ( 25 | 26 | Drag my header 27 | 28 | ); 29 | }, []); 30 | const footer = useMemo(() => { 31 | return ( 32 | 33 | Drag my footer 34 | 35 | ); 36 | }, []); 37 | 38 | function keyExtractor(str: string) { 39 | return str; 40 | } 41 | 42 | function renderItem(info: DragListRenderItemInfo) { 43 | const {item, onDragStart, onDragEnd, isActive} = info; 44 | 45 | return ( 46 | 51 | {item} 52 | 53 | ); 54 | } 55 | 56 | async function onReordered(fromIndex: number, toIndex: number) { 57 | const copy = [...data]; // Don't modify react data in-place 58 | const removed = copy.splice(fromIndex, 1); 59 | 60 | copy.splice(toIndex, 0, removed[0]); // Now insert at the new pos 61 | setData(copy); 62 | } 63 | 64 | async function onScrollReordered(fromIndex: number, toIndex: number) { 65 | const copy = [...scrollData]; // Don't modify react data in-place 66 | const removed = copy.splice(fromIndex, 1); 67 | 68 | copy.splice(toIndex, 0, removed[0]); // Now insert at the new pos 69 | setScrollData(copy); 70 | } 71 | 72 | async function onReorderedHorz(fromIndex: number, toIndex: number) { 73 | const copy = [...horzData]; // Don't modify react data in-place 74 | const removed = copy.splice(fromIndex, 1); 75 | 76 | copy.splice(toIndex, 0, removed[0]); // Now insert at the new pos 77 | setHorzData(copy); 78 | } 79 | 80 | return ( 81 | 82 | Basic List 83 | 89 | Auto-Scrolling List 90 | 100 |