@hyeonqyu/typed-router-react 1.7.1 → 1.8.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.
package/dist/index.d.mts CHANGED
@@ -1,9 +1,11 @@
1
1
  import * as _hyeonqyu_typed_router_core from '@hyeonqyu/typed-router-core';
2
- import { PartialRouteTree as PartialRouteTree$1, RouteTree as RouteTree$1, ResolvedRouteTree as ResolvedRouteTree$1, RoutePathname as RoutePathname$1 } from '@hyeonqyu/typed-router-core';
2
+ import { TypedLinkHrefObject, PartialRouteTree as PartialRouteTree$1, RouteTree as RouteTree$1, ResolvedRouteTree as ResolvedRouteTree$1, RoutePathname as RoutePathname$1 } from '@hyeonqyu/typed-router-core';
3
3
  export * from '@hyeonqyu/typed-router-core';
4
4
  import * as react_router from 'react-router';
5
+ import * as react from 'react';
6
+ import { ComponentProps, ReactNode } from 'react';
7
+ import { Link } from 'react-router-dom';
5
8
  import * as react_jsx_runtime from 'react/jsx-runtime';
6
- import { ReactNode } from 'react';
7
9
 
8
10
  type Paths<TObject, TSplitter extends string, TPrev extends string = '', TMaxDepth extends number = 10, TDepth extends unknown[] = []> = TDepth['length'] extends TMaxDepth ? never : TSplitter | {
9
11
  [K in keyof TObject & string]: TObject[K] extends object ? `${TSplitter}${TPrev extends '' ? K : `${TPrev}${TSplitter}${K}`}` | Paths<TObject[K], TSplitter, TPrev extends '' ? K : `${TPrev}${TSplitter}${K}`, TMaxDepth, [...TDepth, 1]> : `${TSplitter}${TPrev extends '' ? K : `${TPrev}${TSplitter}${K}`}`;
@@ -51,6 +53,11 @@ type ExtractSearchParams<TNode> = TNode extends {
51
53
  } ? TNode['_metadata']['searchParamsSchema']['_output'] : Record<string, unknown>;
52
54
  type GetRouteNode<TRouteTree, TPath extends string> = TPath extends `/${infer First}/${infer Rest}` ? First extends keyof TRouteTree ? GetRouteNode<TRouteTree[First], `/${Rest}`> : never : TPath extends `/${infer Key}` ? Key extends keyof TRouteTree ? TRouteTree[Key] : never : TRouteTree;
53
55
 
56
+ type ReactLinkProps = ComponentProps<typeof Link>;
57
+ type TypedLinkProps<TPathname extends string = string, TRouteTree = unknown> = Omit<ReactLinkProps, 'to'> & {
58
+ to: TPathname | TypedLinkHrefObject<TPathname, TRouteTree>;
59
+ };
60
+
54
61
  declare const createAppRoutes: <TMetadata extends {
55
62
  component: ReactNode;
56
63
  }, TContext>() => <TRouteTree extends PartialRouteTree$1<TMetadata, TContext>>(appRoutes: TRouteTree & RouteTree$1<TMetadata, TContext, TRouteTree>) => {
@@ -58,6 +65,7 @@ declare const createAppRoutes: <TMetadata extends {
58
65
  children: ReactNode;
59
66
  }) => react_jsx_runtime.JSX.Element;
60
67
  useAppRoutes: () => ResolvedRouteTree$1<TMetadata, TContext, TRouteTree>;
68
+ TypedLink: react.ForwardRefExoticComponent<Omit<TypedLinkProps<RoutePathname$1<TMetadata, TContext, TRouteTree>, TRouteTree>, "ref"> & react.RefAttributes<HTMLAnchorElement>>;
61
69
  useTypedNavigate: () => <TPath extends RoutePathname$1<TMetadata, TContext, TRouteTree>>(href: TPath, options?: Omit<react_router.NavigateOptions, "searchParams"> & {
62
70
  searchParams?: _hyeonqyu_typed_router_core.ExtractSearchParams<_hyeonqyu_typed_router_core.GetRouteNode<TRouteTree, TPath>> | undefined;
63
71
  }) => void | Promise<void>;
@@ -81,4 +89,4 @@ declare const createAppRoutes: <TMetadata extends {
81
89
  };
82
90
  };
83
91
 
84
- export { createAppRoutes };
92
+ export { type TypedLinkProps, createAppRoutes };
package/dist/index.d.ts CHANGED
@@ -1,9 +1,11 @@
1
1
  import * as _hyeonqyu_typed_router_core from '@hyeonqyu/typed-router-core';
2
- import { PartialRouteTree as PartialRouteTree$1, RouteTree as RouteTree$1, ResolvedRouteTree as ResolvedRouteTree$1, RoutePathname as RoutePathname$1 } from '@hyeonqyu/typed-router-core';
2
+ import { TypedLinkHrefObject, PartialRouteTree as PartialRouteTree$1, RouteTree as RouteTree$1, ResolvedRouteTree as ResolvedRouteTree$1, RoutePathname as RoutePathname$1 } from '@hyeonqyu/typed-router-core';
3
3
  export * from '@hyeonqyu/typed-router-core';
