diff --git a/.changeset/search-last-query.md b/.changeset/search-last-query.md deleted file mode 100644 index f83c6f424..000000000 --- a/.changeset/search-last-query.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"gitbook": patch ---- - -Keep the last search or ask query visible after closing its surface and restore it when reopening search or an embed. diff --git a/packages/gitbook/src/components/Embeddable/EmbeddableIframeAPI.tsx b/packages/gitbook/src/components/Embeddable/EmbeddableIframeAPI.tsx index f146fa9a6..1c1d96096 100644 --- a/packages/gitbook/src/components/Embeddable/EmbeddableIframeAPI.tsx +++ b/packages/gitbook/src/components/Embeddable/EmbeddableIframeAPI.tsx @@ -197,9 +197,8 @@ export function EmbeddableIframeTabs(props: { active?: string; baseURL: string; siteTitle: string; - onNavigate?: (href: string) => void; }) { - const { ref, active = 'assistant', baseURL, siteTitle, onNavigate } = props; + const { ref, active = 'assistant', baseURL, siteTitle } = props; const actions = useEmbeddableConfiguration((state) => state.actions); const tabs = useEmbeddableTabs(); @@ -262,10 +261,6 @@ export function EmbeddableIframeTabs(props: { className="not-hydrated:animate-blur-in-slow [&_.button-leading-icon]:size-5" iconOnly onClick={() => { - if (tab.key !== active && onNavigate) { - onNavigate(tab.href); - return; - } router.push(tab.href); }} tooltipProps={{ @@ -279,8 +274,7 @@ export function EmbeddableIframeTabs(props: { ) : null; } -export function EmbeddableIframeCloseButton(props: { onClose?: () => void }) { - const { onClose } = props; +export function EmbeddableIframeCloseButton() { const { closeButton } = useEmbeddableConfiguration(); if (!closeButton) { @@ -297,7 +291,6 @@ export function EmbeddableIframeCloseButton(props: { onClose?: () => void }) { className="not-hydrated:animate-blur-in-slow [&_.button-leading-icon]:size-5" iconOnly onClick={() => { - onClose?.(); getChannel()?.send({ type: 'close' }); }} tooltipProps={{ diff --git a/packages/gitbook/src/components/Embeddable/EmbeddableSearch.tsx b/packages/gitbook/src/components/Embeddable/EmbeddableSearch.tsx index f85c728f0..d08c25098 100644 --- a/packages/gitbook/src/components/Embeddable/EmbeddableSearch.tsx +++ b/packages/gitbook/src/components/Embeddable/EmbeddableSearch.tsx @@ -38,13 +38,10 @@ export function EmbeddableSearch(props: EmbeddableSearchProps) { const tabsRef = React.useRef(null); const { askQuery, - abort, - close, cursor, error, fetching, onInputKeyDown, - onResultSelect, query, results, resultsId, @@ -54,10 +51,7 @@ export function EmbeddableSearch(props: EmbeddableSearchProps) { showAsk, withSearchAI, scopeControl, - } = useSearchController( - { ...searchProps, asEmbeddable: hasDocsTab }, - { restoreLastQueryOnMount: true } - ); + } = useSearchController({ ...searchProps, asEmbeddable: hasDocsTab }); return ( @@ -72,8 +66,6 @@ export function EmbeddableSearch(props: EmbeddableSearchProps) { results={results} resultsId={resultsId} resultsRef={resultsRef} - onAskSelect={abort} - onResultSelect={onResultSelect} showAsk={showAsk} dataTestId="embed-search" input={ @@ -105,10 +97,9 @@ export function EmbeddableSearch(props: EmbeddableSearchProps) { active="search" baseURL={baseURL} siteTitle={siteTitle} - onNavigate={close} /> - + } scopeControl={ diff --git a/packages/gitbook/src/components/Search/SearchContainer.tsx b/packages/gitbook/src/components/Search/SearchContainer.tsx index da5062eb9..57ddb214b 100644 --- a/packages/gitbook/src/components/Search/SearchContainer.tsx +++ b/packages/gitbook/src/components/Search/SearchContainer.tsx @@ -50,7 +50,6 @@ export function SearchContainer({ error, fetching, onInputKeyDown, - onResultSelect, open, query, results, @@ -170,8 +169,7 @@ export function SearchContainer({ results={results} resultsId={resultsId} resultsRef={resultsRef} - onAskSelect={abort} - onResultSelect={onResultSelect} + onResultSelect={abort} showAsk={showAsk} scopeControl={scopeControlNode} fillHeight={usesSideSheet || shouldFillHeight} diff --git a/packages/gitbook/src/components/Search/SearchFrame.tsx b/packages/gitbook/src/components/Search/SearchFrame.tsx index ebfe2a56f..8247aaae3 100644 --- a/packages/gitbook/src/components/Search/SearchFrame.tsx +++ b/packages/gitbook/src/components/Search/SearchFrame.tsx @@ -29,8 +29,7 @@ export function SearchFrame(props: { results: ResultType[]; resultsId: string; resultsRef: React.Ref; - onAskSelect?: () => void; - onResultSelect?: (result: ResultType) => void; + onResultSelect?: () => void; scopeControl?: React.ReactNode; showAsk: boolean; sidebar?: React.ReactNode; @@ -51,7 +50,6 @@ export function SearchFrame(props: { results, resultsId, resultsRef, - onAskSelect, onResultSelect, scopeControl, showAsk, @@ -128,7 +126,7 @@ export function SearchFrame(props: { assistant={assistant} active={cursor === results.length + index} withShortcut={assistant === assistants[0]} - onSelect={onAskSelect} + onSelect={onResultSelect} /> )) : null} diff --git a/packages/gitbook/src/components/Search/SearchResults.tsx b/packages/gitbook/src/components/Search/SearchResults.tsx index 9c1349bef..83abc6a28 100644 --- a/packages/gitbook/src/components/Search/SearchResults.tsx +++ b/packages/gitbook/src/components/Search/SearchResults.tsx @@ -50,7 +50,7 @@ export const SearchResults = React.forwardRef(function SearchResults( fetching: boolean; cursor: number | null; error: boolean; - onResultSelect?: (result: ResultType) => void; + onResultSelect?: () => void; }, ref: React.Ref ) { @@ -211,7 +211,7 @@ export const SearchResults = React.forwardRef(function SearchResults( addRecentSearchQuery(siteSpaceId, query, 'search'); } - onResultSelect?.(item); + onResultSelect?.(); }; const resultItemProps = { 'aria-posinset': index + 1, diff --git a/packages/gitbook/src/components/Search/last-query.ts b/packages/gitbook/src/components/Search/last-query.ts deleted file mode 100644 index 79cb47cb6..000000000 --- a/packages/gitbook/src/components/Search/last-query.ts +++ /dev/null @@ -1,52 +0,0 @@ -'use client'; - -import React from 'react'; - -type LastSearchQueryBySiteSpace = Record; - -const listeners = new Set<() => void>(); - -let globalLastSearchQuery: LastSearchQueryBySiteSpace = {}; - -function emitChange() { - listeners.forEach((listener) => listener()); -} - -export function getLastSearchQuery(siteSpaceId: string): string | null { - return globalLastSearchQuery[siteSpaceId] ?? null; -} - -export function setLastSearchQuery(siteSpaceId: string, query: string | null): void { - if (!siteSpaceId) { - return; - } - - const normalizedQuery = query?.trim() || null; - const nextState = { ...globalLastSearchQuery }; - - if (normalizedQuery) { - nextState[siteSpaceId] = normalizedQuery; - } else { - delete nextState[siteSpaceId]; - } - - globalLastSearchQuery = nextState; - emitChange(); -} - -export function clearLastSearchQuery(siteSpaceId: string): void { - setLastSearchQuery(siteSpaceId, null); -} - -function subscribe(listener: () => void) { - listeners.add(listener); - return () => listeners.delete(listener); -} - -export function useLastSearchQuery(siteSpaceId: string): string | null { - return React.useSyncExternalStore( - subscribe, - () => globalLastSearchQuery[siteSpaceId] ?? null, - () => null - ); -} diff --git a/packages/gitbook/src/components/Search/useSearch.tsx b/packages/gitbook/src/components/Search/useSearch.tsx index 3c50f3a7f..1efe04611 100644 --- a/packages/gitbook/src/components/Search/useSearch.tsx +++ b/packages/gitbook/src/components/Search/useSearch.tsx @@ -61,12 +61,6 @@ function normalizeRawState(values: Values) { return values; } -export function shouldKeepSearchState( - values: Pick, 'q' | 'ask' | 'scope'> -): boolean { - return values.q !== null || values.ask !== null || values.scope !== 'default'; -} - export function SearchContextProvider(props: React.PropsWithChildren): React.ReactElement { const { children } = props; @@ -80,7 +74,7 @@ export function SearchContextProvider(props: React.PropsWithChildren): React.Rea const state = React.useMemo(() => { const normalized = normalizeRawState(rawState); - if (!shouldKeepSearchState(normalized)) { + if (normalized.q === null && normalized.ask === null) { return null; } return { diff --git a/packages/gitbook/src/components/Search/useSearchController.tsx b/packages/gitbook/src/components/Search/useSearchController.tsx index 67b810760..567987125 100644 --- a/packages/gitbook/src/components/Search/useSearchController.tsx +++ b/packages/gitbook/src/components/Search/useSearchController.tsx @@ -7,16 +7,10 @@ import { useAI } from '../AI'; import { useTrackEvent } from '../Insights'; import { useBodyLoaded } from '../primitives'; import type { SearchResultsRef } from './SearchResults'; -import { - clearLastSearchQuery, - getLastSearchQuery, - setLastSearchQuery, - useLastSearchQuery, -} from './last-query'; import { addRecentSearchQuery } from './recent-queries'; import type { SearchBaseProps } from './search-props'; import { useSearchState, useSetSearchState } from './useSearch'; -import { type ResultType, useSearchResults } from './useSearchResults'; +import { useSearchResults } from './useSearchResults'; import { useSearchResultsCursor } from './useSearchResultsCursor'; function useInitialAskBootstrap(props: { @@ -115,10 +109,7 @@ function useSearchKeyboardNavigation(props: { }; } -export function useSearchController( - props: SearchBaseProps, - options: { restoreLastQueryOnMount?: boolean } = {} -) { +export function useSearchController(props: SearchBaseProps) { const { asEmbeddable, siteSpace, @@ -139,32 +130,6 @@ export function useSearchController( const resultsRef = React.useRef(null); const isLoaded = useBodyLoaded(); - const restoredLastQueryForSiteSpaceRef = React.useRef(null); - React.useEffect(() => { - if ( - !options.restoreLastQueryOnMount || - restoredLastQueryForSiteSpaceRef.current === siteSpace.id - ) { - return; - } - - restoredLastQueryForSiteSpaceRef.current = siteSpace.id; - const restoredQuery = getLastSearchQuery(siteSpace.id); - if (!restoredQuery) { - return; - } - - void setSearchState( - (prev) => - prev ?? { - ask: null, - query: restoredQuery, - scope: 'default', - open: true, - } - ); - }, [options.restoreLastQueryOnMount, setSearchState, siteSpace.id]); - const withAI = assistants.length > 0; const withSearchAI = assistants.filter((assistant) => assistant.mode === 'search').length > 0; @@ -176,46 +141,38 @@ export function useSearchController( const onClose = React.useCallback( async (to?: string) => { - setSearchState((prev) => { - if (!prev) return null; - - if (prev.query !== null) { - setLastSearchQuery(siteSpace.id, prev.query); - } - - return { ...prev, open: false, query: null }; - }); + setSearchState((prev) => + prev + ? { + ...prev, + open: false, + query: prev.query === '' ? null : prev.query, + } + : null + ); if (to) { router.push(to); } }, - [setSearchState, router, siteSpace.id] + [setSearchState, router] ); const onOpen = React.useCallback(() => { if (state?.open) { return; } - setSearchState((prev) => { - const query = - prev?.query ?? - getLastSearchQuery(siteSpace.id) ?? - (withSearchAI || !withAI ? prev?.ask : null) ?? - ''; - - return { - ask: withAI ? (prev?.ask ?? null) : null, - scope: prev?.scope ?? 'default', - query, - open: true, - }; - }); + setSearchState((prev) => ({ + ask: withAI ? (prev?.ask ?? null) : null, + scope: prev?.scope ?? 'default', + query: prev?.query ?? (withSearchAI || !withAI ? prev?.ask : null) ?? '', + open: true, + })); trackEvent({ type: 'search_open', }); - }, [state?.open, setSearchState, siteSpace.id, trackEvent, withAI, withSearchAI]); + }, [state?.open, setSearchState, trackEvent, withAI, withSearchAI]); const setQuery = React.useCallback( (value: string) => { @@ -255,25 +212,9 @@ export function useSearchController( withSections, }); - const lastSearchQuery = useLastSearchQuery(siteSpace.id); - const searchValue = - state?.query ?? (withSearchAI || !withAI ? state?.ask : null) ?? lastSearchQuery ?? ''; + const searchValue = state?.query ?? (withSearchAI || !withAI ? state?.ask : null) ?? ''; const searchResultsId = `search-results-${React.useId()}`; - const onResultSelect = React.useCallback( - (result: ResultType) => { - clearLastSearchQuery(siteSpace.id); - abort(); - - if (result.type !== 'recommended-question') { - void setSearchState((prev) => - prev ? { ...prev, query: null, open: false } : null - ); - } - }, - [abort, setSearchState, siteSpace.id] - ); - const askInAssistant = React.useCallback( (assistantIndex = 0) => { const assistant = assistants[assistantIndex]; @@ -319,7 +260,6 @@ export function useSearchController( abort, open: onOpen, close: onClose, - onResultSelect, query: normalizedQuery, results, resultsId: searchResultsId,