Fix history handling not properly handling states after update to react-router v5 (#27526)

This commit is contained in:
Claire 2023-10-24 15:24:57 +02:00 committed by GitHub
parent 6cf9f1211b
commit 15182d1e5e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -3,7 +3,11 @@ import React from 'react';
import { Router as OriginalRouter } from 'react-router'; import { Router as OriginalRouter } from 'react-router';
import type { LocationDescriptor, Path } from 'history'; import type {
LocationDescriptor,
LocationDescriptorObject,
Path,
} from 'history';
import { createBrowserHistory } from 'history'; import { createBrowserHistory } from 'history';
import { layoutFromWindow } from 'mastodon/is_mobile'; import { layoutFromWindow } from 'mastodon/is_mobile';
@ -20,39 +24,55 @@ const browserHistory = createBrowserHistory<
const originalPush = browserHistory.push.bind(browserHistory); const originalPush = browserHistory.push.bind(browserHistory);
const originalReplace = browserHistory.replace.bind(browserHistory); const originalReplace = browserHistory.replace.bind(browserHistory);
function extractRealPath(path: HistoryPath) { function normalizePath(
if (typeof path === 'string') return path; path: HistoryPath,
else return path.pathname; state?: MastodonLocationState,
): LocationDescriptorObject<MastodonLocationState> {
const location = typeof path === 'string' ? { pathname: path } : { ...path };
if (location.state === undefined && state !== undefined) {
location.state = state;
} else if (
location.state !== undefined &&
state !== undefined &&
process.env.NODE_ENV === 'development'
) {
// eslint-disable-next-line no-console
console.log(
'You should avoid providing a 2nd state argument to push when the 1st argument is a location-like object that already has state; it is ignored',
);
}
if (
layoutFromWindow() === 'multi-column' &&
!location.pathname?.startsWith('/deck')
) {
location.pathname = `/deck${location.pathname}`;
}
return location;
} }
browserHistory.push = (path: HistoryPath, state?: MastodonLocationState) => { browserHistory.push = (path: HistoryPath, state?: MastodonLocationState) => {
state = state ?? {}; const location = normalizePath(path, state);
state.fromMastodon = true;
const realPath = extractRealPath(path); location.state = location.state ?? {};
if (!realPath) return; location.state.fromMastodon = true;
if (layoutFromWindow() === 'multi-column' && !realPath.startsWith('/deck')) { originalPush(location);
originalPush(`/deck${realPath}`, state);
} else {
originalPush(path, state);
}
}; };
browserHistory.replace = (path: HistoryPath, state?: MastodonLocationState) => { browserHistory.replace = (path: HistoryPath, state?: MastodonLocationState) => {
const location = normalizePath(path, state);
if (!location.pathname) return;
if (browserHistory.location.state?.fromMastodon) { if (browserHistory.location.state?.fromMastodon) {
state = state ?? {}; location.state = location.state ?? {};
state.fromMastodon = true; location.state.fromMastodon = true;
} }
const realPath = extractRealPath(path); originalReplace(location);
if (!realPath) return;
if (layoutFromWindow() === 'multi-column' && !realPath.startsWith('/deck')) {
originalReplace(`/deck${realPath}`, state);
} else {
originalReplace(path, state);
}
}; };
export const Router: React.FC<PropsWithChildren> = ({ children }) => { export const Router: React.FC<PropsWithChildren> = ({ children }) => {