@hyeonqyu/typed-router-next 0.2.10 → 1.0.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,5 +1,5 @@
1
1
  import * as _hyeonqyu_typed_router_core from '@hyeonqyu/typed-router-core';
2
- import { BaseMetadata, PartialRouteTree, RouteTree, ResolvedRouteTree, RoutePathname, PathValue } from '@hyeonqyu/typed-router-core';
2
+ import { SearchParamsForPath, BaseMetadata, PartialRouteTree, RouteTree, ResolvedRouteTree, RoutePathname, PathValue } from '@hyeonqyu/typed-router-core';
3
3
  export * from '@hyeonqyu/typed-router-core';
4
4
  import * as react from 'react';
5
5
  import { ComponentProps } from 'react';
@@ -7,12 +7,12 @@ import Link from 'next/link';
7
7
  import * as react_jsx_runtime from 'react/jsx-runtime';
8
8
 
9
9
  type NextLinkProps = ComponentProps<typeof Link>;
10
- type TypedLinkProps<TPathname extends string = string> = Omit<NextLinkProps, 'href'> & {
11
- href: TPathname | {
12
- pathname: TPathname;
13
- query?: Record<string, string | number | boolean | readonly (string | number | boolean)[]>;
10
+ type TypedLinkProps<TPathname extends string = string, TRouteTree = unknown> = Omit<NextLinkProps, 'href'> & {
11
+ href: TPathname | (TPathname extends infer TPath ? {
12
+ pathname: TPath;
13
+ searchParams?: SearchParamsForPath<TRouteTree, TPath & string>;
14
14
  hash?: string;
15
- };
15
+ } : never);
16
16
  };
17
17
 
18
18
  declare const createAppRoutes: <TMetadata extends BaseMetadata, TContext>() => <TRouteTree extends PartialRouteTree<TMetadata, TContext>>(appRoutes: TRouteTree & RouteTree<TMetadata, TContext, TRouteTree>) => {
@@ -21,24 +21,27 @@ declare const createAppRoutes: <TMetadata extends BaseMetadata, TContext>() => <
21
21
  }) => react_jsx_runtime.JSX.Element;
22
22
  useAppRoutes: () => ResolvedRouteTree<TMetadata, TContext, TRouteTree>;
23
23
  useCurrentRouteNode: <TPath extends RoutePathname<TMetadata, TContext, TRouteTree>>(pathname: TPath) => PathValue<TRouteTree, TPath, "/">;
24
- TypedLink: react.ForwardRefExoticComponent<Omit<TypedLinkProps<RoutePathname<TMetadata, TContext, TRouteTree>>, "ref"> & react.RefAttributes<HTMLAnchorElement>>;
24
+ TypedLink: react.ForwardRefExoticComponent<Omit<TypedLinkProps<RoutePathname<TMetadata, TContext, TRouteTree>, TRouteTree>, "ref"> & react.RefAttributes<HTMLAnchorElement>>;
25
25
  useTypedRouter: () => {
26
26
  back: () => void;
27
27
  forward: () => void;
28
28
  refresh: () => void;
29
- push: (href: RoutePathname<TMetadata, TContext, TRouteTree>, options?: {
29
+ push: <TPath extends RoutePathname<TMetadata, TContext, TRouteTree>>(href: TPath, options?: {
30
30
  scroll?: boolean;
31
- query?: _hyeonqyu_typed_router_core.QueryParams;
32
- }) => void;
33
- replace: (href: RoutePathname<TMetadata, TContext, TRouteTree>, options?: {
31
+ searchParams?: _hyeonqyu_typed_router_core.ExtractSearchParams<_hyeonqyu_typed_router_core.GetRouteNode<TRouteTree, TPath>> | undefined;
32
+ } | undefined) => void;
33
+ replace: <TPath extends RoutePathname<TMetadata, TContext, TRouteTree>>(href: TPath, options?: {
34
34
  scroll?: boolean;
35
- query?: _hyeonqyu_typed_router_core.QueryParams;
36
- }) => void;
37
- prefetch: (href: RoutePathname<TMetadata, TContext, TRouteTree>, options?: {
38
- query?: _hyeonqyu_typed_router_core.QueryParams | undefined;
39
- }) => void;
35
+ searchParams?: _hyeonqyu_typed_router_core.ExtractSearchParams<_hyeonqyu_typed_router_core.GetRouteNode<TRouteTree, TPath>> | undefined;
36
+ } | undefined) => void;
37
+ prefetch: <TPath extends RoutePathname<TMetadata, TContext, TRouteTree>>(href: TPath, options?: {
38
+ searchParams?: _hyeonqyu_typed_router_core.ExtractSearchParams<_hyeonqyu_typed_router_core.GetRouteNode<TRouteTree, TPath>> | undefined;
39
+ } | undefined) => void;
40
40
  };
41
41
  useTypedPathname: () => RoutePathname<TMetadata, TContext, TRouteTree>;
