|
| 1 | +diff --git a/node_modules/@react-navigation/native/lib/module/createMemoryHistory.js b/node_modules/@react-navigation/native/lib/module/createMemoryHistory.js |
| 2 | +index 16fdbef..bc2c96a 100644 |
| 3 | +--- a/node_modules/@react-navigation/native/lib/module/createMemoryHistory.js |
| 4 | ++++ b/node_modules/@react-navigation/native/lib/module/createMemoryHistory.js |
| 5 | +@@ -1,8 +1,23 @@ |
| 6 | + import { nanoid } from 'nanoid/non-secure'; |
| 7 | ++import { findFocusedRouteKey } from './findFocusedRouteKey'; |
| 8 | + export default function createMemoryHistory() { |
| 9 | + let index = 0; |
| 10 | + let items = []; |
| 11 | +- |
| 12 | ++ const log = () => { |
| 13 | ++ console.log(JSON.stringify({ |
| 14 | ++ index, |
| 15 | ++ indexGetter: history.index, |
| 16 | ++ items: items.map((item, i) => { |
| 17 | ++ var _item$state; |
| 18 | ++ return { |
| 19 | ++ selected: history.index === i ? '<<<<<<<' : undefined, |
| 20 | ++ path: item.path, |
| 21 | ++ id: item.id, |
| 22 | ++ state: ((_item$state = item.state) === null || _item$state === void 0 ? void 0 : _item$state.key) || null |
| 23 | ++ }; |
| 24 | ++ }) |
| 25 | ++ }, null, 4)); |
| 26 | ++ }; |
| 27 | + // Pending callbacks for `history.go(n)` |
| 28 | + // We might modify the callback stored if it was interrupted, so we have a ref to identify it |
| 29 | + const pending = []; |
| 30 | +@@ -16,6 +31,9 @@ export default function createMemoryHistory() { |
| 31 | + }); |
| 32 | + }; |
| 33 | + const history = { |
| 34 | ++ get items() { |
| 35 | ++ return items; |
| 36 | ++ }, |
| 37 | + get index() { |
| 38 | + var _window$history$state; |
| 39 | + // We store an id in the state instead of an index |
| 40 | +@@ -32,12 +50,13 @@ export default function createMemoryHistory() { |
| 41 | + }, |
| 42 | + backIndex(_ref) { |
| 43 | + let { |
| 44 | +- path |
| 45 | ++ path, |
| 46 | ++ state |
| 47 | + } = _ref; |
| 48 | + // We need to find the index from the element before current to get closest path to go back to |
| 49 | + for (let i = index - 1; i >= 0; i--) { |
| 50 | + const item = items[i]; |
| 51 | +- if (item.path === path) { |
| 52 | ++ if (item.path === path && findFocusedRouteKey(item.state) === findFocusedRouteKey(state)) { |
| 53 | + return i; |
| 54 | + } |
| 55 | + } |
| 56 | +@@ -68,7 +87,9 @@ export default function createMemoryHistory() { |
| 57 | + window.history.pushState({ |
| 58 | + id |
| 59 | + }, '', path); |
| 60 | ++ // log(); |
| 61 | + }, |
| 62 | ++ |
| 63 | + replace(_ref3) { |
| 64 | + var _window$history$state2; |
| 65 | + let { |
| 66 | +@@ -108,7 +129,9 @@ export default function createMemoryHistory() { |
| 67 | + window.history.replaceState({ |
| 68 | + id |
| 69 | + }, '', pathWithHash); |
| 70 | ++ // log(); |
| 71 | + }, |
| 72 | ++ |
| 73 | + // `history.go(n)` is asynchronous, there are couple of things to keep in mind: |
| 74 | + // - it won't do anything if we can't go `n` steps, the `popstate` event won't fire. |
| 75 | + // - each `history.go(n)` call will trigger a separate `popstate` event with correct location. |
| 76 | +@@ -175,20 +198,17 @@ export default function createMemoryHistory() { |
| 77 | + // But on Firefox, it seems to take much longer, around 50ms from our testing |
| 78 | + // We're using a hacky timeout since there doesn't seem to be way to know for sure |
| 79 | + const timer = setTimeout(() => { |
| 80 | +- const index = pending.findIndex(it => it.ref === done); |
| 81 | +- if (index > -1) { |
| 82 | +- pending[index].cb(); |
| 83 | +- pending.splice(index, 1); |
| 84 | ++ const foundIndex = pending.findIndex(it => it.ref === done); |
| 85 | ++ if (foundIndex > -1) { |
| 86 | ++ pending[foundIndex].cb(); |
| 87 | ++ pending.splice(foundIndex, 1); |
| 88 | + } |
| 89 | ++ index = this.index; |
| 90 | + }, 100); |
| 91 | + const onPopState = () => { |
| 92 | +- var _window$history$state3; |
| 93 | +- const id = (_window$history$state3 = window.history.state) === null || _window$history$state3 === void 0 ? void 0 : _window$history$state3.id; |
| 94 | +- const currentIndex = items.findIndex(item => item.id === id); |
| 95 | +- |
| 96 | + // Fix createMemoryHistory.index variable's value |
| 97 | + // as it may go out of sync when navigating in the browser. |
| 98 | +- index = Math.max(currentIndex, 0); |
| 99 | ++ index = this.index; |
| 100 | + const last = pending.pop(); |
| 101 | + window.removeEventListener('popstate', onPopState); |
| 102 | + last === null || last === void 0 ? void 0 : last.cb(); |
| 103 | +@@ -202,12 +222,17 @@ export default function createMemoryHistory() { |
| 104 | + // Here we normalize it so that only external changes (e.g. user pressing back/forward) trigger the listener |
| 105 | + listen(listener) { |
| 106 | + const onPopState = () => { |
| 107 | ++ // Fix createMemoryHistory.index variable's value |
| 108 | ++ // as it may go out of sync when navigating in the browser. |
| 109 | ++ index = this.index; |
| 110 | + if (pending.length) { |
| 111 | + // This was triggered by `history.go(n)`, we shouldn't call the listener |
| 112 | + return; |
| 113 | + } |
| 114 | + listener(); |
| 115 | ++ // log(); |
| 116 | + }; |
| 117 | ++ |
| 118 | + window.addEventListener('popstate', onPopState); |
| 119 | + return () => window.removeEventListener('popstate', onPopState); |
| 120 | + } |
| 121 | +diff --git a/node_modules/@react-navigation/native/lib/module/findFocusedRouteKey.js b/node_modules/@react-navigation/native/lib/module/findFocusedRouteKey.js |
| 122 | +new file mode 100644 |
| 123 | +index 0000000..16da117 |
| 124 | +--- /dev/null |
| 125 | ++++ b/node_modules/@react-navigation/native/lib/module/findFocusedRouteKey.js |
| 126 | +@@ -0,0 +1,7 @@ |
| 127 | ++import { findFocusedRoute } from '@react-navigation/core'; |
| 128 | ++export const findFocusedRouteKey = state => { |
| 129 | ++ var _findFocusedRoute; |
| 130 | ++ // @ts-ignore |
| 131 | ++ return (_findFocusedRoute = findFocusedRoute(state)) === null || _findFocusedRoute === void 0 ? void 0 : _findFocusedRoute.key; |
| 132 | ++}; |
| 133 | ++//# sourceMappingURL=findFocusedRouteKey.js.map |
| 134 | +\ No newline at end of file |
| 135 | +diff --git a/node_modules/@react-navigation/native/lib/module/useLinking.js b/node_modules/@react-navigation/native/lib/module/useLinking.js |
| 136 | +index 5bf2a88..a6d0670 100644 |
| 137 | +--- a/node_modules/@react-navigation/native/lib/module/useLinking.js |
| 138 | ++++ b/node_modules/@react-navigation/native/lib/module/useLinking.js |
| 139 | +@@ -2,6 +2,7 @@ import { findFocusedRoute, getActionFromState as getActionFromStateDefault, getP |
| 140 | + import isEqual from 'fast-deep-equal'; |
| 141 | + import * as React from 'react'; |
| 142 | + import createMemoryHistory from './createMemoryHistory'; |
| 143 | ++import { findFocusedRouteKey } from './findFocusedRouteKey'; |
| 144 | + import ServerContext from './ServerContext'; |
| 145 | + /** |
| 146 | + * Find the matching navigation state that changed between 2 navigation states |
| 147 | +@@ -60,6 +61,44 @@ const series = cb => { |
| 148 | + return callback; |
| 149 | + }; |
| 150 | + let linkingHandlers = []; |
| 151 | ++const getAllStateKeys = state => { |
| 152 | ++ let current = state; |
| 153 | ++ const keys = []; |
| 154 | ++ if (current.routes) { |
| 155 | ++ for (let route of current.routes) { |
| 156 | ++ keys.push(route.key); |
| 157 | ++ if (route.state) { |
| 158 | ++ // @ts-ignore |
| 159 | ++ keys.push(...getAllStateKeys(route.state)); |
| 160 | ++ } |
| 161 | ++ } |
| 162 | ++ } |
| 163 | ++ return keys; |
| 164 | ++}; |
| 165 | ++const getStaleHistoryDiff = (items, newState) => { |
| 166 | ++ const newStateKeys = getAllStateKeys(newState); |
| 167 | ++ for (let i = items.length - 1; i >= 0; i--) { |
| 168 | ++ const itemFocusedKey = findFocusedRouteKey(items[i].state); |
| 169 | ++ if (newStateKeys.includes(itemFocusedKey)) { |
| 170 | ++ return items.length - i - 1; |
| 171 | ++ } |
| 172 | ++ } |
| 173 | ++ return -1; |
| 174 | ++}; |
| 175 | ++const getHistoryDeltaByKeys = (focusedState, previousFocusedState) => { |
| 176 | ++ const focusedStateKeys = focusedState.routes.map(r => r.key); |
| 177 | ++ const previousFocusedStateKeys = previousFocusedState.routes.map(r => r.key); |
| 178 | ++ const minLength = Math.min(focusedStateKeys.length, previousFocusedStateKeys.length); |
| 179 | ++ let matchingKeys = 0; |
| 180 | ++ for (let i = 0; i < minLength; i++) { |
| 181 | ++ if (focusedStateKeys[i] === previousFocusedStateKeys[i]) { |
| 182 | ++ matchingKeys++; |
| 183 | ++ } else { |
| 184 | ++ break; |
| 185 | ++ } |
| 186 | ++ } |
| 187 | ++ return -(previousFocusedStateKeys.length - matchingKeys); |
| 188 | ++}; |
| 189 | + export default function useLinking(ref, _ref) { |
| 190 | + let { |
| 191 | + independent, |
| 192 | +@@ -251,6 +290,9 @@ export default function useLinking(ref, _ref) { |
| 193 | + // Otherwise it's likely a change triggered by `popstate` |
| 194 | + path !== pendingPath) { |
| 195 | + const historyDelta = (focusedState.history ? focusedState.history.length : focusedState.routes.length) - (previousFocusedState.history ? previousFocusedState.history.length : previousFocusedState.routes.length); |
| 196 | ++ |
| 197 | ++ // The historyDelta and historyDeltaByKeys may differ if the new state has an entry that didn't exist in previous state |
| 198 | ++ const historyDeltaByKeys = getHistoryDeltaByKeys(focusedState, previousFocusedState); |
| 199 | + if (historyDelta > 0) { |
| 200 | + // If history length is increased, we should pushState |
| 201 | + // Note that path might not actually change here, for example, drawer open should pushState |
| 202 | +@@ -262,34 +304,55 @@ export default function useLinking(ref, _ref) { |
| 203 | + // If history length is decreased, i.e. entries were removed, we want to go back |
| 204 | + |
| 205 | + const nextIndex = history.backIndex({ |
| 206 | +- path |
| 207 | ++ path, |
| 208 | ++ state |
| 209 | + }); |
| 210 | + const currentIndex = history.index; |
| 211 | + try { |
| 212 | + if (nextIndex !== -1 && nextIndex < currentIndex) { |
| 213 | + // An existing entry for this path exists and it's less than current index, go back to that |
| 214 | + await history.go(nextIndex - currentIndex); |
| 215 | ++ history.replace({ |
| 216 | ++ path, |
| 217 | ++ state |
| 218 | ++ }); |
| 219 | + } else { |
| 220 | + // We couldn't find an existing entry to go back to, so we'll go back by the delta |
| 221 | + // This won't be correct if multiple routes were pushed in one go before |
| 222 | + // Usually this shouldn't happen and this is a fallback for that |
| 223 | +- await history.go(historyDelta); |
| 224 | ++ await history.go(historyDeltaByKeys); |
| 225 | ++ if (historyDeltaByKeys + 1 === historyDelta) { |
| 226 | ++ history.push({ |
| 227 | ++ path, |
| 228 | ++ state |
| 229 | ++ }); |
| 230 | ++ } else { |
| 231 | ++ history.replace({ |
| 232 | ++ path, |
| 233 | ++ state |
| 234 | ++ }); |
| 235 | ++ } |
| 236 | + } |
| 237 | +- |
| 238 | +- // Store the updated state as well as fix the path if incorrect |
| 239 | +- history.replace({ |
| 240 | +- path, |
| 241 | +- state |
| 242 | +- }); |
| 243 | + } catch (e) { |
| 244 | + // The navigation was interrupted |
| 245 | + } |
| 246 | + } else { |
| 247 | + // If history length is unchanged, we want to replaceState |
| 248 | +- history.replace({ |
| 249 | +- path, |
| 250 | +- state |
| 251 | +- }); |
| 252 | ++ // and remove any entries from history which focued route no longer exists in state |
| 253 | ++ // That may happen if we replace a whole navigator. |
| 254 | ++ const staleHistoryDiff = getStaleHistoryDiff(history.items.slice(0, history.index + 1), state); |
| 255 | ++ if (staleHistoryDiff <= 0) { |
| 256 | ++ history.replace({ |
| 257 | ++ path, |
| 258 | ++ state |
| 259 | ++ }); |
| 260 | ++ } else { |
| 261 | ++ await history.go(-staleHistoryDiff); |
| 262 | ++ history.push({ |
| 263 | ++ path, |
| 264 | ++ state |
| 265 | ++ }); |
| 266 | ++ } |
| 267 | + } |
| 268 | + } else { |
| 269 | + // If no common navigation state was found, assume it's a replace |
0 commit comments