4
4
  import * as react_router from 'react-router';
5
+ import * as react from 'react';
6
+ import { ComponentProps, ReactNode } from 'react';
7
+ import { Link } from 'react-router-dom';
5
8
  import * as react_jsx_runtime from 'react/jsx-runtime';
6
- import { ReactNode } from 'react';
7
9
 
8
10
  type Paths<TObject, TSplitter extends string, TPrev extends string = '', TMaxDepth extends number = 10, TDepth extends unknown[] = []> = TDepth['length'] extends TMaxDepth ? never : TSplitter | {
9
11
  [K in keyof TObject & string]: TObject[K] extends object ? `${TSplitter}${TPrev extends '' ? K : `${TPrev}${TSplitter}${K}`}` | Paths<TObject[K], TSplitter, TPrev extends '' ? K : `${TPrev}${TSplitter}${K}`, TMaxDepth, [...TDepth, 1]> : `${TSplitter}${TPrev extends '' ? K : `${TPrev}${TSplitter}${K}`}`;
@@ -51,6 +53,11 @@ type ExtractSearchParams<TNode> = TNode extends {
51
53
  } ? TNode['_metadata']['searchParamsSchema']['_output'] : Record<string, unknown>;
52
54
  type GetRouteNode<TRouteTree, TPath extends string> = TPath extends `/${infer First}/${infer Rest}` ? First extends keyof TRouteTree ? GetRouteNode<TRouteTree[First], `/${Rest}`> : never : TPath extends `/${infer Key}` ? Key extends keyof TRouteTree ? TRouteTree[Key] : never : TRouteTree;
53
55
 
56
+ type ReactLinkProps = ComponentProps<typeof Link>;
57
+ type TypedLinkProps<TPathname extends string = string, TRouteTree = unknown> = Omit<ReactLinkProps, 'to'> & {
58
+ to: TPathname | TypedLinkHrefObject<TPathname, TRouteTree>;
59
+ };
60
+
54
61
  declare const createAppRoutes: <TMetadata extends {
55
62
  component: ReactNode;
56
63
  }, TContext>() => <TRouteTree extends PartialRouteTree$1<TMetadata, TContext>>(appRoutes: TRouteTree & RouteTree$1<TMetadata, TContext, TRouteTree>) => {
@@ -58,6 +65,7 @@ declare const createAppRoutes: <TMetadata extends {
58
65
  children: ReactNode;
59
66
  }) => react_jsx_runtime.JSX.Element;
60
67
  useAppRoutes: () => ResolvedRouteTree$1<TMetadata, TContext, TRouteTree>;
68
+ TypedLink: react.ForwardRefExoticComponent<Omit<TypedLinkProps<RoutePathname$1<TMetadata, TContext, TRouteTree>, TRouteTree>, "ref"> & react.RefAttributes<HTMLAnchorElement>>;
61
69
  useTypedNavigate: () => <TPath extends RoutePathname$1<TMetadata, TContext, TRouteTree>>(href: TPath, options?: Omit<react_router.NavigateOptions, "searchParams"> & {
62
70
  searchParams?: _hyeonqyu_typed_router_core.ExtractSearchParams<_hyeonqyu_typed_router_core.GetRouteNode<TRouteTree, TPath>> | undefined;
63
71
  }) => void | Promise<void>;
@@ -81,4 +89,4 @@ declare const createAppRoutes: <TMetadata extends {
81
89
  };
82
90
  };
83
91
 
84
- export { createAppRoutes };
92
+ export { type TypedLinkProps, createAppRoutes };
package/dist/index.js CHANGED
@@ -3,6 +3,8 @@
3
3
  var routes_utils = require('@hyeonqyu/typed-router-core/routes.utils');
4
4
  var typedRouterCore = require('@hyeonqyu/typed-router-core');
5
5
  var reactRouterDom = require('react-router-dom');
6
+ var react = require('react');
7
+ var jsxRuntime = require('react/jsx-runtime');
6
8
 
7
9
  // src/index.ts
8
10
  var createTypedNavigate = () => {
@@ -18,13 +20,28 @@ var createTypedNavigate = () => {
18
20
  };
19
21
  };
20
22
  };
