@kirill.konshin/next 0.0.2 → 0.0.4

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.
@@ -8,17 +8,18 @@
8
8
 
9
9
  ✔ ctix 'create' mode complete!
10
10
  transforming...
11
- ✓ 6 modules transformed.
11
+ ✓ 7 modules transformed.
12
12
  rendering chunks...
13
13
 
14
14
  [vite:dts] Start generate declaration files...
15
- dist/noSSR.js 0.35 kB │ map: 1.45 kB
16
- dist/index.js 0.35 kB │ map: 0.09 kB
15
+ dist/noSSR.js 0.35 kB │ map: 1.52 kB
17
16
  dist/useIsInner.js 0.37 kB │ map: 0.61 kB
18
- dist/redirect.js 0.38 kB │ map: 0.85 kB
17
+ dist/redirect.js 0.38 kB │ map: 0.87 kB
19
18
  dist/measure.js 0.38 kB │ map: 1.04 kB
20
- dist/appLink.js 0.80 kB │ map: 1.62 kB
21
- [vite:dts] Declaration files built in 1665ms.
19
+ dist/index.js 0.44 kB │ map: 0.10 kB
20
+ dist/softLink.js 0.72 kB map: 1.85 kB
21
+ dist/appLink.js 1.02 kB │ map: 2.14 kB
22
+ [vite:dts] Declaration files built in 1481ms.
22
23
 
23
- ✓ built in 4.92s
24
+ ✓ built in 6.03s
24
25
  Updated package.json with exports
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @kirill.konshin/next
2
2
 
3
+ ## 0.0.4
4
+
5
+ ### Patch Changes
6
+
7
+ - Minor fixes
8
+
9
+ ## 0.0.3
10
+
11
+ ### Patch Changes
12
+
13
+ - Small fixes
14
+
3
15
  ## 0.0.2
4
16
 
5
17
  ### Patch Changes
package/dist/appLink.d.ts CHANGED
@@ -5,5 +5,6 @@ export type AppLinkProps = {
5
5
  exact?: boolean;
6
6
  activeClassName?: any;
7
7
  } & LinkProps & ComponentProps<typeof Link>;
8
+ export declare function useIsLinkActive(): (href: ComponentProps<typeof Link>['href'], exact: boolean) => boolean;
8
9
  export declare const AppLink: FC<AppLinkProps>;
9
10
  //# sourceMappingURL=appLink.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"appLink.d.ts","sourceRoot":"","sources":["../src/appLink.tsx"],"names":[],"mappings":"AAEA,OAAc,EAAE,cAAc,EAAE,EAAE,EAAQ,MAAM,OAAO,CAAC;AAExD,OAAO,IAAI,EAAE,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAG5C,MAAM,MAAM,YAAY,GAAG;IACvB,QAAQ,EAAE,GAAG,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,eAAe,CAAC,EAAE,GAAG,CAAC;CACzB,GAAG,SAAS,GACT,cAAc,CAAC,OAAO,IAAI,CAAC,CAAC;AAGhC,eAAO,MAAM,OAAO,EAAE,EAAE,CAAC,YAAY,CAwBnC,CAAC"}
1
+ {"version":3,"file":"appLink.d.ts","sourceRoot":"","sources":["../src/appLink.tsx"],"names":[],"mappings":"AAEA,OAAc,EAAE,cAAc,EAAE,EAAE,EAA8B,MAAM,OAAO,CAAC;AAE9E,OAAO,IAAI,EAAE,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAG5C,MAAM,MAAM,YAAY,GAAG;IACvB,QAAQ,EAAE,GAAG,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,eAAe,CAAC,EAAE,GAAG,CAAC;CACzB,GAAG,SAAS,GACT,cAAc,CAAC,OAAO,IAAI,CAAC,CAAC;AAEhC,wBAAgB,eAAe,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,KAAK,OAAO,CAUxG;AAGD,eAAO,MAAM,OAAO,EAAE,EAAE,CAAC,YAAY,CAuBnC,CAAC"}
package/dist/appLink.js CHANGED
@@ -1,9 +1,19 @@
1
1
  "use client";
2
2
  import { jsx } from "react/jsx-runtime";
3
- import { memo } from "react";
3
+ import { memo, useCallback } from "react";
4
4
  import { usePathname } from "next/navigation";
