/** * Composable that manages a find/replace floating surface. * * Owns all search state (query, toggles, match count, active index) and the * resolution chain for custom/external/built-in rendering. The component * receives a FindReplaceHandle with reactive state and actions. * * @param {Object} options * @param {() => import('../core/surface-manager.js').SurfaceManager | null} options.getSurfaceManager * @param {() => SearchEditor | null} options.getActiveEditor * @param {import('vue').Ref} [options.activeEditorRef] - Reactive ref to the active editor (for watching switches) * @param {() => boolean | FindReplaceConfig | undefined} [options.getFindReplaceConfig] - Config getter * @param {() => { search?: any } | null | undefined} [options.getSuperDocUI] - Getter for the * SuperDoc-owned UI controller (`superdoc.ui`). Its `.search` slice is the single V2 * find/replace session authority; the V2 driver never touches `editor.commands`. */ export function useFindReplace({ getSurfaceManager, getActiveEditor, activeEditorRef, getFindReplaceConfig, getSuperDocUI, }: { getSurfaceManager: () => import('../core/surface-manager.js').SurfaceManager | null; getActiveEditor: () => SearchEditor | null; activeEditorRef?: import('vue').Ref | undefined; getFindReplaceConfig?: (() => boolean | FindReplaceConfig | undefined) | undefined; getSuperDocUI?: (() => { search?: any; } | null | undefined) | undefined; }): { open: () => Promise; close: () => void; isOpen: import('vue').Ref; wouldOpen: () => boolean; destroy: () => void; }; /** * The shape of `setSearchSession`, * `nextSearchMatch`, `previousSearchMatch`, `replaceSearchMatch` returns. * The Search extension is renderer-owned; this composable only consumes * the two fields below. */ export type SearchResult = { matches: { length: number; }[]; activeMatchIndex: number; }; /** * The search command subset consumed here. */ export type SearchCommands = { clearSearchSession: () => void; setSearchSession: (query: string, options: { caseSensitive: boolean; ignoreDiacritics: boolean; highlight: boolean; searchModel: "raw" | "visible"; }) => SearchResult; nextSearchMatch: () => SearchResult; previousSearchMatch: () => SearchResult; replaceSearchMatch: (replacement: string) => SearchResult; replaceAllSearchMatches: (replacement: string) => void; }; export type SearchEditor = import('../core/types/index.js').Editor & { commands: SearchCommands; extensionStorage?: Record; storage?: Record; }; /** * The Search extension's storage shape. * The Search extension is renderer-owned; this composable only * needs the fields it reads to detect a live search session and resync * from external mutations. */ export type SearchStorage = { searchIndex?: unknown; searchResults?: unknown; activeMatchIndex?: number | undefined; matches?: { length: number; }[] | undefined; }; export type FindReplaceConfig = import('../core/types/index.js').FindReplaceConfig; export type ResolvedFindReplaceTexts = import('../core/types/index.js').ResolvedFindReplaceTexts; export type FindReplaceHandle = import('../core/types/index.js').FindReplaceHandle; export type FindReplaceContext = import('../core/types/index.js').FindReplaceContext; export type FindReplaceResolution = import('../core/types/index.js').FindReplaceResolution;