42
+ useTypedSearchParams: <TPathname extends string = string>(_pathname: TPathname, _options?: {
43
+ onError?: "throw" | "default" | "raw";
44
+ }) => _hyeonqyu_typed_router_core.ExtractSearchParams<_hyeonqyu_typed_router_core.GetRouteNode<TRouteTree, TPathname>>;
42
45
  _types: {
43
46
  AppRoutesPathname: RoutePathname<TMetadata, TContext, TRouteTree>;
44
47
  AppRoutesMetadata: TMetadata;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _hyeonqyu_typed_router_core from '@hyeonqyu/typed-router-core';
2
- import { BaseMetadata, PartialRouteTree, RouteTree, ResolvedRouteTree, RoutePathname, PathValue } from '@hyeonqyu/typed-router-core';
2
+ import { SearchParamsForPath, BaseMetadata, PartialRouteTree, RouteTree, ResolvedRouteTree, RoutePathname, PathValue } from '@hyeonqyu/typed-router-core';
3
3
  export * from '@hyeonqyu/typed-router-core';
4
4
  import * as react from 'react';
5
5
  import { ComponentProps } from 'react';
@@ -7,12 +7,12 @@ import Link from 'next/link';
7
7
  import * as react_jsx_runtime from 'react/jsx-runtime';
8
8
 
9
9
  type NextLinkProps = ComponentProps<typeof Link>;
10
- type TypedLinkProps<TPathname extends string = string> = Omit<NextLinkProps, 'href'> & {
11
- href: TPathname | {
12
- pathname: TPathname;
13
- query?: Record<string, string | number | boolean | readonly (string | number | boolean)[]>;
10
+ type TypedLinkProps<TPathname extends string = string, TRouteTree = unknown> = Omit<NextLinkProps, 'href'> & {
11
+ href: TPathname | (TPathname extends infer TPath ? {
12
+ pathname: TPath;
13
+ searchParams?: SearchParamsForPath<TRouteTree, TPath & string>;
14
14
  hash?: string;
15
- };
15
+ } : never);
16
16
  };
17
17
 
18
18
  declare const createAppRoutes: <TMetadata extends BaseMetadata, TContext>() => <TRouteTree extends PartialRouteTree<TMetadata, TContext>>(appRoutes: TRouteTree & RouteTree<TMetadata, TContext, TRouteTree>) => {
@@ -21,24 +21,27 @@ declare const createAppRoutes: <TMetadata extends BaseMetadata, TContext>() => <
21
21
  }) => react_jsx_runtime.JSX.Element;
22
22
  useAppRoutes: () => ResolvedRouteTree<TMetadata, TContext, TRouteTree>;
23
23
  useCurrentRouteNode: <TPath extends RoutePathname<TMetadata, TContext, TRouteTree>>(pathname: TPath) => PathValue<TRouteTree, TPath, "/">;
24
- TypedLink: react.ForwardRefExoticComponent<Omit<TypedLinkProps<RoutePathname<TMetadata, TContext, TRouteTree>>, "ref"> & react.RefAttributes<HTMLAnchorElement>>;
24
+ TypedLink: react.ForwardRefExoticComponent<Omit<TypedLinkProps<RoutePathname<TMetadata, TContext, TRouteTree>, TRouteTree>, "ref"> & react.RefAttributes<HTMLAnchorElement>>;
25
25
  useTypedRouter: () => {
26
26
  back: () => void;
27
27
  forward: () => void;
28
28
  refresh: () => void;
29
- push: (href: RoutePathname<TMetadata, TContext, TRouteTree>, options?: {
29
+ push: <TPath extends RoutePathname<TMetadata, TContext, TRouteTree>>(href: TPath, options?: {
30
30
  scroll?: boolean;
31
- query?: _hyeonqyu_typed_router_core.QueryParams;
32
- }) => void;
33
- replace: (href: RoutePathname<TMetadata, TContext, TRouteTree>, options?: {
31
+ searchParams?: _hyeonqyu_typed_router_core.ExtractSearchParams<_hyeonqyu_typed_router_core.GetRouteNode<TRouteTree, TPath>> | undefined;
32
+ } | undefined) => void;
33
+ replace: <TPath extends RoutePathname<TMetadata, TContext, TRouteTree>>(href: TPath, options?: {
34
34
  scroll?: boolean;
35
- query?: _hyeonqyu_typed_router_core.QueryParams;
36
- }) => void;
37
- prefetch: (href: RoutePathname<TMetadata, TContext, TRouteTree>, options?: {
38
- query?: _hyeonqyu_typed_router_core.QueryParams | undefined;
39
- }) => void;
35
+ searchParams?: _hyeonqyu_typed_router_core.ExtractSearchParams<_hyeonqyu_typed_router_core.GetRouteNode<TRouteTree, TPath>> | undefined;
36
+ } | undefined) => void;
37
+ prefetch: <TPath extends RoutePathname<TMetadata, TContext, TRouteTree>>(href: TPath, options?: {
38
+ searchParams?: _hyeonqyu_typed_router_core.ExtractSearchParams<_hyeonqyu_typed_router_core.GetRouteNode<TRouteTree, TPath>> | undefined;
39
+ } | undefined) => void;
40
40
  };
41
41
  useTypedPathname: () => RoutePathname<TMetadata, TContext, TRouteTree>;
42
+ useTypedSearchParams: <TPathname extends string = string>(_pathname: TPathname, _options?: {
43
+ onError?: "throw" | "default" | "raw";
44
+ }) => _hyeonqyu_typed_router_core.ExtractSearchParams<_hyeonqyu_typed_router_core.GetRouteNode<TRouteTree, TPathname>>;
42
45
  _types: {
43
46
  AppRoutesPathname: RoutePathname<TMetadata, TContext, TRouteTree>;
44
47
  AppRoutesMetadata: TMetadata;
package/dist/index.js CHANGED
@@ -20,9 +20,9 @@ var createTypedPathname = /* @__PURE__ */ __name(() => {
20
20
  };
21
21
  }, "createTypedPathname");
22
22
  var createTypedRouter = /* @__PURE__ */ __name(() => {
23
- const getHrefWithQuery = /* @__PURE__ */ __name((href, query) => {
24
- return `${href}${typedRouterCore.toQueryString(query ?? {}, { includeQuestionMark: true })}`;
25
- }, "getHrefWithQuery");
23
+ const getHrefWithSearchParams = /* @__PURE__ */ __name((href, searchParams) => {
24
+ return `${href}${typedRouterCore.toSearchParamsString(searchParams ?? {}, { includeQuestionMark: true })}`;
25
+ }, "getHrefWithSearchParams");
26
26
  return () => {
27
27
  const router = navigation.useRouter();
28
28
  return {
@@ -30,17 +30,32 @@ var createTypedRouter = /* @__PURE__ */ __name(() => {
30
30
  forward: router.forward,
31
31
  refresh: router.refresh,
32
32
  push: /* @__PURE__ */ __name((href, options) => {
33
- return router.push(getHrefWithQuery(href, options?.query), options);
33
+ return router.push(getHrefWithSearchParams(href, options?.searchParams), options);
34
34
  }, "push"),
35
35
  replace: /* @__PURE__ */ __name((href, options) => {
36
- return router.replace(getHrefWithQuery(href, options?.query), options);
36
+ return router.replace(getHrefWithSearchParams(href, options?.searchParams), options);
37
37
  }, "replace"),
38
38
  prefetch: /* @__PURE__ */ __name((href, options) => {
39
- return router.prefetch(getHrefWithQuery(href, options?.query));
39
+ return router.prefetch(getHrefWithSearchParams(href, options?.searchParams));
40
40
  }, "prefetch")
41
41
  };
42
42
  };
43
43
  }, "createTypedRouter");
44
+ var createTypedSearchParams = /* @__PURE__ */ __name(() => {
45
+ return (_pathname, _options) => {
46
+ const searchParams = navigation.useSearchParams();
47
+ const rawParams = {};
48
+ searchParams.forEach((value, key) => {
49
+ const existing = rawParams[key];
50
+ if (existing !== void 0) {
51
+ rawParams[key] = Array.isArray(existing) ? [...existing, value] : [existing, value];
52
+ } else {
53
+ rawParams[key] = value;
54
+ }
55
+ });
56
+ return rawParams;
57
+ };
58
+ }, "createTypedSearchParams");
44
59
  var createTypedLink = /* @__PURE__ */ __name(() => {
45
60
  const TypedLink = react.forwardRef((props, ref) => {
46
61
  return /* @__PURE__ */ jsxRuntime.jsx(Link__default.default, { ref, ...props });
@@ -54,6 +69,7 @@ var createAppRoutes = /* @__PURE__ */ __name(() => {
54
69
  const TypedLink = createTypedLink();
55
70
  const useTypedRouter = createTypedRouter();
56
71
  const useTypedPathname = createTypedPathname();
72
+ const useTypedSearchParams = createTypedSearchParams();
57
73
  return {
58
74
  AppRoutesProvider,
59
75
  useAppRoutes,
@@ -61,6 +77,7 @@ var createAppRoutes = /* @__PURE__ */ __name(() => {
61
77
  TypedLink,
62
78
  useTypedRouter,
63
79
  useTypedPathname,
80
+ useTypedSearchParams,
64
81
  _types: {
65
82
  ..._types,
66
83
  AppRoutesPathname: {}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/pathname.hooks.ts","../src/router.hooks.ts","../src/TypedLink.tsx","../src/index.tsx"],"names":["usePathname","toQueryString","useRouter","forwardRef","jsx","Link","createAppRoutesCore"],"mappings":";;;;;;;;;;;;;;;AAEO,IAAM,sCAAsB,MAAA,CAAA,MAAyC;AAC1E,EAAA,OAAO,MAAM;AACX,IAAA,MAAM,WAAWA,sBAAA,EAAY;AAC7B,IAAA,OAAO,QAAA;AAAA,EACT,CAAA;AACF,CAAA,EALmC,qBAAA,CAAA;ACQ5B,IAAM,oCAAoB,MAAA,CAAA,MAAyC;AACxE,EAAA,MAAM,gBAAA,mBAAmB,MAAA,CAAA,CAAC,IAAA,EAAiB,KAAA,KAAwB;AACjE,IAAA,OAAO,CAAA,EAAG,IAAI,CAAA,EAAGC,6BAAA,CAAc,KAAA,IAAS,EAAC,EAAG,EAAE,mBAAA,EAAqB,IAAA,EAAM,CAAC,CAAA,CAAA;AAAA,EAC5E,CAAA,EAFyB,kBAAA,CAAA;AAIzB,EAAA,OAAO,MAAM;AACX,IAAA,MAAM,SAASC,oBAAA,EAAU;AAEzB,IAAA,OAAO;AAAA,MACL,MAAM,MAAA,CAAO,IAAA;AAAA,MACb,SAAS,MAAA,CAAO,OAAA;AAAA,MAChB,SAAS,MAAA,CAAO,OAAA;AAAA,MAChB,IAAA,kBAAM,MAAA,CAAA,CAAC,IAAA,EAAiB,OAAA,KAA8B;AACpD,QAAA,OAAO,OAAO,IAAA,CAAK,gBAAA,CAAiB,MAAM,OAAA,EAAS,KAAK,GAAG,OAAO,CAAA;AAAA,MACpE,CAAA,EAFM,MAAA,CAAA;AAAA,MAGN,OAAA,kBAAS,MAAA,CAAA,CAAC,IAAA,EAAiB,OAAA,KAA8B;AACvD,QAAA,OAAO,OAAO,OAAA,CAAQ,gBAAA,CAAiB,MAAM,OAAA,EAAS,KAAK,GAAG,OAAO,CAAA;AAAA,MACvE,CAAA,EAFS,SAAA,CAAA;AAAA,MAGT,QAAA,kBAAU,MAAA,CAAA,CAAC,IAAA,EAAiB,OAAA,KAA8B;AACxD,QAAA,OAAO,OAAO,QAAA,CAAS,gBAAA,CAAiB,IAAA,EAAM,OAAA,EAAS,KAAK,CAAC,CAAA;AAAA,MAC/D,CAAA,EAFU,UAAA;AAAA,KAGZ;AAAA,EACF,CAAA;AACF,CAAA,EAvBiC,mBAAA,CAAA;ACM1B,IAAM,kCAAkB,MAAA,CAAA,MAAyC;AACtE,EAAA,MAAM,SAAA,GAAYC,gBAAA,CAAiE,CAAC,KAAA,EAAO,GAAA,KAAQ;AACjG,IAAA,uBAAOC,cAAA,CAACC,qBAAA,EAAA,EAAK,GAAA,EAAW,GAAI,KAAA,EAAyB,CAAA;AAAA,EACvD,CAAC,CAAA;AAED,EAAA,SAAA,CAAU,WAAA,GAAc,WAAA;AAExB,EAAA,OAAO,SAAA;AACT,CAAA,EAR+B,iBAAA,CAAA;ACVxB,IAAM,kCAAkB,MAAA,CAAA,MAAgD;AAC7E,EAAA,OAAO,CAA2D,SAAA,KAAuE;AACvI,IAAA,MAAM,EAAE,mBAAmB,YAAA,EAAc,mBAAA,EAAqB,QAAO,GAAIC,4BAAA,GAA2C,SAAS,CAAA;AAK7H,IAAA,MAAM,YAAY,eAAA,EAA0B;AAC5C,IAAA,MAAM,iBAAiB,iBAAA,EAA4B;AACnD,IAAA,MAAM,mBAAmB,mBAAA,EAA8B;AAEvD,IAAA,OAAO;AAAA,MACL,iBAAA;AAAA,MACA,YAAA;AAAA,MACA,mBAAA;AAAA,MACA,SAAA;AAAA,MACA,cAAA;AAAA,MACA,gBAAA;AAAA,MACA,MAAA,EAAQ;AAAA,QACN,GAAG,MAAA;AAAA,QACH,mBAAmB;AAAC;AACtB,KACF;AAAA,EACF,CAAA;AACF,CAAA,EAxB+B,iBAAA","file":"index.js","sourcesContent":["import { usePathname } from 'next/navigation';\n\nexport const createTypedPathname = <TPathname extends string = string>() => {\n return () => {\n const pathname = usePathname();\n return pathname as TPathname;\n };\n};\n","import { QueryParams, toQueryString } from '@hyeonqyu/typed-router-core';\nimport { useRouter } from 'next/navigation';\n\ntype NavigateOptions = {\n scroll?: boolean;\n query?: QueryParams;\n};\n\ntype PrefetchOptions = Pick<NavigateOptions, 'query'>;\n\nexport const createTypedRouter = <TPathname extends string = string>() => {\n const getHrefWithQuery = (href: TPathname, query?: QueryParams) => {\n return `${href}${toQueryString(query ?? {}, { includeQuestionMark: true })}`;\n };\n\n return () => {\n const router = useRouter();\n\n return {\n back: router.back,\n forward: router.forward,\n refresh: router.refresh,\n push: (href: TPathname, options?: NavigateOptions) => {\n return router.push(getHrefWithQuery(href, options?.query), options);\n },\n replace: (href: TPathname, options?: NavigateOptions) => {\n return router.replace(getHrefWithQuery(href, options?.query), options);\n },\n prefetch: (href: TPathname, options?: PrefetchOptions) => {\n return router.prefetch(getHrefWithQuery(href, options?.query));\n },\n };\n };\n};\n","import Link from 'next/link';\nimport type { ComponentProps, ComponentRef } from 'react';\nimport { forwardRef } from 'react';\n\ntype NextLinkProps = ComponentProps<typeof Link>;\n\nexport type TypedLinkProps<TPathname extends string = string> = Omit<NextLinkProps, 'href'> & {\n href:\n | TPathname\n | {\n pathname: TPathname;\n query?: Record<string, string | number | boolean | readonly (string | number | boolean)[]>;\n hash?: string;\n };\n};\n\nexport const createTypedLink = <TPathname extends string = string>() => {\n const TypedLink = forwardRef<ComponentRef<typeof Link>, TypedLinkProps<TPathname>>((props, ref) => {\n return <Link ref={ref} {...(props as NextLinkProps)} />;\n });\n\n TypedLink.displayName = 'TypedLink';\n\n return TypedLink;\n};\n","import type { BaseMetadata, PartialRouteTree, PathValue, ResolvedRouteTree, RoutePathname, RouteTree } from '@hyeonqyu/typed-router-core';\nimport { createAppRoutes as createAppRoutesCore } from '@hyeonqyu/typed-router-core/routes.utils';\nimport { createTypedPathname } from './pathname.hooks';\nimport { createTypedRouter } from './router.hooks';\nimport { createTypedLink } from './TypedLink';\n\nexport const createAppRoutes = <TMetadata extends BaseMetadata, TContext>() => {\n return <TRouteTree extends PartialRouteTree<TMetadata, TContext>>(appRoutes: TRouteTree & RouteTree<TMetadata, TContext, TRouteTree>) => {\n const { AppRoutesProvider, useAppRoutes, useCurrentRouteNode, _types } = createAppRoutesCore<TMetadata, TContext>()(appRoutes);\n\n type Pathname = RoutePathname<TMetadata, TContext, TRouteTree>;\n type Routes = ResolvedRouteTree<TMetadata, TContext, TRouteTree>;\n\n const TypedLink = createTypedLink<Pathname>();\n const useTypedRouter = createTypedRouter<Pathname>();\n const useTypedPathname = createTypedPathname<Pathname>();\n\n return {\n AppRoutesProvider,\n useAppRoutes: useAppRoutes as () => Routes,\n useCurrentRouteNode: useCurrentRouteNode as <TPath extends Pathname>(pathname: TPath) => PathValue<TRouteTree, TPath, '/'>,\n TypedLink,\n useTypedRouter,\n useTypedPathname,\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"]}
1
+ {"version":3,"sources":["../src/pathname.hooks.ts","../src/router.hooks.ts","../src/searchParams.hooks.ts","../src/TypedLink.tsx","../src/index.tsx"],"names":["usePathname","toSearchParamsString","useRouter","useSearchParams","forwardRef","jsx","Link","createAppRoutesCore"],"mappings":"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","file":"index.js","sourcesContent":["import { usePathname } from 'next/navigation';\n\nexport const createTypedPathname = <TPathname extends string = string>() => {\n return () => {\n const pathname = usePathname();\n return pathname as TPathname;\n };\n};\n","import { SearchParams, SearchParamsForPath, toSearchParamsString } from '@hyeonqyu/typed-router-core';\nimport { useRouter } from 'next/navigation';\n\ntype NavigateOptions<TSearchParams = SearchParams> = {\n scroll?: boolean;\n searchParams?: TSearchParams;\n};\n\ntype PrefetchOptions<TSearchParams = SearchParams> = Pick<NavigateOptions<TSearchParams>, 'searchParams'>;\n\nexport const createTypedRouter = <TPathname extends string = string, TRouteTree = unknown>() => {\n const getHrefWithSearchParams = (href: TPathname, searchParams?: SearchParams) => {\n return `${href}${toSearchParamsString(searchParams ?? {}, { includeQuestionMark: true })}`;\n };\n\n return () => {\n const router = useRouter();\n\n return {\n back: router.back,\n forward: router.forward,\n refresh: router.refresh,\n push: <TPath extends TPathname>(href: TPath, options?: NavigateOptions<SearchParamsForPath<TRouteTree, TPath>>) => {\n return router.push(getHrefWithSearchParams(href, options?.searchParams as SearchParams), options);\n },\n replace: <TPath extends TPathname>(href: TPath, options?: NavigateOptions<SearchParamsForPath<TRouteTree, TPath>>) => {\n return router.replace(getHrefWithSearchParams(href, options?.searchParams as SearchParams), options);\n },\n prefetch: <TPath extends TPathname>(href: TPath, options?: PrefetchOptions<SearchParamsForPath<TRouteTree, TPath>>) => {\n return router.prefetch(getHrefWithSearchParams(href, options?.searchParams as SearchParams));\n },\n };\n };\n};\n","import type { SearchParamsForPath } from '@hyeonqyu/typed-router-core';\nimport { useSearchParams } from 'next/navigation';\n\ntype ParseOptions = {\n /**\n * Error handling mode\n * - 'throw': Throw error on validation failure\n * - 'default': Return schema defaults on validation failure\n * - 'raw': Return raw unparsed values on validation failure\n */\n onError?: 'throw' | 'default' | 'raw';\n};\n\nexport const createTypedSearchParams = <TRouteTree = unknown>() => {\n return <TPathname extends string = string>(_pathname: TPathname, _options?: ParseOptions) => {\n const searchParams = useSearchParams();\n\n type ExpectedParams = SearchParamsForPath<TRouteTree, TPathname>;\n\n // Convert URLSearchParams to plain object\n const rawParams: Record<string, unknown> = {};\n searchParams.forEach((value, key) => {\n const existing = rawParams[key];\n if (existing !== undefined) {\n // Handle multiple values for the same key\n rawParams[key] = Array.isArray(existing) ? [...existing, value] : [existing, value];\n } else {\n rawParams[key] = value;\n }\n });\n\n // For now, return raw params as ExpectedParams\n // When schema is available at runtime, we would parse with Zod here\n return rawParams as ExpectedParams;\n };\n};\n","import type { SearchParamsForPath } from '@hyeonqyu/typed-router-core';\nimport Link from 'next/link';\nimport type { ComponentProps, ComponentRef } from 'react';\nimport { forwardRef } from 'react';\n\ntype NextLinkProps = ComponentProps<typeof Link>;\n\nexport type TypedLinkProps<TPathname extends string = string, TRouteTree = unknown> = Omit<NextLinkProps, 'href'> & {\n href:\n | TPathname\n | (TPathname extends infer TPath\n ? {\n pathname: TPath;\n searchParams?: SearchParamsForPath<TRouteTree, TPath & string>;\n hash?: string;\n }\n : never);\n};\n\nexport const createTypedLink = <TPathname extends string = string, TRouteTree = unknown>() => {\n const TypedLink = forwardRef<ComponentRef<typeof Link>, TypedLinkProps<TPathname, TRouteTree>>((props, ref) => {\n return <Link ref={ref} {...(props as NextLinkProps)} />;\n });\n\n TypedLink.displayName = 'TypedLink';\n\n return TypedLink;\n};\n","import type { BaseMetadata, PartialRouteTree, PathValue, ResolvedRouteTree, RoutePathname, RouteTree } from '@hyeonqyu/typed-router-core';\nimport { createAppRoutes as createAppRoutesCore } from '@hyeonqyu/typed-router-core/routes.utils';\nimport { createTypedPathname } from './pathname.hooks';\nimport { createTypedRouter } from './router.hooks';\nimport { createTypedSearchParams } from './searchParams.hooks';\nimport { createTypedLink } from './TypedLink';\n\nexport const createAppRoutes = <TMetadata extends BaseMetadata, TContext>() => {\n return <TRouteTree extends PartialRouteTree<TMetadata, TContext>>(appRoutes: TRouteTree & RouteTree<TMetadata, TContext, TRouteTree>) => {\n const { AppRoutesProvider, useAppRoutes, useCurrentRouteNode, _types } = createAppRoutesCore<TMetadata, TContext>()(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 useTypedRouter = createTypedRouter<Pathname, TRouteTree>();\n const useTypedPathname = createTypedPathname<Pathname>();\n const useTypedSearchParams = createTypedSearchParams<TRouteTree>();\n\n return {\n AppRoutesProvider,\n useAppRoutes: useAppRoutes as () => Routes,\n useCurrentRouteNode: useCurrentRouteNode as <TPath extends Pathname>(pathname: TPath) => PathValue<TRouteTree, TPath, '/'>,\n TypedLink,\n useTypedRouter,\n useTypedPathname,\n useTypedSearchParams,\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,6 +1,6 @@
1
1
  import { createAppRoutes as createAppRoutes$1 } from '@hyeonqyu/typed-router-core/routes.utils';
2
- import { useRouter, usePathname } from 'next/navigation';
3
- import { toQueryString } from '@hyeonqyu/typed-router-core';
2
+ import { useRouter, usePathname, useSearchParams } from 'next/navigation';
3
+ import { toSearchParamsString } from '@hyeonqyu/typed-router-core';
4
4
  export * from '@hyeonqyu/typed-router-core';
5
5
  import Link from 'next/link';
6
6
  import { forwardRef } from 'react';
@@ -15,9 +15,9 @@ var createTypedPathname = /* @__PURE__ */ __name(() => {
15
15
  };
16
16
  }, "createTypedPathname");
17
17
  var createTypedRouter = /* @__PURE__ */ __name(() => {
18
- const getHrefWithQuery = /* @__PURE__ */ __name((href, query) => {
19
- return `${href}${toQueryString(query ?? {}, { includeQuestionMark: true })}`;
20
- }, "getHrefWithQuery");
18
+ const getHrefWithSearchParams = /* @__PURE__ */ __name((href, searchParams) => {
19
+ return `${href}${toSearchParamsString(searchParams ?? {}, { includeQuestionMark: true })}`;
20
+ }, "getHrefWithSearchParams");
21
21
  return () => {
22
22
  const router = useRouter();
23
23
  return {
@@ -25,17 +25,32 @@ var createTypedRouter = /* @__PURE__ */ __name(() => {
25
25
  forward: router.forward,
26
26
  refresh: router.refresh,
27
27
  push: /* @__PURE__ */ __name((href, options) => {
28
- return router.push(getHrefWithQuery(href, options?.query), options);
28
+ return router.push(getHrefWithSearchParams(href, options?.searchParams), options);
29
29
  }, "push"),
30
30
  replace: /* @__PURE__ */ __name((href, options) => {
31
- return router.replace(getHrefWithQuery(href, options?.query), options);
31
+ return router.replace(getHrefWithSearchParams(href, options?.searchParams), options);
32
32
  }, "replace"),
33
33
  prefetch: /* @__PURE__ */ __name((href, options) => {
34
- return router.prefetch(getHrefWithQuery(href, options?.query));
34
+ return router.prefetch(getHrefWithSearchParams(href, options?.searchParams));
35
35
  }, "prefetch")
36
36
  };
37
37
  };
38
38
  }, "createTypedRouter");
39
+ var createTypedSearchParams = /* @__PURE__ */ __name(() => {
40
+ return (_pathname, _options) => {
41
+ const searchParams = useSearchParams();
42
+ const rawParams = {};
43
+ searchParams.forEach((value, key) => {
44
+ const existing = rawParams[key];
45
+ if (existing !== void 0) {
46
+ rawParams[key] = Array.isArray(existing) ? [...existing, value] : [existing, value];
47
+ } else {
48
+ rawParams[key] = value;
49
+ }
50
+ });
51
+ return rawParams;
52
+ };
53
+ }, "createTypedSearchParams");
39
54
  var createTypedLink = /* @__PURE__ */ __name(() => {
40
55
  const TypedLink = forwardRef((props, ref) => {
41
56
  return /* @__PURE__ */ jsx(Link, { ref, ...props });
@@ -49,6 +64,7 @@ var createAppRoutes = /* @__PURE__ */ __name(() => {
49
64
  const TypedLink = createTypedLink();
50
65
  const useTypedRouter = createTypedRouter();
51
66
  const useTypedPathname = createTypedPathname();
67
+ const useTypedSearchParams = createTypedSearchParams();
52
68
  return {
53
69
  AppRoutesProvider,
54
70
  useAppRoutes,
@@ -56,6 +72,7 @@ var createAppRoutes = /* @__PURE__ */ __name(() => {
56
72
  TypedLink,
57
73
  useTypedRouter,
58
74
  useTypedPathname,
75
+ useTypedSearchParams,
59
76
  _types: {
60
77
  ..._types,
61
78
  AppRoutesPathname: {}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/pathname.hooks.ts","../src/router.hooks.ts","../src/TypedLink.tsx","../src/index.tsx"],"names":["createAppRoutesCore"],"mappings":";;;;;;;;;;AAEO,IAAM,sCAAsB,MAAA,CAAA,MAAyC;AAC1E,EAAA,OAAO,MAAM;AACX,IAAA,MAAM,WAAW,WAAA,EAAY;AAC7B,IAAA,OAAO,QAAA;AAAA,EACT,CAAA;AACF,CAAA,EALmC,qBAAA,CAAA;ACQ5B,IAAM,oCAAoB,MAAA,CAAA,MAAyC;AACxE,EAAA,MAAM,gBAAA,mBAAmB,MAAA,CAAA,CAAC,IAAA,EAAiB,KAAA,KAAwB;AACjE,IAAA,OAAO,CAAA,EAAG,IAAI,CAAA,EAAG,aAAA,CAAc,KAAA,IAAS,EAAC,EAAG,EAAE,mBAAA,EAAqB,IAAA,EAAM,CAAC,CAAA,CAAA;AAAA,EAC5E,CAAA,EAFyB,kBAAA,CAAA;AAIzB,EAAA,OAAO,MAAM;AACX,IAAA,MAAM,SAAS,SAAA,EAAU;AAEzB,IAAA,OAAO;AAAA,MACL,MAAM,MAAA,CAAO,IAAA;AAAA,MACb,SAAS,MAAA,CAAO,OAAA;AAAA,MAChB,SAAS,MAAA,CAAO,OAAA;AAAA,MAChB,IAAA,kBAAM,MAAA,CAAA,CAAC,IAAA,EAAiB,OAAA,KAA8B;AACpD,QAAA,OAAO,OAAO,IAAA,CAAK,gBAAA,CAAiB,MAAM,OAAA,EAAS,KAAK,GAAG,OAAO,CAAA;AAAA,MACpE,CAAA,EAFM,MAAA,CAAA;AAAA,MAGN,OAAA,kBAAS,MAAA,CAAA,CAAC,IAAA,EAAiB,OAAA,KAA8B;AACvD,QAAA,OAAO,OAAO,OAAA,CAAQ,gBAAA,CAAiB,MAAM,OAAA,EAAS,KAAK,GAAG,OAAO,CAAA;AAAA,MACvE,CAAA,EAFS,SAAA,CAAA;AAAA,MAGT,QAAA,kBAAU,MAAA,CAAA,CAAC,IAAA,EAAiB,OAAA,KAA8B;AACxD,QAAA,OAAO,OAAO,QAAA,CAAS,gBAAA,CAAiB,IAAA,EAAM,OAAA,EAAS,KAAK,CAAC,CAAA;AAAA,MAC/D,CAAA,EAFU,UAAA;AAAA,KAGZ;AAAA,EACF,CAAA;AACF,CAAA,EAvBiC,mBAAA,CAAA;ACM1B,IAAM,kCAAkB,MAAA,CAAA,MAAyC;AACtE,EAAA,MAAM,SAAA,GAAY,UAAA,CAAiE,CAAC,KAAA,EAAO,GAAA,KAAQ;AACjG,IAAA,uBAAO,GAAA,CAAC,IAAA,EAAA,EAAK,GAAA,EAAW,GAAI,KAAA,EAAyB,CAAA;AAAA,EACvD,CAAC,CAAA;AAED,EAAA,SAAA,CAAU,WAAA,GAAc,WAAA;AAExB,EAAA,OAAO,SAAA;AACT,CAAA,EAR+B,iBAAA,CAAA;ACVxB,IAAM,kCAAkB,MAAA,CAAA,MAAgD;AAC7E,EAAA,OAAO,CAA2D,SAAA,KAAuE;AACvI,IAAA,MAAM,EAAE,mBAAmB,YAAA,EAAc,mBAAA,EAAqB,QAAO,GAAIA,iBAAA,GAA2C,SAAS,CAAA;AAK7H,IAAA,MAAM,YAAY,eAAA,EAA0B;AAC5C,IAAA,MAAM,iBAAiB,iBAAA,EAA4B;AACnD,IAAA,MAAM,mBAAmB,mBAAA,EAA8B;AAEvD,IAAA,OAAO;AAAA,MACL,iBAAA;AAAA,MACA,YAAA;AAAA,MACA,mBAAA;AAAA,MACA,SAAA;AAAA,MACA,cAAA;AAAA,MACA,gBAAA;AAAA,MACA,MAAA,EAAQ;AAAA,QACN,GAAG,MAAA;AAAA,QACH,mBAAmB;AAAC;AACtB,KACF;AAAA,EACF,CAAA;AACF,CAAA,EAxB+B,iBAAA","file":"index.mjs","sourcesContent":["import { usePathname } from 'next/navigation';\n\nexport const createTypedPathname = <TPathname extends string = string>() => {\n return () => {\n const pathname = usePathname();\n return pathname as TPathname;\n };\n};\n","import { QueryParams, toQueryString } from '@hyeonqyu/typed-router-core';\nimport { useRouter } from 'next/navigation';\n\ntype NavigateOptions = {\n scroll?: boolean;\n query?: QueryParams;\n};\n\ntype PrefetchOptions = Pick<NavigateOptions, 'query'>;\n\nexport const createTypedRouter = <TPathname extends string = string>() => {\n const getHrefWithQuery = (href: TPathname, query?: QueryParams) => {\n return `${href}${toQueryString(query ?? {}, { includeQuestionMark: true })}`;\n };\n\n return () => {\n const router = useRouter();\n\n return {\n back: router.back,\n forward: router.forward,\n refresh: router.refresh,\n push: (href: TPathname, options?: NavigateOptions) => {\n return router.push(getHrefWithQuery(href, options?.query), options);\n },\n replace: (href: TPathname, options?: NavigateOptions) => {\n return router.replace(getHrefWithQuery(href, options?.query), options);\n },\n prefetch: (href: TPathname, options?: PrefetchOptions) => {\n return router.prefetch(getHrefWithQuery(href, options?.query));\n },\n };\n };\n};\n","import Link from 'next/link';\nimport type { ComponentProps, ComponentRef } from 'react';\nimport { forwardRef } from 'react';\n\ntype NextLinkProps = ComponentProps<typeof Link>;\n\nexport type TypedLinkProps<TPathname extends string = string> = Omit<NextLinkProps, 'href'> & {\n href:\n | TPathname\n | {\n pathname: TPathname;\n query?: Record<string, string | number | boolean | readonly (string | number | boolean)[]>;\n hash?: string;\n };\n};\n\nexport const createTypedLink = <TPathname extends string = string>() => {\n const TypedLink = forwardRef<ComponentRef<typeof Link>, TypedLinkProps<TPathname>>((props, ref) => {\n return <Link ref={ref} {...(props as NextLinkProps)} />;\n });\n\n TypedLink.displayName = 'TypedLink';\n\n return TypedLink;\n};\n","import type { BaseMetadata, PartialRouteTree, PathValue, ResolvedRouteTree, RoutePathname, RouteTree } from '@hyeonqyu/typed-router-core';\nimport { createAppRoutes as createAppRoutesCore } from '@hyeonqyu/typed-router-core/routes.utils';\nimport { createTypedPathname } from './pathname.hooks';\nimport { createTypedRouter } from './router.hooks';\nimport { createTypedLink } from './TypedLink';\n\nexport const createAppRoutes = <TMetadata extends BaseMetadata, TContext>() => {\n return <TRouteTree extends PartialRouteTree<TMetadata, TContext>>(appRoutes: TRouteTree & RouteTree<TMetadata, TContext, TRouteTree>) => {\n const { AppRoutesProvider, useAppRoutes, useCurrentRouteNode, _types } = createAppRoutesCore<TMetadata, TContext>()(appRoutes);\n\n type Pathname = RoutePathname<TMetadata, TContext, TRouteTree>;\n type Routes = ResolvedRouteTree<TMetadata, TContext, TRouteTree>;\n\n const TypedLink = createTypedLink<Pathname>();\n const useTypedRouter = createTypedRouter<Pathname>();\n const useTypedPathname = createTypedPathname<Pathname>();\n\n return {\n AppRoutesProvider,\n useAppRoutes: useAppRoutes as () => Routes,\n useCurrentRouteNode: useCurrentRouteNode as <TPath extends Pathname>(pathname: TPath) => PathValue<TRouteTree, TPath, '/'>,\n TypedLink,\n useTypedRouter,\n useTypedPathname,\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"]}
1
+ {"version":3,"sources":["../src/pathname.hooks.ts","../src/router.hooks.ts","../src/searchParams.hooks.ts","../src/TypedLink.tsx","../src/index.tsx"],"names":["createAppRoutesCore"],"mappings":"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","file":"index.mjs","sourcesContent":["import { usePathname } from 'next/navigation';\n\nexport const createTypedPathname = <TPathname extends string = string>() => {\n return () => {\n const pathname = usePathname();\n return pathname as TPathname;\n };\n};\n","import { SearchParams, SearchParamsForPath, toSearchParamsString } from '@hyeonqyu/typed-router-core';\nimport { useRouter } from 'next/navigation';\n\ntype NavigateOptions<TSearchParams = SearchParams> = {\n scroll?: boolean;\n searchParams?: TSearchParams;\n};\n\ntype PrefetchOptions<TSearchParams = SearchParams> = Pick<NavigateOptions<TSearchParams>, 'searchParams'>;\n\nexport const createTypedRouter = <TPathname extends string = string, TRouteTree = unknown>() => {\n const getHrefWithSearchParams = (href: TPathname, searchParams?: SearchParams) => {\n return `${href}${toSearchParamsString(searchParams ?? {}, { includeQuestionMark: true })}`;\n };\n\n return () => {\n const router = useRouter();\n\n return {\n back: router.back,\n forward: router.forward,\n refresh: router.refresh,\n push: <TPath extends TPathname>(href: TPath, options?: NavigateOptions<SearchParamsForPath<TRouteTree, TPath>>) => {\n return router.push(getHrefWithSearchParams(href, options?.searchParams as SearchParams), options);\n },\n replace: <TPath extends TPathname>(href: TPath, options?: NavigateOptions<SearchParamsForPath<TRouteTree, TPath>>) => {\n return router.replace(getHrefWithSearchParams(href, options?.searchParams as SearchParams), options);\n },\n prefetch: <TPath extends TPathname>(href: TPath, options?: PrefetchOptions<SearchParamsForPath<TRouteTree, TPath>>) => {\n return router.prefetch(getHrefWithSearchParams(href, options?.searchParams as SearchParams));\n },\n };\n };\n};\n","import type { SearchParamsForPath } from '@hyeonqyu/typed-router-core';\nimport { useSearchParams } from 'next/navigation';\n\ntype ParseOptions = {\n /**\n * Error handling mode\n * - 'throw': Throw error on validation failure\n * - 'default': Return schema defaults on validation failure\n * - 'raw': Return raw unparsed values on validation failure\n */\n onError?: 'throw' | 'default' | 'raw';\n};\n\nexport const createTypedSearchParams = <TRouteTree = unknown>() => {\n return <TPathname extends string = string>(_pathname: TPathname, _options?: ParseOptions) => {\n const searchParams = useSearchParams();\n\n type ExpectedParams = SearchParamsForPath<TRouteTree, TPathname>;\n\n // Convert URLSearchParams to plain object\n const rawParams: Record<string, unknown> = {};\n searchParams.forEach((value, key) => {\n const existing = rawParams[key];\n if (existing !== undefined) {\n // Handle multiple values for the same key\n rawParams[key] = Array.isArray(existing) ? [...existing, value] : [existing, value];\n } else {\n rawParams[key] = value;\n }\n });\n\n // For now, return raw params as ExpectedParams\n // When schema is available at runtime, we would parse with Zod here\n return rawParams as ExpectedParams;\n };\n};\n","import type { SearchParamsForPath } from '@hyeonqyu/typed-router-core';\nimport Link from 'next/link';\nimport type { ComponentProps, ComponentRef } from 'react';\nimport { forwardRef } from 'react';\n\ntype NextLinkProps = ComponentProps<typeof Link>;\n\nexport type TypedLinkProps<TPathname extends string = string, TRouteTree = unknown> = Omit<NextLinkProps, 'href'> & {\n href:\n | TPathname\n | (TPathname extends infer TPath\n ? {\n pathname: TPath;\n searchParams?: SearchParamsForPath<TRouteTree, TPath & string>;\n hash?: string;\n }\n : never);\n};\n\nexport const createTypedLink = <TPathname extends string = string, TRouteTree = unknown>() => {\n const TypedLink = forwardRef<ComponentRef<typeof Link>, TypedLinkProps<TPathname, TRouteTree>>((props, ref) => {\n return <Link ref={ref} {...(props as NextLinkProps)} />;\n });\n\n TypedLink.displayName = 'TypedLink';\n\n return TypedLink;\n};\n","import type { BaseMetadata, PartialRouteTree, PathValue, ResolvedRouteTree, RoutePathname, RouteTree } from '@hyeonqyu/typed-router-core';\nimport { createAppRoutes as createAppRoutesCore } from '@hyeonqyu/typed-router-core/routes.utils';\nimport { createTypedPathname } from './pathname.hooks';\nimport { createTypedRouter } from './router.hooks';\nimport { createTypedSearchParams } from './searchParams.hooks';\nimport { createTypedLink } from './TypedLink';\n\nexport const createAppRoutes = <TMetadata extends BaseMetadata, TContext>() => {\n return <TRouteTree extends PartialRouteTree<TMetadata, TContext>>(appRoutes: TRouteTree & RouteTree<TMetadata, TContext, TRouteTree>) => {\n const { AppRoutesProvider, useAppRoutes, useCurrentRouteNode, _types } = createAppRoutesCore<TMetadata, TContext>()(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 useTypedRouter = createTypedRouter<Pathname, TRouteTree>();\n const useTypedPathname = createTypedPathname<Pathname>();\n const useTypedSearchParams = createTypedSearchParams<TRouteTree>();\n\n return {\n AppRoutesProvider,\n useAppRoutes: useAppRoutes as () => Routes,\n useCurrentRouteNode: useCurrentRouteNode as <TPath extends Pathname>(pathname: TPath) => PathValue<TRouteTree, TPath, '/'>,\n TypedLink,\n useTypedRouter,\n useTypedPathname,\n useTypedSearchParams,\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-next",
3
- "version": "0.2.10",
3
+ "version": "1.0.0",
4
4
  "description": "Type-safe IA-first routing for Next.js",
5
5
  "author": "hyeonQyu <dhk0561@naver.com>",
6
6
  "license": "MIT",
@@ -46,7 +46,7 @@
46
46
  "type": "tsc --noEmit"
47
47
  },
48
48
  "peerDependencies": {
49
- "next": "^13.0.0 || ^14.0.0 || ^15.0.0",
49
+ "next": "^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0",
50
50
  "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
51
51
  },
52
52
  "dependencies": {