Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | 332x 1727x 1727x 14x 58x 58x 1218x 1424x 4803x 4803x 4741x 4741x 4741x 26x 26x 332x 3652x 3652x 6308x 6308x 3652x | import React from "react";
import type { SearchMiddleware } from "@tanstack/react-router";
import {
stripSearchParams,
useParams,
useNavigate as useRawNavigate,
useRouter,
useRouterState,
} from "@tanstack/react-router";
import type { ValidateNavigateOptions } from "@tanstack/router-core";
import { mapValues, omitBy } from "remeda";
import { z } from "zod";
import type { NavigationContextType } from "~app/contexts/navigation-context";
import type { OutputRouteSearchParams, RouteId } from "~app/utils/navigation";
import { searchParamsMapping } from "~app/utils/navigation";
import { updateSetStateAction } from "~utils/react";
declare module "@react-types/shared" {
// oxlint-disable-next-line typescript/consistent-type-definitions
interface RouterConfig {
routerOptions: ValidateNavigateOptions;
}
}
export const navigationContext: NavigationContextType = {
useNavigate: () => {
const navigate = useRawNavigate();
return (options) => {
void navigate(options);
};
},
usePush: () => {
const router = useRouter();
return (url) => router.history.push(url);
},
useBack: () => {
const router = useRouter();
return () => router.history.back();
},
useParams: (key) => useParams({ from: key }),
usePathname: () => useRouterState().location.pathname,
useSearchParams: <K extends RouteId>(key: K) => {
const router = useRouter();
return router.routesById[key].useSearch();
},
useUpdateSearchParam: <K extends RouteId>() => {
const navigate = useRawNavigate();
return React.useCallback(
(param) =>
(setStateAction, options = {}) => {
void navigate({
search: (prev) => ({
...prev,
[param]: updateSetStateAction(
setStateAction,
(prev as OutputRouteSearchParams<K>)[param],
),
}),
to: ".",
...options,
});
},
[navigate],
);
},
};
export const searchParamsWithDefaults = <
K extends keyof typeof searchParamsMapping,
>(
key: K,
) => {
const schema = searchParamsMapping[key];
const defaultValues = mapValues(
omitBy(schema.shape, (value) => !(value instanceof z.ZodCatch)),
(value) =>
value instanceof z.ZodCatch
? value.def.catchValue({
/* oxlint-disable typescript/no-deprecated */
error: { issues: [] },
input: undefined,
/* oxlint-enable typescript/no-deprecated */
value: undefined,
issues: [],
})
: undefined,
);
return {
validateSearch: schema,
search: {
middlewares: [
// Apparently, the type inference is different in linter and typescript compiler
// Any is needed because we don't use search middleware functions
// oxlint-disable-next-line typescript/no-unnecessary-type-assertion typescript/no-explicit-any
stripSearchParams(defaultValues) as SearchMiddleware<any>,
],
},
};
};
|