@greatapps/common 1.1.642 → 1.1.644
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/hooks/useRouter.mjs +1 -3
- package/dist/hooks/useRouter.mjs.map +1 -1
- package/dist/providers/navigation.provider.mjs +37 -12
- package/dist/providers/navigation.provider.mjs.map +1 -1
- package/package.json +1 -1
- package/src/hooks/useRouter.ts +1 -4
- package/src/providers/navigation.provider.tsx +41 -13
package/dist/hooks/useRouter.mjs
CHANGED
|
@@ -3,12 +3,10 @@ import { useRouter as useNextRouter } from "next/navigation";
|
|
|
3
3
|
import { useNavigationContext } from "../providers/navigation.provider";
|
|
4
4
|
function useRouter() {
|
|
5
5
|
const router = useNextRouter();
|
|
6
|
-
const { defaultFallback, internalNavCountRef
|
|
6
|
+
const { defaultFallback, internalNavCountRef } = useNavigationContext();
|
|
7
7
|
function back(options) {
|
|
8
8
|
const fallback = typeof options === "string" ? options : options?.fallback || defaultFallback;
|
|
9
9
|
if (internalNavCountRef.current > 0) {
|
|
10
|
-
internalNavCountRef.current -= 1;
|
|
11
|
-
expectingBackRef.current = true;
|
|
12
10
|
router.back();
|
|
13
11
|
return;
|
|
14
12
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hooks/useRouter.ts"],"sourcesContent":["\"use client\";\n\nimport { useRouter as useNextRouter } from \"next/navigation\";\nimport { useNavigationContext } from \"../providers/navigation.provider\";\n\ntype SafeBackOptions = { fallback?: string };\n\ntype AppRouter = ReturnType<typeof useNextRouter>;\n\nexport interface SafeAppRouter extends Omit<AppRouter, \"back\"> {\n back: (options?: SafeBackOptions | string) => void;\n safeBack: (options?: SafeBackOptions | string) => void;\n}\n\nexport function useRouter(): SafeAppRouter {\n const router = useNextRouter();\n const { defaultFallback, internalNavCountRef
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/useRouter.ts"],"sourcesContent":["\"use client\";\n\nimport { useRouter as useNextRouter } from \"next/navigation\";\nimport { useNavigationContext } from \"../providers/navigation.provider\";\n\ntype SafeBackOptions = { fallback?: string };\n\ntype AppRouter = ReturnType<typeof useNextRouter>;\n\nexport interface SafeAppRouter extends Omit<AppRouter, \"back\"> {\n back: (options?: SafeBackOptions | string) => void;\n safeBack: (options?: SafeBackOptions | string) => void;\n}\n\nexport function useRouter(): SafeAppRouter {\n const router = useNextRouter();\n const { defaultFallback, internalNavCountRef } = useNavigationContext();\n\n function back(options?: SafeBackOptions | string) {\n const fallback =\n typeof options === \"string\"\n ? options\n : options?.fallback || defaultFallback;\n\n if (internalNavCountRef.current > 0) {\n router.back();\n return;\n }\n\n router.replace(fallback);\n }\n\n return {\n ...router,\n back,\n safeBack: back,\n };\n}\n"],"mappings":";AAEA,SAAS,aAAa,qBAAqB;AAC3C,SAAS,4BAA4B;AAW9B,SAAS,YAA2B;AACzC,QAAM,SAAS,cAAc;AAC7B,QAAM,EAAE,iBAAiB,oBAAoB,IAAI,qBAAqB;AAEtE,WAAS,KAAK,SAAoC;AAChD,UAAM,WACJ,OAAO,YAAY,WACf,UACA,SAAS,YAAY;AAE3B,QAAI,oBAAoB,UAAU,GAAG;AACnC,aAAO,KAAK;AACZ;AAAA,IACF;AAEA,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAEA,SAAO;AAAA,IACL,GAAG;AAAA,IACH;AAAA,IACA,UAAU;AAAA,EACZ;AACF;","names":[]}
|
|
@@ -6,33 +6,58 @@ import {
|
|
|
6
6
|
useEffect,
|
|
7
7
|
useRef
|
|
8
8
|
} from "react";
|
|
9
|
-
import { usePathname } from "next/navigation";
|
|
9
|
+
import { usePathname, useSearchParams } from "next/navigation";
|
|
10
10
|
const NavigationContext = createContext(null);
|
|
11
|
+
function seedCountFromReferrer() {
|
|
12
|
+
if (typeof window === "undefined") return 0;
|
|
13
|
+
if (window.history.length <= 1) return 0;
|
|
14
|
+
try {
|
|
15
|
+
if (!document.referrer) return 0;
|
|
16
|
+
if (new URL(document.referrer).origin === window.location.origin) {
|
|
17
|
+
return 1;
|
|
18
|
+
}
|
|
19
|
+
} catch {
|
|
20
|
+
}
|
|
21
|
+
return 0;
|
|
22
|
+
}
|
|
11
23
|
function NavigationProvider({
|
|
12
24
|
children,
|
|
13
25
|
defaultFallback = "/"
|
|
14
26
|
}) {
|
|
15
27
|
const pathname = usePathname();
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
28
|
+
const searchParams = useSearchParams();
|
|
29
|
+
const currentKey = `${pathname}?${searchParams?.toString() ?? ""}`;
|
|
30
|
+
const internalNavCountRef = useRef(seedCountFromReferrer());
|
|
31
|
+
const lastKeyRef = useRef(null);
|
|
32
|
+
const popStateFiredRef = useRef(false);
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
const onPopState = () => {
|
|
35
|
+
popStateFiredRef.current = true;
|
|
36
|
+
};
|
|
37
|
+
window.addEventListener("popstate", onPopState);
|
|
38
|
+
return () => window.removeEventListener("popstate", onPopState);
|
|
39
|
+
}, []);
|
|
19
40
|
useEffect(() => {
|
|
20
|
-
if (
|
|
21
|
-
|
|
41
|
+
if (lastKeyRef.current === null) {
|
|
42
|
+
lastKeyRef.current = currentKey;
|
|
22
43
|
return;
|
|
23
44
|
}
|
|
24
|
-
if (
|
|
25
|
-
if (
|
|
26
|
-
|
|
45
|
+
if (lastKeyRef.current === currentKey) return;
|
|
46
|
+
if (popStateFiredRef.current) {
|
|
47
|
+
popStateFiredRef.current = false;
|
|
48
|
+
internalNavCountRef.current = Math.max(
|
|
49
|
+
0,
|
|
50
|
+
internalNavCountRef.current - 1
|
|
51
|
+
);
|
|
27
52
|
} else {
|
|
28
53
|
internalNavCountRef.current += 1;
|
|
29
54
|
}
|
|
30
|
-
|
|
31
|
-
}, [
|
|
55
|
+
lastKeyRef.current = currentKey;
|
|
56
|
+
}, [currentKey]);
|
|
32
57
|
return /* @__PURE__ */ jsx(
|
|
33
58
|
NavigationContext.Provider,
|
|
34
59
|
{
|
|
35
|
-
value: { defaultFallback, internalNavCountRef
|
|
60
|
+
value: { defaultFallback, internalNavCountRef },
|
|
36
61
|
children
|
|
37
62
|
}
|
|
38
63
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/providers/navigation.provider.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n createContext,\n ReactNode,\n useContext,\n useEffect,\n useRef,\n type RefObject,\n} from \"react\";\nimport { usePathname } from \"next/navigation\";\n\ninterface NavigationContextValue {\n defaultFallback: string;\n internalNavCountRef: RefObject<number>;\n
|
|
1
|
+
{"version":3,"sources":["../../src/providers/navigation.provider.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n createContext,\n ReactNode,\n useContext,\n useEffect,\n useRef,\n type RefObject,\n} from \"react\";\nimport { usePathname, useSearchParams } from \"next/navigation\";\n\ninterface NavigationContextValue {\n defaultFallback: string;\n internalNavCountRef: RefObject<number>;\n}\n\nconst NavigationContext = createContext<NavigationContextValue | null>(null);\n\nfunction seedCountFromReferrer(): number {\n if (typeof window === \"undefined\") return 0;\n if (window.history.length <= 1) return 0;\n try {\n if (!document.referrer) return 0;\n if (new URL(document.referrer).origin === window.location.origin) {\n return 1;\n }\n } catch {\n // ignore\n }\n return 0;\n}\n\ninterface NavigationProviderProps {\n children: ReactNode;\n defaultFallback?: string;\n}\n\nexport function NavigationProvider({\n children,\n defaultFallback = \"/\",\n}: NavigationProviderProps) {\n const pathname = usePathname();\n const searchParams = useSearchParams();\n const currentKey = `${pathname}?${searchParams?.toString() ?? \"\"}`;\n\n const internalNavCountRef = useRef(seedCountFromReferrer());\n const lastKeyRef = useRef<string | null>(null);\n const popStateFiredRef = useRef(false);\n\n useEffect(() => {\n const onPopState = () => {\n popStateFiredRef.current = true;\n };\n window.addEventListener(\"popstate\", onPopState);\n return () => window.removeEventListener(\"popstate\", onPopState);\n }, []);\n\n useEffect(() => {\n if (lastKeyRef.current === null) {\n lastKeyRef.current = currentKey;\n return;\n }\n if (lastKeyRef.current === currentKey) return;\n\n if (popStateFiredRef.current) {\n popStateFiredRef.current = false;\n internalNavCountRef.current = Math.max(\n 0,\n internalNavCountRef.current - 1\n );\n } else {\n internalNavCountRef.current += 1;\n }\n lastKeyRef.current = currentKey;\n }, [currentKey]);\n\n return (\n <NavigationContext.Provider\n value={{ defaultFallback, internalNavCountRef }}\n >\n {children}\n </NavigationContext.Provider>\n );\n}\n\nexport function useNavigationContext(): NavigationContextValue {\n const ctx = useContext(NavigationContext);\n if (!ctx) {\n throw new Error(\n \"useNavigationContext must be used inside <NavigationProvider>\"\n );\n }\n return ctx;\n}\n\nexport function useNavigationFallback(): string {\n return useNavigationContext().defaultFallback;\n}\n"],"mappings":";AA8EI;AA5EJ;AAAA,EACE;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP,SAAS,aAAa,uBAAuB;AAO7C,MAAM,oBAAoB,cAA6C,IAAI;AAE3E,SAAS,wBAAgC;AACvC,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,MAAI,OAAO,QAAQ,UAAU,EAAG,QAAO;AACvC,MAAI;AACF,QAAI,CAAC,SAAS,SAAU,QAAO;AAC/B,QAAI,IAAI,IAAI,SAAS,QAAQ,EAAE,WAAW,OAAO,SAAS,QAAQ;AAChE,aAAO;AAAA,IACT;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAOO,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA,kBAAkB;AACpB,GAA4B;AAC1B,QAAM,WAAW,YAAY;AAC7B,QAAM,eAAe,gBAAgB;AACrC,QAAM,aAAa,GAAG,QAAQ,IAAI,cAAc,SAAS,KAAK,EAAE;AAEhE,QAAM,sBAAsB,OAAO,sBAAsB,CAAC;AAC1D,QAAM,aAAa,OAAsB,IAAI;AAC7C,QAAM,mBAAmB,OAAO,KAAK;AAErC,YAAU,MAAM;AACd,UAAM,aAAa,MAAM;AACvB,uBAAiB,UAAU;AAAA,IAC7B;AACA,WAAO,iBAAiB,YAAY,UAAU;AAC9C,WAAO,MAAM,OAAO,oBAAoB,YAAY,UAAU;AAAA,EAChE,GAAG,CAAC,CAAC;AAEL,YAAU,MAAM;AACd,QAAI,WAAW,YAAY,MAAM;AAC/B,iBAAW,UAAU;AACrB;AAAA,IACF;AACA,QAAI,WAAW,YAAY,WAAY;AAEvC,QAAI,iBAAiB,SAAS;AAC5B,uBAAiB,UAAU;AAC3B,0BAAoB,UAAU,KAAK;AAAA,QACjC;AAAA,QACA,oBAAoB,UAAU;AAAA,MAChC;AAAA,IACF,OAAO;AACL,0BAAoB,WAAW;AAAA,IACjC;AACA,eAAW,UAAU;AAAA,EACvB,GAAG,CAAC,UAAU,CAAC;AAEf,SACE;AAAA,IAAC,kBAAkB;AAAA,IAAlB;AAAA,MACC,OAAO,EAAE,iBAAiB,oBAAoB;AAAA,MAE7C;AAAA;AAAA,EACH;AAEJ;AAEO,SAAS,uBAA+C;AAC7D,QAAM,MAAM,WAAW,iBAAiB;AACxC,MAAI,CAAC,KAAK;AACR,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,wBAAgC;AAC9C,SAAO,qBAAqB,EAAE;AAChC;","names":[]}
|
package/package.json
CHANGED
package/src/hooks/useRouter.ts
CHANGED
|
@@ -14,8 +14,7 @@ export interface SafeAppRouter extends Omit<AppRouter, "back"> {
|
|
|
14
14
|
|
|
15
15
|
export function useRouter(): SafeAppRouter {
|
|
16
16
|
const router = useNextRouter();
|
|
17
|
-
const { defaultFallback, internalNavCountRef
|
|
18
|
-
useNavigationContext();
|
|
17
|
+
const { defaultFallback, internalNavCountRef } = useNavigationContext();
|
|
19
18
|
|
|
20
19
|
function back(options?: SafeBackOptions | string) {
|
|
21
20
|
const fallback =
|
|
@@ -24,8 +23,6 @@ export function useRouter(): SafeAppRouter {
|
|
|
24
23
|
: options?.fallback || defaultFallback;
|
|
25
24
|
|
|
26
25
|
if (internalNavCountRef.current > 0) {
|
|
27
|
-
internalNavCountRef.current -= 1;
|
|
28
|
-
expectingBackRef.current = true;
|
|
29
26
|
router.back();
|
|
30
27
|
return;
|
|
31
28
|
}
|
|
@@ -8,16 +8,29 @@ import {
|
|
|
8
8
|
useRef,
|
|
9
9
|
type RefObject,
|
|
10
10
|
} from "react";
|
|
11
|
-
import { usePathname } from "next/navigation";
|
|
11
|
+
import { usePathname, useSearchParams } from "next/navigation";
|
|
12
12
|
|
|
13
13
|
interface NavigationContextValue {
|
|
14
14
|
defaultFallback: string;
|
|
15
15
|
internalNavCountRef: RefObject<number>;
|
|
16
|
-
expectingBackRef: RefObject<boolean>;
|
|
17
16
|
}
|
|
18
17
|
|
|
19
18
|
const NavigationContext = createContext<NavigationContextValue | null>(null);
|
|
20
19
|
|
|
20
|
+
function seedCountFromReferrer(): number {
|
|
21
|
+
if (typeof window === "undefined") return 0;
|
|
22
|
+
if (window.history.length <= 1) return 0;
|
|
23
|
+
try {
|
|
24
|
+
if (!document.referrer) return 0;
|
|
25
|
+
if (new URL(document.referrer).origin === window.location.origin) {
|
|
26
|
+
return 1;
|
|
27
|
+
}
|
|
28
|
+
} catch {
|
|
29
|
+
// ignore
|
|
30
|
+
}
|
|
31
|
+
return 0;
|
|
32
|
+
}
|
|
33
|
+
|
|
21
34
|
interface NavigationProviderProps {
|
|
22
35
|
children: ReactNode;
|
|
23
36
|
defaultFallback?: string;
|
|
@@ -28,28 +41,43 @@ export function NavigationProvider({
|
|
|
28
41
|
defaultFallback = "/",
|
|
29
42
|
}: NavigationProviderProps) {
|
|
30
43
|
const pathname = usePathname();
|
|
31
|
-
const
|
|
32
|
-
const
|
|
33
|
-
|
|
44
|
+
const searchParams = useSearchParams();
|
|
45
|
+
const currentKey = `${pathname}?${searchParams?.toString() ?? ""}`;
|
|
46
|
+
|
|
47
|
+
const internalNavCountRef = useRef(seedCountFromReferrer());
|
|
48
|
+
const lastKeyRef = useRef<string | null>(null);
|
|
49
|
+
const popStateFiredRef = useRef(false);
|
|
50
|
+
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
const onPopState = () => {
|
|
53
|
+
popStateFiredRef.current = true;
|
|
54
|
+
};
|
|
55
|
+
window.addEventListener("popstate", onPopState);
|
|
56
|
+
return () => window.removeEventListener("popstate", onPopState);
|
|
57
|
+
}, []);
|
|
34
58
|
|
|
35
59
|
useEffect(() => {
|
|
36
|
-
if (
|
|
37
|
-
|
|
60
|
+
if (lastKeyRef.current === null) {
|
|
61
|
+
lastKeyRef.current = currentKey;
|
|
38
62
|
return;
|
|
39
63
|
}
|
|
40
|
-
if (
|
|
64
|
+
if (lastKeyRef.current === currentKey) return;
|
|
41
65
|
|
|
42
|
-
if (
|
|
43
|
-
|
|
66
|
+
if (popStateFiredRef.current) {
|
|
67
|
+
popStateFiredRef.current = false;
|
|
68
|
+
internalNavCountRef.current = Math.max(
|
|
69
|
+
0,
|
|
70
|
+
internalNavCountRef.current - 1
|
|
71
|
+
);
|
|
44
72
|
} else {
|
|
45
73
|
internalNavCountRef.current += 1;
|
|
46
74
|
}
|
|
47
|
-
|
|
48
|
-
}, [
|
|
75
|
+
lastKeyRef.current = currentKey;
|
|
76
|
+
}, [currentKey]);
|
|
49
77
|
|
|
50
78
|
return (
|
|
51
79
|
<NavigationContext.Provider
|
|
52
|
-
value={{ defaultFallback, internalNavCountRef
|
|
80
|
+
value={{ defaultFallback, internalNavCountRef }}
|
|
53
81
|
>
|
|
54
82
|
{children}
|
|
55
83
|
</NavigationContext.Provider>
|