vdc-editor 0.1.216 → 0.1.218

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { c as Z, a as Y, C as be, P as Ce, b as ve, D as ye, d as Ee, _ as Se, e as we, f as Te, S as oe, o as Ie, g as Re, h as Oe, i as Ne, j as We, k as Me, l as He, m as Ae, n as $e } from "./index-DMLnh9u3.mjs";
1
+ import { c as Z, a as Y, C as be, P as Ce, b as ve, D as ye, d as Ee, _ as Se, e as we, f as Te, S as oe, o as Ie, g as Re, h as Oe, i as Ne, j as We, k as Me, l as He, m as Ae, n as $e } from "./index-BTaZZr4K.mjs";
2
2
  import { defineComponent as P, createElementBlock as v, openBlock as m, createVNode as E, createElementVNode as h, unref as s, ref as L, onMounted as ee, nextTick as le, createCommentVNode as ie, normalizeClass as z, withModifiers as te, toDisplayString as G, normalizeStyle as ae, Fragment as K, renderList as q, createTextVNode as V, createBlock as B, createStaticVNode as Le, withCtx as $, reactive as ce, computed as se, watch as ue, normalizeProps as De, guardReactiveProps as Pe, renderSlot as Be, onUnmounted as re, resolveDynamicComponent as ze } from "vue";
3
3
  import { useWindowSize as je, useEventListener as Ge } from "@vueuse/core";
