From 0dcb2e16d668e256384aa3eff68c7e23e320d6db Mon Sep 17 00:00:00 2001 From: btea <2356281422@qq.com> Date: Fri, 31 Jul 2026 08:22:59 +0800 Subject: [PATCH 1/2] fix(web): sync URL hash when following same-page search hits `followSearchHit` only called `scrollIntoView()` for same-page hits, leaving the address bar without a hash (or stuck on a stale one from a previously followed hit). Push the hit's hash via `history.pushState` before scrolling so the URL always reflects the jumped-to anchor. --- .changeset/tidy-donuts-search.md | 5 +++++ .../generators/web/ui/components/SearchBox/index.jsx | 10 +++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 .changeset/tidy-donuts-search.md diff --git a/.changeset/tidy-donuts-search.md b/.changeset/tidy-donuts-search.md new file mode 100644 index 00000000..9c48fd61 --- /dev/null +++ b/.changeset/tidy-donuts-search.md @@ -0,0 +1,5 @@ +--- +'@node-core/doc-kit': patch +--- + +Sync the URL hash when following same-page search hits diff --git a/packages/core/src/generators/web/ui/components/SearchBox/index.jsx b/packages/core/src/generators/web/ui/components/SearchBox/index.jsx index 37e3e708..84073e08 100644 --- a/packages/core/src/generators/web/ui/components/SearchBox/index.jsx +++ b/packages/core/src/generators/web/ui/components/SearchBox/index.jsx @@ -36,11 +36,15 @@ const followSearchHit = event => { return; } - requestAnimationFrame(() => + requestAnimationFrame(() => { + // Keep the URL hash in sync with the followed hit, since + // `scrollIntoView` alone leaves the previous hash untouched. + history.pushState(null, '', target.hash || target.pathname); + document .getElementById(decodeURIComponent(target.hash.slice(1))) - ?.scrollIntoView() - ); + ?.scrollIntoView(); + }); }); }; From 7f459f757343a942c1ed0e4cef2682544539427c Mon Sep 17 00:00:00 2001 From: btea <2356281422@qq.com> Date: Fri, 31 Jul 2026 10:04:20 +0800 Subject: [PATCH 2/2] fix: update --- .../web/ui/components/SearchBox/index.jsx | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/packages/core/src/generators/web/ui/components/SearchBox/index.jsx b/packages/core/src/generators/web/ui/components/SearchBox/index.jsx index 84073e08..7356ccfc 100644 --- a/packages/core/src/generators/web/ui/components/SearchBox/index.jsx +++ b/packages/core/src/generators/web/ui/components/SearchBox/index.jsx @@ -21,7 +21,7 @@ const followSearchHit = event => { return; } - const target = new URL(event.currentTarget.href); + const { href } = event.currentTarget; event.preventDefault(); @@ -30,22 +30,16 @@ const followSearchHit = event => { new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }) ); - requestAnimationFrame(() => { - if (target.pathname !== window.location.pathname) { - window.location.href = target.href; - return; - } - + // A plain `location.href` assignment covers both cases: same-page hits + // become a native fragment navigation (hash, scroll and history entry + // included), cross-page hits simply load the target page. The nested + // `requestAnimationFrame` waits for the modal to actually close — + // navigating while it is still open suppresses the fragment scroll. + requestAnimationFrame(() => requestAnimationFrame(() => { - // Keep the URL hash in sync with the followed hit, since - // `scrollIntoView` alone leaves the previous hash untouched. - history.pushState(null, '', target.hash || target.pathname); - - document - .getElementById(decodeURIComponent(target.hash.slice(1))) - ?.scrollIntoView(); - }); - }); + window.location.href = href; + }) + ); }; /**