23
+ var createTypedLink = () => {
24
+ const TypedLink = react.forwardRef((props, ref) => {
25
+ const { to, ...restProps } = props;
26
+ if (typeof to === "string") {
27
+ return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Link, { ref, to, ...restProps });
28
+ }
29
+ const { pathname, searchParams, hash } = to;
30
+ const finalTo = typedRouterCore.buildTypedHref(pathname, searchParams, hash);
31
+ return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Link, { ref, to: finalTo, ...restProps });
32
+ });
33
+ TypedLink.displayName = "TypedLink";
34
+ return TypedLink;
35
+ };
21
36
  var createAppRoutes = () => {
22
37
  return (appRoutes) => {
23
38
  const { AppRoutesProvider, useAppRoutes, getPathnameFromNode, freezeAppRoutes, useCurrentRouteNode, _types } = routes_utils.createAppRoutes()(appRoutes);
39
+ const TypedLink = createTypedLink();
24
40
  const useTypedNavigate = createTypedNavigate();
25
41
  return {
26
42
  AppRoutesProvider,
27
43
  useAppRoutes,
44
+ TypedLink,
28
45
  useTypedNavigate,
29
46
  getPathnameFromNode,
30
47
  freezeAppRoutes,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/navigate.hooks.ts","../src/index.ts"],"names":["replaceDynamicSegments","toSearchParamsString","useNavigate","coreCreateAppRoutes"],"mappings":";;;;;;;AAQO,IAAM,sBAAsB,MAA+D;AAChG,EAAA,MAAM,uBAAA,GAA0B,CAAC,IAAA,EAAiB,YAAA,KAAgC;AAChF,IAAA,MAAM,EAAE,QAAA,EAAU,eAAA,EAAgB,GAAIA,sCAAA,CAAuB,MAAgB,YAAY,CAAA;AACzF,IAAA,OAAO,CAAA,EAAG,QAAQ,CAAA,EAAGC,oCAAA,CAAqB,iBAAiB,EAAE,mBAAA,EAAqB,IAAA,EAAM,CAAC,CAAA,CAAA;AAAA,EAC3F,CAAA;AAEA,EAAA,OAAO,MAAM;AACX,IAAA,MAAM,WAAWC,0BAAA,EAAY;AAE7B,IAAA,OAAO,CAA0B,MAAa,OAAA,KAA2E;AACvH,MAAA,MAAM,SAAA,GAAY,uBAAA,CAAwB,IAAA,EAAM,OAAA,EAAS,YAA4B,CAAA;AACrF,MAAA,OAAO,QAAA,CAAS,WAAW,OAAO,CAAA;AAAA,IACpC,CAAA;AAAA,EACF,CAAA;AACF,CAAA;ACjBO,IAAM,kBAAkB,MAA4D;AACzF,EAAA,OAAO,CAA2D,SAAA,KAAuE;AACvI,IAAA,MAAM,EAAE,iBAAA,EAAmB,YAAA,EAAc,mBAAA,EAAqB,eAAA,EAAiB,qBAAqB,MAAA,EAAO,GAAIC,4BAAA,EAG7G,CAAE,SAAS,CAAA;AAKb,IAAA,MAAM,mBAAmB,mBAAA,EAA0C;AAEnE,IAAA,OAAO;AAAA,MACL,iBAAA;AAAA,MACA,YAAA;AAAA,MACA,gBAAA;AAAA,MACA,mBAAA;AAAA,MACA,eAAA;AAAA,MACA,mBAAA;AAAA,MACA,SAAA;AAAA,MACA,MAAA,EAAQ;AAAA,QACN,GAAG,MAAA;AAAA,QACH,mBAAmB;AAAC;AACtB,KACF;AAAA,EACF,CAAA;AACF","file":"index.js","sourcesContent":["import { replaceDynamicSegments, SearchParams, SearchParamsForPath, toSearchParamsString } from '@hyeonqyu/typed-router-core';\nimport { NavigateOptions, useNavigate } from 'react-router-dom';\n\ntype TypedNavigateOptions<TSearchParams = SearchParams> = Omit<NavigateOptions, 'searchParams'> & {\n /** Custom typed search params */\n searchParams?: TSearchParams;\n};\n\nexport const createTypedNavigate = <TPathname extends string = string, TRouteTree = unknown>() => {\n const getHrefWithSearchParams = (href: TPathname, searchParams?: SearchParams) => {\n const { pathname, remainingParams } = replaceDynamicSegments(href as string, searchParams);\n return `${pathname}${toSearchParamsString(remainingParams, { includeQuestionMark: true })}`;\n };\n\n return () => {\n const navigate = useNavigate();\n\n return <TPath extends TPathname>(href: TPath, options?: TypedNavigateOptions<SearchParamsForPath<TRouteTree, TPath>>) => {\n const finalHref = getHrefWithSearchParams(href, options?.searchParams as SearchParams);\n return navigate(finalHref, options);\n };\n };\n};\n","import { type PartialRouteTree, type ResolvedRouteTree, type RoutePathname, type RouteTree } from '@hyeonqyu/typed-router-core';\nimport { createAppRoutes as coreCreateAppRoutes } from '@hyeonqyu/typed-router-core/routes.utils';\nimport { ReactNode } from 'react';\nimport { createTypedNavigate } from './navigate.hooks';\n\nexport const createAppRoutes = <TMetadata extends { component: ReactNode }, TContext>() => {\n return <TRouteTree extends PartialRouteTree<TMetadata, TContext>>(appRoutes: TRouteTree & RouteTree<TMetadata, TContext, TRouteTree>) => {\n const { AppRoutesProvider, useAppRoutes, getPathnameFromNode, freezeAppRoutes, useCurrentRouteNode, _types } = coreCreateAppRoutes<\n TMetadata,\n TContext\n >()(appRoutes);\n\n type Pathname = RoutePathname<TMetadata, TContext, TRouteTree>;\n type Routes = ResolvedRouteTree<TMetadata, TContext, TRouteTree>;\n\n const useTypedNavigate = createTypedNavigate<Pathname, TRouteTree>();\n\n return {\n AppRoutesProvider,\n useAppRoutes: useAppRoutes as () => Routes,\n useTypedNavigate,\n getPathnameFromNode,\n freezeAppRoutes,\n useCurrentRouteNode,\n appRoutes,\n _types: {\n ..._types,\n AppRoutesPathname: {} as Pathname,\n },\n };\n };\n};\n\nexport * from '@hyeonqyu/typed-router-core';\n"]}
1
+ {"version":3,"sources":["../src/navigate.hooks.ts","../src/TypedLink.tsx","../src/index.ts"],"names":["replaceDynamicSegments","toSearchParamsString","useNavigate","forwardRef","jsx","Link","buildTypedHref","coreCreateAppRoutes"],"mappings":";;;;;;;;;AAQO,IAAM,sBAAsB,MAA+D;AAChG,EAAA,MAAM,uBAAA,GAA0B,CAAC,IAAA,EAAiB,YAAA,KAAgC;AAChF,IAAA,MAAM,EAAE,QAAA,EAAU,eAAA,EAAgB,GAAIA,sCAAA,CAAuB,MAAgB,YAAY,CAAA;AACzF,IAAA,OAAO,CAAA,EAAG,QAAQ,CAAA,EAAGC,oCAAA,CAAqB,iBAAiB,EAAE,mBAAA,EAAqB,IAAA,EAAM,CAAC,CAAA,CAAA;AAAA,EAC3F,CAAA;AAEA,EAAA,OAAO,MAAM;AACX,IAAA,MAAM,WAAWC,0BAAA,EAAY;AAE7B,IAAA,OAAO,CAA0B,MAAa,OAAA,KAA2E;AACvH,MAAA,MAAM,SAAA,GAAY,uBAAA,CAAwB,IAAA,EAAM,OAAA,EAAS,YAA4B,CAAA;AACrF,MAAA,OAAO,QAAA,CAAS,WAAW,OAAO,CAAA;AAAA,IACpC,CAAA;AAAA,EACF,CAAA;AACF,CAAA;ACXO,IAAM,kBAAkB,MAA+D;AAC5F,EAAA,MAAM,SAAA,GAAYC,gBAAA,CAA6E,CAAC,KAAA,EAAO,GAAA,KAAQ;AAC7G,IAAA,MAAM,EAAE,EAAA,EAAI,GAAG,SAAA,EAAU,GAAI,KAAA;AAE7B,IAAA,IAAI,OAAO,OAAO,QAAA,EAAU;AAC1B,MAAA,uBAAOC,cAAA,CAACC,mBAAA,EAAA,EAAK,GAAA,EAAU,EAAA,EAAS,GAAG,SAAA,EAAW,CAAA;AAAA,IAChD;AAEA,IAAA,MAAM,EAAE,QAAA,EAAU,YAAA,EAAc,IAAA,EAAK,GAAI,EAAA;AACzC,IAAA,MAAM,OAAA,GAAUC,8BAAA,CAAe,QAAA,EAAoB,YAAA,EAA8B,IAAI,CAAA;AAErF,IAAA,sCAAQD,mBAAA,EAAA,EAAK,GAAA,EAAU,EAAA,EAAI,OAAA,EAAU,GAAG,SAAA,EAAW,CAAA;AAAA,EACrD,CAAC,CAAA;AAED,EAAA,SAAA,CAAU,WAAA,GAAc,WAAA;AAExB,EAAA,OAAO,SAAA;AACT,CAAA;ACtBO,IAAM,kBAAkB,MAA4D;AACzF,EAAA,OAAO,CAA2D,SAAA,KAAuE;AACvI,IAAA,MAAM,EAAE,iBAAA,EAAmB,YAAA,EAAc,mBAAA,EAAqB,eAAA,EAAiB,qBAAqB,MAAA,EAAO,GAAIE,4BAAA,EAG7G,CAAE,SAAS,CAAA;AAKb,IAAA,MAAM,YAAY,eAAA,EAAsC;AACxD,IAAA,MAAM,mBAAmB,mBAAA,EAA0C;AAEnE,IAAA,OAAO;AAAA,MACL,iBAAA;AAAA,MACA,YAAA;AAAA,MACA,SAAA;AAAA,MACA,gBAAA;AAAA,MACA,mBAAA;AAAA,MACA,eAAA;AAAA,MACA,mBAAA;AAAA,MACA,SAAA;AAAA,MACA,MAAA,EAAQ;AAAA,QACN,GAAG,MAAA;AAAA,QACH,mBAAmB;AAAC;AACtB,KACF;AAAA,EACF,CAAA;AACF","file":"index.js","sourcesContent":["import { replaceDynamicSegments, SearchParams, SearchParamsForPath, toSearchParamsString } from '@hyeonqyu/typed-router-core';\nimport { NavigateOptions, useNavigate } from 'react-router-dom';\n\ntype TypedNavigateOptions<TSearchParams = SearchParams> = Omit<NavigateOptions, 'searchParams'> & {\n /** Custom typed search params */\n searchParams?: TSearchParams;\n};\n\nexport const createTypedNavigate = <TPathname extends string = string, TRouteTree = unknown>() => {\n const getHrefWithSearchParams = (href: TPathname, searchParams?: SearchParams) => {\n const { pathname, remainingParams } = replaceDynamicSegments(href as string, searchParams);\n return `${pathname}${toSearchParamsString(remainingParams, { includeQuestionMark: true })}`;\n };\n\n return () => {\n const navigate = useNavigate();\n\n return <TPath extends TPathname>(href: TPath, options?: TypedNavigateOptions<SearchParamsForPath<TRouteTree, TPath>>) => {\n const finalHref = getHrefWithSearchParams(href, options?.searchParams as SearchParams);\n return navigate(finalHref, options);\n };\n };\n};\n","import { buildTypedHref, type TypedLinkHrefObject, type SearchParams } from '@hyeonqyu/typed-router-core';\nimport { Link } from 'react-router-dom';\nimport type { ComponentProps, ComponentRef } from 'react';\nimport { forwardRef } from 'react';\n\ntype ReactLinkProps = ComponentProps<typeof Link>;\n\nexport type TypedLinkProps<TPathname extends string = string, TRouteTree = unknown> = Omit<ReactLinkProps, 'to'> & {\n to: TPathname | TypedLinkHrefObject<TPathname, TRouteTree>;\n};\n\nexport const createTypedLink = <TPathname extends string = string, TRouteTree = unknown>() => {\n const TypedLink = forwardRef<ComponentRef<typeof Link>, TypedLinkProps<TPathname, TRouteTree>>((props, ref) => {\n const { to, ...restProps } = props;\n\n if (typeof to === 'string') {\n return <Link ref={ref} to={to} {...restProps} />;\n }\n\n const { pathname, searchParams, hash } = to;\n const finalTo = buildTypedHref(pathname as string, searchParams as SearchParams, hash);\n\n return <Link ref={ref} to={finalTo} {...restProps} />;\n });\n\n TypedLink.displayName = 'TypedLink';\n\n return TypedLink;\n};\n","import { type PartialRouteTree, type ResolvedRouteTree, type RoutePathname, type RouteTree } from '@hyeonqyu/typed-router-core';\nimport { createAppRoutes as coreCreateAppRoutes } from '@hyeonqyu/typed-router-core/routes.utils';\nimport { ReactNode } from 'react';\nimport { createTypedNavigate } from './navigate.hooks';\nimport { createTypedLink } from './TypedLink';\n\nexport const createAppRoutes = <TMetadata extends { component: ReactNode }, TContext>() => {\n return <TRouteTree extends PartialRouteTree<TMetadata, TContext>>(appRoutes: TRouteTree & RouteTree<TMetadata, TContext, TRouteTree>) => {\n const { AppRoutesProvider, useAppRoutes, getPathnameFromNode, freezeAppRoutes, useCurrentRouteNode, _types } = coreCreateAppRoutes<\n TMetadata,\n TContext\n >()(appRoutes);\n\n type Pathname = RoutePathname<TMetadata, TContext, TRouteTree>;\n type Routes = ResolvedRouteTree<TMetadata, TContext, TRouteTree>;\n\n const TypedLink = createTypedLink<Pathname, TRouteTree>();\n const useTypedNavigate = createTypedNavigate<Pathname, TRouteTree>();\n\n return {\n AppRoutesProvider,\n useAppRoutes: useAppRoutes as () => Routes,\n TypedLink,\n useTypedNavigate,\n getPathnameFromNode,\n freezeAppRoutes,\n useCurrentRouteNode,\n appRoutes,\n _types: {\n ..._types,\n AppRoutesPathname: {} as Pathname,\n },\n };\n };\n};\n\nexport * from '@hyeonqyu/typed-router-core';\nexport type { TypedLinkProps } from './TypedLink';\n"]}
package/dist/index.mjs CHANGED
@@ -1,7 +1,9 @@
1
1
  import { createAppRoutes as createAppRoutes$1 } from '@hyeonqyu/typed-router-core/routes.utils';
2
- import { replaceDynamicSegments, toSearchParamsString } from '@hyeonqyu/typed-router-core';
2
+ import { buildTypedHref, replaceDynamicSegments, toSearchParamsString } from '@hyeonqyu/typed-router-core';
3
3
  export * from '@hyeonqyu/typed-router-core';
4
- import { useNavigate } from 'react-router-dom';
4
+ import { Link, useNavigate } from 'react-router-dom';
5
+ import { forwardRef } from 'react';
6
+ import { jsx } from 'react/jsx-runtime';
5
7
 
6
8
  // src/index.ts
7
9
  var createTypedNavigate = () => {
@@ -17,13 +19,28 @@ var createTypedNavigate = () => {
17
19
  };
18
20
  };
19
21
  };
22
+ var createTypedLink = () => {
23
+ const TypedLink = forwardRef((props, ref) => {
24
+ const { to, ...restProps } = props;
25
+ if (typeof to === "string") {
26
+ return /* @__PURE__ */ jsx(Link, { ref, to, ...restProps });
27
+ }
28
+ const { pathname, searchParams, hash } = to;
29
+ const finalTo = buildTypedHref(pathname, searchParams, hash);
30
+ return /* @__PURE__ */ jsx(Link, { ref, to: finalTo, ...restProps });
31
+ });
32
+ TypedLink.displayName = "TypedLink";
33
+ return TypedLink;
34
+ };
20
35
  var createAppRoutes = () => {
21
36
  return (appRoutes) => {
22
37
  const { AppRoutesProvider, useAppRoutes, getPathnameFromNode, freezeAppRoutes, useCurrentRouteNode, _types } = createAppRoutes$1()(appRoutes);
38
+ const TypedLink = createTypedLink();
23
39
  const useTypedNavigate = createTypedNavigate();
24
40
  return {
25
41
  AppRoutesProvider,
26
42
  useAppRoutes,
43
+ TypedLink,
27
44
  useTypedNavigate,
28
45
  getPathnameFromNode,
29
46
  freezeAppRoutes,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/navigate.hooks.ts","../src/index.ts"],"names":["coreCreateAppRoutes"],"mappings":";;;;;;AAQO,IAAM,sBAAsB,MAA+D;AAChG,EAAA,MAAM,uBAAA,GAA0B,CAAC,IAAA,EAAiB,YAAA,KAAgC;AAChF,IAAA,MAAM,EAAE,QAAA,EAAU,eAAA,EAAgB,GAAI,sBAAA,CAAuB,MAAgB,YAAY,CAAA;AACzF,IAAA,OAAO,CAAA,EAAG,QAAQ,CAAA,EAAG,oBAAA,CAAqB,iBAAiB,EAAE,mBAAA,EAAqB,IAAA,EAAM,CAAC,CAAA,CAAA;AAAA,EAC3F,CAAA;AAEA,EAAA,OAAO,MAAM;AACX,IAAA,MAAM,WAAW,WAAA,EAAY;AAE7B,IAAA,OAAO,CAA0B,MAAa,OAAA,KAA2E;AACvH,MAAA,MAAM,SAAA,GAAY,uBAAA,CAAwB,IAAA,EAAM,OAAA,EAAS,YAA4B,CAAA;AACrF,MAAA,OAAO,QAAA,CAAS,WAAW,OAAO,CAAA;AAAA,IACpC,CAAA;AAAA,EACF,CAAA;AACF,CAAA;ACjBO,IAAM,kBAAkB,MAA4D;AACzF,EAAA,OAAO,CAA2D,SAAA,KAAuE;AACvI,IAAA,MAAM,EAAE,iBAAA,EAAmB,YAAA,EAAc,mBAAA,EAAqB,eAAA,EAAiB,qBAAqB,MAAA,EAAO,GAAIA,iBAAA,EAG7G,CAAE,SAAS,CAAA;AAKb,IAAA,MAAM,mBAAmB,mBAAA,EAA0C;AAEnE,IAAA,OAAO;AAAA,MACL,iBAAA;AAAA,MACA,YAAA;AAAA,MACA,gBAAA;AAAA,MACA,mBAAA;AAAA,MACA,eAAA;AAAA,MACA,mBAAA;AAAA,MACA,SAAA;AAAA,MACA,MAAA,EAAQ;AAAA,QACN,GAAG,MAAA;AAAA,QACH,mBAAmB;AAAC;AACtB,KACF;AAAA,EACF,CAAA;AACF","file":"index.mjs","sourcesContent":["import { replaceDynamicSegments, SearchParams, SearchParamsForPath, toSearchParamsString } from '@hyeonqyu/typed-router-core';\nimport { NavigateOptions, useNavigate } from 'react-router-dom';\n\ntype TypedNavigateOptions<TSearchParams = SearchParams> = Omit<NavigateOptions, 'searchParams'> & {\n /** Custom typed search params */\n searchParams?: TSearchParams;\n};\n\nexport const createTypedNavigate = <TPathname extends string = string, TRouteTree = unknown>() => {\n const getHrefWithSearchParams = (href: TPathname, searchParams?: SearchParams) => {\n const { pathname, remainingParams } = replaceDynamicSegments(href as string, searchParams);\n return `${pathname}${toSearchParamsString(remainingParams, { includeQuestionMark: true })}`;\n };\n\n return () => {\n const navigate = useNavigate();\n\n return <TPath extends TPathname>(href: TPath, options?: TypedNavigateOptions<SearchParamsForPath<TRouteTree, TPath>>) => {\n const finalHref = getHrefWithSearchParams(href, options?.searchParams as SearchParams);\n return navigate(finalHref, options);\n };\n };\n};\n","import { type PartialRouteTree, type ResolvedRouteTree, type RoutePathname, type RouteTree } from '@hyeonqyu/typed-router-core';\nimport { createAppRoutes as coreCreateAppRoutes } from '@hyeonqyu/typed-router-core/routes.utils';\nimport { ReactNode } from 'react';\nimport { createTypedNavigate } from './navigate.hooks';\n\nexport const createAppRoutes = <TMetadata extends { component: ReactNode }, TContext>() => {\n return <TRouteTree extends PartialRouteTree<TMetadata, TContext>>(appRoutes: TRouteTree & RouteTree<TMetadata, TContext, TRouteTree>) => {\n const { AppRoutesProvider, useAppRoutes, getPathnameFromNode, freezeAppRoutes, useCurrentRouteNode, _types } = coreCreateAppRoutes<\n TMetadata,\n TContext\n >()(appRoutes);\n\n type Pathname = RoutePathname<TMetadata, TContext, TRouteTree>;\n type Routes = ResolvedRouteTree<TMetadata, TContext, TRouteTree>;\n\n const useTypedNavigate = createTypedNavigate<Pathname, TRouteTree>();\n\n return {\n AppRoutesProvider,\n useAppRoutes: useAppRoutes as () => Routes,\n useTypedNavigate,\n getPathnameFromNode,\n freezeAppRoutes,\n useCurrentRouteNode,\n appRoutes,\n _types: {\n ..._types,\n AppRoutesPathname: {} as Pathname,\n },\n };\n };\n};\n\nexport * from '@hyeonqyu/typed-router-core';\n"]}
1
+ {"version":3,"sources":["../src/navigate.hooks.ts","../src/TypedLink.tsx","../src/index.ts"],"names":["coreCreateAppRoutes"],"mappings":";;;;;;;;AAQO,IAAM,sBAAsB,MAA+D;AAChG,EAAA,MAAM,uBAAA,GAA0B,CAAC,IAAA,EAAiB,YAAA,KAAgC;AAChF,IAAA,MAAM,EAAE,QAAA,EAAU,eAAA,EAAgB,GAAI,sBAAA,CAAuB,MAAgB,YAAY,CAAA;AACzF,IAAA,OAAO,CAAA,EAAG,QAAQ,CAAA,EAAG,oBAAA,CAAqB,iBAAiB,EAAE,mBAAA,EAAqB,IAAA,EAAM,CAAC,CAAA,CAAA;AAAA,EAC3F,CAAA;AAEA,EAAA,OAAO,MAAM;AACX,IAAA,MAAM,WAAW,WAAA,EAAY;AAE7B,IAAA,OAAO,CAA0B,MAAa,OAAA,KAA2E;AACvH,MAAA,MAAM,SAAA,GAAY,uBAAA,CAAwB,IAAA,EAAM,OAAA,EAAS,YAA4B,CAAA;AACrF,MAAA,OAAO,QAAA,CAAS,WAAW,OAAO,CAAA;AAAA,IACpC,CAAA;AAAA,EACF,CAAA;AACF,CAAA;ACXO,IAAM,kBAAkB,MAA+D;AAC5F,EAAA,MAAM,SAAA,GAAY,UAAA,CAA6E,CAAC,KAAA,EAAO,GAAA,KAAQ;AAC7G,IAAA,MAAM,EAAE,EAAA,EAAI,GAAG,SAAA,EAAU,GAAI,KAAA;AAE7B,IAAA,IAAI,OAAO,OAAO,QAAA,EAAU;AAC1B,MAAA,uBAAO,GAAA,CAAC,IAAA,EAAA,EAAK,GAAA,EAAU,EAAA,EAAS,GAAG,SAAA,EAAW,CAAA;AAAA,IAChD;AAEA,IAAA,MAAM,EAAE,QAAA,EAAU,YAAA,EAAc,IAAA,EAAK,GAAI,EAAA;AACzC,IAAA,MAAM,OAAA,GAAU,cAAA,CAAe,QAAA,EAAoB,YAAA,EAA8B,IAAI,CAAA;AAErF,IAAA,2BAAQ,IAAA,EAAA,EAAK,GAAA,EAAU,EAAA,EAAI,OAAA,EAAU,GAAG,SAAA,EAAW,CAAA;AAAA,EACrD,CAAC,CAAA;AAED,EAAA,SAAA,CAAU,WAAA,GAAc,WAAA;AAExB,EAAA,OAAO,SAAA;AACT,CAAA;ACtBO,IAAM,kBAAkB,MAA4D;AACzF,EAAA,OAAO,CAA2D,SAAA,KAAuE;AACvI,IAAA,MAAM,EAAE,iBAAA,EAAmB,YAAA,EAAc,mBAAA,EAAqB,eAAA,EAAiB,qBAAqB,MAAA,EAAO,GAAIA,iBAAA,EAG7G,CAAE,SAAS,CAAA;AAKb,IAAA,MAAM,YAAY,eAAA,EAAsC;AACxD,IAAA,MAAM,mBAAmB,mBAAA,EAA0C;AAEnE,IAAA,OAAO;AAAA,MACL,iBAAA;AAAA,MACA,YAAA;AAAA,MACA,SAAA;AAAA,MACA,gBAAA;AAAA,MACA,mBAAA;AAAA,MACA,eAAA;AAAA,MACA,mBAAA;AAAA,MACA,SAAA;AAAA,MACA,MAAA,EAAQ;AAAA,QACN,GAAG,MAAA;AAAA,QACH,mBAAmB;AAAC;AACtB,KACF;AAAA,EACF,CAAA;AACF","file":"index.mjs","sourcesContent":["import { replaceDynamicSegments, SearchParams, SearchParamsForPath, toSearchParamsString } from '@hyeonqyu/typed-router-core';\nimport { NavigateOptions, useNavigate } from 'react-router-dom';\n\ntype TypedNavigateOptions<TSearchParams = SearchParams> = Omit<NavigateOptions, 'searchParams'> & {\n /** Custom typed search params */\n searchParams?: TSearchParams;\n};\n\nexport const createTypedNavigate = <TPathname extends string = string, TRouteTree = unknown>() => {\n const getHrefWithSearchParams = (href: TPathname, searchParams?: SearchParams) => {\n const { pathname, remainingParams } = replaceDynamicSegments(href as string, searchParams);\n return `${pathname}${toSearchParamsString(remainingParams, { includeQuestionMark: true })}`;\n };\n\n return () => {\n const navigate = useNavigate();\n\n return <TPath extends TPathname>(href: TPath, options?: TypedNavigateOptions<SearchParamsForPath<TRouteTree, TPath>>) => {\n const finalHref = getHrefWithSearchParams(href, options?.searchParams as SearchParams);\n return navigate(finalHref, options);\n };\n };\n};\n","import { buildTypedHref, type TypedLinkHrefObject, type SearchParams } from '@hyeonqyu/typed-router-core';\nimport { Link } from 'react-router-dom';\nimport type { ComponentProps, ComponentRef } from 'react';\nimport { forwardRef } from 'react';\n\ntype ReactLinkProps = ComponentProps<typeof Link>;\n\nexport type TypedLinkProps<TPathname extends string = string, TRouteTree = unknown> = Omit<ReactLinkProps, 'to'> & {\n to: TPathname | TypedLinkHrefObject<TPathname, TRouteTree>;\n};\n\nexport const createTypedLink = <TPathname extends string = string, TRouteTree = unknown>() => {\n const TypedLink = forwardRef<ComponentRef<typeof Link>, TypedLinkProps<TPathname, TRouteTree>>((props, ref) => {\n const { to, ...restProps } = props;\n\n if (typeof to === 'string') {\n return <Link ref={ref} to={to} {...restProps} />;\n }\n\n const { pathname, searchParams, hash } = to;\n const finalTo = buildTypedHref(pathname as string, searchParams as SearchParams, hash);\n\n return <Link ref={ref} to={finalTo} {...restProps} />;\n });\n\n TypedLink.displayName = 'TypedLink';\n\n return TypedLink;\n};\n","import { type PartialRouteTree, type ResolvedRouteTree, type RoutePathname, type RouteTree } from '@hyeonqyu/typed-router-core';\nimport { createAppRoutes as coreCreateAppRoutes } from '@hyeonqyu/typed-router-core/routes.utils';\nimport { ReactNode } from 'react';\nimport { createTypedNavigate } from './navigate.hooks';\nimport { createTypedLink } from './TypedLink';\n\nexport const createAppRoutes = <TMetadata extends { component: ReactNode }, TContext>() => {\n return <TRouteTree extends PartialRouteTree<TMetadata, TContext>>(appRoutes: TRouteTree & RouteTree<TMetadata, TContext, TRouteTree>) => {\n const { AppRoutesProvider, useAppRoutes, getPathnameFromNode, freezeAppRoutes, useCurrentRouteNode, _types } = coreCreateAppRoutes<\n TMetadata,\n TContext\n >()(appRoutes);\n\n type Pathname = RoutePathname<TMetadata, TContext, TRouteTree>;\n type Routes = ResolvedRouteTree<TMetadata, TContext, TRouteTree>;\n\n const TypedLink = createTypedLink<Pathname, TRouteTree>();\n const useTypedNavigate = createTypedNavigate<Pathname, TRouteTree>();\n\n return {\n AppRoutesProvider,\n useAppRoutes: useAppRoutes as () => Routes,\n TypedLink,\n useTypedNavigate,\n getPathnameFromNode,\n freezeAppRoutes,\n useCurrentRouteNode,\n appRoutes,\n _types: {\n ..._types,\n AppRoutesPathname: {} as Pathname,\n },\n };\n };\n};\n\nexport * from '@hyeonqyu/typed-router-core';\nexport type { TypedLinkProps } from './TypedLink';\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyeonqyu/typed-router-react",
3
- "version": "1.7.1",
3
+ "version": "1.8.0",
4
4
  "description": "Type-safe IA-first routing for React Router",
5
5
  "author": "hyeonQyu <dhk0561@naver.com>",
6
6
  "license": "MIT",