From 7f6a4c62e59aeea2656aa026e2bdf7e0d9d4edea Mon Sep 17 00:00:00 2001 From: ByungCheol Date: Sun, 7 Jun 2026 17:50:43 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20PC(Electron)=20=EC=9C=84=EC=A7=80?= =?UTF-8?q?=EC=9C=85=20=ED=95=9C=EA=B8=80=20IME=20=EC=A4=91=EB=B3=B5=20?= =?UTF-8?q?=E2=86=92=20=EC=97=90=EB=94=94=ED=84=B0=EB=A5=BC=20=EB=A7=88?= =?UTF-8?q?=ED=81=AC=EB=8B=A4=EC=9A=B4=20=EB=AA=A8=EB=93=9C=EB=A1=9C=20?= =?UTF-8?q?=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 진단: 제목(일반 입력)은 정상, 본문 위지윅(contenteditable)만 첫 자음 중복 → ProseMirror+Electron IME 버그 - MarkdownEditor: Electron 감지 시 initialEditType='markdown'(텍스트 기반 입력) → IME 정상. 웹/APK는 위지윅 유지 - 앞서의 불필요한 조합(composition) 처리 코드 제거(원인이 아니었음) Co-Authored-By: Claude Opus 4.8 --- src/components/editor/MarkdownEditor.vue | 43 +++++++----------------- 1 file changed, 12 insertions(+), 31 deletions(-) diff --git a/src/components/editor/MarkdownEditor.vue b/src/components/editor/MarkdownEditor.vue index b2382bc..068a59f 100644 --- a/src/components/editor/MarkdownEditor.vue +++ b/src/components/editor/MarkdownEditor.vue @@ -14,32 +14,22 @@ const props = defineProps({ }) const emit = defineEmits(['update:modelValue']) +// PC(Electron)는 위지윅(contenteditable)에서 한글 IME 첫 자음이 중복되는 Chromium 버그가 있어 +// 마크다운(텍스트 기반) 모드로 입력받는다. 웹/모바일(APK)은 위지윅 유지. +const isElectron = typeof navigator !== 'undefined' && /electron/i.test(navigator.userAgent) +const editType = isElectron ? 'markdown' : props.initialEditType + const el = ref(null) let editor = null -// 에디터가 마지막으로 emit 한 값. 부모가 되돌려준 echo 를 구분해 한글 조합(IME)이 깨지지 않게 한다. +// 에디터가 마지막으로 emit 한 값. 부모가 되돌려준 echo 를 구분해 입력 중 setMarkdown 으로 끊기지 않게. let lastEmitted = props.modelValue || '' -// IME(한글 등) 조합 중 여부. 조합 중에는 getMarkdown/emit 을 보류해 첫 자음이 중복되는 문제를 막는다. -let composing = false - -function emitValue() { - if (!editor) return - lastEmitted = editor.getMarkdown() - emit('update:modelValue', lastEmitted) -} -function onCompStart() { - composing = true -} -function onCompEnd() { - composing = false - emitValue() // 조합 완료 시 한 번만 반영 -} onMounted(() => { editor = new Editor({ el: el.value, height: props.height, - initialEditType: props.initialEditType, - hideModeSwitch: true, // 마크다운/위지윅 전환 탭 숨김 (WYSIWYG 전용) + initialEditType: editType, + hideModeSwitch: true, plugins: [codeSyntaxHighlight], // 코드 구문 강조 initialValue: props.modelValue || '', placeholder: props.placeholder, @@ -47,24 +37,19 @@ onMounted(() => { autofocus: false, events: { change: () => { - // 조합 중에는 보류 — 조합 중 getMarkdown 호출이 IME 를 끊어 자음 중복을 유발한다. - if (composing) return - emitValue() + lastEmitted = editor.getMarkdown() + emit('update:modelValue', lastEmitted) }, }, }) - // 조합 이벤트는 contenteditable 에서 버블링되어 래퍼(el)에서 잡힌다. - el.value.addEventListener('compositionstart', onCompStart) - el.value.addEventListener('compositionend', onCompEnd) }) -// 외부 값 변경(수정 로드, 제출 후 초기화 등)만 에디터에 반영. -// 에디터 자신이 방금 emit 한 값(echo)이거나 조합 중이면 무시 → 입력 중 setMarkdown 으로 IME 조합이 끊기지 않게 한다. +// 외부 값 변경(수정 로드, 제출 후 초기화 등)만 에디터에 반영. echo 는 무시. watch( () => props.modelValue, (val) => { const v = val || '' - if (composing || v === lastEmitted) return + if (v === lastEmitted) return if (editor && v !== editor.getMarkdown()) { lastEmitted = v editor.setMarkdown(v) @@ -73,10 +58,6 @@ watch( ) onBeforeUnmount(() => { - if (el.value) { - el.value.removeEventListener('compositionstart', onCompStart) - el.value.removeEventListener('compositionend', onCompEnd) - } editor?.destroy() editor = null })