5
5
  import Link from "next/link";
6
6
  import clsx from "clsx";
7
+ function useIsLinkActive() {
8
+ const pathname = usePathname();
9
+ return useCallback(
10
+ (href, exact) => {
11
+ const hrefPath = typeof href === "string" ? href : href.pathname || "/";
12
+ return !exact && pathname.startsWith(hrefPath) || exact && pathname === hrefPath;
13
+ },
14
+ [pathname]
15
+ );
16
+ }
7
17
  const AppLink = memo(function AppLink2({
8
18
  href,
9
19
  children,
@@ -14,15 +24,14 @@ const AppLink = memo(function AppLink2({
14
24
  exact = false,
15
25
  ...props
16
26
  }) {
17
- const pathname = usePathname();
18
- const hrefPath = typeof href === "string" ? href : href.pathname || "/";
27
+ const isActive = useIsLinkActive();
19
28
  return /* @__PURE__ */ jsx(
20
29
  Link,
21
30
  {
22
31
  ...props,
23
32
  href,
24
33
  className: clsx(className, {
25
- [activeClassName]: !exact && pathname.startsWith(hrefPath) || exact && pathname === hrefPath
34
+ [activeClassName]: isActive(href, exact)
26
35
  }),
27
36
  prefetch,
28
37
  children
@@ -30,6 +39,7 @@ const AppLink = memo(function AppLink2({
30
39
  );
31
40
  });
32
41
  export {
33
- AppLink
42
+ AppLink,
43
+ useIsLinkActive
34
44
  };
35
45
  //# sourceMappingURL=appLink.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"appLink.js","sources":["../src/appLink.tsx"],"sourcesContent":["'use client';\n\nimport React, { ComponentProps, FC, memo } from 'react';\nimport { usePathname } from 'next/navigation';\nimport Link, { LinkProps } from 'next/link';\nimport clsx from 'clsx';\n\nexport type AppLinkProps = {\n children: any;\n exact?: boolean;\n activeClassName?: any;\n} & LinkProps &\n ComponentProps<typeof Link>;\n\n//TODO Test this\nexport const AppLink: FC<AppLinkProps> = memo(function AppLink({\n href,\n children,\n className = '',\n activeClassName = '',\n prefetch = false, // set explicit default\n exact = false,\n ...props\n}) {\n const pathname = usePathname();\n const hrefPath = typeof href === 'string' ? href : href.pathname || '/';\n\n return (\n <Link\n {...props}\n href={href}\n className={clsx(className, {\n [activeClassName]: (!exact && pathname.startsWith(hrefPath)) || (exact && pathname === hrefPath),\n })}\n prefetch={prefetch}\n >\n {children}\n </Link>\n );\n});\n"],"names":["AppLink"],"mappings":";;;;;;AAeO,MAAM,UAA4B,KAAK,SAASA,SAAQ;AAAA,EAC3D;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,kBAAkB;AAAA,EAClB,WAAW;AAAA;AAAA,EACX,QAAQ;AAAA,EACR,GAAG;AACP,GAAG;AACC,QAAM,WAAW,YAAA;AACjB,QAAM,WAAW,OAAO,SAAS,WAAW,OAAO,KAAK,YAAY;AAEpE,SACI;AAAA,IAAC;AAAA,IAAA;AAAA,MACI,GAAG;AAAA,MACJ;AAAA,MACA,WAAW,KAAK,WAAW;AAAA,QACvB,CAAC,eAAe,GAAI,CAAC,SAAS,SAAS,WAAW,QAAQ,KAAO,SAAS,aAAa;AAAA,MAAA,CAC1F;AAAA,MACD;AAAA,MAEC;AAAA,IAAA;AAAA,EAAA;AAGb,CAAC;"}
1
+ {"version":3,"file":"appLink.js","sources":["../src/appLink.tsx"],"sourcesContent":["'use client';\n\nimport React, { ComponentProps, FC, memo, useCallback, useMemo } from 'react';\nimport { usePathname } from 'next/navigation';\nimport Link, { LinkProps } from 'next/link';\nimport clsx from 'clsx';\n\nexport type AppLinkProps = {\n children: any;\n exact?: boolean;\n activeClassName?: any;\n} & LinkProps &\n ComponentProps<typeof Link>;\n\nexport function useIsLinkActive(): (href: ComponentProps<typeof Link>['href'], exact: boolean) => boolean {\n const pathname = usePathname();\n\n return useCallback(\n (href: ComponentProps<typeof Link>['href'], exact: boolean): boolean => {\n const hrefPath = typeof href === 'string' ? href : href.pathname || '/';\n return (!exact && pathname.startsWith(hrefPath)) || (exact && pathname === hrefPath);\n },\n [pathname],\n );\n}\n\n//TODO Test this\nexport const AppLink: FC<AppLinkProps> = memo(function AppLink({\n href,\n children,\n className = '',\n activeClassName = '',\n prefetch = false, // set explicit default\n exact = false,\n ...props\n}) {\n const isActive = useIsLinkActive();\n\n return (\n <Link\n {...props}\n href={href}\n className={clsx(className, {\n [activeClassName]: isActive(href, exact),\n })}\n prefetch={prefetch}\n >\n {children}\n </Link>\n );\n});\n"],"names":["AppLink"],"mappings":";;;;;;AAcO,SAAS,kBAA0F;AACtG,QAAM,WAAW,YAAA;AAEjB,SAAO;AAAA,IACH,CAAC,MAA2C,UAA4B;AACpE,YAAM,WAAW,OAAO,SAAS,WAAW,OAAO,KAAK,YAAY;AACpE,aAAQ,CAAC,SAAS,SAAS,WAAW,QAAQ,KAAO,SAAS,aAAa;AAAA,IAC/E;AAAA,IACA,CAAC,QAAQ;AAAA,EAAA;AAEjB;AAGO,MAAM,UAA4B,KAAK,SAASA,SAAQ;AAAA,EAC3D;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,kBAAkB;AAAA,EAClB,WAAW;AAAA;AAAA,EACX,QAAQ;AAAA,EACR,GAAG;AACP,GAAG;AACC,QAAM,WAAW,gBAAA;AAEjB,SACI;AAAA,IAAC;AAAA,IAAA;AAAA,MACI,GAAG;AAAA,MACJ;AAAA,MACA,WAAW,KAAK,WAAW;AAAA,QACvB,CAAC,eAAe,GAAG,SAAS,MAAM,KAAK;AAAA,MAAA,CAC1C;AAAA,MACD;AAAA,MAEC;AAAA,IAAA;AAAA,EAAA;AAGb,CAAC;"}
package/dist/index.d.ts CHANGED
@@ -2,5 +2,6 @@ export * from './appLink';
2
2
  export * from './measure';
3
3
  export * from './noSSR';
4
4
  export * from './redirect';
5
+ export * from './softLink';
5
6
  export * from './useIsInner';
6
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC"}
package/dist/index.js CHANGED
@@ -1,15 +1,18 @@
1
- import { AppLink } from "./appLink.js";
1
+ import { AppLink, useIsLinkActive } from "./appLink.js";
2
2
  import { isProd, measurer } from "./measure.js";
3
3
  import { NoSSR } from "./noSSR.js";
4
4
  import { Redirect } from "./redirect.js";
5
+ import { SoftLink } from "./softLink.js";
5
6
  import { useIsIndex, useIsInner } from "./useIsInner.js";
6
7
  export {
7
8
  AppLink,
8
9
  NoSSR,
9
10
  Redirect,
11
+ SoftLink,
10
12
  isProd,
11
13
  measurer,
12
14
  useIsIndex,
13
- useIsInner
15
+ useIsInner,
16
+ useIsLinkActive
14
17
  };
15
18
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"noSSR.d.ts","sourceRoot":"","sources":["../src/noSSR.tsx"],"names":[],"mappings":"AAEA,OAAc,EAAE,EAAE,EAAQ,GAAG,EAA6B,MAAM,OAAO,CAAC;AAExE,MAAM,MAAM,UAAU,GAAG;IACrB,QAAQ,EAAE,GAAG,CAAC;IACd,KAAK,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;CACvB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,KAAK,EAAE,EAAE,CAAC,UAAU,CAQ/B,CAAC"}
1
+ {"version":3,"file":"noSSR.d.ts","sourceRoot":"","sources":["../src/noSSR.tsx"],"names":[],"mappings":"AAEA,OAAc,EAAE,EAAE,EAAQ,GAAG,EAA6B,MAAM,OAAO,CAAC;AAExE,MAAM,MAAM,UAAU,GAAG;IACrB,QAAQ,EAAE,GAAG,CAAC;IACd,KAAK,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;CACvB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,KAAK,EAAE,EAAE,CAAC,UAAU,CAS/B,CAAC"}
package/dist/noSSR.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"noSSR.js","sources":["../src/noSSR.tsx"],"sourcesContent":["'use client';\n\nimport React, { FC, memo, JSX, useLayoutEffect, useState } from 'react';\n\nexport type NoSSRProps = {\n children: any;\n onSSR?: JSX.Element;\n};\n\n/**\n * Prefer using Next.js `dynamic()` import with `ssr: false` because this will also remove import from server bundle.\n *\n * ```tsx\n * 'use client';\n *\n * import React from 'react';\n * import dynamic from 'next/dynamic';\n *\n * const PageClient = dynamic(() => import('./pageClient'), { ssr: false });\n *\n * export default function Page() {\n * return (\n * <PageClient />\n * );\n * }\n * ```\n *\n * In other cases this component can be used to just prevent server rendering.\n *\n * @see https://github.com/kadirahq/react-no-ssr/blob/master/src/index.js\n * @see https://nextjs.org/docs/messages/react-hydration-error#solution-1-using-useeffect-to-run-on-the-client-only\n */\nexport const NoSSR: FC<NoSSRProps> = memo(function NoSSR({ children, onSSR = null }): any {\n const [canRender, setCanRender] = useState(false);\n\n useLayoutEffect(() => {\n setCanRender(true);\n }, []);\n\n return canRender ? children : onSSR;\n});\n"],"names":["NoSSR"],"mappings":";;AAgCO,MAAM,QAAwB,KAAK,SAASA,OAAM,EAAE,UAAU,QAAQ,QAAa;AACtF,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAEhD,kBAAgB,MAAM;AAClB,iBAAa,IAAI;AAAA,EACrB,GAAG,CAAA,CAAE;AAEL,SAAO,YAAY,WAAW;AAClC,CAAC;"}
1
+ {"version":3,"file":"noSSR.js","sources":["../src/noSSR.tsx"],"sourcesContent":["'use client';\n\nimport React, { FC, memo, JSX, useLayoutEffect, useState } from 'react';\n\nexport type NoSSRProps = {\n children: any;\n onSSR?: JSX.Element;\n};\n\n/**\n * Prefer using Next.js `dynamic()` import with `ssr: false` because this will also remove import from server bundle.\n *\n * ```tsx\n * 'use client';\n *\n * import React from 'react';\n * import dynamic from 'next/dynamic';\n *\n * const PageClient = dynamic(() => import('./pageClient'), { ssr: false });\n *\n * export default function Page() {\n * return (\n * <PageClient />\n * );\n * }\n * ```\n *\n * In other cases this component can be used to just prevent server rendering.\n *\n * @see https://github.com/kadirahq/react-no-ssr/blob/master/src/index.js\n * @see https://nextjs.org/docs/messages/react-hydration-error#solution-1-using-useeffect-to-run-on-the-client-only\n */\nexport const NoSSR: FC<NoSSRProps> = memo(function NoSSR({ children, onSSR = null }): any {\n const [canRender, setCanRender] = useState(false);\n\n useLayoutEffect(() => {\n // eslint-disable-next-line react-hooks/set-state-in-effect\n setCanRender(true);\n }, []);\n\n return canRender ? children : onSSR;\n});\n"],"names":["NoSSR"],"mappings":";;AAgCO,MAAM,QAAwB,KAAK,SAASA,OAAM,EAAE,UAAU,QAAQ,QAAa;AACtF,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAEhD,kBAAgB,MAAM;AAElB,iBAAa,IAAI;AAAA,EACrB,GAAG,CAAA,CAAE;AAEL,SAAO,YAAY,WAAW;AAClC,CAAC;"}
@@ -4,5 +4,8 @@ export type RedirectProps = {
4
4
  to: LinkProps['href'];
5
5
  replace?: LinkProps['replace'];
6
6
  };
7
+ /**
8
+ * @deprecated
9
+ */
7
10
  export declare const Redirect: FC<RedirectProps>;
8
11
  //# sourceMappingURL=redirect.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"redirect.d.ts","sourceRoot":"","sources":["../src/redirect.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,EAAE,EAAmB,MAAM,OAAO,CAAC;AAC5C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE3C,MAAM,MAAM,aAAa,GAAG;IACxB,EAAE,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;IACtB,OAAO,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAClC,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,EAAE,CAAC,aAAa,CAMrC,CAAC"}
1
+ {"version":3,"file":"redirect.d.ts","sourceRoot":"","sources":["../src/redirect.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,EAAE,EAAmB,MAAM,OAAO,CAAC;AAC5C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE3C,MAAM,MAAM,aAAa,GAAG;IACxB,EAAE,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;IACtB,OAAO,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAClC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,EAAE,CAAC,aAAa,CAMrC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"redirect.js","sources":["../src/redirect.tsx"],"sourcesContent":["'use client';\n\nimport { useRouter } from 'next/navigation';\nimport { FC, memo, useEffect } from 'react';\nimport type { LinkProps } from 'next/link';\n\nexport type RedirectProps = {\n to: LinkProps['href'];\n replace?: LinkProps['replace'];\n};\n\nexport const Redirect: FC<RedirectProps> = memo(function Redirect({ to, replace }) {\n const router = useRouter();\n useEffect(() => {\n router[replace ? 'replace' : 'push'](to.toString()); //TODO Test this\n }, [replace, router, to]);\n return null;\n});\n"],"names":["Redirect"],"mappings":";;;AAWO,MAAM,WAA8B,KAAK,SAASA,UAAS,EAAE,IAAI,WAAW;AAC/E,QAAM,SAAS,UAAA;AACf,YAAU,MAAM;AACZ,WAAO,UAAU,YAAY,MAAM,EAAE,GAAG,UAAU;AAAA,EACtD,GAAG,CAAC,SAAS,QAAQ,EAAE,CAAC;AACxB,SAAO;AACX,CAAC;"}
1
+ {"version":3,"file":"redirect.js","sources":["../src/redirect.tsx"],"sourcesContent":["'use client';\n\nimport { useRouter } from 'next/navigation';\nimport { FC, memo, useEffect } from 'react';\nimport type { LinkProps } from 'next/link';\n\nexport type RedirectProps = {\n to: LinkProps['href'];\n replace?: LinkProps['replace'];\n};\n\n/**\n * @deprecated\n */\nexport const Redirect: FC<RedirectProps> = memo(function Redirect({ to, replace }) {\n const router = useRouter();\n useEffect(() => {\n router[replace ? 'replace' : 'push'](to.toString()); //TODO Test this\n }, [replace, router, to]);\n return null;\n});\n"],"names":["Redirect"],"mappings":";;;AAcO,MAAM,WAA8B,KAAK,SAASA,UAAS,EAAE,IAAI,WAAW;AAC/E,QAAM,SAAS,UAAA;AACf,YAAU,MAAM;AACZ,WAAO,UAAU,YAAY,MAAM,EAAE,GAAG,UAAU;AAAA,EACtD,GAAG,CAAC,SAAS,QAAQ,EAAE,CAAC;AACxB,SAAO;AACX,CAAC;"}
@@ -0,0 +1,14 @@
1
+ import { default as Link, LinkProps } from 'next/link';
2
+ import { ReactNode } from 'react';
3
+ export type SoftLinkProps = LinkProps & {
4
+ children?: ReactNode;
5
+ };
6
+ /**
7
+ * Search Params update w/o rerender
8
+ *
9
+ * https://nextjs.org/docs/app/api-reference/functions/use-search-params#prerendering
10
+ * https://github.com/vercel/next.js/issues/43691#issuecomment-2078921491
11
+ * https://nextjs.org/docs/app/building-your-application/routing/linking-and-navigating#using-the-native-history-api
12
+ */
13
+ export declare const SoftLink: typeof Link;
14
+ //# sourceMappingURL=softLink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"softLink.d.ts","sourceRoot":"","sources":["../src/softLink.tsx"],"names":[],"mappings":"AAEA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAc,EAAQ,SAAS,EAAe,MAAM,OAAO,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG;IACpC,QAAQ,CAAC,EAAE,SAAS,CAAC;CACxB,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,QAAQ,EAoBf,OAAO,IAAI,CAAC"}
@@ -0,0 +1,22 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import Link from "next/link";
4
+ import { memo, useCallback } from "react";
5
+ const SoftLink = memo(function SoftLink2({ href, children, replace, ...props }) {
6
+ const onClick = useCallback(
7
+ (e) => {
8
+ e.preventDefault();
9
+ window.history[replace ? "replaceState" : "pushState"](
10
+ null,
11
+ "",
12
+ typeof href === "string" ? href : `${href["pathname"] || ""}?${typeof href["query"] === "string" ? href["query"] : new URLSearchParams(href["query"]).toString()}`
13
+ );
14
+ },
15
+ [href, replace]
16
+ );
17
+ return /* @__PURE__ */ jsx(Link, { href, ...props, onClick, children });
18
+ });
19
+ export {
20
+ SoftLink
21
+ };
22
+ //# sourceMappingURL=softLink.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"softLink.js","sources":["../src/softLink.tsx"],"sourcesContent":["'use client';\n\nimport Link from 'next/link';\nimport React, { memo, ReactNode, useCallback } from 'react';\nimport { LinkProps } from 'next/link';\n\nexport type SoftLinkProps = LinkProps & {\n children?: ReactNode;\n};\n\n/**\n * Search Params update w/o rerender\n *\n * https://nextjs.org/docs/app/api-reference/functions/use-search-params#prerendering\n * https://github.com/vercel/next.js/issues/43691#issuecomment-2078921491\n * https://nextjs.org/docs/app/building-your-application/routing/linking-and-navigating#using-the-native-history-api\n */\nexport const SoftLink = memo<SoftLinkProps>(function SoftLink({ href, children, replace, ...props }) {\n const onClick = useCallback(\n (e) => {\n e.preventDefault();\n window.history[replace ? 'replaceState' : 'pushState'](\n null,\n '',\n typeof href === 'string'\n ? href\n : `${href['pathname'] || ''}?${typeof href['query'] === 'string' ? href['query'] : new URLSearchParams(href['query'] as never).toString()}`,\n );\n },\n [href, replace],\n );\n\n return (\n <Link href={href} {...props} onClick={onClick}>\n {children}\n </Link>\n );\n}) as typeof Link;\n"],"names":["SoftLink"],"mappings":";;;;AAiBO,MAAM,WAAW,KAAoB,SAASA,UAAS,EAAE,MAAM,UAAU,SAAS,GAAG,SAAS;AACjG,QAAM,UAAU;AAAA,IACZ,CAAC,MAAM;AACH,QAAE,eAAA;AACF,aAAO,QAAQ,UAAU,iBAAiB,WAAW;AAAA,QACjD;AAAA,QACA;AAAA,QACA,OAAO,SAAS,WACV,OACA,GAAG,KAAK,UAAU,KAAK,EAAE,IAAI,OAAO,KAAK,OAAO,MAAM,WAAW,KAAK,OAAO,IAAI,IAAI,gBAAgB,KAAK,OAAO,CAAU,EAAE,UAAU;AAAA,MAAA;AAAA,IAErJ;AAAA,IACA,CAAC,MAAM,OAAO;AAAA,EAAA;AAGlB,6BACK,MAAA,EAAK,MAAa,GAAG,OAAO,SACxB,UACL;AAER,CAAC;"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kirill.konshin/next",
3
3
  "description": "Utilities",
4
- "version": "0.0.2",
4
+ "version": "0.0.4",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "----- BUILD -----": "",
@@ -54,5 +54,10 @@
54
54
  },
55
55
  "main": "./dist/index.js",
56
56
  "module": "./dist/index.js",
57
- "types": "./dist/index.d.ts"
57
+ "types": "./dist/index.d.ts",
58
+ "repository": {
59
+ "type": "git",
60
+ "url": "https://github.com/kirill-konshin/utils.git",
61
+ "directory": "packages/next"
62
+ }
58
63
  }
package/src/appLink.tsx CHANGED
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import React, { ComponentProps, FC, memo } from 'react';
3
+ import React, { ComponentProps, FC, memo, useCallback, useMemo } from 'react';
4
4
  import { usePathname } from 'next/navigation';
5
5
  import Link, { LinkProps } from 'next/link';
6
6
  import clsx from 'clsx';
@@ -12,6 +12,18 @@ export type AppLinkProps = {
12
12
  } & LinkProps &
13
13
  ComponentProps<typeof Link>;
14
14
 
15
+ export function useIsLinkActive(): (href: ComponentProps<typeof Link>['href'], exact: boolean) => boolean {
16
+ const pathname = usePathname();
17
+
18
+ return useCallback(
19
+ (href: ComponentProps<typeof Link>['href'], exact: boolean): boolean => {
20
+ const hrefPath = typeof href === 'string' ? href : href.pathname || '/';
21
+ return (!exact && pathname.startsWith(hrefPath)) || (exact && pathname === hrefPath);
22
+ },
23
+ [pathname],
24
+ );
25
+ }
26
+
15
27
  //TODO Test this
16
28
  export const AppLink: FC<AppLinkProps> = memo(function AppLink({
17
29
  href,
@@ -22,15 +34,14 @@ export const AppLink: FC<AppLinkProps> = memo(function AppLink({
22
34
  exact = false,
23
35
  ...props
24
36
  }) {
25
- const pathname = usePathname();
26
- const hrefPath = typeof href === 'string' ? href : href.pathname || '/';
37
+ const isActive = useIsLinkActive();
27
38
 
28
39
  return (
29
40
  <Link
30
41
  {...props}
31
42
  href={href}
32
43
  className={clsx(className, {
33
- [activeClassName]: (!exact && pathname.startsWith(hrefPath)) || (exact && pathname === hrefPath),
44
+ [activeClassName]: isActive(href, exact),
34
45
  })}
35
46
  prefetch={prefetch}
36
47
  >
package/src/index.ts CHANGED
@@ -2,4 +2,5 @@ export * from './appLink';
2
2
  export * from './measure';
3
3
  export * from './noSSR';
4
4
  export * from './redirect';
5
+ export * from './softLink';
5
6
  export * from './useIsInner';
package/src/noSSR.tsx CHANGED
@@ -34,6 +34,7 @@ export const NoSSR: FC<NoSSRProps> = memo(function NoSSR({ children, onSSR = nul
34
34
  const [canRender, setCanRender] = useState(false);
35
35
 
36
36
  useLayoutEffect(() => {
37
+ // eslint-disable-next-line react-hooks/set-state-in-effect
37
38
  setCanRender(true);
38
39
  }, []);
39
40
 
package/src/redirect.tsx CHANGED
@@ -9,6 +9,9 @@ export type RedirectProps = {
9
9
  replace?: LinkProps['replace'];
10
10
  };
11
11
 
12
+ /**
13
+ * @deprecated
14
+ */
12
15
  export const Redirect: FC<RedirectProps> = memo(function Redirect({ to, replace }) {
13
16
  const router = useRouter();
14
17
  useEffect(() => {
@@ -0,0 +1,38 @@
1
+ 'use client';
2
+
3
+ import Link from 'next/link';
4
+ import React, { memo, ReactNode, useCallback } from 'react';
5
+ import { LinkProps } from 'next/link';
6
+
7
+ export type SoftLinkProps = LinkProps & {
8
+ children?: ReactNode;
9
+ };
10
+
11
+ /**
12
+ * Search Params update w/o rerender
13
+ *
14
+ * https://nextjs.org/docs/app/api-reference/functions/use-search-params#prerendering
15
+ * https://github.com/vercel/next.js/issues/43691#issuecomment-2078921491
16
+ * https://nextjs.org/docs/app/building-your-application/routing/linking-and-navigating#using-the-native-history-api
17
+ */
18
+ export const SoftLink = memo<SoftLinkProps>(function SoftLink({ href, children, replace, ...props }) {
19
+ const onClick = useCallback(
20
+ (e) => {
21
+ e.preventDefault();
22
+ window.history[replace ? 'replaceState' : 'pushState'](
23
+ null,
24
+ '',
25
+ typeof href === 'string'
26
+ ? href
27
+ : `${href['pathname'] || ''}?${typeof href['query'] === 'string' ? href['query'] : new URLSearchParams(href['query'] as never).toString()}`,
28
+ );
29
+ },
30
+ [href, replace],
31
+ );
32
+
33
+ return (
34
+ <Link href={href} {...props} onClick={onClick}>
35
+ {children}
36
+ </Link>
37
+ );
38
+ }) as typeof Link;