# 自定义搜索面板

替换搜索 UI，保留统一的查询、选中和替换事务。

## 接入位置

创建选项 `searchPanel` 接受 `ComponentViewRenderer<SearchPanelProps>`。Vue 用 `VueComponentViewRenderer(SearchPanel)`；与节点组件一样，`VueNodeViewHost` 必须位于已有 Provider 树中。

~~~ts
import { VueComponentViewRenderer } from '@quirekit/msfe-vue'
import SearchPanel from './search-panel.vue'

const options = {
  searchPanel: VueComponentViewRenderer(SearchPanel),
  // Provide markdown and extensions as in the Vue integration guide.
}
~~~

原生搜索快捷键继续打开该面板。不要在宿主另建一份全文搜索索引，再通过 DOM 高亮覆盖正文。

## 最小可复制的面板

此片段使用 QuireKit 公共输入和按钮；放入 `search-panel.vue`，按上方方式接入。

~~~vue
<script setup lang="ts">
import type { SearchPanelProps } from '@quirekit/msfe-core'
import { QuireInput, QuireButton } from '@quirekit/ui/vue'
defineProps<{ view: SearchPanelProps }>()
</script>
<template>
  <div class="flex flex-wrap items-center gap-2 p-qk-surface">
    <QuireInput :model-value="view.query.search" aria-label="查找"
      @update:model-value="value => view.setQuery({ search: value ?? '' })" />
    <QuireButton :disabled="!view.valid || view.composing"
      @click="view.run('next')">下一项</QuireButton>
    <QuireButton variant="ghost" @click="view.run('close')">关闭</QuireButton>
  </div>
</template>
~~~

生产面板应按应用语言提供标签，必要时通过 `view.phrase(key)` 获取宿主 CodeMirror 文案。不要在中文模式直接展示固定英文提示。

## 字段和动作

`query` 包含 `search`、`replace`、`caseSensitive`、`regexp`、`wholeWord`。通过 `setQuery(partial)` 局部更新，不直接修改传入对象。`valid` 判断非空查询是否可执行，包含正则有效性。`matches` 给出命中计数：`total` 为命中总数（最多统计 1000 个，超出时 `limited` 为真），`current` 为主选区恰好覆盖的第几个命中，没有覆盖时为 0。

`run()` 接受 `next`、`previous`、`all`、`replace`、`replaceAll`、`close`。替换控件在 `readOnly` 或 `composing` 时禁用；查找和复制仍可使用。动作返回布尔值，面板卸载后的过期动作不可继续写文档。

## 扩展为完整面板

增加替换输入、大小写/全词/正则开关及结果导航，都调用上述字段和动作。键盘提交在输入法组合结束后执行；面板关闭后由现有搜索生命周期恢复焦点。避免宿主的全局 Enter 处理器抢走输入框事件。

验证：无效正则、零结果、中文组合、替换后撤销、只读查找、打开时选区、关闭后焦点、窄屏和两种主题。精确协议见 [渲染 API](/api/rendering)。
