Extension for integrating Languagetool with TipTap. You can have your self-hosted instance of LanguageTool, details for that are here.
A ⭐️ to the repo if you 👍 / ❤️ what I'm doing would be much appreciated. If you're using this extension and making money from it, it'd be very kind of you to ❤️ Sponsor me. If you're looking for a dev to work you on your project's Rich Text Editor with or as **a frontend developer, DM me on Discord/Twitter/LinkedIn👨💻🤩.
I've made a bunch of extensions for Tiptap 2, some of them are Google Docs like Commenting, Search and Replace, Resizable Images and Videos with tiptap. You can check it our here https://github.com/sereneinserenade#a-glance-of-my-projects.
Special thanks to @rezaffm for sponsoring this project.
You can try out live-demo with mocked data at https://tiptap-languagetool.vercel.app/ or look at the demo-video below. The code for demo is in mocked-demo
branch.
Demo Video
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.
Project Setup(Stuff that nobody really cares about)
npm install
npm run serve
npm run build
npm run lint