Extension for integrating Languagetool with TipTap. You can have your self-hosted instance of LanguageTool, details are here.
Special thanks to https://github.com/rezaffm for sponsoring this project.
language-tool.mp4
Copy the languagetool.ts or languagetool.js file in your project depending on whether you use TypeScript or not. Then import the extension from that file and give it to the TipTap.
import { LanguageTool, Match } from './extensions/languagetool'
const match = ref<Match>(null)
const updateMatch = (editor: Editor) => match.value = editor.extensionStorage.languagetool.match
const replacements = computed(() => match.value?.replacements || [])
const matchMessage = computed(() => match.value?.message || 'No Message')
const updateHtml = () => navigator.clipboard.writeText(editor.value.getHTML())
const acceptSuggestion = (sug) => {
editor.value.commands.insertContent(sug.value)
}
const proofread = () => editor.value.commands.proofread()
const editor = useEditor({
content,
extensions: [StarterKit, LanguageTool.configure({
language: 'auto', // it can detect language automatically or you can write your own language like 'en-US'
apiUrl: YOUR_LANGUAGETOOL_SERVER_URL_HERE + 'check', // For testing purposes, you can use [Public API](https://dev.languagetool.org/public-http-api), but keep an eye on the rules that they've written there
automaticMode: true, // if true, it will start proofreading immediately otherwise only when you execute `proofread` command of the extension.
})],
onUpdate({ editor }) {
setTimeout(() => updateMatch(editor as any))
},
onSelectionUpdate({ editor }) {
setTimeout(() => updateMatch(editor as any))
},
})
Now showing the suggestion on click, so now in the vue component where you've implemented tiptap.
<bubble-menu
class="bubble-menu"
v-if="editor"
:editor="editor"
:tippy-options="{ placement: 'bottom', animation: 'fade' }"
>
<section class="bubble-menu-section-container">
<section class="message-section">
{{ matchMessage }}
</section>
<section class="suggestions-section">
<article
v-for="(replacement, i) in replacements"
@click="() => acceptSuggestion(replacement)"
:key="i + replacement.value"
class="suggestion"
>
{{ replacement.value }}
</article>
</section>
</section>
</bubble-menu>
You can implement your own styles or copy the ones in Tiptap.vue.
npm install
npm run serve
npm run build
npm run lint