Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexander Iklyukov committed Oct 21, 2023
1 parent 4940116 commit d607b20
Show file tree
Hide file tree
Showing 24 changed files with 390 additions and 82 deletions.
Binary file added docs/img/autocomplete.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@
"license": "MIT",
"private": true,
"packageManager": "pnpm@8.3.1",
"type": "module",
"engines": {
"pnpm": ">=8"
},
"scripts": {
"demo": "pnpm run --filter @favy/router-demo dev"
"demo": "pnpm run --filter @favy/router-demo dev",
"pub": "tsx ./bin/publish.mts"
},
"devDependencies": {
"typescript": "^5.2.2"
"tsx": "^3.13.0",
"typescript": "^5.2.2",
"zx": "^7.2.3"
}
}
4 changes: 2 additions & 2 deletions packages/demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
"preview": "vite preview"
},
"dependencies": {
"@favy/wayfind": "workspace:*",
"@favy/wayfind-react": "workspace:*",
"@favy/wayfind": "0.0.2",
"@favy/wayfind-react": "0.0.1",
"scheduler": "^0.23.0",
"type-fest": "^4.4.0"
},
Expand Down
1 change: 1 addition & 0 deletions packages/demo/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Demo
2 changes: 1 addition & 1 deletion packages/demo/src/lazy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const UserIdComponent: React.FC = () => {

return (
<div className='bg-green-200'>
user: {vars.id} / ${vars.p}
user: {vars.id} / page: {vars.p}
</div>
);
};
Expand Down
32 changes: 13 additions & 19 deletions packages/demo/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,25 @@ import { createRoot } from "react-dom/client";
import { useIsActive, useNavigate, Link } from "./routerComponent";
import { router } from "./router";

type A = {
to: `/users/${number}/` | `/posts/` | "/";
};

const B: React.FC<A> = () => {};

const Wtf = () => {
return (
<div>
<B to={"/posts/"} />
</div>
);
};

