From 42718dd0a9d921a19fefccad3b41387101c6f368 Mon Sep 17 00:00:00 2001 From: Mitul Agrawal Date: Thu, 14 Nov 2024 16:26:22 +0530 Subject: [PATCH 1/9] return searchHook from memoryLocation --- packages/wouter/src/memory-location.js | 12 ++++++++++-- packages/wouter/types/memory-location.d.ts | 6 ++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/wouter/src/memory-location.js b/packages/wouter/src/memory-location.js index 8e212ef6..d018ac48 100644 --- a/packages/wouter/src/memory-location.js +++ b/packages/wouter/src/memory-location.js @@ -7,10 +7,12 @@ import { useSyncExternalStore } from "./react-deps.js"; export const memoryLocation = ({ path = "/", + searchPath = "", static: staticLocation, record, } = {}) => { - let currentPath = path; + let currentPath = path + (searchPath && (path.split("?")[1] ? "&" : "?")) + searchPath; + let currentSearch = currentPath.split("?")[1] || ""; const history = [currentPath]; const emitter = mitt(); @@ -24,6 +26,7 @@ export const memoryLocation = ({ } currentPath = path; + currentSearch = path.split("?")[1] || ""; emitter.emit("navigate", path); }; @@ -39,15 +42,20 @@ export const memoryLocation = ({ navigate, ]; + const useMemoryQuery = () => [ + useSyncExternalStore(subscribe, () => currentSearch) + ]; + function reset() { // clean history array with mutation to preserve link history.splice(0, history.length); - navigateImplementation(path); + navigateImplementation(path + (searchPath && (path.split("?")[1] ? "&" : "?")) + searchPath); } return { hook: useMemoryLocation, + searchHook: useMemoryQuery, navigate, history: record ? history : undefined, reset: record ? reset : undefined, diff --git a/packages/wouter/types/memory-location.d.ts b/packages/wouter/types/memory-location.d.ts index 55639038..665e1310 100644 --- a/packages/wouter/types/memory-location.d.ts +++ b/packages/wouter/types/memory-location.d.ts @@ -1,20 +1,22 @@ -import { BaseLocationHook, Path } from "./location-hook.js"; +import { BaseLocationHook, BaseSearchHook, Path, SearchString } from "./location-hook.js"; type Navigate = ( to: Path, options?: { replace?: boolean; state?: S } ) => void; -type HookReturnValue = { hook: BaseLocationHook; navigate: Navigate }; +type HookReturnValue = { hook: BaseLocationHook; searchHook: BaseSearchHook, navigate: Navigate }; type StubHistory = { history: Path[]; reset: () => void }; export function memoryLocation(options?: { path?: Path; + searchPath?: SearchString; static?: boolean; record?: false; }): HookReturnValue; export function memoryLocation(options?: { path?: Path; + searchPath?: SearchString; static?: boolean; record: true; }): HookReturnValue & StubHistory; From 97f556a1d7c04e77e3d4fb8996b6de18dc6b37ef Mon Sep 17 00:00:00 2001 From: Mitul Agrawal Date: Thu, 14 Nov 2024 16:28:18 +0530 Subject: [PATCH 2/9] add memoryLocation searchHook tests --- packages/wouter/test/memory-location.test.ts | 21 ++++++++++++++++++++ packages/wouter/test/use-search.test.tsx | 13 ++++++++++++ 2 files changed, 34 insertions(+) diff --git a/packages/wouter/test/memory-location.test.ts b/packages/wouter/test/memory-location.test.ts index 5b20a991..7ae3c00a 100644 --- a/packages/wouter/test/memory-location.test.ts +++ b/packages/wouter/test/memory-location.test.ts @@ -23,6 +23,17 @@ it("should support initial path", () => { unmount(); }); +it("should support initial path with query", () => { + const { searchHook } = memoryLocation({ path: "/test-case?foo=bar" }); + // const { searchHook } = memoryLocation({ path: "/test-case", searchPath: "foo=bar" }); + + const { result, unmount } = renderHook(() => searchHook()); + const [value] = result.current; + + expect(value).toBe("foo=bar"); + unmount(); +}); + it('should return location hook that has initial path "/" by default', () => { const { hook } = memoryLocation(); @@ -33,6 +44,16 @@ it('should return location hook that has initial path "/" by default', () => { unmount(); }); +it('should return search hook that has initial query "" by default', () => { + const { searchHook } = memoryLocation(); + + const { result, unmount } = renderHook(() => searchHook()); + const [value] = result.current; + + expect(value).toBe(""); + unmount(); +}); + it("should return standalone `navigate` method", () => { const { hook, navigate } = memoryLocation(); diff --git a/packages/wouter/test/use-search.test.tsx b/packages/wouter/test/use-search.test.tsx index ad8fe4d9..43e78235 100644 --- a/packages/wouter/test/use-search.test.tsx +++ b/packages/wouter/test/use-search.test.tsx @@ -1,6 +1,7 @@ import { renderHook, act } from "@testing-library/react"; import { useSearch, Router } from "wouter"; import { navigate } from "wouter/use-browser-location"; +import { memoryLocation } from "wouter/memory-location"; import { it, expect, beforeEach } from "vitest"; beforeEach(() => history.replaceState(null, "", "/")); @@ -24,6 +25,18 @@ it("can be customized in the Router", () => { expect(result.current).toEqual("none"); }); +it("can be customized with memoryLocation", () => { + const { searchHook } = memoryLocation({ path: "/foo?key=value" }); + + const { result } = renderHook(() => useSearch(), { + wrapper: (props) => { + return {props.children}; + }, + }); + + expect(result.current).toEqual("key=value"); +}); + it("unescapes search string", () => { const { result: searchResult } = renderHook(() => useSearch()); From 7a9770a88e494973eb6a453e983e9bd162c6bbbc Mon Sep 17 00:00:00 2001 From: Mitul Agrawal Date: Wed, 12 Feb 2025 18:36:47 +0530 Subject: [PATCH 3/9] simplify memory location hook --- packages/wouter/src/memory-location.js | 13 ++++++++++--- packages/wouter/types/memory-location.d.ts | 13 +++++++++++-- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/packages/wouter/src/memory-location.js b/packages/wouter/src/memory-location.js index d018ac48..f359eea3 100644 --- a/packages/wouter/src/memory-location.js +++ b/packages/wouter/src/memory-location.js @@ -11,7 +11,14 @@ export const memoryLocation = ({ static: staticLocation, record, } = {}) => { - let currentPath = path + (searchPath && (path.split("?")[1] ? "&" : "?")) + searchPath; + let initialPath = path; + if (searchPath) { + // join with & if path contains search query, and ? otherwise + initialPath += path.split("?")[1] ? "&" : "?"; + initialPath += searchPath; + } + + let currentPath = initialPath; let currentSearch = currentPath.split("?")[1] || ""; const history = [currentPath]; const emitter = mitt(); @@ -43,14 +50,14 @@ export const memoryLocation = ({ ]; const useMemoryQuery = () => [ - useSyncExternalStore(subscribe, () => currentSearch) + useSyncExternalStore(subscribe, () => currentSearch), ]; function reset() { // clean history array with mutation to preserve link history.splice(0, history.length); - navigateImplementation(path + (searchPath && (path.split("?")[1] ? "&" : "?")) + searchPath); + navigateImplementation(initialPath); } return { diff --git a/packages/wouter/types/memory-location.d.ts b/packages/wouter/types/memory-location.d.ts index 665e1310..d40d44a0 100644 --- a/packages/wouter/types/memory-location.d.ts +++ b/packages/wouter/types/memory-location.d.ts @@ -1,11 +1,20 @@ -import { BaseLocationHook, BaseSearchHook, Path, SearchString } from "./location-hook.js"; +import { + BaseLocationHook, + BaseSearchHook, + Path, + SearchString, +} from "./location-hook.js"; type Navigate = ( to: Path, options?: { replace?: boolean; state?: S } ) => void; -type HookReturnValue = { hook: BaseLocationHook; searchHook: BaseSearchHook, navigate: Navigate }; +type HookReturnValue = { + hook: BaseLocationHook; + searchHook: BaseSearchHook; + navigate: Navigate; +}; type StubHistory = { history: Path[]; reset: () => void }; export function memoryLocation(options?: { From 6ac1a2c2c7a6dce96cd059d61f42e82eca83bd26 Mon Sep 17 00:00:00 2001 From: Mitul Agrawal Date: Wed, 12 Feb 2025 18:37:47 +0530 Subject: [PATCH 4/9] add memory location test with search parameter --- packages/wouter/test/memory-location.test.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/wouter/test/memory-location.test.ts b/packages/wouter/test/memory-location.test.ts index 7ae3c00a..a9c810f2 100644 --- a/packages/wouter/test/memory-location.test.ts +++ b/packages/wouter/test/memory-location.test.ts @@ -25,7 +25,6 @@ it("should support initial path", () => { it("should support initial path with query", () => { const { searchHook } = memoryLocation({ path: "/test-case?foo=bar" }); - // const { searchHook } = memoryLocation({ path: "/test-case", searchPath: "foo=bar" }); const { result, unmount } = renderHook(() => searchHook()); const [value] = result.current; @@ -34,6 +33,19 @@ it("should support initial path with query", () => { unmount(); }); +it("should support search path as parameter", () => { + const { searchHook } = memoryLocation({ + path: "/test-case?foo=bar", + searchPath: "key=value", + }); + + const { result, unmount } = renderHook(() => searchHook()); + const [value] = result.current; + + expect(value).toBe("foo=bar&key=value"); + unmount(); +}); + it('should return location hook that has initial path "/" by default', () => { const { hook } = memoryLocation(); From 75686753a079dedb65ab7b54b194f1257148a0ee Mon Sep 17 00:00:00 2001 From: Mitul Agrawal Date: Wed, 12 Feb 2025 18:38:06 +0530 Subject: [PATCH 5/9] add use search test with search parameter --- packages/wouter/test/use-search.test.tsx | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/wouter/test/use-search.test.tsx b/packages/wouter/test/use-search.test.tsx index 43e78235..d9fd9093 100644 --- a/packages/wouter/test/use-search.test.tsx +++ b/packages/wouter/test/use-search.test.tsx @@ -37,6 +37,21 @@ it("can be customized with memoryLocation", () => { expect(result.current).toEqual("key=value"); }); +it("can be customized with memoryLocation using search path parameter", () => { + const { searchHook } = memoryLocation({ + path: "/foo?key=value", + searchPath: "foo=bar", + }); + + const { result } = renderHook(() => useSearch(), { + wrapper: (props) => { + return {props.children}; + }, + }); + + expect(result.current).toEqual("key=value&foo=bar"); +}); + it("unescapes search string", () => { const { result: searchResult } = renderHook(() => useSearch()); From 7fd1de23dc49ddcbfca8cead373be1f269921dd4 Mon Sep 17 00:00:00 2001 From: Mitul Agrawal Date: Wed, 12 Feb 2025 23:59:58 +0530 Subject: [PATCH 6/9] return path without search query --- packages/wouter/src/memory-location.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/wouter/src/memory-location.js b/packages/wouter/src/memory-location.js index f359eea3..4d970038 100644 --- a/packages/wouter/src/memory-location.js +++ b/packages/wouter/src/memory-location.js @@ -18,8 +18,7 @@ export const memoryLocation = ({ initialPath += searchPath; } - let currentPath = initialPath; - let currentSearch = currentPath.split("?")[1] || ""; + let [currentPath, currentSearch = ""] = initialPath.split("?"); const history = [currentPath]; const emitter = mitt(); @@ -32,8 +31,7 @@ export const memoryLocation = ({ } } - currentPath = path; - currentSearch = path.split("?")[1] || ""; + [currentPath, currentSearch = ""] = path.split("?"); emitter.emit("navigate", path); }; From b81665d9a7a80beb1b53c14724de86cf5e1dcd32 Mon Sep 17 00:00:00 2001 From: Mitul Agrawal Date: Thu, 13 Feb 2025 00:00:22 +0530 Subject: [PATCH 7/9] return query string directly --- packages/wouter/src/memory-location.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/wouter/src/memory-location.js b/packages/wouter/src/memory-location.js index 4d970038..60a8e36f 100644 --- a/packages/wouter/src/memory-location.js +++ b/packages/wouter/src/memory-location.js @@ -47,9 +47,8 @@ export const memoryLocation = ({ navigate, ]; - const useMemoryQuery = () => [ - useSyncExternalStore(subscribe, () => currentSearch), - ]; + const useMemoryQuery = () => + useSyncExternalStore(subscribe, () => currentSearch); function reset() { // clean history array with mutation to preserve link From ed60bc998e4d463b449bb828930698aec8c425d9 Mon Sep 17 00:00:00 2001 From: Mitul Agrawal Date: Thu, 13 Feb 2025 00:18:50 +0530 Subject: [PATCH 8/9] update search hook tests --- packages/wouter/test/memory-location.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/wouter/test/memory-location.test.ts b/packages/wouter/test/memory-location.test.ts index a9c810f2..305a86cd 100644 --- a/packages/wouter/test/memory-location.test.ts +++ b/packages/wouter/test/memory-location.test.ts @@ -27,7 +27,7 @@ it("should support initial path with query", () => { const { searchHook } = memoryLocation({ path: "/test-case?foo=bar" }); const { result, unmount } = renderHook(() => searchHook()); - const [value] = result.current; + const value = result.current; expect(value).toBe("foo=bar"); unmount(); @@ -40,7 +40,7 @@ it("should support search path as parameter", () => { }); const { result, unmount } = renderHook(() => searchHook()); - const [value] = result.current; + const value = result.current; expect(value).toBe("foo=bar&key=value"); unmount(); @@ -60,7 +60,7 @@ it('should return search hook that has initial query "" by default', () => { const { searchHook } = memoryLocation(); const { result, unmount } = renderHook(() => searchHook()); - const [value] = result.current; + const value = result.current; expect(value).toBe(""); unmount(); From d6a84d0a6885f8638ffd9fc55b3163f6d02889cf Mon Sep 17 00:00:00 2001 From: Mitul Agrawal Date: Thu, 13 Feb 2025 02:03:26 +0530 Subject: [PATCH 9/9] fix initial history path Co-authored-by: Till Prochaska <1512805+tillprochaska@users.noreply.github.com> --- packages/wouter/src/memory-location.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/wouter/src/memory-location.js b/packages/wouter/src/memory-location.js index 60a8e36f..bef05f9a 100644 --- a/packages/wouter/src/memory-location.js +++ b/packages/wouter/src/memory-location.js @@ -19,7 +19,7 @@ export const memoryLocation = ({ } let [currentPath, currentSearch = ""] = initialPath.split("?"); - const history = [currentPath]; + const history = [initialPath]; const emitter = mitt(); const navigateImplementation = (path, { replace = false } = {}) => {