4
4
  const U = {
@@ -684,4 +684,4 @@ const vt = /* @__PURE__ */ Se(kt, [["render", Ct]]), yt = { class: "text-xs py-4
684
684
  export {
685
685
  Mt as default
686
686
  };
687
- //# sourceMappingURL=BulkSpellChecker-B72PQGBe.mjs.map
687
+ //# sourceMappingURL=BulkSpellChecker-AqPYywBr.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"BulkSpellChecker-B72PQGBe.mjs","sources":["../src/constants/bulkSpellChecker.ts","../node_modules/lucide-vue-next/dist/esm/icons/arrow-left-right.js","../node_modules/lucide-vue-next/dist/esm/icons/circle-alert.js","../node_modules/lucide-vue-next/dist/esm/icons/circle-check.js","../src/components/BulkSpellCheckerHelpText.vue","../src/utils/bulkSpellchecker.ts","../src/components/BulkSpellCheckerWrongWordList.vue","../src/components/ui/SpinnerIcon.vue","../src/components/BulkSpellCheckerLoading.vue","../src/components/BulkSpellCheckerContent.vue","../src/hooks/useBulkSpellCheckerStore.ts","../src/components/ui/dialog/DialogTrigger.vue","../src/components/BulkSpellChecker.vue"],"sourcesContent":["export const ERROR_TYPE = {\n SPACING: 1,\n SPELLING: 2,\n}\n\nexport const SPELL_CHECK_CODE = {\n NOTHING_TO_CHANGE: 'NOTHING_TO_CHANGE',\n} as const\n\nexport const SPELL_CHECK_STATUS = {\n LOADING: 'loading',\n HAS_ERROR: 'hasError',\n NO_ERROR: 'noError',\n FAIL: 'fail',\n} as const\n\nexport type SpellCheckStatus = (typeof SPELL_CHECK_STATUS)[keyof typeof SPELL_CHECK_STATUS]\n\nexport const EDITOR_NAME = {\n EDITOR_COMMENT: 'editorComment',\n EDITOR_CONTENT: 'editorContent',\n} as const\n\nexport type EditorName = (typeof EDITOR_NAME)[keyof typeof EDITOR_NAME]\n","/**\n * @license lucide-vue-next v0.439.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst ArrowLeftRight = createLucideIcon(\"ArrowLeftRightIcon\", [\n [\"path\", { d: \"M8 3 4 7l4 4\", key: \"9rb6wj\" }],\n [\"path\", { d: \"M4 7h16\", key: \"6tx8e3\" }],\n [\"path\", { d: \"m16 21 4-4-4-4\", key: \"siv7j2\" }],\n [\"path\", { d: \"M20 17H4\", key: \"h6l3hr\" }]\n]);\n\nexport { ArrowLeftRight as default };\n//# sourceMappingURL=arrow-left-right.js.map\n","/**\n * @license lucide-vue-next v0.439.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst CircleAlert = createLucideIcon(\"CircleAlertIcon\", [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"line\", { x1: \"12\", x2: \"12\", y1: \"8\", y2: \"12\", key: \"1pkeuh\" }],\n [\"line\", { x1: \"12\", x2: \"12.01\", y1: \"16\", y2: \"16\", key: \"4dfq90\" }]\n]);\n\nexport { CircleAlert as default };\n//# sourceMappingURL=circle-alert.js.map\n","/**\n * @license lucide-vue-next v0.439.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst CircleCheck = createLucideIcon(\"CircleCheckIcon\", [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"path\", { d: \"m9 12 2 2 4-4\", key: \"dzmm74\" }]\n]);\n\nexport { CircleCheck as default };\n//# sourceMappingURL=circle-check.js.map\n","<script setup lang=\"ts\">\nimport { cn } from '@/utils'\nimport { ChevronDown } from 'lucide-vue-next'\n\ninterface Props {\n text: string\n}\nconst props = defineProps<Props>()\n\nconst expanded = ref(false)\nconst showButton = ref(false)\nconst helpRef = ref<HTMLElement | null>(null)\n\nfunction toggle() {\n expanded.value = !expanded.value\n}\n\nonMounted(async () => {\n await nextTick()\n if (helpRef.value && helpRef.value.scrollHeight > 32) {\n showButton.value = true\n }\n})\n</script>\n\n<template>\n <div class=\"relative\">\n <div\n ref=\"helpRef\"\n class=\"text-gray-700 dark:text-gray-400 transition-all\"\n :class=\"expanded ? 'max-h-none' : 'max-h-[32px] overflow-hidden'\"\n v-html=\"text\"\n ></div>\n\n <div\n v-if=\"showButton\"\n class=\"\"\n :class=\"\n cn(\n 'w-32 flex items-end justify-end bg-gradient-to-l from-white via-white to-transparent dark:from-ed-background dark:via-ed-background',\n expanded ? 'ml-auto opacity-60' : 'absolute bottom-0 right-0'\n )\n \"\n >\n <button class=\"flex items-center gap-1\" @click.stop=\"toggle\">\n <span class=\"border-b border-gray-500\">{{ expanded ? '접기' : '자세히' }}</span>\n <ChevronDown class=\"w-4 h-4 transition-transform\" :class=\"expanded ? 'rotate-180' : ''\" />\n </button>\n </div>\n </div>\n</template>\n","import { ERROR_TYPE } from '@/constants'\nimport { WrongWordItem } from '@/type'\nimport { Editor } from '@tiptap/core'\nimport { Plugin, PluginKey } from 'prosemirror-state'\nimport { Decoration, DecorationSet } from 'prosemirror-view'\n\nconst HIGHLIGHT_KEY = new PluginKey('bulk-spellcheck-highlight')\n\nfunction createHighlightPlugin(editor: Editor, errors: WrongWordItem[], blockSeparator = '\\n') {\n return new Plugin({\n key: HIGHLIGHT_KEY,\n props: {\n decorations(state) {\n const decos: Decoration[] = []\n const errorColorMap = {\n [ERROR_TYPE.SPACING]: 'bulk-highlight text-blue-500 border-b-2 border-blue-500',\n [ERROR_TYPE.SPELLING]: 'bulk-highlight text-red-500 border-b-2 border-red-500',\n }\n\n errors.forEach(item => {\n const from = findDocPosFromOffset(editor, item.startIndex, blockSeparator)\n const to = findDocPosFromOffset(editor, item.endIndex - 1, blockSeparator) + 1\n\n const errorType = item.errorHelpDtos?.[0]?.errorType\n const className = errorColorMap[errorType ?? -1] || 'bulk-highlight text-green-500 border-b-2 border-green-500' // type integrated\n\n const safeFrom = Math.max(0, Math.min(from, state.doc.content.size))\n const safeTo = Math.max(0, Math.min(to, state.doc.content.size))\n if (safeFrom < safeTo) {\n decos.push(Decoration.inline(safeFrom, safeTo, { class: className }))\n }\n })\n\n return DecorationSet.create(state.doc, decos)\n },\n },\n })\n}\n\nexport function applyHighlights(editor: Editor, errors: WrongWordItem[]) {\n editor.unregisterPlugin(HIGHLIGHT_KEY)\n\n if (!errors.length) return\n\n const plugin = createHighlightPlugin(editor, errors)\n editor.registerPlugin(plugin)\n}\n\nexport function clearHighlights(editor: Editor) {\n if (!editor) return\n\n editor.unregisterPlugin(HIGHLIGHT_KEY)\n}\n\nexport function buildPlainIndexToDocPosMap(editor: Editor, blockSeparator = '\\n') {\n const map: (number | null)[] = []\n let plainIndex = 0\n let firstBlock = true\n\n editor.state.doc.descendants((node, pos) => {\n if (node.isText && node.text) {\n for (let i = 0; i < node.text.length; i++) {\n map[plainIndex++] = pos + i\n }\n }\n\n const nodeName = node.type && (node.type as any).name\n const isHardBreak = nodeName === 'hardBreak' || nodeName === 'hard_break' || nodeName === 'br'\n if (isHardBreak && blockSeparator.length > 0) {\n for (let k = 0; k < blockSeparator.length; k++) {\n map[plainIndex++] = pos\n }\n }\n\n if (node.isBlock) {\n if (!firstBlock && blockSeparator.length > 0) {\n for (let k = 0; k < blockSeparator.length; k++) {\n map[plainIndex++] = pos \n }\n }\n firstBlock = false\n }\n\n return true\n })\n\n return map\n}\n\nexport function findDocPosFromOffset(editor: Editor,offset: number, blockSeparator = '\\n') {\n const map = buildPlainIndexToDocPosMap(editor, blockSeparator)\n if (offset < 0) offset = 0\n if (offset >= map.length) {\n return editor.state.doc.content.size\n }\n const mapped = map[offset]\n if (mapped == null) {\n for (let i = offset; i < map.length; i++) if (map[i] != null) return map[i] as number\n for (let i = offset - 1; i >= 0; i--) if (map[i] != null) return map[i] as number\n return editor.state.doc.content.size\n }\n return mapped as number\n}\n","<script setup lang=\"ts\">\nimport { EDITOR_NAME, EditorName, ERROR_TYPE } from '@/constants'\nimport { ArrowLeftRight } from 'lucide-vue-next'\nimport { Editor } from '@tiptap/core'\nimport { EditorsState, WrongWordItem } from '@/type'\nimport { applyHighlights, findDocPosFromOffset } from '@/utils/bulkSpellchecker'\n\ninterface Props {\n editorsState: EditorsState\n}\nconst props = defineProps<Props>()\n\nfunction getErrorColor(errorType?: number) {\n const errorColorMap = {\n [ERROR_TYPE.SPACING]: 'bg-blue-500',\n [ERROR_TYPE.SPELLING]: 'bg-red-500',\n }\n return errorColorMap[errorType ?? -1] || 'bg-green-500' // integrated\n}\n\nfunction getNoSuggestionText(editor: Editor) {\n return editor?.extensionStorage?.spellchecker?.spellchecker?.uiStrings?.uiStrings || 'No suggestions found'\n}\n\nfunction resetHightlightSection(key: EditorName) {\n if (key === EDITOR_NAME.EDITOR_COMMENT) {\n props.editorsState[EDITOR_NAME.EDITOR_CONTENT].editor?.commands.setTextSelection(0)\n return\n }\n\n if (key === EDITOR_NAME.EDITOR_CONTENT) {\n props.editorsState[EDITOR_NAME.EDITOR_COMMENT].editor?.commands.setTextSelection(0)\n return\n }\n}\n\nfunction scrollToError(key: EditorName, editor: Editor, item: WrongWordItem) {\n if (!editor) return\n\n resetHightlightSection(key)\n\n const from = findDocPosFromOffset(editor, item.startIndex)\n const to = findDocPosFromOffset(editor, item.endIndex - 1) + 1\n\n editor.chain().setTextSelection({ from, to }).focus().run()\n\n const mid = Math.max(0, Math.floor((from + to) / 2))\n const domAtPos = editor.view.domAtPos(mid)\n const maybeNode = domAtPos.node as unknown\n\n let el: HTMLElement | null = null\n\n if (maybeNode instanceof Element) {\n el = maybeNode as HTMLElement\n } else if (maybeNode instanceof Text) {\n el = maybeNode.parentElement\n } else {\n el = (maybeNode as any)?.parentElement ?? (editor.view.dom as HTMLElement)\n }\n\n if (el?.scrollIntoView) {\n el.scrollIntoView({ behavior: 'smooth', block: 'center' })\n }\n}\n\nfunction replaceWithCorrectWord(editor: Editor, errors: WrongWordItem[], item: WrongWordItem, replacement: string) {\n if (!editor) return\n\n const from = findDocPosFromOffset(editor, item.startIndex)\n const to = findDocPosFromOffset(editor, item.endIndex - 1) + 1\n\n const tr = editor.state.tr.insertText(replacement, from, to)\n editor.view.dispatch(tr)\n editor.view.focus()\n\n const delta = replacement.length - (item.wrongWord?.length ?? 0)\n const origStart = item.startIndex\n const origEnd = item.endIndex\n\n for (let i = errors.length - 1; i >= 0; i--) {\n const err = errors[i]\n\n if (err.startIndex >= origStart && err.startIndex < origEnd) {\n errors.splice(i, 1)\n continue\n }\n\n if (err.startIndex > origStart) {\n err.startIndex += delta\n err.endIndex += delta\n }\n }\n\n const idx = errors.indexOf(item)\n if (idx !== -1) errors.splice(idx, 1)\n\n applyHighlights(editor, errors)\n}\n\nconst contentEl = ref<HTMLElement | null>(null)\nconst standardMaxHeight = 450\nconst maxHeight = ref(standardMaxHeight)\nconst { height: windowHeight } = useWindowSize()\n\nfunction computeMaxHeight() {\n const el = contentEl.value\n if (!el) return\n\n const gap = 80\n const rect = el.getBoundingClientRect()\n const availableViewportHeight = windowHeight.value - rect.top - gap\n\n maxHeight.value = standardMaxHeight > availableViewportHeight ? availableViewportHeight : standardMaxHeight\n}\n\nonMounted(() => {\n computeMaxHeight()\n useEventListener(window, 'resize', computeMaxHeight)\n})\n</script>\n\n<template>\n <div ref=\"contentEl\" :style=\"{ maxHeight: `${maxHeight}px` }\" class=\"pr-1 overflow-y-auto\">\n <template v-for=\"(editorData, key) in editorsState\" :key=\"key\">\n <div\n v-for=\"(item, idx) in editorData.wrongWords\"\n :key=\"idx\"\n class=\"border-b border-gray-400 dark:border-ed-muted pb-5 mb-5 cursor-pointer\"\n @click=\"scrollToError(key, editorsState[key].editor as Editor, item)\"\n >\n <div class=\"flex items-center mb-2\">\n <span class=\"w-16 font-medium\">입력 내용</span>\n <div class=\"flex items-center gap-2\">\n <span class=\"w-1.5 h-1.5 rounded-full\" :class=\"getErrorColor(item.errorHelpDtos[0]?.errorType)\"></span>\n <span class=\"break-all whitespace-normal\">{{ item.wrongWord }}</span>\n </div>\n </div>\n\n <div class=\"flex items-center mb-2\">\n <span class=\"w-16 font-medium\">대치어</span>\n <div v-if=\"item.correctWord.length\" class=\"flex-1 space-y-1\">\n <div\n v-for=\"(sub, sidx) in item.correctWord\"\n :key=\"sidx\"\n class=\"font-semibold px-3 py-1.5 rounded bg-gray-100 dark:bg-ed-muted flex items-center justify-between\"\n >\n <div class=\"text-sm\">\n {{ sub }}\n </div>\n <button\n class=\"flex items-center gap-1 text-blue-500\"\n @click.stop=\"replaceWithCorrectWord(editorData.editor as Editor, editorData.wrongWords, item, sub)\"\n >\n <ArrowLeftRight class=\"w-4 h-4\" /> <span>바꾸기</span>\n </button>\n </div>\n </div>\n <div v-else>\n {{ getNoSuggestionText(editorData.editor as Editor) }}\n </div>\n </div>\n\n <div class=\"flex\">\n <span class=\"w-16 font-medium\">도움말</span>\n <div class=\"flex-1\">\n <BulkSpellCheckerHelpText :text=\"item.errorHelpDtos[0]?.errorMessage\" />\n </div>\n </div>\n </div>\n </template>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { cn } from '@/utils'\n\ninterface Props {\n fillWhite?: boolean\n class?: string\n}\nconst props = withDefaults(defineProps<Props>(), {\n fillWhite: false,\n class: '',\n})\n</script>\n\n<template>\n <svg :class=\"cn('animate-spin h-5 w-5 mr-0.5', props.class)\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <circle\n v-if=\"fillWhite\"\n class=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n fill=\"#ffffff\"\n stroke=\"currentColor\"\n stroke-width=\"4\"\n ></circle>\n <circle v-else class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\"></circle>\n <path\n class=\"opacity-100\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n ></path>\n </svg>\n</template>\n\n<style scoped></style>\n","<template>\n <div class=\"min-h-[188px] flex flex-col items-center justify-center gap-y-2 text-sm\">\n <SpinnerIcon fill-white class=\"h-10 w-10 text-blue-500\" />\n <div>맞춤법 검사 중입니다</div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { SPELL_CHECK_STATUS, SpellCheckStatus } from '@/constants'\nimport { cn } from '@/utils'\nimport { EditorsState } from '@/type'\n\ninterface Props {\n editorsState: EditorsState,\n spellCheckStatus: SpellCheckStatus\n allWrongWordsMissSuggestions: boolean\n}\nconst props = defineProps<Props>()\n\nconst emit = defineEmits<{\n (e: 'close-modal'): void\n (e: 'run-spellcheck'): void\n (e: 'replace-all-editor-errors'): void\n}>()\n</script>\n\n<template>\n <div class=\"text-xs py-4 px-6\">\n <BulkSpellCheckerLoading v-if=\"spellCheckStatus === SPELL_CHECK_STATUS.LOADING\" />\n <BulkSpellCheckerWrongWordList v-else-if=\"spellCheckStatus === SPELL_CHECK_STATUS.HAS_ERROR\" :editorsState=\"editorsState\" />\n <BulkSpellCheckerNotWrongWord v-else-if=\"spellCheckStatus === SPELL_CHECK_STATUS.NO_ERROR\" />\n <BulkSpellCheckerFail v-else-if=\"spellCheckStatus === SPELL_CHECK_STATUS.FAIL\" />\n\n <div class=\"flex items-center justify-between mt-3\">\n <ul class=\"flex items-cente gap-x-4\">\n <li class=\"flex items-center gap-x-1\"><span class=\"w-1.5 h-1.5 rounded-full bg-red-500\"></span>맞춤법</li>\n <li class=\"flex items-center gap-x-1\"><span class=\"w-1.5 h-1.5 rounded-full bg-blue-500\"></span>띄어쓰기</li>\n <li class=\"flex items-center gap-x-1\"><span class=\"w-1.5 h-1.5 rounded-full bg-green-500\"></span>통합교정</li>\n </ul>\n\n <div class=\"flex gap-x-1\">\n <Button\n variant=\"outline\"\n :class=\"\n cn(\n 'border-blue-500 text-blue-500 text-xs px-3 py-2 h-auto hover:bg-white/80 hover:opacity-80 hover:text-blue-500 dark:text-dark-blue-100 dark:hover:bg-dark-blue-400 dark:hover:text-dark-blue-50 dark:hover:border-dark-blue-100',\n spellCheckStatus === SPELL_CHECK_STATUS.LOADING &&\n 'text-gray-300 bg-gray-100 border-gray-100 pointer-events-none dark:bg-ed-muted/70 dark:border-ed-muted/70 dark:text-gray-500'\n )\n \"\n @click=\"emit('run-spellcheck')\"\n >다시 검사하기</Button\n >\n\n <Button\n :class=\"\n cn(\n 'border-blue-500 text-white text-xs px-3 py-2 h-auto bg-blue-500 hover:bg-blue-500/80',\n (spellCheckStatus !== SPELL_CHECK_STATUS.HAS_ERROR || allWrongWordsMissSuggestions) &&\n 'text-gray-300 bg-gray-100 hover:bg-gray-100 pointer-events-none dark:bg-ed-muted/70 dark:text-gray-500'\n )\n \"\n @click=\"emit('replace-all-editor-errors')\"\n >모두 바꾸기</Button\n >\n </div>\n </div>\n </div>\n</template>\n","import { EDITOR_NAME, EditorName, SPELL_CHECK_CODE, SPELL_CHECK_STATUS, SpellCheckStatus } from '@/constants'\nimport { EditorsState, SpellCheckResponse, WrongWordItem } from '@/type'\nimport { Editor } from '@tiptap/core'\nimport axios from 'axios'\nimport { applyHighlights, clearHighlights, buildPlainIndexToDocPosMap } from '@/utils/bulkSpellchecker'\nimport { SPELLCHECKER_META_LIST } from '@/extensions/SpellChecker/spellchecker-extension'\n\nexport const useBulkSpellCheckerStore = () => {\n const editorsState: EditorsState = reactive({\n [EDITOR_NAME.EDITOR_COMMENT]: {\n editor: null,\n wrongWords: [],\n },\n [EDITOR_NAME.EDITOR_CONTENT]: {\n editor: null,\n wrongWords: [],\n },\n })\n\n function setEditor(editorKey: EditorName, editorInstance: Editor | null) {\n editorsState[editorKey].editor = editorInstance\n }\n\n const spellCheckStatus = ref<SpellCheckStatus>(SPELL_CHECK_STATUS.NO_ERROR)\n\n function resetAllEditorWrongWords() {\n Object.values(editorsState).forEach(editorState => {\n editorState.wrongWords = []\n })\n }\n\n function evaluateStatus(hasFail: boolean, hasError: boolean) {\n if (hasFail) return SPELL_CHECK_STATUS.FAIL\n if (hasError) return SPELL_CHECK_STATUS.HAS_ERROR\n return SPELL_CHECK_STATUS.NO_ERROR\n }\n\n async function handleRunSpellCheck() {\n spellCheckStatus.value = SPELL_CHECK_STATUS.LOADING\n\n let hasError = false\n let hasFail = false\n\n for (const [editorKey, { editor }] of Object.entries(editorsState)) {\n if (!editor) continue\n\n const apiUrl = editor?.extensionManager.extensions.find(ext => ext.name === 'spellchecker')?.options.proofreader\n .api\n const content = editor.getText({ blockSeparator: '\\n' })\n if (!apiUrl || !content) continue\n\n try {\n const { data: response } = await axios.post<SpellCheckResponse>(apiUrl, {\n value: content,\n })\n\n if (!response.success && response.code !== SPELL_CHECK_CODE.NOTHING_TO_CHANGE) {\n hasFail = true\n editorsState[editorKey].wrongWords = []\n continue\n }\n\n if (response.data?.wrongWordResponseDto) {\n hasError = true\n editorsState[editorKey].wrongWords = response.data.wrongWordResponseDto\n continue\n }\n\n editorsState[editorKey].wrongWords = []\n } catch (error) {\n console.error('handleRunSpellCheck error: ', error)\n hasFail = true\n }\n }\n\n spellCheckStatus.value = evaluateStatus(hasFail, hasError)\n }\n\n const countTotalWrongWords = computed(() => {\n return Object.values(editorsState).reduce((sum, { wrongWords }) => {\n return sum + wrongWords.length\n }, 0)\n })\n\n watch(countTotalWrongWords, newVal => {\n if (newVal === 0) {\n spellCheckStatus.value = evaluateStatus(false, false)\n }\n })\n\n const allWrongWordsMissSuggestions = computed(() => {\n const allWrongWords = Object.values(editorsState).flatMap(es => es.wrongWords)\n if (allWrongWords.length === 0) return false\n return allWrongWords.every(w => !Array.isArray(w.correctWord) || w.correctWord.length === 0)\n })\n\n function applyAllEditorHighlightErrors() {\n for (const [_, { editor, wrongWords }] of Object.entries(editorsState)) {\n if (!editor) continue\n applyHighlights(editor as Editor, wrongWords)\n }\n }\n\n function clearAllEditorHighlightErrors() {\n for (const [_, { editor }] of Object.entries(editorsState)) {\n if (!editor) continue\n clearHighlights(editor as Editor)\n }\n }\n\n async function reRunSpellCheckAndHighlight() {\n await handleRunSpellCheck()\n applyAllEditorHighlightErrors()\n }\n\n let isEnableCurrent = true\n function disableSpellCheckRealTime(isEnableSpellCheckRealTime: boolean) {\n isEnableCurrent = isEnableSpellCheckRealTime\n if (!isEnableSpellCheckRealTime) return\n\n for (const [_, { editor }] of Object.entries(editorsState)) {\n if (!editor) continue\n editor.extensionStorage.spellchecker.spellchecker.setEnabledProofreadText(false)\n editor.view.dispatch(editor.state.tr.setMeta(SPELLCHECKER_META_LIST.IS_ACTIVE_SPELLCHECK, false))\n }\n }\n\n function resetEnableSpellCheckRealTime() {\n if (!isEnableCurrent) return\n\n for (const [_, { editor }] of Object.entries(editorsState)) {\n if (!editor) continue\n editor.extensionStorage.spellchecker.spellchecker.setEnabledProofreadText(true)\n editor.view.dispatch(editor.state.tr.setMeta(SPELLCHECKER_META_LIST.IS_ACTIVE_SPELLCHECK, true))\n }\n }\n\n function replaceAllErrors(editor: Editor, errors: WrongWordItem[], blockSeparator = '\\n') {\n if (!editor) return\n if (!errors.length) return\n\n const map = buildPlainIndexToDocPosMap(editor, blockSeparator)\n\n function getMappedPos(offset: number) {\n if (offset < 0) offset = 0\n if (offset >= map.length) return editor.state.doc.content.size\n if (map[offset] != null) return map[offset] as number\n for (let i = offset; i < map.length; i++) if (map[i] != null) return map[i] as number\n for (let i = offset - 1; i >= 0; i--) if (map[i] != null) return map[i] as number\n return editor.state.doc.content.size\n }\n\n const replacements = errors.map(item => {\n const from = getMappedPos(item.startIndex)\n const to = getMappedPos(Math.max(0, item.endIndex - 1)) + 1\n const replacement = item.correctWord?.[0] ?? item.wrongWord\n return { item, from, to, replacement }\n })\n\n const validRepls = replacements.filter(r => typeof r.from === 'number' && typeof r.to === 'number' && r.from < r.to)\n\n if (!validRepls.length) return\n\n validRepls.sort((a, b) => b.from - a.from)\n\n const tr = editor.state.tr\n let lastAppliedFrom = Number.POSITIVE_INFINITY\n const appliedItems = new Set<WrongWordItem>()\n\n for (const r of validRepls) {\n if (r.to > lastAppliedFrom) {\n continue\n }\n\n tr.insertText(r.replacement, r.from, r.to)\n\n appliedItems.add(r.item)\n lastAppliedFrom = r.from\n }\n\n if (appliedItems.size > 0) {\n editor.view.dispatch(tr)\n editor.view.focus()\n }\n\n if (appliedItems.size > 0) {\n errors = errors.filter(e => ![...appliedItems].some(a => a === e))\n }\n\n applyHighlights(editor, errors)\n }\n\n function replaceAllEditorErrors() {\n for (const [_, { editor, wrongWords }] of Object.entries(editorsState)) {\n if (!editor) continue\n replaceAllErrors(editor as Editor, wrongWords)\n }\n }\n\n return {\n editorsState,\n spellCheckStatus,\n countTotalWrongWords,\n allWrongWordsMissSuggestions,\n setEditor,\n resetAllEditorWrongWords,\n disableSpellCheckRealTime,\n resetEnableSpellCheckRealTime,\n applyAllEditorHighlightErrors,\n clearAllEditorHighlightErrors,\n reRunSpellCheckAndHighlight,\n handleRunSpellCheck,\n replaceAllEditorErrors,\n }\n}\n","<script setup lang=\"ts\">\nimport { DialogTrigger, type DialogTriggerProps } from 'radix-vue'\n\nconst props = defineProps<DialogTriggerProps>()\n</script>\n\n<template>\n <DialogTrigger v-bind=\"props\">\n <slot />\n </DialogTrigger>\n</template>\n","<script setup lang=\"ts\">\nimport { EDITOR_NAME } from '@/constants'\nimport { useBulkSpellCheckerStore } from '@/hooks/useBulkSpellCheckerStore'\nimport { Editor } from '@tiptap/core'\nimport { DialogTrigger } from './ui/dialog'\n\ninterface Props {\n editor: Editor\n editorComment?: Editor\n isEnableSpellCheckRealTime: boolean\n}\nconst props = defineProps<Props>()\n\nconst {\n editorsState,\n countTotalWrongWords,\n spellCheckStatus,\n allWrongWordsMissSuggestions,\n setEditor,\n disableSpellCheckRealTime,\n resetEnableSpellCheckRealTime,\n handleRunSpellCheck,\n resetAllEditorWrongWords,\n applyAllEditorHighlightErrors,\n clearAllEditorHighlightErrors,\n reRunSpellCheckAndHighlight,\n replaceAllEditorErrors,\n} = useBulkSpellCheckerStore()\n\nconst isOpenModal = ref(false)\n\nconst dragOffset = reactive({ x: 0, y: 0 })\nconst dragging = ref(false)\nconst offset = { x: 0, y: 0 }\n\nconst onMouseDown = (e: MouseEvent) => {\n dragging.value = true\n offset.x = e.clientX - dragOffset.x\n offset.y = e.clientY - dragOffset.y\n document.addEventListener('mousemove', onMouseMove)\n document.addEventListener('mouseup', onMouseUp)\n}\n\nconst onMouseMove = (e: MouseEvent) => {\n if (!dragging.value) return\n dragOffset.x = e.clientX - offset.x\n dragOffset.y = e.clientY - offset.y\n}\n\nconst onMouseUp = () => {\n dragging.value = false\n document.removeEventListener('mousemove', onMouseMove)\n document.removeEventListener('mouseup', onMouseUp)\n}\n\nonUnmounted(() => {\n document.removeEventListener('mousemove', onMouseMove)\n document.removeEventListener('mouseup', onMouseUp)\n})\n\nconst triggerRef = ref<InstanceType<typeof DialogTrigger> | null>(null)\nconst position = ref({ top: 0, right: 0 })\n\nconst updatePosition = () => {\n if (triggerRef.value) {\n const rect = triggerRef.value.$el.getBoundingClientRect()\n\n position.value = {\n top: rect.bottom + window.scrollY + 5,\n right: window.innerWidth - rect.right - window.scrollX,\n }\n\n dragOffset.x = 0\n dragOffset.y = 0\n }\n}\n\nonMounted(async () => {\n if (props.editorComment) {\n setEditor(EDITOR_NAME.EDITOR_COMMENT, props.editorComment)\n }\n setEditor(EDITOR_NAME.EDITOR_CONTENT, props.editor)\n})\n\nonUnmounted(() => {\n setEditor(EDITOR_NAME.EDITOR_COMMENT, null)\n setEditor(EDITOR_NAME.EDITOR_CONTENT, null)\n})\n\nwatch(isOpenModal, async val => {\n if (val) {\n await nextTick()\n updatePosition()\n disableSpellCheckRealTime(props.isEnableSpellCheckRealTime)\n await handleRunSpellCheck()\n applyAllEditorHighlightErrors()\n } else {\n resetAllEditorWrongWords()\n resetEnableSpellCheckRealTime()\n clearAllEditorHighlightErrors()\n }\n})\n\nconst bulkSpellCheckerBtnConfig = props.editor?.extensionManager.extensions.find(e => e.name === 'spellchecker')\n ?.options.bulkSpellCheckerButton\n</script>\n\n<template>\n <Dialog :open=\"isOpenModal\">\n <DialogTrigger as-child ref=\"triggerRef\" @click=\"isOpenModal = !isOpenModal\">\n <button\n v-if=\"!bulkSpellCheckerBtnConfig\"\n class=\"border-blue-500 text-white text-xs text-nowrap px-3 py-2 h-auto bg-blue-500 hover:bg-blue-500/80 flex items-center rounded\"\n >\n <Icon name=\"checkUnderline\" />맞춤법 일괄 교정\n </button>\n\n <component\n v-else\n :is=\"bulkSpellCheckerBtnConfig.component\"\n :buttonName=\"bulkSpellCheckerBtnConfig.props.buttonName\"\n :icon=\"bulkSpellCheckerBtnConfig.props.icon\"\n :type=\"bulkSpellCheckerBtnConfig.props.type\"\n :disabled=\"bulkSpellCheckerBtnConfig.props.disabled\"\n :iconPosition=\"bulkSpellCheckerBtnConfig.props.iconPosition\"\n :buttonSize=\"bulkSpellCheckerBtnConfig.props.buttonSize\"\n :iconClass=\"bulkSpellCheckerBtnConfig.props.iconClass\"\n />\n </DialogTrigger>\n\n <DialogContent is-overlay-transparent class=\"p-0 gap-0 !animate-none !transition-none dark:border-ed-muted\" as-child>\n <div\n class=\"z-[70]\"\n :style=\"{\n transform: `translate(${dragOffset.x}px, ${dragOffset.y}px)`,\n top: `${position.top}px`,\n right: `${position.right}px`,\n left: 'auto',\n }\"\n >\n <DialogHeader\n class=\"bg-ed-blue-light py-3.5 px-6 rounded-t-[5px] cursor-move text-blue-500 dark:text-dark-blue-100 flex-row items-center justify-between\"\n @mousedown.prevent=\"onMouseDown\"\n >\n <DialogTitle class=\"text-base space-x-2\">\n <span>맞춤법/문법 오류</span>\n <Badge class=\"text-sm bg-blue-500 hover:bg-blue-500 dark:bg-dark-blue-100 px-2\">{{ countTotalWrongWords }}개</Badge></DialogTitle\n >\n\n <DialogClose @click=\"isOpenModal = false\" class=\"text-xs flex items-center gap-x-1\">\n <Icon name=\"Close\" class=\"w-4 h-4\" />{{ $t('editor.close') }}\n </DialogClose>\n </DialogHeader>\n\n <DialogDescription></DialogDescription>\n\n <BulkSpellCheckerContent\n :editorsState=\"editorsState\"\n :spellCheckStatus=\"spellCheckStatus\"\n :allWrongWordsMissSuggestions=\"allWrongWordsMissSuggestions\"\n @close-modal=\"isOpenModal = false\"\n @run-spellcheck=\"reRunSpellCheckAndHighlight\"\n @replace-all-editor-errors=\"(replaceAllEditorErrors(), (isOpenModal = false))\"\n />\n </div>\n </DialogContent>\n </Dialog>\n</template>\n\n<style scoped></style>\n"],"names":["ERROR_TYPE","SPELL_CHECK_CODE","SPELL_CHECK_STATUS","EDITOR_NAME","ArrowLeftRight","createLucideIcon","CircleAlert","CircleCheck","expanded","ref","showButton","helpRef","toggle","onMounted","nextTick","HIGHLIGHT_KEY","PluginKey","createHighlightPlugin","editor","errors","blockSeparator","Plugin","state","decos","errorColorMap","item","from","findDocPosFromOffset","to","errorType","_b","_a","className","safeFrom","safeTo","Decoration","DecorationSet","applyHighlights","plugin","clearHighlights","buildPlainIndexToDocPosMap","map","plainIndex","firstBlock","node","pos","i","nodeName","k","offset","mapped","standardMaxHeight","props","__props","getErrorColor","getNoSuggestionText","_d","_c","resetHightlightSection","key","scrollToError","mid","maybeNode","el","replaceWithCorrectWord","replacement","tr","delta","origStart","origEnd","err","idx","contentEl","maxHeight","windowHeight","useWindowSize","computeMaxHeight","gap","rect","availableViewportHeight","useEventListener","_openBlock","_createElementBlock","_hoisted_1","_createVNode","_component_SpinnerIcon","emit","__emit","useBulkSpellCheckerStore","editorsState","reactive","setEditor","editorKey","editorInstance","spellCheckStatus","resetAllEditorWrongWords","editorState","evaluateStatus","hasFail","hasError","handleRunSpellCheck","apiUrl","ext","content","response","axios","error","countTotalWrongWords","computed","sum","wrongWords","watch","newVal","allWrongWordsMissSuggestions","allWrongWords","es","w","applyAllEditorHighlightErrors","_","clearAllEditorHighlightErrors","reRunSpellCheckAndHighlight","isEnableCurrent","disableSpellCheckRealTime","isEnableSpellCheckRealTime","SPELLCHECKER_META_LIST","resetEnableSpellCheckRealTime","replaceAllErrors","getMappedPos","validRepls","r","a","b","lastAppliedFrom","appliedItems","e","replaceAllEditorErrors","isOpenModal","dragOffset","dragging","onMouseDown","onMouseMove","onMouseUp","onUnmounted","triggerRef","position","updatePosition","val","bulkSpellCheckerBtnConfig"],"mappings":"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","x_google_ignoreList":[1,2,3]}
1
+ {"version":3,"file":"BulkSpellChecker-AqPYywBr.mjs","sources":["../src/constants/bulkSpellChecker.ts","../node_modules/lucide-vue-next/dist/esm/icons/arrow-left-right.js","../node_modules/lucide-vue-next/dist/esm/icons/circle-alert.js","../node_modules/lucide-vue-next/dist/esm/icons/circle-check.js","../src/components/BulkSpellCheckerHelpText.vue","../src/utils/bulkSpellchecker.ts","../src/components/BulkSpellCheckerWrongWordList.vue","../src/components/ui/SpinnerIcon.vue","../src/components/BulkSpellCheckerLoading.vue","../src/components/BulkSpellCheckerContent.vue","../src/hooks/useBulkSpellCheckerStore.ts","../src/components/ui/dialog/DialogTrigger.vue","../src/components/BulkSpellChecker.vue"],"sourcesContent":["export const ERROR_TYPE = {\n SPACING: 1,\n SPELLING: 2,\n}\n\nexport const SPELL_CHECK_CODE = {\n NOTHING_TO_CHANGE: 'NOTHING_TO_CHANGE',\n} as const\n\nexport const SPELL_CHECK_STATUS = {\n LOADING: 'loading',\n HAS_ERROR: 'hasError',\n NO_ERROR: 'noError',\n FAIL: 'fail',\n} as const\n\nexport type SpellCheckStatus = (typeof SPELL_CHECK_STATUS)[keyof typeof SPELL_CHECK_STATUS]\n\nexport const EDITOR_NAME = {\n EDITOR_COMMENT: 'editorComment',\n EDITOR_CONTENT: 'editorContent',\n} as const\n\nexport type EditorName = (typeof EDITOR_NAME)[keyof typeof EDITOR_NAME]\n","/**\n * @license lucide-vue-next v0.439.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst ArrowLeftRight = createLucideIcon(\"ArrowLeftRightIcon\", [\n [\"path\", { d: \"M8 3 4 7l4 4\", key: \"9rb6wj\" }],\n [\"path\", { d: \"M4 7h16\", key: \"6tx8e3\" }],\n [\"path\", { d: \"m16 21 4-4-4-4\", key: \"siv7j2\" }],\n [\"path\", { d: \"M20 17H4\", key: \"h6l3hr\" }]\n]);\n\nexport { ArrowLeftRight as default };\n//# sourceMappingURL=arrow-left-right.js.map\n","/**\n * @license lucide-vue-next v0.439.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst CircleAlert = createLucideIcon(\"CircleAlertIcon\", [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"line\", { x1: \"12\", x2: \"12\", y1: \"8\", y2: \"12\", key: \"1pkeuh\" }],\n [\"line\", { x1: \"12\", x2: \"12.01\", y1: \"16\", y2: \"16\", key: \"4dfq90\" }]\n]);\n\nexport { CircleAlert as default };\n//# sourceMappingURL=circle-alert.js.map\n","/**\n * @license lucide-vue-next v0.439.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst CircleCheck = createLucideIcon(\"CircleCheckIcon\", [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"path\", { d: \"m9 12 2 2 4-4\", key: \"dzmm74\" }]\n]);\n\nexport { CircleCheck as default };\n//# sourceMappingURL=circle-check.js.map\n","<script setup lang=\"ts\">\nimport { cn } from '@/utils'\nimport { ChevronDown } from 'lucide-vue-next'\n\ninterface Props {\n text: string\n}\nconst props = defineProps<Props>()\n\nconst expanded = ref(false)\nconst showButton = ref(false)\nconst helpRef = ref<HTMLElement | null>(null)\n\nfunction toggle() {\n expanded.value = !expanded.value\n}\n\nonMounted(async () => {\n await nextTick()\n if (helpRef.value && helpRef.value.scrollHeight > 32) {\n showButton.value = true\n }\n})\n</script>\n\n<template>\n <div class=\"relative\">\n <div\n ref=\"helpRef\"\n class=\"text-gray-700 dark:text-gray-400 transition-all\"\n :class=\"expanded ? 'max-h-none' : 'max-h-[32px] overflow-hidden'\"\n v-html=\"text\"\n ></div>\n\n <div\n v-if=\"showButton\"\n class=\"\"\n :class=\"\n cn(\n 'w-32 flex items-end justify-end bg-gradient-to-l from-white via-white to-transparent dark:from-ed-background dark:via-ed-background',\n expanded ? 'ml-auto opacity-60' : 'absolute bottom-0 right-0'\n )\n \"\n >\n <button class=\"flex items-center gap-1\" @click.stop=\"toggle\">\n <span class=\"border-b border-gray-500\">{{ expanded ? '접기' : '자세히' }}</span>\n <ChevronDown class=\"w-4 h-4 transition-transform\" :class=\"expanded ? 'rotate-180' : ''\" />\n </button>\n </div>\n </div>\n</template>\n","import { ERROR_TYPE } from '@/constants'\nimport { WrongWordItem } from '@/type'\nimport { Editor } from '@tiptap/core'\nimport { Plugin, PluginKey } from 'prosemirror-state'\nimport { Decoration, DecorationSet } from 'prosemirror-view'\n\nconst HIGHLIGHT_KEY = new PluginKey('bulk-spellcheck-highlight')\n\nfunction createHighlightPlugin(editor: Editor, errors: WrongWordItem[], blockSeparator = '\\n') {\n return new Plugin({\n key: HIGHLIGHT_KEY,\n props: {\n decorations(state) {\n const decos: Decoration[] = []\n const errorColorMap = {\n [ERROR_TYPE.SPACING]: 'bulk-highlight text-blue-500 border-b-2 border-blue-500',\n [ERROR_TYPE.SPELLING]: 'bulk-highlight text-red-500 border-b-2 border-red-500',\n }\n\n errors.forEach(item => {\n const from = findDocPosFromOffset(editor, item.startIndex, blockSeparator)\n const to = findDocPosFromOffset(editor, item.endIndex - 1, blockSeparator) + 1\n\n const errorType = item.errorHelpDtos?.[0]?.errorType\n const className = errorColorMap[errorType ?? -1] || 'bulk-highlight text-green-500 border-b-2 border-green-500' // type integrated\n\n const safeFrom = Math.max(0, Math.min(from, state.doc.content.size))\n const safeTo = Math.max(0, Math.min(to, state.doc.content.size))\n if (safeFrom < safeTo) {\n decos.push(Decoration.inline(safeFrom, safeTo, { class: className }))\n }\n })\n\n return DecorationSet.create(state.doc, decos)\n },\n },\n })\n}\n\nexport function applyHighlights(editor: Editor, errors: WrongWordItem[]) {\n editor.unregisterPlugin(HIGHLIGHT_KEY)\n\n if (!errors.length) return\n\n const plugin = createHighlightPlugin(editor, errors)\n editor.registerPlugin(plugin)\n}\n\nexport function clearHighlights(editor: Editor) {\n if (!editor) return\n\n editor.unregisterPlugin(HIGHLIGHT_KEY)\n}\n\nexport function buildPlainIndexToDocPosMap(editor: Editor, blockSeparator = '\\n') {\n const map: (number | null)[] = []\n let plainIndex = 0\n let firstBlock = true\n\n editor.state.doc.descendants((node, pos) => {\n if (node.isText && node.text) {\n for (let i = 0; i < node.text.length; i++) {\n map[plainIndex++] = pos + i\n }\n }\n\n const nodeName = node.type && (node.type as any).name\n const isHardBreak = nodeName === 'hardBreak' || nodeName === 'hard_break' || nodeName === 'br'\n if (isHardBreak && blockSeparator.length > 0) {\n for (let k = 0; k < blockSeparator.length; k++) {\n map[plainIndex++] = pos\n }\n }\n\n if (node.isBlock) {\n if (!firstBlock && blockSeparator.length > 0) {\n for (let k = 0; k < blockSeparator.length; k++) {\n map[plainIndex++] = pos \n }\n }\n firstBlock = false\n }\n\n return true\n })\n\n return map\n}\n\nexport function findDocPosFromOffset(editor: Editor,offset: number, blockSeparator = '\\n') {\n const map = buildPlainIndexToDocPosMap(editor, blockSeparator)\n if (offset < 0) offset = 0\n if (offset >= map.length) {\n return editor.state.doc.content.size\n }\n const mapped = map[offset]\n if (mapped == null) {\n for (let i = offset; i < map.length; i++) if (map[i] != null) return map[i] as number\n for (let i = offset - 1; i >= 0; i--) if (map[i] != null) return map[i] as number\n return editor.state.doc.content.size\n }\n return mapped as number\n}\n","<script setup lang=\"ts\">\nimport { EDITOR_NAME, EditorName, ERROR_TYPE } from '@/constants'\nimport { ArrowLeftRight } from 'lucide-vue-next'\nimport { Editor } from '@tiptap/core'\nimport { EditorsState, WrongWordItem } from '@/type'\nimport { applyHighlights, findDocPosFromOffset } from '@/utils/bulkSpellchecker'\n\ninterface Props {\n editorsState: EditorsState\n}\nconst props = defineProps<Props>()\n\nfunction getErrorColor(errorType?: number) {\n const errorColorMap = {\n [ERROR_TYPE.SPACING]: 'bg-blue-500',\n [ERROR_TYPE.SPELLING]: 'bg-red-500',\n }\n return errorColorMap[errorType ?? -1] || 'bg-green-500' // integrated\n}\n\nfunction getNoSuggestionText(editor: Editor) {\n return editor?.extensionStorage?.spellchecker?.spellchecker?.uiStrings?.uiStrings || 'No suggestions found'\n}\n\nfunction resetHightlightSection(key: EditorName) {\n if (key === EDITOR_NAME.EDITOR_COMMENT) {\n props.editorsState[EDITOR_NAME.EDITOR_CONTENT].editor?.commands.setTextSelection(0)\n return\n }\n\n if (key === EDITOR_NAME.EDITOR_CONTENT) {\n props.editorsState[EDITOR_NAME.EDITOR_COMMENT].editor?.commands.setTextSelection(0)\n return\n }\n}\n\nfunction scrollToError(key: EditorName, editor: Editor, item: WrongWordItem) {\n if (!editor) return\n\n resetHightlightSection(key)\n\n const from = findDocPosFromOffset(editor, item.startIndex)\n const to = findDocPosFromOffset(editor, item.endIndex - 1) + 1\n\n editor.chain().setTextSelection({ from, to }).focus().run()\n\n const mid = Math.max(0, Math.floor((from + to) / 2))\n const domAtPos = editor.view.domAtPos(mid)\n const maybeNode = domAtPos.node as unknown\n\n let el: HTMLElement | null = null\n\n if (maybeNode instanceof Element) {\n el = maybeNode as HTMLElement\n } else if (maybeNode instanceof Text) {\n el = maybeNode.parentElement\n } else {\n el = (maybeNode as any)?.parentElement ?? (editor.view.dom as HTMLElement)\n }\n\n if (el?.scrollIntoView) {\n el.scrollIntoView({ behavior: 'smooth', block: 'center' })\n }\n}\n\nfunction replaceWithCorrectWord(editor: Editor, errors: WrongWordItem[], item: WrongWordItem, replacement: string) {\n if (!editor) return\n\n const from = findDocPosFromOffset(editor, item.startIndex)\n const to = findDocPosFromOffset(editor, item.endIndex - 1) + 1\n\n const tr = editor.state.tr.insertText(replacement, from, to)\n editor.view.dispatch(tr)\n editor.view.focus()\n\n const delta = replacement.length - (item.wrongWord?.length ?? 0)\n const origStart = item.startIndex\n const origEnd = item.endIndex\n\n for (let i = errors.length - 1; i >= 0; i--) {\n const err = errors[i]\n\n if (err.startIndex >= origStart && err.startIndex < origEnd) {\n errors.splice(i, 1)\n continue\n }\n\n if (err.startIndex > origStart) {\n err.startIndex += delta\n err.endIndex += delta\n }\n }\n\n const idx = errors.indexOf(item)\n if (idx !== -1) errors.splice(idx, 1)\n\n applyHighlights(editor, errors)\n}\n\nconst contentEl = ref<HTMLElement | null>(null)\nconst standardMaxHeight = 450\nconst maxHeight = ref(standardMaxHeight)\nconst { height: windowHeight } = useWindowSize()\n\nfunction computeMaxHeight() {\n const el = contentEl.value\n if (!el) return\n\n const gap = 80\n const rect = el.getBoundingClientRect()\n const availableViewportHeight = windowHeight.value - rect.top - gap\n\n maxHeight.value = standardMaxHeight > availableViewportHeight ? availableViewportHeight : standardMaxHeight\n}\n\nonMounted(() => {\n computeMaxHeight()\n useEventListener(window, 'resize', computeMaxHeight)\n})\n</script>\n\n<template>\n <div ref=\"contentEl\" :style=\"{ maxHeight: `${maxHeight}px` }\" class=\"pr-1 overflow-y-auto\">\n <template v-for=\"(editorData, key) in editorsState\" :key=\"key\">\n <div\n v-for=\"(item, idx) in editorData.wrongWords\"\n :key=\"idx\"\n class=\"border-b border-gray-400 dark:border-ed-muted pb-5 mb-5 cursor-pointer\"\n @click=\"scrollToError(key, editorsState[key].editor as Editor, item)\"\n >\n <div class=\"flex items-center mb-2\">\n <span class=\"w-16 font-medium\">입력 내용</span>\n <div class=\"flex items-center gap-2\">\n <span class=\"w-1.5 h-1.5 rounded-full\" :class=\"getErrorColor(item.errorHelpDtos[0]?.errorType)\"></span>\n <span class=\"break-all whitespace-normal\">{{ item.wrongWord }}</span>\n </div>\n </div>\n\n <div class=\"flex items-center mb-2\">\n <span class=\"w-16 font-medium\">대치어</span>\n <div v-if=\"item.correctWord.length\" class=\"flex-1 space-y-1\">\n <div\n v-for=\"(sub, sidx) in item.correctWord\"\n :key=\"sidx\"\n class=\"font-semibold px-3 py-1.5 rounded bg-gray-100 dark:bg-ed-muted flex items-center justify-between\"\n >\n <div class=\"text-sm\">\n {{ sub }}\n </div>\n <button\n class=\"flex items-center gap-1 text-blue-500\"\n @click.stop=\"replaceWithCorrectWord(editorData.editor as Editor, editorData.wrongWords, item, sub)\"\n >\n <ArrowLeftRight class=\"w-4 h-4\" /> <span>바꾸기</span>\n </button>\n </div>\n </div>\n <div v-else>\n {{ getNoSuggestionText(editorData.editor as Editor) }}\n </div>\n </div>\n\n <div class=\"flex\">\n <span class=\"w-16 font-medium\">도움말</span>\n <div class=\"flex-1\">\n <BulkSpellCheckerHelpText :text=\"item.errorHelpDtos[0]?.errorMessage\" />\n </div>\n </div>\n </div>\n </template>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { cn } from '@/utils'\n\ninterface Props {\n fillWhite?: boolean\n class?: string\n}\nconst props = withDefaults(defineProps<Props>(), {\n fillWhite: false,\n class: '',\n})\n</script>\n\n<template>\n <svg :class=\"cn('animate-spin h-5 w-5 mr-0.5', props.class)\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <circle\n v-if=\"fillWhite\"\n class=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n fill=\"#ffffff\"\n stroke=\"currentColor\"\n stroke-width=\"4\"\n ></circle>\n <circle v-else class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\"></circle>\n <path\n class=\"opacity-100\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n ></path>\n </svg>\n</template>\n\n<style scoped></style>\n","<template>\n <div class=\"min-h-[188px] flex flex-col items-center justify-center gap-y-2 text-sm\">\n <SpinnerIcon fill-white class=\"h-10 w-10 text-blue-500\" />\n <div>맞춤법 검사 중입니다</div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { SPELL_CHECK_STATUS, SpellCheckStatus } from '@/constants'\nimport { cn } from '@/utils'\nimport { EditorsState } from '@/type'\n\ninterface Props {\n editorsState: EditorsState,\n spellCheckStatus: SpellCheckStatus\n allWrongWordsMissSuggestions: boolean\n}\nconst props = defineProps<Props>()\n\nconst emit = defineEmits<{\n (e: 'close-modal'): void\n (e: 'run-spellcheck'): void\n (e: 'replace-all-editor-errors'): void\n}>()\n</script>\n\n<template>\n <div class=\"text-xs py-4 px-6\">\n <BulkSpellCheckerLoading v-if=\"spellCheckStatus === SPELL_CHECK_STATUS.LOADING\" />\n <BulkSpellCheckerWrongWordList v-else-if=\"spellCheckStatus === SPELL_CHECK_STATUS.HAS_ERROR\" :editorsState=\"editorsState\" />\n <BulkSpellCheckerNotWrongWord v-else-if=\"spellCheckStatus === SPELL_CHECK_STATUS.NO_ERROR\" />\n <BulkSpellCheckerFail v-else-if=\"spellCheckStatus === SPELL_CHECK_STATUS.FAIL\" />\n\n <div class=\"flex items-center justify-between mt-3\">\n <ul class=\"flex items-cente gap-x-4\">\n <li class=\"flex items-center gap-x-1\"><span class=\"w-1.5 h-1.5 rounded-full bg-red-500\"></span>맞춤법</li>\n <li class=\"flex items-center gap-x-1\"><span class=\"w-1.5 h-1.5 rounded-full bg-blue-500\"></span>띄어쓰기</li>\n <li class=\"flex items-center gap-x-1\"><span class=\"w-1.5 h-1.5 rounded-full bg-green-500\"></span>통합교정</li>\n </ul>\n\n <div class=\"flex gap-x-1\">\n <Button\n variant=\"outline\"\n :class=\"\n cn(\n 'border-blue-500 text-blue-500 text-xs px-3 py-2 h-auto hover:bg-white/80 hover:opacity-80 hover:text-blue-500 dark:text-dark-blue-100 dark:hover:bg-dark-blue-400 dark:hover:text-dark-blue-50 dark:hover:border-dark-blue-100',\n spellCheckStatus === SPELL_CHECK_STATUS.LOADING &&\n 'text-gray-300 bg-gray-100 border-gray-100 pointer-events-none dark:bg-ed-muted/70 dark:border-ed-muted/70 dark:text-gray-500'\n )\n \"\n @click=\"emit('run-spellcheck')\"\n >다시 검사하기</Button\n >\n\n <Button\n :class=\"\n cn(\n 'border-blue-500 text-white text-xs px-3 py-2 h-auto bg-blue-500 hover:bg-blue-500/80',\n (spellCheckStatus !== SPELL_CHECK_STATUS.HAS_ERROR || allWrongWordsMissSuggestions) &&\n 'text-gray-300 bg-gray-100 hover:bg-gray-100 pointer-events-none dark:bg-ed-muted/70 dark:text-gray-500'\n )\n \"\n @click=\"emit('replace-all-editor-errors')\"\n >모두 바꾸기</Button\n >\n </div>\n </div>\n </div>\n</template>\n","import { EDITOR_NAME, EditorName, SPELL_CHECK_CODE, SPELL_CHECK_STATUS, SpellCheckStatus } from '@/constants'\nimport { EditorsState, SpellCheckResponse, WrongWordItem } from '@/type'\nimport { Editor } from '@tiptap/core'\nimport axios from 'axios'\nimport { applyHighlights, clearHighlights, buildPlainIndexToDocPosMap } from '@/utils/bulkSpellchecker'\nimport { SPELLCHECKER_META_LIST } from '@/extensions/SpellChecker/spellchecker-extension'\n\nexport const useBulkSpellCheckerStore = () => {\n const editorsState: EditorsState = reactive({\n [EDITOR_NAME.EDITOR_COMMENT]: {\n editor: null,\n wrongWords: [],\n },\n [EDITOR_NAME.EDITOR_CONTENT]: {\n editor: null,\n wrongWords: [],\n },\n })\n\n function setEditor(editorKey: EditorName, editorInstance: Editor | null) {\n editorsState[editorKey].editor = editorInstance\n }\n\n const spellCheckStatus = ref<SpellCheckStatus>(SPELL_CHECK_STATUS.NO_ERROR)\n\n function resetAllEditorWrongWords() {\n Object.values(editorsState).forEach(editorState => {\n editorState.wrongWords = []\n })\n }\n\n function evaluateStatus(hasFail: boolean, hasError: boolean) {\n if (hasFail) return SPELL_CHECK_STATUS.FAIL\n if (hasError) return SPELL_CHECK_STATUS.HAS_ERROR\n return SPELL_CHECK_STATUS.NO_ERROR\n }\n\n async function handleRunSpellCheck() {\n spellCheckStatus.value = SPELL_CHECK_STATUS.LOADING\n\n let hasError = false\n let hasFail = false\n\n for (const [editorKey, { editor }] of Object.entries(editorsState)) {\n if (!editor) continue\n\n const apiUrl = editor?.extensionManager.extensions.find(ext => ext.name === 'spellchecker')?.options.proofreader\n .api\n const content = editor.getText({ blockSeparator: '\\n' })\n if (!apiUrl || !content) continue\n\n try {\n const { data: response } = await axios.post<SpellCheckResponse>(apiUrl, {\n value: content,\n })\n\n if (!response.success && response.code !== SPELL_CHECK_CODE.NOTHING_TO_CHANGE) {\n hasFail = true\n editorsState[editorKey].wrongWords = []\n continue\n }\n\n if (response.data?.wrongWordResponseDto) {\n hasError = true\n editorsState[editorKey].wrongWords = response.data.wrongWordResponseDto\n continue\n }\n\n editorsState[editorKey].wrongWords = []\n } catch (error) {\n console.error('handleRunSpellCheck error: ', error)\n hasFail = true\n }\n }\n\n spellCheckStatus.value = evaluateStatus(hasFail, hasError)\n }\n\n const countTotalWrongWords = computed(() => {\n return Object.values(editorsState).reduce((sum, { wrongWords }) => {\n return sum + wrongWords.length\n }, 0)\n })\n\n watch(countTotalWrongWords, newVal => {\n if (newVal === 0) {\n spellCheckStatus.value = evaluateStatus(false, false)\n }\n })\n\n const allWrongWordsMissSuggestions = computed(() => {\n const allWrongWords = Object.values(editorsState).flatMap(es => es.wrongWords)\n if (allWrongWords.length === 0) return false\n return allWrongWords.every(w => !Array.isArray(w.correctWord) || w.correctWord.length === 0)\n })\n\n function applyAllEditorHighlightErrors() {\n for (const [_, { editor, wrongWords }] of Object.entries(editorsState)) {\n if (!editor) continue\n applyHighlights(editor as Editor, wrongWords)\n }\n }\n\n function clearAllEditorHighlightErrors() {\n for (const [_, { editor }] of Object.entries(editorsState)) {\n if (!editor) continue\n clearHighlights(editor as Editor)\n }\n }\n\n async function reRunSpellCheckAndHighlight() {\n await handleRunSpellCheck()\n applyAllEditorHighlightErrors()\n }\n\n let isEnableCurrent = true\n function disableSpellCheckRealTime(isEnableSpellCheckRealTime: boolean) {\n isEnableCurrent = isEnableSpellCheckRealTime\n if (!isEnableSpellCheckRealTime) return\n\n for (const [_, { editor }] of Object.entries(editorsState)) {\n if (!editor) continue\n editor.extensionStorage.spellchecker.spellchecker.setEnabledProofreadText(false)\n editor.view.dispatch(editor.state.tr.setMeta(SPELLCHECKER_META_LIST.IS_ACTIVE_SPELLCHECK, false))\n }\n }\n\n function resetEnableSpellCheckRealTime() {\n if (!isEnableCurrent) return\n\n for (const [_, { editor }] of Object.entries(editorsState)) {\n if (!editor) continue\n editor.extensionStorage.spellchecker.spellchecker.setEnabledProofreadText(true)\n editor.view.dispatch(editor.state.tr.setMeta(SPELLCHECKER_META_LIST.IS_ACTIVE_SPELLCHECK, true))\n }\n }\n\n function replaceAllErrors(editor: Editor, errors: WrongWordItem[], blockSeparator = '\\n') {\n if (!editor) return\n if (!errors.length) return\n\n const map = buildPlainIndexToDocPosMap(editor, blockSeparator)\n\n function getMappedPos(offset: number) {\n if (offset < 0) offset = 0\n if (offset >= map.length) return editor.state.doc.content.size\n if (map[offset] != null) return map[offset] as number\n for (let i = offset; i < map.length; i++) if (map[i] != null) return map[i] as number\n for (let i = offset - 1; i >= 0; i--) if (map[i] != null) return map[i] as number\n return editor.state.doc.content.size\n }\n\n const replacements = errors.map(item => {\n const from = getMappedPos(item.startIndex)\n const to = getMappedPos(Math.max(0, item.endIndex - 1)) + 1\n const replacement = item.correctWord?.[0] ?? item.wrongWord\n return { item, from, to, replacement }\n })\n\n const validRepls = replacements.filter(r => typeof r.from === 'number' && typeof r.to === 'number' && r.from < r.to)\n\n if (!validRepls.length) return\n\n validRepls.sort((a, b) => b.from - a.from)\n\n const tr = editor.state.tr\n let lastAppliedFrom = Number.POSITIVE_INFINITY\n const appliedItems = new Set<WrongWordItem>()\n\n for (const r of validRepls) {\n if (r.to > lastAppliedFrom) {\n continue\n }\n\n tr.insertText(r.replacement, r.from, r.to)\n\n appliedItems.add(r.item)\n lastAppliedFrom = r.from\n }\n\n if (appliedItems.size > 0) {\n editor.view.dispatch(tr)\n editor.view.focus()\n }\n\n if (appliedItems.size > 0) {\n errors = errors.filter(e => ![...appliedItems].some(a => a === e))\n }\n\n applyHighlights(editor, errors)\n }\n\n function replaceAllEditorErrors() {\n for (const [_, { editor, wrongWords }] of Object.entries(editorsState)) {\n if (!editor) continue\n replaceAllErrors(editor as Editor, wrongWords)\n }\n }\n\n return {\n editorsState,\n spellCheckStatus,\n countTotalWrongWords,\n allWrongWordsMissSuggestions,\n setEditor,\n resetAllEditorWrongWords,\n disableSpellCheckRealTime,\n resetEnableSpellCheckRealTime,\n applyAllEditorHighlightErrors,\n clearAllEditorHighlightErrors,\n reRunSpellCheckAndHighlight,\n handleRunSpellCheck,\n replaceAllEditorErrors,\n }\n}\n","<script setup lang=\"ts\">\nimport { DialogTrigger, type DialogTriggerProps } from 'radix-vue'\n\nconst props = defineProps<DialogTriggerProps>()\n</script>\n\n<template>\n <DialogTrigger v-bind=\"props\">\n <slot />\n </DialogTrigger>\n</template>\n","<script setup lang=\"ts\">\nimport { EDITOR_NAME } from '@/constants'\nimport { useBulkSpellCheckerStore } from '@/hooks/useBulkSpellCheckerStore'\nimport { Editor } from '@tiptap/core'\nimport { DialogTrigger } from './ui/dialog'\n\ninterface Props {\n editor: Editor\n editorComment?: Editor\n isEnableSpellCheckRealTime: boolean\n}\nconst props = defineProps<Props>()\n\nconst {\n editorsState,\n countTotalWrongWords,\n spellCheckStatus,\n allWrongWordsMissSuggestions,\n setEditor,\n disableSpellCheckRealTime,\n resetEnableSpellCheckRealTime,\n handleRunSpellCheck,\n resetAllEditorWrongWords,\n applyAllEditorHighlightErrors,\n clearAllEditorHighlightErrors,\n reRunSpellCheckAndHighlight,\n replaceAllEditorErrors,\n} = useBulkSpellCheckerStore()\n\nconst isOpenModal = ref(false)\n\nconst dragOffset = reactive({ x: 0, y: 0 })\nconst dragging = ref(false)\nconst offset = { x: 0, y: 0 }\n\nconst onMouseDown = (e: MouseEvent) => {\n dragging.value = true\n offset.x = e.clientX - dragOffset.x\n offset.y = e.clientY - dragOffset.y\n document.addEventListener('mousemove', onMouseMove)\n document.addEventListener('mouseup', onMouseUp)\n}\n\nconst onMouseMove = (e: MouseEvent) => {\n if (!dragging.value) return\n dragOffset.x = e.clientX - offset.x\n dragOffset.y = e.clientY - offset.y\n}\n\nconst onMouseUp = () => {\n dragging.value = false\n document.removeEventListener('mousemove', onMouseMove)\n document.removeEventListener('mouseup', onMouseUp)\n}\n\nonUnmounted(() => {\n document.removeEventListener('mousemove', onMouseMove)\n document.removeEventListener('mouseup', onMouseUp)\n})\n\nconst triggerRef = ref<InstanceType<typeof DialogTrigger> | null>(null)\nconst position = ref({ top: 0, right: 0 })\n\nconst updatePosition = () => {\n if (triggerRef.value) {\n const rect = triggerRef.value.$el.getBoundingClientRect()\n\n position.value = {\n top: rect.bottom + window.scrollY + 5,\n right: window.innerWidth - rect.right - window.scrollX,\n }\n\n dragOffset.x = 0\n dragOffset.y = 0\n }\n}\n\nonMounted(async () => {\n if (props.editorComment) {\n setEditor(EDITOR_NAME.EDITOR_COMMENT, props.editorComment)\n }\n setEditor(EDITOR_NAME.EDITOR_CONTENT, props.editor)\n})\n\nonUnmounted(() => {\n setEditor(EDITOR_NAME.EDITOR_COMMENT, null)\n setEditor(EDITOR_NAME.EDITOR_CONTENT, null)\n})\n\nwatch(isOpenModal, async val => {\n if (val) {\n await nextTick()\n updatePosition()\n disableSpellCheckRealTime(props.isEnableSpellCheckRealTime)\n await handleRunSpellCheck()\n applyAllEditorHighlightErrors()\n } else {\n resetAllEditorWrongWords()\n resetEnableSpellCheckRealTime()\n clearAllEditorHighlightErrors()\n }\n})\n\nconst bulkSpellCheckerBtnConfig = props.editor?.extensionManager.extensions.find(e => e.name === 'spellchecker')\n ?.options.bulkSpellCheckerButton\n</script>\n\n<template>\n <Dialog :open=\"isOpenModal\">\n <DialogTrigger as-child ref=\"triggerRef\" @click=\"isOpenModal = !isOpenModal\">\n <button\n v-if=\"!bulkSpellCheckerBtnConfig\"\n class=\"border-blue-500 text-white text-xs text-nowrap px-3 py-2 h-auto bg-blue-500 hover:bg-blue-500/80 flex items-center rounded\"\n >\n <Icon name=\"checkUnderline\" />맞춤법 일괄 교정\n </button>\n\n <component\n v-else\n :is=\"bulkSpellCheckerBtnConfig.component\"\n :buttonName=\"bulkSpellCheckerBtnConfig.props.buttonName\"\n :icon=\"bulkSpellCheckerBtnConfig.props.icon\"\n :type=\"bulkSpellCheckerBtnConfig.props.type\"\n :disabled=\"bulkSpellCheckerBtnConfig.props.disabled\"\n :iconPosition=\"bulkSpellCheckerBtnConfig.props.iconPosition\"\n :buttonSize=\"bulkSpellCheckerBtnConfig.props.buttonSize\"\n :iconClass=\"bulkSpellCheckerBtnConfig.props.iconClass\"\n />\n </DialogTrigger>\n\n <DialogContent is-overlay-transparent class=\"p-0 gap-0 !animate-none !transition-none dark:border-ed-muted\" as-child>\n <div\n class=\"z-[70]\"\n :style=\"{\n transform: `translate(${dragOffset.x}px, ${dragOffset.y}px)`,\n top: `${position.top}px`,\n right: `${position.right}px`,\n left: 'auto',\n }\"\n >\n <DialogHeader\n class=\"bg-ed-blue-light py-3.5 px-6 rounded-t-[5px] cursor-move text-blue-500 dark:text-dark-blue-100 flex-row items-center justify-between\"\n @mousedown.prevent=\"onMouseDown\"\n >\n <DialogTitle class=\"text-base space-x-2\">\n <span>맞춤법/문법 오류</span>\n <Badge class=\"text-sm bg-blue-500 hover:bg-blue-500 dark:bg-dark-blue-100 px-2\">{{ countTotalWrongWords }}개</Badge></DialogTitle\n >\n\n <DialogClose @click=\"isOpenModal = false\" class=\"text-xs flex items-center gap-x-1\">\n <Icon name=\"Close\" class=\"w-4 h-4\" />{{ $t('editor.close') }}\n </DialogClose>\n </DialogHeader>\n\n <DialogDescription></DialogDescription>\n\n <BulkSpellCheckerContent\n :editorsState=\"editorsState\"\n :spellCheckStatus=\"spellCheckStatus\"\n :allWrongWordsMissSuggestions=\"allWrongWordsMissSuggestions\"\n @close-modal=\"isOpenModal = false\"\n @run-spellcheck=\"reRunSpellCheckAndHighlight\"\n @replace-all-editor-errors=\"(replaceAllEditorErrors(), (isOpenModal = false))\"\n />\n </div>\n </DialogContent>\n </Dialog>\n</template>\n\n<style scoped></style>\n"],"names":["ERROR_TYPE","SPELL_CHECK_CODE","SPELL_CHECK_STATUS","EDITOR_NAME","ArrowLeftRight","createLucideIcon","CircleAlert","CircleCheck","expanded","ref","showButton","helpRef","toggle","onMounted","nextTick","HIGHLIGHT_KEY","PluginKey","createHighlightPlugin","editor","errors","blockSeparator","Plugin","state","decos","errorColorMap","item","from","findDocPosFromOffset","to","errorType","_b","_a","className","safeFrom","safeTo","Decoration","DecorationSet","applyHighlights","plugin","clearHighlights","buildPlainIndexToDocPosMap","map","plainIndex","firstBlock","node","pos","i","nodeName","k","offset","mapped","standardMaxHeight","props","__props","getErrorColor","getNoSuggestionText","_d","_c","resetHightlightSection","key","scrollToError","mid","maybeNode","el","replaceWithCorrectWord","replacement","tr","delta","origStart","origEnd","err","idx","contentEl","maxHeight","windowHeight","useWindowSize","computeMaxHeight","gap","rect","availableViewportHeight","useEventListener","_openBlock","_createElementBlock","_hoisted_1","_createVNode","_component_SpinnerIcon","emit","__emit","useBulkSpellCheckerStore","editorsState","reactive","setEditor","editorKey","editorInstance","spellCheckStatus","resetAllEditorWrongWords","editorState","evaluateStatus","hasFail","hasError","handleRunSpellCheck","apiUrl","ext","content","response","axios","error","countTotalWrongWords","computed","sum","wrongWords","watch","newVal","allWrongWordsMissSuggestions","allWrongWords","es","w","applyAllEditorHighlightErrors","_","clearAllEditorHighlightErrors","reRunSpellCheckAndHighlight","isEnableCurrent","disableSpellCheckRealTime","isEnableSpellCheckRealTime","SPELLCHECKER_META_LIST","resetEnableSpellCheckRealTime","replaceAllErrors","getMappedPos","validRepls","r","a","b","lastAppliedFrom","appliedItems","e","replaceAllEditorErrors","isOpenModal","dragOffset","dragging","onMouseDown","onMouseMove","onMouseUp","onUnmounted","triggerRef","position","updatePosition","val","bulkSpellCheckerBtnConfig"],"mappings":"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","x_google_ignoreList":[1,2,3]}
@@ -31804,7 +31804,7 @@ const iG = { class: "flex gap-2 items-center overflow-x-auto overflow-y-hidden [
31804
31804
  customClassToolbar: {}
31805
31805
  },
31806
31806
  setup(t) {
31807
- const e = dR(() => import("./BulkSpellChecker-B72PQGBe.mjs")), { t: n } = Zt(), o = t, r = Yt("isEditable", H(!0)), i = ["fontSize", "fontFamily", "superText", "spellchecker", "fontSizeIncreaseDecrease"], s = X(() => {
31807
+ const e = dR(() => import("./BulkSpellChecker-AqPYywBr.mjs")), { t: n } = Zt(), o = t, r = Yt("isEditable", H(!0)), i = ["fontSize", "fontFamily", "superText", "spellchecker", "fontSizeIncreaseDecrease"], s = X(() => {
31808
31808
  const f = [...o.editor.extensionManager.extensions].sort((m, b) => m.name === "superText" ? 1 : b.name === "superText" ? -1 : 0);
31809
31809
  let h = [];
31810
31810
  for (const m of f) {
@@ -47954,12 +47954,14 @@ const Loe = ht.create({
47954
47954
  name: "deviceEnv",
47955
47955
  addOptions() {
47956
47956
  return {
47957
- initial: !1
47957
+ initial: !1,
47958
+ specialCharModal: void 0
47958
47959
  };
47959
47960
  },
47960
47961
  addStorage() {
47961
47962
  return {
47962
- isMobile: this.options.initial
47963
+ isMobile: this.options.initial,
47964
+ specialCharModal: this.options.specialCharModal
47963
47965
  };
47964
47966
  },
47965
47967
  addCommands() {
@@ -48782,7 +48784,7 @@ const sre = {
48782
48784
  z2,
48783
48785
  i2,
48784
48786
  Loe,
48785
- Doe,
48787
+ Doe.configure(this.options.deviceEnv),
48786
48788
  // MoreMark,
48787
48789
  H_.configure({ multicolor: !0 })
48788
48790
  );
@@ -54705,61 +54707,60 @@ const sae = { class: "flex flex-1" }, J2 = /* @__PURE__ */ j({
54705
54707
  },
54706
54708
  emits: ["close-long-press-menu"],
54707
54709
  setup(t, { emit: e }) {
54708
- var d;
54709
- const n = t, o = e, { t: r } = Zt(), i = X(() => [...n.editor.extensionManager.extensions].find((h) => h.name === "superText")), s = H(!1), a = (d = n.editor.extensionManager.extensions.find((f) => f.name === "superText")) == null ? void 0 : d.options.specialCharModal, l = (f) => {
54710
- const { state: h } = n.editor, { from: m } = h.selection;
54711
- n.editor.commands.insertContentAt(m, f);
54710
+ const n = t, o = e, { t: r } = Zt(), i = X(() => [...n.editor.extensionManager.extensions].find((f) => f.name === "superText")), s = H(!1), a = X(() => n.editor.storage.deviceEnv.specialCharModal), l = (d) => {
54711
+ const { state: f } = n.editor, { from: h } = f.selection;
54712
+ n.editor.commands.insertContentAt(h, d);
54712
54713
  }, u = () => {
54713
54714
  n.editor.chain().focus().toggleSuperInputMoblie().run(), o("close-long-press-menu");
54714
- const f = $te(n.editor);
54715
- n.editor.commands.setSuperTextContent(f);
54715
+ const d = $te(n.editor);
54716
+ n.editor.commands.setSuperTextContent(d);
54716
54717
  };
54717
- return (f, h) => {
54718
- var m, b, v;
54718
+ return (d, f) => {
54719
+ var h, m, b;
54719
54720
  return O(), ce(nt, null, [
54720
54721
  Q("div", vae, [
54721
- g(i) && !f.disableSuperInput && f.mode !== g(Xe).EDITOR ? (O(), ce("button", {
54722
+ g(i) && !d.disableSuperInput && d.mode !== g(Xe).EDITOR ? (O(), ce("button", {
54722
54723
  key: 0,
54723
54724
  class: "bubble-menu-item",
54724
54725
  onClick: u
54725
54726
  }, Le(g(r)("editor.super")), 1)) : Se("", !0),
54726
54727
  Q("button", {
54727
54728
  class: "bubble-menu-item",
54728
- onClick: h[0] || (h[0] = (w) => s.value = !0)
54729
+ onClick: f[0] || (f[0] = (v) => s.value = !0)
54729
54730
  }, Le(g(r)("editor.insertSpecial")), 1),
54730
- f.hasClipboard ? (O(), ce("button", {
54731
+ d.hasClipboard ? (O(), ce("button", {
54731
54732
  key: 1,
54732
54733
  class: "bubble-menu-item",
54733
- onClick: h[1] || (h[1] = (w) => f.editor.chain().focus().pasteContent().run())
54734
+ onClick: f[1] || (f[1] = (v) => d.editor.chain().focus().pasteContent().run())
54734
54735
  }, Le(g(r)("editor.paste")), 1)) : Se("", !0),
54735
54736
  Q("button", {
54736
54737
  class: "bubble-menu-item",
54737
- onClick: h[2] || (h[2] = (w) => f.editor.chain().focus().cutContent().run())
54738
+ onClick: f[2] || (f[2] = (v) => d.editor.chain().focus().cutContent().run())
54738
54739
  }, Le(g(r)("editor.cut")), 1),
54739
54740
  Q("button", {
54740
54741
  class: "bubble-menu-item",
54741
- onClick: h[3] || (h[3] = () => {
54742
- f.editor.chain().focus().copyContent().setTextSelection(0).blur().run(), o("close-long-press-menu");
54742
+ onClick: f[3] || (f[3] = () => {
54743
+ d.editor.chain().focus().copyContent().setTextSelection(0).blur().run(), o("close-long-press-menu");
54743
54744
  })
54744
54745
  }, Le(g(r)("editor.copy")), 1),
54745
54746
  Q("button", {
54746
54747
  class: "bubble-menu-item",
54747
- onClick: h[4] || (h[4] = (w) => f.editor.chain().focus().selectAll().run())
54748
+ onClick: f[4] || (f[4] = (v) => d.editor.chain().focus().selectAll().run())
54748
54749
  }, Le(g(r)("editor.selectAll")), 1)
54749
54750
  ]),
54750
54751
  (O(), F(td, { to: "body" }, [
54751
- (O(), F(jn((m = g(a)) == null ? void 0 : m.component), {
54752
+ (O(), F(jn((h = g(a)) == null ? void 0 : h.component), {
54752
54753
  "is-open": g(s),
54753
54754
  open: g(s),
54754
- class: ze((v = (b = g(a)) == null ? void 0 : b.componentProps) == null ? void 0 : v.class),
54755
+ class: ze((b = (m = g(a)) == null ? void 0 : m.componentProps) == null ? void 0 : b.class),
54755
54756
  onSelectedChar: l,
54756
- onClose: h[5] || (h[5] = (w) => s.value = !1)
54757
+ onClose: f[5] || (f[5] = (v) => s.value = !1)
54757
54758
  }, null, 40, ["is-open", "open", "class"]))
54758
54759
  ]))
54759
54760
  ], 64);
54760
54761
  };
54761
54762
  }
54762
- }), wae = /* @__PURE__ */ ls(yae, [["__scopeId", "data-v-e8f0c575"]]);
54763
+ }), wae = /* @__PURE__ */ ls(yae, [["__scopeId", "data-v-edf74589"]]);
54763
54764
  class S7 {
54764
54765
  isNativeWebViewAvailable() {
54765
54766
  return window.ReactNativeWebView !== void 0;
@@ -57444,4 +57445,4 @@ export {
57444
57445
  lle as y,
57445
57446
  nle as z
57446
57447
  };
57447
- //# sourceMappingURL=index-DMLnh9u3.mjs.map
57448
+ //# sourceMappingURL=index-BTaZZr4K.mjs.map