const Head = () => {
const isActiveRoot = useIsActive("/");
const go = useNavigate();

return (
<div className='w-full bg-blue-100 p-5 text-2xl flex gap-20 text-gray-800 items-center'>
useIsActive("/") = {isActiveRoot.toString()}{" "}
<button className='bg-blue-400 rounded-md px-4 py-2 shadow-md' onClick={() => go("/")}>
<button
className='bg-blue-400 rounded-md px-4 py-2 shadow-md'
onClick={() =>
go({
to: "/users/{id}?page={p}",
vars: {
id: 42,
p: 2,
},
})
}
>
go to "/"
</button>
</div>
Expand All @@ -39,15 +36,12 @@ function App() {
<Head></Head>
<div className='p-2 px-4 text-xl'>
<div className='flex gap-4'>
<Link to='/a'>/</Link>
<Link to='/'>/</Link>
<Link to='/posts'>/posts</Link>
<Link to='/users'>/users</Link>
<Link to='/users/{id}?page={p}' vars={{ id: 42, p: 2 }}>
/users/42
</Link>
{/* <Link to='/users/{id}?page={p}' vars={{ id: 42, p: 2 }}>
/users/42
</Link> */}
<Link to='/logs/{page}' vars={{ page: 10 }}>
/logs/10
</Link>
Expand Down
12 changes: 9 additions & 3 deletions packages/demo/src/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,17 @@ const root = route({
"/posts": () => (
<div>
redirecting
<Redirect to='/' />
<Redirect
to='/users/{id}?page={p}'
vars={{
id: 42,
p: 2,
}}
/>
</div>
),
"/logs/{page}": () => {
throw "random error " + Date.now();
"/logs/{page}": (ctx) => {
throw `random error ${ctx.page} ` + Date.now();
},
error: ({ error }) => <div style={{ color: "red" }}>Throw error: {`${error}`}</div>,
render: () => <div>render root</div>,
Expand Down
9 changes: 0 additions & 9 deletions packages/demo/src/routerComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
import { getComponents } from "@favy/wayfind-react";
import { router } from "./router";

// router.go("/users/{id}?page={p}", {
// id: 1,
// p: "5",
// });
// router.go("/");
// router.go("/", {});
// type pp = (typeof router)["paths"];
// type xx = (typeof router)["var"];
// const d: xx = "/logs/123";
export const { Link, Redirect, useVar, useIsActive, useNavigate } = getComponents(router, {
Link: {
default: {
Expand Down
16 changes: 11 additions & 5 deletions packages/wayfind-react/package.json
Original file line number Diff line number Diff line change
@@ -1,25 +1,31 @@
{
"name": "@favy/wayfind-react",
"license": "MIT",
"version": "0.0.1",
"version": "0.0.3",
"main": "./src/index.ts",
"module": "./src/index.ts",
"exports": {
".": {
"import": "./src/index.ts",
"require": "./src/index.ts"
}
},
"scripts": {
"build": "tsup index.ts --format cjs,esm --dts",
"build": "tsup src/index.ts --format cjs,esm --dts",
"release": "pnpm run build && changeset publish",
"lint": "tsc"
},
"devDependencies": {
"@changesets/cli": "^2.26.1",
"@favy/wayfind": "workspace:*",
"@types/react": "^18.2.8",
"tsup": "^7.2.0",
"typescript": "^5.2.2"
},
"peerDependencies": {
"react": "^18.2.0"
"react": "^18.2.0",
"@favy/wayfind": "workspace:*"
},
"dependencies": {
"react": "^18.2.0",
"type-fest": "^4.4.0"
}
}
1 change: 1 addition & 0 deletions packages/wayfind-react/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# wayfind-react
1 change: 1 addition & 0 deletions packages/wayfind-react/src/RouterContext.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { createContext } from "react";
import { RouterInstance } from "@favy/wayfind";

Expand Down
8 changes: 6 additions & 2 deletions packages/wayfind-react/src/components/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ type HTMLAnchorProps = React.HTMLProps<HTMLAnchorElement>;

type DefaultProps = HTMLAnchorProps & { href: string };

type ToRouteProps<PATHS extends string, VARS> = Omit<HTMLAnchorProps, "href"> & {
export type ToRouteProps<PATHS extends string, VARS> = {
to: PATHS;
// eslint-disable-next-line @typescript-eslint/ban-types
} & (IsEmptyObject<VARS> extends false ? { vars: VARS } : {});

export type LinkProps<PATHS extends string, VARS> = ToRouteProps<PATHS, VARS> | DefaultProps;
export type LinkProps<PATHS extends string, VARS> =
| (Omit<HTMLAnchorProps, "href"> & ToRouteProps<PATHS, VARS>)
| DefaultProps;

export const makeLink = (config: ConfProps["Link"] = { active: {}, default: {} }) => {
return <PATHS extends string, VARS>(props: LinkProps<PATHS, VARS>) => {
Expand Down Expand Up @@ -60,6 +62,8 @@ export const makeLink = (config: ConfProps["Link"] = { active: {}, default: {} }
// @ts-ignore
href={props?.href ?? url}
onClick={(e) => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
if (props?.to) {
e.preventDefault();

Expand Down
11 changes: 9 additions & 2 deletions packages/wayfind-react/src/components/Redirect.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import { useContext, useLayoutEffect } from "react";
import { RouterContext } from "../RouterContext";
import { ToRouteProps } from "./Link";

export const Redirect = <T extends string, V>({ to, vars }: { to: T; vars: V }) => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
export const Redirect = <T extends string, V>({ to, vars }: ToRouteProps<T, V>) => {
const ctx = useContext(RouterContext).router;

useLayoutEffect(() => {
ctx?.go(to);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
ctx?.go(to, vars);
});

return <></>;
};
8 changes: 5 additions & 3 deletions packages/wayfind-react/src/components/getComponents.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { makeLink, LinkProps } from "./Link";
/* eslint-disable @typescript-eslint/no-explicit-any */
import { makeLink, LinkProps, ToRouteProps } from "./Link";
import { RouterInstance, RouteType, ExtractVars } from "@favy/wayfind";
import { makeVarHook } from "../hooks/useVar";
import { Redirect } from "./Redirect";
Expand All @@ -16,13 +17,14 @@ export const getComponents = <T extends RouterInstance<C, any, any>, C extends R
router: T,
config: ConfProps
) => {
type RedirectProps = { [k in T["paths"]]: ToRouteProps<k, ExtractVars<k, string | number>> }[T["paths"]];
return {
Link: makeLink(config["Link"]) as (
props: { [k in T["paths"]]: LinkProps<k, ExtractVars<k, string | number>> }[T["paths"]]
) => JSX.Element,
Redirect: Redirect as (props: { to: T["paths"] }) => JSX.Element,
Redirect: Redirect as (props: RedirectProps) => JSX.Element,
useVar: makeVarHook<T["var"]>(),
useIsActive: makeIsActiveHook<T["paths"]>(),
useNavigate: makeNavigateHook<T["paths"]>(),
useNavigate: makeNavigateHook<RedirectProps>(),
};
};
19 changes: 11 additions & 8 deletions packages/wayfind-react/src/hooks/useNavigate.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { useContext } from "react";
import { RouterContext } from "../RouterContext";

export const makeNavigateHook = <T extends string>() => {
const useNavigate = () => {
const ctx = useContext(RouterContext).router;
return <U extends T>(url: U) => ctx?.go(url);
}

return useNavigate
}
export const makeNavigateHook = <P>() => {
const useNavigate = () => {
const ctx = useContext(RouterContext).router;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (props: P) => ctx?.go(props.url, props.vars);
};

return useNavigate;
};
14 changes: 9 additions & 5 deletions packages/wayfind-react/src/router.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { RouterContext } from "./RouterContext";
import type { RouterInstance } from "..";
import { RouteType } from "../RouteType";
import type { RouterInstance } from "@favy/wayfind";
import { RouteType } from "@favy/wayfind";
import { useEffect, useReducer } from "react";

export interface RouteProps<C extends RouteType<any, any>> extends React.PropsWithChildren {
Expand All @@ -16,14 +17,17 @@ export const Router = <C extends RouteType<any, any>>(props: RouteProps<C>) => {
}, []);

const router = props.router?.route;

const renderContent = () => {
try {
return typeof router.route === "function" ? router.route() : router.route.render();
} catch(error) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return typeof router.route === "function" ? router.route(router) : router.route?.render?.(router);
} catch (error) {
if (router.errorRender) {
return router.errorRender({ error });
}

throw error;
}
};
Expand Down
9 changes: 8 additions & 1 deletion packages/wayfind/package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
{
"name": "@favy/wayfind",
"license": "MIT",
"version": "0.0.1",
"version": "0.0.5",
"main": "./src/index.ts",
"module": "./src/index.ts",
"exports": {
".": {
"import": "./src/index.ts",
"require": "./src/index.ts"
}
},
"scripts": {
"build": "tsup src/index.ts --format cjs,esm --dts",
"release": "pnpm run build && changeset publish",
Expand Down
1 change: 1 addition & 0 deletions packages/wayfind/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# wayfind
3 changes: 2 additions & 1 deletion packages/wayfind/src/Parsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@

export const parsers = {
number: (value: string) => Number(value),
bigint: (value: string) => BigInt(value),
string: (value: string) => value,
// boolean: (value: string) => Boolean(value),
boolean: (value: string) => Boolean(value),
};

export type Parsers = {
Expand Down
2 changes: 1 addition & 1 deletion packages/wayfind/src/RouteType.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// type ReplaceVars<T extends string> = T extends `${infer L}{${string}}${infer R}` ? `${L}${number}${ReplaceVars<R>}` : T;

type RouteRender<RET> = (params: string) => RET;
type RouteRender<RET> = (params: unknown) => RET;

type RouteParams<RET, ID extends string> = {
render: RouteRender<RET>;
Expand Down
6 changes: 5 additions & 1 deletion packages/wayfind/src/createRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export const createRouter = <const C extends RouteType<any, any>>(config: C) =>
window.addEventListener("popstate", handleChange);
handleChange();

// eslint-disable-next-line @typescript-eslint/no-unused-vars
type RemoveType<S extends string> = S extends `${infer L}{${infer N}:${infer T}}${infer R}`
? `${L}{${N}}${RemoveType<R>}`
: S;
Expand Down Expand Up @@ -71,6 +72,8 @@ export type RouterInstance<C extends RouteType<any, any>, P extends string, V> =
route: {
vars: Record<string, string>;
route: RouteType<any, any>[keyof RouteType<any, any>];
render: () => unknown;
errorRender: (args: { error: unknown }) => unknown;
};
match(path: string): unknown;
isActive(path: string): boolean;
Expand Down Expand Up @@ -131,7 +134,7 @@ const findRoute = <R>(routes: R, path: string) => {
}
};

const isActive = <R>(routes: R, path: string) => {
export const isActive = <R>(routes: R, path: string) => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
for (const r of routes) {
Expand All @@ -157,6 +160,7 @@ const flatRoute = <T>(route: RouteType<T, any>, prefix = "", res: Record<string,
};

export const applyVars = (path: string, vars: any) => {
if (!vars) return path;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return path.replace(/\{(.+?)\}/g, (_, name) => vars[name]);
Expand Down
1 change: 1 addition & 0 deletions packages/wayfind/src/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { RouteType } from "./RouteType";

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const route = <const C extends RouteType<any, any>>(config: C) => {
return config;
};
Loading

0 comments on commit d607b20

Please sign in to comment.