mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-16 04:27:21 +00:00
public commit
This commit is contained in:
79
app/src/ui/components/wouter/Link.tsx
Normal file
79
app/src/ui/components/wouter/Link.tsx
Normal file
@@ -0,0 +1,79 @@
|
||||
import { useInsertionEffect, useRef } from "react";
|
||||
import { type LinkProps, Link as WouterLink, useRoute, useRouter } from "wouter";
|
||||
import { useEvent } from "../../hooks/use-event";
|
||||
|
||||
/*
|
||||
* Transforms `path` into its relative `base` version
|
||||
* If base isn't part of the path provided returns absolute path e.g. `~/app`
|
||||
*/
|
||||
export const relativePath = (base = "", path = "") =>
|
||||
!path.toLowerCase().indexOf(base.toLowerCase()) ? path.slice(base.length) || "/" : "~" + path;
|
||||
|
||||
export const absolutePath = (to, base = "") => (to[0] === "~" ? to.slice(1) : base + to);
|
||||
|
||||
/*
|
||||
* Removes leading question mark
|
||||
*/
|
||||
export const stripQm = (str) => (str[0] === "?" ? str.slice(1) : str);
|
||||
|
||||
/*
|
||||
* decodes escape sequences such as %20
|
||||
*/
|
||||
|
||||
// biome-ignore lint/suspicious/noShadowRestrictedNames: <explanation>
|
||||
export const unescape = (str) => {
|
||||
try {
|
||||
return decodeURI(str);
|
||||
} catch (_e) {
|
||||
// fail-safe mode: if string can't be decoded do nothing
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
const useLocationFromRouter = (router) => {
|
||||
const [location, navigate] = router.hook(router);
|
||||
|
||||
// the function reference should stay the same between re-renders, so that
|
||||
// it can be passed down as an element prop without any performance concerns.
|
||||
// (This is achieved via `useEvent`.)
|
||||
return [
|
||||
unescape(relativePath(router.base, location)),
|
||||
useEvent((to, navOpts) => navigate(absolutePath(to, router.base), navOpts))
|
||||
];
|
||||
};
|
||||
|
||||
export function Link({ className, ...props }: { className?: string } & LinkProps) {
|
||||
const router = useRouter();
|
||||
const [path, navigate] = useLocationFromRouter(router);
|
||||
|
||||
function isActive(absPath: string, href: string) {
|
||||
if (absPath.startsWith(href)) {
|
||||
const l = absPath.replace(href, "");
|
||||
return l.length === 0 || l[0] === "/";
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function handleClick(e) {}
|
||||
|
||||
const _href = props.href ?? props.to;
|
||||
const href = router
|
||||
.hrefs(
|
||||
_href[0] === "~" ? _href.slice(1) : router.base + _href,
|
||||
router // pass router as a second argument for convinience
|
||||
)
|
||||
.replace("//", "/");
|
||||
const absPath = absolutePath(path, router.base).replace("//", "/");
|
||||
const active =
|
||||
href.replace(router.base, "").length <= 1 ? href === absPath : isActive(absPath, href);
|
||||
const a = useRoute(_href);
|
||||
|
||||
/*if (active) {
|
||||
console.log("link", { a, path, absPath, href, to, active, router });
|
||||
}*/
|
||||
return (
|
||||
// @ts-expect-error className is not typed on WouterLink
|
||||
<WouterLink className={`${active ? "active " : ""}${className}`} {...props} />
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user