@firtoz/router-toolkit 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@firtoz/router-toolkit",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Type-safe React Router 7 framework mode helpers with enhanced fetching, form submission, and state management",
5
5
  "main": "./src/index.ts",
6
6
  "module": "./src/index.ts",
@@ -11,7 +11,10 @@
11
11
  "import": "./src/index.ts",
12
12
  "require": "./src/index.ts"
13
13
  },
14
- "./*": ["./src/*.ts", "./src/*.tsx"]
14
+ "./*": [
15
+ "./src/*.ts",
16
+ "./src/*.tsx"
17
+ ]
15
18
  },
16
19
  "files": [
17
20
  "src/**/*",
@@ -20,8 +23,12 @@
20
23
  "scripts": {
21
24
  "build": "echo 'No build step - using TypeScript source directly'",
22
25
  "typecheck": "tsc --noEmit",
23
- "lint": "eslint src",
24
- "test": "echo 'No tests yet'"
26
+ "lint": "biome check src",
27
+ "format": "biome format src --write",
28
+ "test": "echo 'No tests yet'",
29
+ "changeset": "changeset",
30
+ "version": "changeset version",
31
+ "release": "changeset publish"
25
32
  },
26
33
  "keywords": [
27
34
  "react-router",
@@ -49,6 +56,8 @@
49
56
  "zod": "^3.25.69"
50
57
  },
51
58
  "devDependencies": {
59
+ "@biomejs/biome": "^2.0.6",
60
+ "@changesets/cli": "^2.29.5",
52
61
  "@types/react": "^19.1.8",
53
62
  "react": "^19.1.0",
54
63
  "react-router": "^7.6.3",
package/src/types/Func.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  // biome-ignore lint/suspicious/noExplicitAny: We really want to use any here
2
- export type Func = (...args: any[]) => unknown;
2
+ export type Func = (...args: any[]) => unknown;
@@ -1,17 +1,8 @@
1
- import type { href, Register } from "react-router";
2
-
3
- type AnyParams = Record<string, string | undefined>;
4
- type AnyPages = Record<string, {
5
- params: AnyParams;
6
- }>;
7
-
8
- export type RegisterPages = Register extends {
9
- pages: infer Registered extends AnyPages;
10
- } ? Registered : AnyPages;
11
-
12
- export type HrefArgs<T extends keyof RegisterPages> = Parameters<typeof href<T>> extends [
13
- string,
14
- ...infer Rest,
15
- ] ? Rest : [];
16
-
17
- export type RoutePath<TPath extends keyof RegisterPages> = TPath;
1
+ import type { href } from "react-router";
2
+ import type { RegisterPages } from "./RegisterPages";
3
+
4
+ export type HrefArgs<T extends keyof RegisterPages> = Parameters<
5
+ typeof href<T>
6
+ > extends [string, ...infer Rest]
7
+ ? Rest
8
+ : [];
@@ -0,0 +1,15 @@
1
+ import type { Register } from "react-router";
2
+
3
+ type AnyParams = Record<string, string | undefined>;
4
+ type AnyPages = Record<
5
+ string,
6
+ {
7
+ params: AnyParams;
8
+ }
9
+ >;
10
+
11
+ export type RegisterPages = Register extends {
12
+ pages: infer Registered extends AnyPages;
13
+ }
14
+ ? Registered
15
+ : AnyPages;
@@ -0,0 +1,3 @@
1
+ import type { RegisterPages } from "./RegisterPages";
2
+
3
+ export type RoutePath<TPath extends keyof RegisterPages> = TPath;
@@ -1,7 +1,8 @@
1
1
  import { useCallback, useEffect, useMemo, useState } from "react";
2
2
  import { href, useFetcher, type useLoaderData } from "react-router";
3
3
  import type { Func } from "./types/Func";
4
- import type { HrefArgs, RegisterPages } from "./types/HrefArgs";
4
+ import type { HrefArgs } from "./types/HrefArgs";
5
+ import type { RegisterPages } from "./types/RegisterPages";
5
6
 
6
7
  type RouteModule = {
7
8
  file: keyof RegisterPages;
@@ -10,7 +11,9 @@ type RouteModule = {
10
11
 
11
12
  export const useDynamicFetcher = <TInfo extends RouteModule>(
12
13
  path: TInfo["file"],
13
- ...args: TInfo["file"] extends "undefined" ? HrefArgs<"/"> : HrefArgs<TInfo["file"]>
14
+ ...args: TInfo["file"] extends "undefined"
15
+ ? HrefArgs<"/">
16
+ : HrefArgs<TInfo["file"]>
14
17
  ): Omit<ReturnType<typeof useFetcher<TInfo["loader"]>>, "load" | "submit"> & {
15
18
  load: (queryParams?: Record<string, string>) => Promise<void>;
16
19
  } => {
@@ -49,24 +52,13 @@ export const useDynamicFetcher = <TInfo extends RouteModule>(
49
52
  const fetchCache = new Map<string, unknown>();
50
53
 
51
54
  // Hook that uses regular fetch instead of useFetcher to avoid route invalidation
52
- export const useCachedFetch = <
53
- TInfo extends {
54
- file: string;
55
- module: RouteModule;
56
- },
57
- >(
58
- path: TInfo["file"] extends "undefined"
59
- ? "/"
60
- : `/${TInfo["file"]}` extends keyof RegisterPages
61
- ? `/${TInfo["file"]}`
62
- : never,
55
+ export const useCachedFetch = <TInfo extends RouteModule>(
56
+ path: TInfo["file"],
63
57
  ...args: TInfo["file"] extends "undefined"
64
58
  ? HrefArgs<"/">
65
- : `/${TInfo["file"]}` extends keyof RegisterPages
66
- ? HrefArgs<`/${TInfo["file"]}`>
67
- : never
59
+ : HrefArgs<TInfo["file"]>
68
60
  ): {
69
- data: ReturnType<typeof useLoaderData<TInfo["module"]["loader"]>> | undefined;
61
+ data: ReturnType<typeof useLoaderData<TInfo["loader"]>> | undefined;
70
62
  isLoading: boolean;
71
63
  error: Error | undefined;
72
64
  } => {
@@ -83,10 +75,12 @@ export const useCachedFetch = <
83
75
  const [isLoading, setIsLoading] = useState(false);
84
76
  const [error, setError] = useState<Error | undefined>(undefined);
85
77
  const [data, setData] = useState<
86
- ReturnType<typeof useLoaderData<TInfo["module"]["loader"]>> | undefined
78
+ ReturnType<typeof useLoaderData<TInfo["loader"]>> | undefined
87
79
  >(() =>
88
80
  fetchCache.has(cacheKey)
89
- ? (fetchCache.get(cacheKey) as ReturnType<typeof useLoaderData<TInfo["module"]["loader"]>>)
81
+ ? (fetchCache.get(cacheKey) as ReturnType<
82
+ typeof useLoaderData<TInfo["loader"]>
83
+ >)
90
84
  : undefined,
91
85
  );
92
86
 
@@ -112,7 +106,7 @@ export const useCachedFetch = <
112
106
 
113
107
  // Update cache and state
114
108
  fetchCache.set(cacheKey, result);
115
- setData(result as ReturnType<typeof useLoaderData<TInfo["module"]["loader"]>>);
109
+ setData(result as ReturnType<typeof useLoaderData<TInfo["loader"]>>);
116
110
  } catch (err) {
117
111
  setError(err instanceof Error ? err : new Error(String(err)));
118
112
  } finally {
@@ -124,4 +118,4 @@ export const useCachedFetch = <
124
118
  }, [url, cacheKey]);
125
119
 
126
120
  return { data, isLoading, error };
127
- };
121
+ };
@@ -7,8 +7,9 @@ import {
7
7
  useFetcher,
8
8
  } from "react-router";
9
9
  import type { z } from "zod/v4";
10
- import { HrefArgs, RegisterPages } from "./types/HrefArgs";
11
- import { Func } from "./types";
10
+ import type { Func } from "./types/Func";
11
+ import type { HrefArgs } from "./types/HrefArgs";
12
+ import type { RegisterPages } from "./types/RegisterPages";
12
13
 
13
14
  type RouteModule = {
14
15
  file: keyof RegisterPages;
@@ -24,15 +25,23 @@ type SubmitFunc<TModule extends RouteModule> = (
24
25
  ) => Promise<void>;
25
26
 
26
27
  type SubmitForm = (
27
- props: Omit<FetcherFormProps & React.RefAttributes<HTMLFormElement>, "action" | "method"> & {
28
+ props: Omit<
29
+ FetcherFormProps & React.RefAttributes<HTMLFormElement>,
30
+ "action" | "method"
31
+ > & {
28
32
  method: Exclude<SubmitOptions["method"], "GET">;
29
33
  },
30
34
  ) => React.ReactElement;
31
35
 
32
36
  export const useDynamicSubmitter = <TInfo extends RouteModule>(
33
37
  path: TInfo["file"],
34
- ...args: TInfo["file"] extends "undefined" ? HrefArgs<"/"> : HrefArgs<TInfo["file"]>
35
- ): Omit<ReturnType<typeof useFetcher<TInfo["action"]>>, "load" | "submit" | "Form"> & {
38
+ ...args: TInfo["file"] extends "undefined"
39
+ ? HrefArgs<"/">
40
+ : HrefArgs<TInfo["file"]>
41
+ ): Omit<
42
+ ReturnType<typeof useFetcher<TInfo["action"]>>,
43
+ "load" | "submit" | "Form"
44
+ > & {
36
45
  submit: SubmitFunc<TInfo>;
37
46
  Form: SubmitForm;
38
47
  } => {
@@ -8,7 +8,10 @@ import type { useFetcher } from "react-router";
8
8
  */
9
9
  export const useFetcherStateChanged = (
10
10
  fetcher: Pick<ReturnType<typeof useFetcher>, "state">,
11
- onChange: (lastState: typeof fetcher.state | undefined, newState: typeof fetcher.state) => void,
11
+ onChange: (
12
+ lastState: typeof fetcher.state | undefined,
13
+ newState: typeof fetcher.state,
14
+ ) => void,
12
15
  ) => {
13
16
  const lastStateRef = useRef<typeof fetcher.state>(fetcher.state);
14
17
 
@@ -18,4 +21,4 @@ export const useFetcherStateChanged = (
18
21
  lastStateRef.current = fetcher.state;
19
22
  }
20
23
  }, [fetcher.state, onChange]);
21
- };
24
+ };
@@ -1,2 +0,0 @@
1
- export type { Func } from "./Func";
2
- export type { HrefArgs,RoutePath } from "./HrefArgs";