diff --git a/src/renderer/src/components/CodeEditor/hook.ts b/src/renderer/src/components/CodeEditor/hooks.ts similarity index 56% rename from src/renderer/src/components/CodeEditor/hook.ts rename to src/renderer/src/components/CodeEditor/hooks.ts index 7e3bd28327..71d74ca3a5 100644 --- a/src/renderer/src/components/CodeEditor/hook.ts +++ b/src/renderer/src/components/CodeEditor/hooks.ts @@ -1,7 +1,8 @@ import { linter } from '@codemirror/lint' // statically imported by @uiw/codemirror-extensions-basic-setup +import { EditorView } from '@codemirror/view' import { useCodeStyle } from '@renderer/context/CodeStyleProvider' -import { Extension } from '@uiw/react-codemirror' -import { useEffect, useState } from 'react' +import { Extension, keymap } from '@uiw/react-codemirror' +import { useEffect, useMemo, useState } from 'react' // 语言对应的 linter 加载器 const linterLoaders: Record Promise> = { @@ -53,3 +54,55 @@ export const useLanguageExtensions = (language: string, lint?: boolean) => { return extensions } + +interface UseSaveKeymapProps { + onSave?: (content: string) => void + enabled?: boolean +} + +/** + * CodeMirror 扩展,用于处理保存快捷键 (Cmd/Ctrl + S) + * @param onSave 保存时触发的回调函数 + * @param enabled 是否启用此快捷键 + * @returns 扩展或空数组 + */ +export function useSaveKeymap({ onSave, enabled = true }: UseSaveKeymapProps) { + return useMemo(() => { + if (!enabled || !onSave) { + return [] + } + + return keymap.of([ + { + key: 'Mod-s', + run: (view: EditorView) => { + onSave(view.state.doc.toString()) + return true + }, + preventDefault: true + } + ]) + }, [onSave, enabled]) +} + +interface UseBlurHandlerProps { + onBlur?: (content: string) => void +} + +/** + * CodeMirror 扩展,用于处理编辑器的 blur 事件 + * @param onBlur blur 事件触发时的回调函数 + * @returns 扩展或空数组 + */ +export function useBlurHandler({ onBlur }: UseBlurHandlerProps) { + return useMemo(() => { + if (!onBlur) { + return [] + } + return EditorView.domEventHandlers({ + blur: (_event, view) => { + onBlur(view.state.doc.toString()) + } + }) + }, [onBlur]) +} diff --git a/src/renderer/src/components/CodeEditor/index.tsx b/src/renderer/src/components/CodeEditor/index.tsx index db699fa030..db7dd5f1ba 100644 --- a/src/renderer/src/components/CodeEditor/index.tsx +++ b/src/renderer/src/components/CodeEditor/index.tsx @@ -1,7 +1,7 @@ import { CodeTool, TOOL_SPECS, useCodeTool } from '@renderer/components/CodeToolbar' import { useCodeStyle } from '@renderer/context/CodeStyleProvider' import { useSettings } from '@renderer/hooks/useSettings' -import CodeMirror, { Annotation, BasicSetupOptions, EditorView, Extension, keymap } from '@uiw/react-codemirror' +import CodeMirror, { Annotation, BasicSetupOptions, EditorView, Extension } from '@uiw/react-codemirror' import diff from 'fast-diff' import { ChevronsDownUp, @@ -14,7 +14,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { memo } from 'react' import { useTranslation } from 'react-i18next' -import { useLanguageExtensions } from './hook' +import { useBlurHandler, useLanguageExtensions, useSaveKeymap } from './hooks' // 标记非用户编辑的变更 const External = Annotation.define() @@ -25,6 +25,7 @@ interface Props { language: string onSave?: (newContent: string) => void onChange?: (newContent: string) => void + onBlur?: (newContent: string) => void setTools?: (value: React.SetStateAction) => void height?: string minHeight?: string @@ -54,6 +55,7 @@ const CodeEditor = ({ language, onSave, onChange, + onBlur, setTools, height, minHeight, @@ -166,28 +168,18 @@ const CodeEditor = ({ setIsUnwrapped(!wrappable) }, [wrappable]) - // 保存功能的快捷键 - const saveKeymap = useMemo(() => { - return keymap.of([ - { - key: 'Mod-s', - run: () => { - handleSave() - return true - }, - preventDefault: true - } - ]) - }, [handleSave]) + const saveKeymapExtension = useSaveKeymap({ onSave, enabled: enableKeymap }) + const blurExtension = useBlurHandler({ onBlur }) const customExtensions = useMemo(() => { return [ ...(extensions ?? []), ...langExtensions, ...(isUnwrapped ? [] : [EditorView.lineWrapping]), - ...(enableKeymap ? [saveKeymap] : []) - ] - }, [extensions, langExtensions, isUnwrapped, enableKeymap, saveKeymap]) + saveKeymapExtension, + blurExtension + ].flat() + }, [extensions, langExtensions, isUnwrapped, saveKeymapExtension, blurExtension]) return (