@aminnairi/react-router 2.0.1 → 2.2.0

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.
Files changed (3) hide show
  1. package/README.md +55 -0
  2. package/index.tsx +17 -9
  3. package/package.json +3 -2
package/README.md CHANGED
@@ -690,6 +690,45 @@ createPage({
690
690
  });
691
691
  ```
692
692
 
693
+ You can also provide a custom render function as the second argument to fully control the rendered output. This is useful when you want to use a different component library or need more control over the markup.
694
+
695
+ ```tsx
696
+ import { Fragment } from "react";
697
+ import { createPage, useLink, UseLinkRenderFunction } from "@aminnairi/react-router";
698
+
699
+ const user = createPage({
700
+ path: "/users/:user",
701
+ element: function User({ parameters: { user } }) {
702
+ return <h1>User#{user}</h1>;
703
+ },
704
+ });
705
+
706
+ createPage({
707
+ path: "/about",
708
+ element: function About() {
709
+ const CustomLink = useLink(user, ({ path, onClick, children }) => {
710
+ return (
711
+ <button className="nav-button" onClick={onClick}>
712
+ {children}
713
+ </button>
714
+ );
715
+ });
716
+
717
+ return (
718
+ <Fragment>
719
+ <h1>About</h1>
720
+ <CustomLink parameters={{ user: "123" }}>User#123</CustomLink>
721
+ </Fragment>
722
+ );
723
+ },
724
+ });
725
+ ```
726
+
727
+ The render function receives an object with the following properties:
728
+ - `path`: The computed URL path with parameters filled in
729
+ - `onClick`: The click event handler that prevents default navigation and handles routing
730
+ - `children`: The children passed to the link component
731
+
693
732
  ### useSearch
694
733
 
695
734
  Allow you to get one or more search query from the URL.
@@ -849,6 +888,7 @@ See [`LICENSE`](./LICENSE).
849
888
 
850
889
  ### Versions
851
890
 
891
+ - [`2.1.0`](#210)
852
892
  - [`2.0.1`](#201)
853
893
  - [`2.0.0`](#200)
854
894
  - [`1.1.0`](#110)
@@ -857,6 +897,21 @@ See [`LICENSE`](./LICENSE).
857
897
  - [`0.1.1`](#011)
858
898
  - [`0.1.0`](#010)
859
899
 
900
+ ### 2.1.0
901
+
902
+ #### Major changes
903
+
904
+ None.
905
+
906
+ #### Minor changes
907
+
908
+ - Added optional `render` parameter to `useLink` hook for custom render functions
909
+ - Added `UseLinkRenderFunction` type for custom render function signatures
910
+
911
+ #### Bug & security fixes
912
+
913
+ None.
914
+
860
915
  ### 2.0.1
861
916
 
862
917
  #### Major changes
package/index.tsx CHANGED
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable */
2
- import { useEffect, useState, FunctionComponent, useMemo, Component, PropsWithChildren, createContext, SetStateAction, Dispatch, ReactNode, useContext, useCallback, memo, MouseEvent } from "react";
2
+ import { useEffect, useState, FunctionComponent, useMemo, Component, PropsWithChildren, createContext, SetStateAction, Dispatch, ReactNode, useContext, useCallback, memo, MouseEvent, ComponentProps, JSXElementConstructor, ElementType, ComponentPropsWithoutRef, MouseEventHandler } from "react";
3
3
 
4
4
  export type AbsolutePath<Path extends string> =
5
5
  Path extends `${infer Start}:${string}/${infer Rest}`
@@ -228,30 +228,38 @@ export const useHash = () => {
228
228
  return hash;
229
229
  };
230
230
 
231
- export const useLink = <Path extends string>(page: Page<Path>) => {
232
- const Link = memo(({ children, parameters }: { children: ReactNode, parameters: Parameters<Path> }) => {
231
+ export type LinkProps<Path extends string> = {
232
+ children: ReactNode,
233
+ parameters: Parameters<Path>
234
+ }
235
+
236
+ export type UseLinkRenderFunction = (props: { path: string, onClick: MouseEventHandler, children: ReactNode }) => ReactNode
237
+
238
+ export const useLink = <Path extends string>(page: Page<Path>, render?: UseLinkRenderFunction) => {
239
+ const Link = memo(({ children, parameters }: LinkProps<Path>) => {
233
240
  const { prefix } = useContext(Context);
234
241
  const navigateToPage = useNavigateToPage(page);
235
242
 
236
- const pathWithParameters = useMemo(() => {
243
+ const path = useMemo(() => {
237
244
  return Object.entries(parameters).reduce((previousPath, [parameterName, parameterValue]) => {
238
245
  return previousPath.replace(`:${parameterName}`, parameterValue);
239
246
  }, sanitizePath(`${prefix ?? ""}/${page.path}`));
240
247
  }, [prefix, page, parameters]);
241
248
 
242
- const navigate = useCallback((event: MouseEvent) => {
249
+ const onClick = useCallback((event: MouseEvent) => {
243
250
  event.preventDefault();
244
251
  navigateToPage(parameters);
245
252
  }, [navigateToPage, parameters]);
246
253
 
254
+ if (render) {
255
+ return render({ path, onClick, children });
256
+ }
257
+
247
258
  return (
248
- <a
249
- href={pathWithParameters}
250
- onClick={navigate}>
259
+ <a href={path} onClick={onClick}>
251
260
  {children}
252
261
  </a>
253
262
  );
254
-
255
263
  });
256
264
 
257
265
  return Link;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "type": "module",
3
3
  "name": "@aminnairi/react-router",
4
4
  "description": "Type-safe router for the React library",
5
- "version": "2.0.1",
5
+ "version": "2.2.0",
6
6
  "homepage": "https://github.com/aminnairi/react-router#readme",
7
7
  "license": "MIT",
8
8
  "bugs": {
@@ -34,6 +34,7 @@
34
34
  "@typescript-eslint/eslint-plugin": "^7.2.0",
35
35
  "@typescript-eslint/parser": "^7.2.0",
36
36
  "eslint": "^8.57.0",
37
- "eslint-plugin-react-hooks": "^4.6.0"
37
+ "eslint-plugin-react-hooks": "^4.6.0",
38
+ "typescript": "^5.9.3"
38
39
  }
39
40
  }