From b07cfcd60d603783a3fd4892fad2b4e3a525049d Mon Sep 17 00:00:00 2001 From: Seviche Date: Wed, 29 Mar 2023 23:27:06 +0800 Subject: [PATCH] Feat: init slash menu --- package.json | 4 + pnpm-lock.yaml | 225 ++++++++++++++----------- src/components/Tiptap/CommandsList.vue | 117 +++++++++++++ src/components/Tiptap/Editor.vue | 5 + src/components/Tiptap/commands.js | 26 +++ src/components/Tiptap/suggestion.js | 111 ++++++++++++ 6 files changed, 394 insertions(+), 94 deletions(-) create mode 100644 src/components/Tiptap/CommandsList.vue create mode 100644 src/components/Tiptap/commands.js create mode 100644 src/components/Tiptap/suggestion.js diff --git a/package.json b/package.json index ceac500..6c60fe4 100644 --- a/package.json +++ b/package.json @@ -14,15 +14,18 @@ "@egoist/tailwindcss-icons": "^1.0.7", "@iconify/json": "^2.2.40", "@prosemirror-adapter/vue": "^0.2.3", + "@tiptap/core": "^2.0.0", "@tiptap/extension-bubble-menu": "2.0.0-beta.220", "@tiptap/extension-character-count": "2.0.0-beta.220", "@tiptap/extension-link": "2.0.0-beta.220", "@tiptap/extension-typography": "2.0.0-beta.220", "@tiptap/pm": "2.0.0-beta.220", "@tiptap/starter-kit": "2.0.0-beta.220", + "@tiptap/suggestion": "^2.0.0", "@tiptap/vue-3": "2.0.0-beta.220", "install": "^0.13.0", "masto": "^5.10.0", + "tippy.js": "^6.3.7", "vue": "^3.2.47" }, "devDependencies": { @@ -36,6 +39,7 @@ "husky": "^8.0.3", "lint-staged": "^13.2.0", "postcss": "^8.4.21", + "sass": "^1.60.0", "tailwindcss": "^3.2.7", "typescript": "^5.0.2", "vite": "^4.2.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e500a2a..0e8d6f5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,33 +10,42 @@ dependencies: '@prosemirror-adapter/vue': specifier: ^0.2.3 version: 0.2.3(vue@3.2.47) + '@tiptap/core': + specifier: ^2.0.0 + version: 2.0.0(@tiptap/pm@2.0.0-beta.220) '@tiptap/extension-bubble-menu': specifier: 2.0.0-beta.220 - version: 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)(@tiptap/pm@2.0.0-beta.220) + version: 2.0.0-beta.220(@tiptap/core@2.0.0)(@tiptap/pm@2.0.0-beta.220) '@tiptap/extension-character-count': specifier: 2.0.0-beta.220 - version: 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)(@tiptap/pm@2.0.0-beta.220) + version: 2.0.0-beta.220(@tiptap/core@2.0.0)(@tiptap/pm@2.0.0-beta.220) '@tiptap/extension-link': specifier: 2.0.0-beta.220 - version: 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)(@tiptap/pm@2.0.0-beta.220) + version: 2.0.0-beta.220(@tiptap/core@2.0.0)(@tiptap/pm@2.0.0-beta.220) '@tiptap/extension-typography': specifier: 2.0.0-beta.220 - version: 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220) + version: 2.0.0-beta.220(@tiptap/core@2.0.0) '@tiptap/pm': specifier: 2.0.0-beta.220 - version: 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220) + version: 2.0.0-beta.220(@tiptap/core@2.0.0) '@tiptap/starter-kit': specifier: 2.0.0-beta.220 version: 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220) + '@tiptap/suggestion': + specifier: ^2.0.0 + version: 2.0.0(@tiptap/core@2.0.0)(@tiptap/pm@2.0.0-beta.220) '@tiptap/vue-3': specifier: 2.0.0-beta.220 - version: 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)(@tiptap/pm@2.0.0-beta.220)(vue@3.2.47) + version: 2.0.0-beta.220(@tiptap/core@2.0.0)(@tiptap/pm@2.0.0-beta.220)(vue@3.2.47) install: specifier: ^0.13.0 version: 0.13.0 masto: specifier: ^5.10.0 version: 5.10.0 + tippy.js: + specifier: ^6.3.7 + version: 6.3.7 vue: specifier: ^3.2.47 version: 3.2.47 @@ -72,6 +81,9 @@ devDependencies: postcss: specifier: ^8.4.21 version: 8.4.21 + sass: + specifier: ^1.60.0 + version: 1.60.0 tailwindcss: specifier: ^3.2.7 version: 3.2.7(postcss@8.4.21) @@ -80,7 +92,7 @@ devDependencies: version: 5.0.2 vite: specifier: ^4.2.1 - version: 4.2.1 + version: 4.2.1(sass@1.60.0) vue-tsc: specifier: ^1.2.0 version: 1.2.0(typescript@5.0.2) @@ -634,226 +646,226 @@ packages: tailwindcss: 3.2.7(postcss@8.4.21) dev: true - /@tiptap/core@2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220): - resolution: {integrity: sha512-F2Q666xJqijBU5o+GqekqseNgIEMTs6BhsLDaf9DwThhljGLS8RXKnSvQxrxLNrYEPpw39n/G3Qt8YAOk5qR6w==} + /@tiptap/core@2.0.0(@tiptap/pm@2.0.0-beta.220): + resolution: {integrity: sha512-bFHsNPcEgiHU+C8r+0qk6SGvfrCas8Djz5yv6bOgnfU/oHYmho7D9Gy0WUlzEnEPi21FU0fQ7V/k/iSroR4lMA==} peerDependencies: - '@tiptap/pm': ^2.0.0-beta.209 + '@tiptap/pm': ^2.0.0 dependencies: - '@tiptap/pm': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220) + '@tiptap/pm': 2.0.0-beta.220(@tiptap/core@2.0.0) dev: false - /@tiptap/extension-blockquote@2.0.0-beta.220(@tiptap/core@2.0.0-beta.220): + /@tiptap/extension-blockquote@2.0.0-beta.220(@tiptap/core@2.0.0): resolution: {integrity: sha512-uE1VRU/doQzXsfsZ/JqsbSbXeZYTJnyQkSfHYA2ZYhbEM2XqDEsYkgcmZEJgunUZJpERf+3ZTfTpqaHq29iMMg==} peerDependencies: '@tiptap/core': ^2.0.0-beta.1 dependencies: - '@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220) + '@tiptap/core': 2.0.0(@tiptap/pm@2.0.0-beta.220) dev: false - /@tiptap/extension-bold@2.0.0-beta.220(@tiptap/core@2.0.0-beta.220): + /@tiptap/extension-bold@2.0.0-beta.220(@tiptap/core@2.0.0): resolution: {integrity: sha512-KcEuKI85Drug/cCWbDy+HxhYrD+rLXHEBG10DmKPvgPpKHG/2wOau6LwUwyV4muWR8CR2mIO+mEc3yVBD8nNwQ==} peerDependencies: '@tiptap/core': ^2.0.0-beta.209 dependencies: - '@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220) + '@tiptap/core': 2.0.0(@tiptap/pm@2.0.0-beta.220) dev: false - /@tiptap/extension-bubble-menu@2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)(@tiptap/pm@2.0.0-beta.220): + /@tiptap/extension-bubble-menu@2.0.0-beta.220(@tiptap/core@2.0.0)(@tiptap/pm@2.0.0-beta.220): resolution: {integrity: sha512-wthyec7s0vZlTSEAAZEgoFfx/1Arwg1zxDUrrE+YAost/Yn+w4xQksz/ts5Bx90iOk2qsJ+jzzttLRV17Ku7lA==} peerDependencies: '@tiptap/core': ^2.0.0-beta.209 '@tiptap/pm': ^2.0.0-beta.209 dependencies: - '@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220) - '@tiptap/pm': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220) + '@tiptap/core': 2.0.0(@tiptap/pm@2.0.0-beta.220) + '@tiptap/pm': 2.0.0-beta.220(@tiptap/core@2.0.0) lodash: 4.17.21 tippy.js: 6.3.7 dev: false - /@tiptap/extension-bullet-list@2.0.0-beta.220(@tiptap/core@2.0.0-beta.220): + /@tiptap/extension-bullet-list@2.0.0-beta.220(@tiptap/core@2.0.0): resolution: {integrity: sha512-QQ/0ZlYy6Hgb+UAc79V+fxvI+AaQf20cbKtBXaR8TIZ0x4FotSma89bKh+CIXMhFiBGXTcYBaYhl7OwACsKtxw==} peerDependencies: '@tiptap/core': ^2.0.0-beta.209 dependencies: - '@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220) + '@tiptap/core': 2.0.0(@tiptap/pm@2.0.0-beta.220) dev: false - /@tiptap/extension-character-count@2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)(@tiptap/pm@2.0.0-beta.220): + /@tiptap/extension-character-count@2.0.0-beta.220(@tiptap/core@2.0.0)(@tiptap/pm@2.0.0-beta.220): resolution: {integrity: sha512-D2AbDi7Q429Ua6U+MdEtxyIEue8KEATOGfmvDlSv5wS+EsUbh6fkG/6yUKFtke2DaePXqbpkxfwXgLT0JP4zTg==} peerDependencies: '@tiptap/core': ^2.0.0-beta.209 '@tiptap/pm': ^2.0.0-beta.209 dependencies: - '@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220) - '@tiptap/pm': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220) + '@tiptap/core': 2.0.0(@tiptap/pm@2.0.0-beta.220) + '@tiptap/pm': 2.0.0-beta.220(@tiptap/core@2.0.0) dev: false - /@tiptap/extension-code-block@2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)(@tiptap/pm@2.0.0-beta.220): + /@tiptap/extension-code-block@2.0.0-beta.220(@tiptap/core@2.0.0)(@tiptap/pm@2.0.0-beta.220): resolution: {integrity: sha512-fgA7yTfHqhBtMJF7I9FPJ6UWuZPtxOQiN45Iv9LNmFIB6YRucdpmF+daZ27sElu0a+eICZyXwVn4w4iJphifuw==} peerDependencies: '@tiptap/core': ^2.0.0-beta.209 '@tiptap/pm': ^2.0.0-beta.209 dependencies: - '@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220) - '@tiptap/pm': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220) + '@tiptap/core': 2.0.0(@tiptap/pm@2.0.0-beta.220) + '@tiptap/pm': 2.0.0-beta.220(@tiptap/core@2.0.0) dev: false - /@tiptap/extension-code@2.0.0-beta.220(@tiptap/core@2.0.0-beta.220): + /@tiptap/extension-code@2.0.0-beta.220(@tiptap/core@2.0.0): resolution: {integrity: sha512-JKKDZoceagqVXeC1XF/gOkKhLtsbYJYV+MRDorLnQVz4tXcg/SMs5Ez7OM9MxSSior8fIbUFMNsj1/UNlG+tFw==} peerDependencies: '@tiptap/core': ^2.0.0-beta.209 dependencies: - '@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220) + '@tiptap/core': 2.0.0(@tiptap/pm@2.0.0-beta.220) dev: false - /@tiptap/extension-document@2.0.0-beta.220(@tiptap/core@2.0.0-beta.220): + /@tiptap/extension-document@2.0.0-beta.220(@tiptap/core@2.0.0): resolution: {integrity: sha512-2sja4ZvOb4iynHrzinnclCSFgLyo6fJc1fBV5fIYaOgZOYcvz9KK8fgKiq+wIpG58sJEmQ5kcwwBlkXv+NTK+g==} peerDependencies: '@tiptap/core': ^2.0.0-beta.209 dependencies: - '@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220) + '@tiptap/core': 2.0.0(@tiptap/pm@2.0.0-beta.220) dev: false - /@tiptap/extension-dropcursor@2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)(@tiptap/pm@2.0.0-beta.220): + /@tiptap/extension-dropcursor@2.0.0-beta.220(@tiptap/core@2.0.0)(@tiptap/pm@2.0.0-beta.220): resolution: {integrity: sha512-BIaA4Lvb3xL9KFN+K6SO2IHqLO6hDmGN2/rGKHFaU3Eh+oiXM2G73KTSS5KIP1u872zY1RpAtswSc4kjv3cuVw==} peerDependencies: '@tiptap/core': ^2.0.0-beta.209 '@tiptap/pm': ^2.0.0-beta.209 dependencies: - '@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220) - '@tiptap/pm': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220) + '@tiptap/core': 2.0.0(@tiptap/pm@2.0.0-beta.220) + '@tiptap/pm': 2.0.0-beta.220(@tiptap/core@2.0.0) dev: false - /@tiptap/extension-floating-menu@2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)(@tiptap/pm@2.0.0-beta.220): + /@tiptap/extension-floating-menu@2.0.0-beta.220(@tiptap/core@2.0.0)(@tiptap/pm@2.0.0-beta.220): resolution: {integrity: sha512-+WfcBEedm82ntaVIEQAGz0Om96Rpav7a+4f7e8N4PrLKm6nZ3gBaEkZVQ6vjJ6S/1htiWCv1XosYIwRboPBG0w==} peerDependencies: '@tiptap/core': ^2.0.0-beta.209 '@tiptap/pm': ^2.0.0-beta.209 dependencies: - '@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220) - '@tiptap/pm': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220) + '@tiptap/core': 2.0.0(@tiptap/pm@2.0.0-beta.220) + '@tiptap/pm': 2.0.0-beta.220(@tiptap/core@2.0.0) tippy.js: 6.3.7 dev: false - /@tiptap/extension-gapcursor@2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)(@tiptap/pm@2.0.0-beta.220): + /@tiptap/extension-gapcursor@2.0.0-beta.220(@tiptap/core@2.0.0)(@tiptap/pm@2.0.0-beta.220): resolution: {integrity: sha512-W5N2Ey+thufUOrs2TFGpEGBGue7ZEhcUXvxcsZlGbrjVa9Y+4rEp68Du4y7yM0hCeSj2GGwiV+uPzkc0CSDE/g==} peerDependencies: '@tiptap/core': ^2.0.0-beta.209 '@tiptap/pm': ^2.0.0-beta.209 dependencies: - '@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220) - '@tiptap/pm': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220) + '@tiptap/core': 2.0.0(@tiptap/pm@2.0.0-beta.220) + '@tiptap/pm': 2.0.0-beta.220(@tiptap/core@2.0.0) dev: false - /@tiptap/extension-hard-break@2.0.0-beta.220(@tiptap/core@2.0.0-beta.220): + /@tiptap/extension-hard-break@2.0.0-beta.220(@tiptap/core@2.0.0): resolution: {integrity: sha512-oY3454o53YNFbuokzyGzG4PdMHkIYreY3nrALioZ0SwYeoFNcGA6Zcn4rDRfdp+QvbbiHfeBTR/CpWF13HZYTg==} peerDependencies: '@tiptap/core': ^2.0.0-beta.209 dependencies: - '@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220) + '@tiptap/core': 2.0.0(@tiptap/pm@2.0.0-beta.220) dev: false - /@tiptap/extension-heading@2.0.0-beta.220(@tiptap/core@2.0.0-beta.220): + /@tiptap/extension-heading@2.0.0-beta.220(@tiptap/core@2.0.0): resolution: {integrity: sha512-7mrHRj++UaZ26C2Gjwb0WKWAzpiKb8TOYkVC2uMaCwaNhLDXpFEwZ7RtJRSTNBHkIGnMO46BH8Z0qlkFMmk9Jw==} peerDependencies: '@tiptap/core': ^2.0.0-beta.209 dependencies: - '@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220) + '@tiptap/core': 2.0.0(@tiptap/pm@2.0.0-beta.220) dev: false - /@tiptap/extension-history@2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)(@tiptap/pm@2.0.0-beta.220): + /@tiptap/extension-history@2.0.0-beta.220(@tiptap/core@2.0.0)(@tiptap/pm@2.0.0-beta.220): resolution: {integrity: sha512-qNL2a9UhnlmCs4y2iQYrfeMB8vEX3bHozBJanHu0PWNQJcj90R5xqorBp/bRcqZdi0kuQfxcTnGHtLUpN/U0TA==} peerDependencies: '@tiptap/core': ^2.0.0-beta.209 '@tiptap/pm': ^2.0.0-beta.209 dependencies: - '@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220) - '@tiptap/pm': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220) + '@tiptap/core': 2.0.0(@tiptap/pm@2.0.0-beta.220) + '@tiptap/pm': 2.0.0-beta.220(@tiptap/core@2.0.0) dev: false - /@tiptap/extension-horizontal-rule@2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)(@tiptap/pm@2.0.0-beta.220): + /@tiptap/extension-horizontal-rule@2.0.0-beta.220(@tiptap/core@2.0.0)(@tiptap/pm@2.0.0-beta.220): resolution: {integrity: sha512-XMIs4R+4BoH5LpIxey513mZuus0XLHqjVayqtf03enmjBTLWzkixvvWLPLw4a47FJL5Q8l4REFHxjNifRzOKkg==} peerDependencies: '@tiptap/core': ^2.0.0-beta.209 '@tiptap/pm': ^2.0.0-beta.209 dependencies: - '@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220) - '@tiptap/pm': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220) + '@tiptap/core': 2.0.0(@tiptap/pm@2.0.0-beta.220) + '@tiptap/pm': 2.0.0-beta.220(@tiptap/core@2.0.0) dev: false - /@tiptap/extension-italic@2.0.0-beta.220(@tiptap/core@2.0.0-beta.220): + /@tiptap/extension-italic@2.0.0-beta.220(@tiptap/core@2.0.0): resolution: {integrity: sha512-aWAgqoR8fql9fJ7T/ZrEqovkEjZXbUpvlvWEvdBDMG3id8ZTGNDpdDKdvI6J/Rl5ZGPIg1TpHJtd+UixheWQsQ==} peerDependencies: '@tiptap/core': ^2.0.0-beta.209 dependencies: - '@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220) + '@tiptap/core': 2.0.0(@tiptap/pm@2.0.0-beta.220) dev: false - /@tiptap/extension-link@2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)(@tiptap/pm@2.0.0-beta.220): + /@tiptap/extension-link@2.0.0-beta.220(@tiptap/core@2.0.0)(@tiptap/pm@2.0.0-beta.220): resolution: {integrity: sha512-vjEA8cE37ZZVVgPHSpttw3kbJoClb+ya/BVukDtJ1h6C7mIR1rqzNxTgpbnXJuA8xww0JOjpa5dpzEgcs294fA==} peerDependencies: '@tiptap/core': ^2.0.0-beta.209 '@tiptap/pm': ^2.0.0-beta.209 dependencies: - '@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220) - '@tiptap/pm': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220) + '@tiptap/core': 2.0.0(@tiptap/pm@2.0.0-beta.220) + '@tiptap/pm': 2.0.0-beta.220(@tiptap/core@2.0.0) linkifyjs: 4.1.1 dev: false - /@tiptap/extension-list-item@2.0.0-beta.220(@tiptap/core@2.0.0-beta.220): + /@tiptap/extension-list-item@2.0.0-beta.220(@tiptap/core@2.0.0): resolution: {integrity: sha512-+O0ivwxPP2l/m9PAowb2ytDT/cM5kwu0s1W5MUsHPIqf+M6ahnl4ESjhWZfDHUzvjqPq6MTbqoQLHbB1KS/N7w==} peerDependencies: '@tiptap/core': ^2.0.0-beta.209 dependencies: - '@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220) + '@tiptap/core': 2.0.0(@tiptap/pm@2.0.0-beta.220) dev: false - /@tiptap/extension-ordered-list@2.0.0-beta.220(@tiptap/core@2.0.0-beta.220): + /@tiptap/extension-ordered-list@2.0.0-beta.220(@tiptap/core@2.0.0): resolution: {integrity: sha512-j3DmxJfwmNxFfMnvO7glmGlhYeZSIUnRrKnZu2KkpD6OcGJSh9y/yfnYwcuK80XbzEG/jKKIw0M2yRveOvyVwA==} peerDependencies: '@tiptap/core': ^2.0.0-beta.209 dependencies: - '@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220) + '@tiptap/core': 2.0.0(@tiptap/pm@2.0.0-beta.220) dev: false - /@tiptap/extension-paragraph@2.0.0-beta.220(@tiptap/core@2.0.0-beta.220): + /@tiptap/extension-paragraph@2.0.0-beta.220(@tiptap/core@2.0.0): resolution: {integrity: sha512-ZGCzNGFYV4wa3l1nXtDIaYp7O6f0DrGTSl3alKkDTQe3SOmzXS2HjgWl9yPw8VXpU9W5mMGhXd+nGn/jUk+f/A==} peerDependencies: '@tiptap/core': ^2.0.0-beta.209 dependencies: - '@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220) + '@tiptap/core': 2.0.0(@tiptap/pm@2.0.0-beta.220) dev: false - /@tiptap/extension-strike@2.0.0-beta.220(@tiptap/core@2.0.0-beta.220): + /@tiptap/extension-strike@2.0.0-beta.220(@tiptap/core@2.0.0): resolution: {integrity: sha512-cIM2ma6mzk08pijOn+KS3ZoHWaUVsVT+OF3m6xewjwJdC0ILg9nApEOhPFrhbeDcxcPmJMlgBl/xeUrEu1HQMg==} peerDependencies: '@tiptap/core': ^2.0.0-beta.209 dependencies: - '@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220) + '@tiptap/core': 2.0.0(@tiptap/pm@2.0.0-beta.220) dev: false - /@tiptap/extension-text@2.0.0-beta.220(@tiptap/core@2.0.0-beta.220): + /@tiptap/extension-text@2.0.0-beta.220(@tiptap/core@2.0.0): resolution: {integrity: sha512-3tnffc2YMjNyv7Lbad6fx9wYDE/Buz8vhx76M2AOSrjYbzmTJf7mLkgdlPM0VTy7FGZD5CGgHJAgYNt5HIqPkQ==} peerDependencies: '@tiptap/core': ^2.0.0-beta.209 dependencies: - '@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220) + '@tiptap/core': 2.0.0(@tiptap/pm@2.0.0-beta.220) dev: false - /@tiptap/extension-typography@2.0.0-beta.220(@tiptap/core@2.0.0-beta.220): + /@tiptap/extension-typography@2.0.0-beta.220(@tiptap/core@2.0.0): resolution: {integrity: sha512-MsQ5WFPUzoC/l8kxnUEYc2dR2eWgve0Ga8+qAJ/s0CLcf7UYGGoFGGobSYwjk++fgNUJMPKEvTpZU2eqjTYAPA==} peerDependencies: '@tiptap/core': ^2.0.0-beta.209 dependencies: - '@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220) + '@tiptap/core': 2.0.0(@tiptap/pm@2.0.0-beta.220) dev: false - /@tiptap/pm@2.0.0-beta.220(@tiptap/core@2.0.0-beta.220): + /@tiptap/pm@2.0.0-beta.220(@tiptap/core@2.0.0): resolution: {integrity: sha512-O9mGcmwUpEr630HY9RylIyZJKnpXi3xWINWNiAEfRJ1br5j5pHRoVRJQ1HzU+6+Z+i/8qp3zRHGLTBqihaZETA==} peerDependencies: '@tiptap/core': ^2.0.0-beta.209 dependencies: - '@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220) + '@tiptap/core': 2.0.0(@tiptap/pm@2.0.0-beta.220) prosemirror-changeset: 2.2.0 prosemirror-collab: 1.3.0 prosemirror-commands: 1.5.1 @@ -877,40 +889,50 @@ packages: /@tiptap/starter-kit@2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220): resolution: {integrity: sha512-3992NxY5sEp5xmLE/qv/yt1YkgpSpJiUlDRj02isJ0Xsxa4G6bNq+N+tN2rHB0Y8dtYVBSX2vV/DZYVX8O+Gpg==} dependencies: - '@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220) - '@tiptap/extension-blockquote': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220) - '@tiptap/extension-bold': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220) - '@tiptap/extension-bullet-list': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220) - '@tiptap/extension-code': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220) - '@tiptap/extension-code-block': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)(@tiptap/pm@2.0.0-beta.220) - '@tiptap/extension-document': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220) - '@tiptap/extension-dropcursor': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)(@tiptap/pm@2.0.0-beta.220) - '@tiptap/extension-gapcursor': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)(@tiptap/pm@2.0.0-beta.220) - '@tiptap/extension-hard-break': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220) - '@tiptap/extension-heading': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220) - '@tiptap/extension-history': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)(@tiptap/pm@2.0.0-beta.220) - '@tiptap/extension-horizontal-rule': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)(@tiptap/pm@2.0.0-beta.220) - '@tiptap/extension-italic': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220) - '@tiptap/extension-list-item': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220) - '@tiptap/extension-ordered-list': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220) - '@tiptap/extension-paragraph': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220) - '@tiptap/extension-strike': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220) - '@tiptap/extension-text': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220) + '@tiptap/core': 2.0.0(@tiptap/pm@2.0.0-beta.220) + '@tiptap/extension-blockquote': 2.0.0-beta.220(@tiptap/core@2.0.0) + '@tiptap/extension-bold': 2.0.0-beta.220(@tiptap/core@2.0.0) + '@tiptap/extension-bullet-list': 2.0.0-beta.220(@tiptap/core@2.0.0) + '@tiptap/extension-code': 2.0.0-beta.220(@tiptap/core@2.0.0) + '@tiptap/extension-code-block': 2.0.0-beta.220(@tiptap/core@2.0.0)(@tiptap/pm@2.0.0-beta.220) + '@tiptap/extension-document': 2.0.0-beta.220(@tiptap/core@2.0.0) + '@tiptap/extension-dropcursor': 2.0.0-beta.220(@tiptap/core@2.0.0)(@tiptap/pm@2.0.0-beta.220) + '@tiptap/extension-gapcursor': 2.0.0-beta.220(@tiptap/core@2.0.0)(@tiptap/pm@2.0.0-beta.220) + '@tiptap/extension-hard-break': 2.0.0-beta.220(@tiptap/core@2.0.0) + '@tiptap/extension-heading': 2.0.0-beta.220(@tiptap/core@2.0.0) + '@tiptap/extension-history': 2.0.0-beta.220(@tiptap/core@2.0.0)(@tiptap/pm@2.0.0-beta.220) + '@tiptap/extension-horizontal-rule': 2.0.0-beta.220(@tiptap/core@2.0.0)(@tiptap/pm@2.0.0-beta.220) + '@tiptap/extension-italic': 2.0.0-beta.220(@tiptap/core@2.0.0) + '@tiptap/extension-list-item': 2.0.0-beta.220(@tiptap/core@2.0.0) + '@tiptap/extension-ordered-list': 2.0.0-beta.220(@tiptap/core@2.0.0) + '@tiptap/extension-paragraph': 2.0.0-beta.220(@tiptap/core@2.0.0) + '@tiptap/extension-strike': 2.0.0-beta.220(@tiptap/core@2.0.0) + '@tiptap/extension-text': 2.0.0-beta.220(@tiptap/core@2.0.0) transitivePeerDependencies: - '@tiptap/pm' dev: false - /@tiptap/vue-3@2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)(@tiptap/pm@2.0.0-beta.220)(vue@3.2.47): + /@tiptap/suggestion@2.0.0(@tiptap/core@2.0.0)(@tiptap/pm@2.0.0-beta.220): + resolution: {integrity: sha512-U4POIQXKOJu/1a81W2A0COVx0ncAh9VxyMx3DkSZd/gPxjXbWIq1EKcb+TJOo+317fA9WVtWYKRCkFRMv5f24g==} + peerDependencies: + '@tiptap/core': ^2.0.0 + '@tiptap/pm': ^2.0.0 + dependencies: + '@tiptap/core': 2.0.0(@tiptap/pm@2.0.0-beta.220) + '@tiptap/pm': 2.0.0-beta.220(@tiptap/core@2.0.0) + dev: false + + /@tiptap/vue-3@2.0.0-beta.220(@tiptap/core@2.0.0)(@tiptap/pm@2.0.0-beta.220)(vue@3.2.47): resolution: {integrity: sha512-rhSKUECLE6NOjTYZHheXAGpyIqruhxkU/9YfWNLWNFIHHW9wHO+t/B3XMJAWBwgkUvRRepU5JmBBIfYd8RgqTA==} peerDependencies: '@tiptap/core': ^2.0.0-beta.209 '@tiptap/pm': ^2.0.0-beta.209 vue: ^3.0.0 dependencies: - '@tiptap/core': 2.0.0-beta.220(@tiptap/pm@2.0.0-beta.220) - '@tiptap/extension-bubble-menu': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)(@tiptap/pm@2.0.0-beta.220) - '@tiptap/extension-floating-menu': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220)(@tiptap/pm@2.0.0-beta.220) - '@tiptap/pm': 2.0.0-beta.220(@tiptap/core@2.0.0-beta.220) + '@tiptap/core': 2.0.0(@tiptap/pm@2.0.0-beta.220) + '@tiptap/extension-bubble-menu': 2.0.0-beta.220(@tiptap/core@2.0.0)(@tiptap/pm@2.0.0-beta.220) + '@tiptap/extension-floating-menu': 2.0.0-beta.220(@tiptap/core@2.0.0)(@tiptap/pm@2.0.0-beta.220) + '@tiptap/pm': 2.0.0-beta.220(@tiptap/core@2.0.0) vue: 3.2.47 dev: false @@ -1100,7 +1122,7 @@ packages: vite: ^4.0.0 vue: ^3.2.25 dependencies: - vite: 4.2.1 + vite: 4.2.1(sass@1.60.0) vue: 3.2.47 dev: true @@ -2685,6 +2707,10 @@ packages: engines: {node: '>= 4'} dev: true + /immutable@4.3.0: + resolution: {integrity: sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==} + dev: true + /import-fresh@3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} engines: {node: '>=6'} @@ -3912,6 +3938,16 @@ packages: regexp-tree: 0.1.24 dev: true + /sass@1.60.0: + resolution: {integrity: sha512-updbwW6fNb5gGm8qMXzVO7V4sWf7LMXnMly/JEyfbfERbVH46Fn6q02BX7/eHTdKpE7d+oTkMMQpFWNUMfFbgQ==} + engines: {node: '>=12.0.0'} + hasBin: true + dependencies: + chokidar: 3.5.3 + immutable: 4.3.0 + source-map-js: 1.0.2 + dev: true + /semver@5.7.1: resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} hasBin: true @@ -4328,7 +4364,7 @@ packages: spdx-expression-parse: 3.0.1 dev: true - /vite@4.2.1: + /vite@4.2.1(sass@1.60.0): resolution: {integrity: sha512-7MKhqdy0ISo4wnvwtqZkjke6XN4taqQ2TBaTccLIpOKv7Vp2h4Y+NpmWCnGDeSvvn45KxvWgGyb0MkHvY1vgbg==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true @@ -4357,6 +4393,7 @@ packages: postcss: 8.4.21 resolve: 1.22.1 rollup: 3.20.2 + sass: 1.60.0 optionalDependencies: fsevents: 2.3.2 dev: true diff --git a/src/components/Tiptap/CommandsList.vue b/src/components/Tiptap/CommandsList.vue new file mode 100644 index 0000000..f0df2ca --- /dev/null +++ b/src/components/Tiptap/CommandsList.vue @@ -0,0 +1,117 @@ + + + + + diff --git a/src/components/Tiptap/Editor.vue b/src/components/Tiptap/Editor.vue index d45cb7a..b75135f 100644 --- a/src/components/Tiptap/Editor.vue +++ b/src/components/Tiptap/Editor.vue @@ -4,6 +4,8 @@ import StarterKit from '@tiptap/starter-kit' import Typography from '@tiptap/extension-typography' import Link from '@tiptap/extension-link' import BubbleMenu from './BubbleMenu.vue' +import Commands from './commands' +import suggestion from './suggestion' const editor = useEditor({ content: `

@@ -18,6 +20,9 @@ const editor = useEditor({ Link.configure({ openOnClick: false, }), + Commands.configure({ + suggestion, + }), ], editable: true, autofocus: true, diff --git a/src/components/Tiptap/commands.js b/src/components/Tiptap/commands.js new file mode 100644 index 0000000..ea3f57f --- /dev/null +++ b/src/components/Tiptap/commands.js @@ -0,0 +1,26 @@ +import { Extension } from '@tiptap/core' +import Suggestion from '@tiptap/suggestion' + +export default Extension.create({ + name: 'commands', + + addOptions() { + return { + suggestion: { + char: '/', + command: ({ editor, range, props }) => { + props.command({ editor, range }) + }, + }, + } + }, + + addProseMirrorPlugins() { + return [ + Suggestion({ + editor: this.editor, + ...this.options.suggestion, + }), + ] + }, +}) diff --git a/src/components/Tiptap/suggestion.js b/src/components/Tiptap/suggestion.js new file mode 100644 index 0000000..dd59062 --- /dev/null +++ b/src/components/Tiptap/suggestion.js @@ -0,0 +1,111 @@ +import { VueRenderer } from '@tiptap/vue-3' +import tippy from 'tippy.js' + +import CommandsList from './CommandsList.vue' + +export default { + items: ({ query }) => { + return [ + { + title: 'H1', + command: ({ editor, range }) => { + editor + .chain() + .focus() + .deleteRange(range) + .setNode('heading', { level: 1 }) + .run() + }, + }, + { + title: 'H2', + command: ({ editor, range }) => { + editor + .chain() + .focus() + .deleteRange(range) + .setNode('heading', { level: 2 }) + .run() + }, + }, + { + title: 'bold', + command: ({ editor, range }) => { + editor + .chain() + .focus() + .deleteRange(range) + .setMark('bold') + .run() + }, + }, + { + title: 'italic', + command: ({ editor, range }) => { + editor + .chain() + .focus() + .deleteRange(range) + .setMark('italic') + .run() + }, + }, + ].filter(item => item.title.toLowerCase().startsWith(query.toLowerCase())).slice(0, 10) + }, + + render: () => { + let component + let popup + + return { + onStart: (props) => { + component = new VueRenderer(CommandsList, { + // using vue 2: + // parent: this, + // propsData: props, + props, + editor: props.editor, + }) + + if (!props.clientRect) + return + + popup = tippy('body', { + getReferenceClientRect: props.clientRect, + appendTo: () => document.body, + content: component.element, + showOnCreate: true, + interactive: true, + trigger: 'manual', + placement: 'bottom-start', + }) + }, + + onUpdate(props) { + component.updateProps(props) + + if (!props.clientRect) + return + + popup[0].setProps({ + getReferenceClientRect: props.clientRect, + }) + }, + + onKeyDown(props) { + if (props.event.key === 'Escape') { + popup[0].hide() + + return true + } + + return component.ref?.onKeyDown(props) + }, + + onExit() { + popup[0].destroy() + component.destroy() + }, + } + }, +}