Add new component for html editing

This commit is contained in:
Ramon Wenger 2022-02-24 16:49:39 +01:00
parent b5ffb3ee29
commit 031e4d58de
5 changed files with 412 additions and 48 deletions

234
client/package-lock.json generated
View File

@ -2398,6 +2398,11 @@
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz",
"integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g=="
},
"@popperjs/core": {
"version": "2.11.2",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.2.tgz",
"integrity": "sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA=="
},
"@sindresorhus/is": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz",
@ -2413,6 +2418,82 @@
"defer-to-connect": "^1.0.1"
}
},
"@tiptap/core": {
"version": "2.0.0-beta.174",
"resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.0.0-beta.174.tgz",
"integrity": "sha512-APQDto40PdvagG1HTwkKlieQS4Vp6GXNe7qgV1Qo2QCgJCLyxc/fXCTghtrOx0CQb+9JT7fjSLZxbSyUFXjx7Q==",
"requires": {
"@types/prosemirror-commands": "^1.0.4",
"@types/prosemirror-keymap": "^1.0.4",
"@types/prosemirror-model": "^1.16.0",
"@types/prosemirror-schema-list": "^1.0.3",
"@types/prosemirror-state": "^1.2.8",
"@types/prosemirror-transform": "^1.1.5",
"@types/prosemirror-view": "^1.23.1",
"prosemirror-commands": "^1.2.1",
"prosemirror-keymap": "^1.1.5",
"prosemirror-model": "^1.16.1",
"prosemirror-schema-list": "^1.1.6",
"prosemirror-state": "^1.3.4",
"prosemirror-transform": "^1.3.3",
"prosemirror-view": "^1.23.6"
}
},
"@tiptap/extension-bubble-menu": {
"version": "2.0.0-beta.55",
"resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.0.0-beta.55.tgz",
"integrity": "sha512-v32/QnwwRbepdbrho8mTYru1/XNW/rJi3Mjrgo3rrIs67R86aEPmhmdzD3QEQUJhAJkduuwdw8zElmVWqIJQ9w==",
"requires": {
"prosemirror-state": "^1.3.4",
"prosemirror-view": "^1.23.6",
"tippy.js": "^6.3.7"
}
},
"@tiptap/extension-bullet-list": {
"version": "2.0.0-beta.26",
"resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-2.0.0-beta.26.tgz",
"integrity": "sha512-1n5HV8gY1tLjPk4x48nva6SZlFHoPlRfF6pqSu9JcJxPO7FUSPxUokuz4swYNe0LRrtykfyNz44dUcxKVhoFow=="
},
"@tiptap/extension-document": {
"version": "2.0.0-beta.15",
"resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-2.0.0-beta.15.tgz",
"integrity": "sha512-ypENC+xUYD5m2t+KOKNYqyXnanXd5fxyIyhR1qeEEwwQwMXGNrO3kCH6O4mIDCpy+/WqHvVay2tV5dVsXnvY8w=="
},
"@tiptap/extension-floating-menu": {
"version": "2.0.0-beta.50",
"resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-2.0.0-beta.50.tgz",
"integrity": "sha512-aQu1HtthMIYEPylr6kzioLxMiObLbcgwx9xZzF03KwNnkjQLbjZOeJX2RwSYVpiVgtfPBGOm3N/br6NSYec4yQ==",
"requires": {
"prosemirror-state": "^1.3.4",
"prosemirror-view": "^1.23.6",
"tippy.js": "^6.3.7"
}
},
"@tiptap/extension-list-item": {
"version": "2.0.0-beta.20",
"resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-2.0.0-beta.20.tgz",
"integrity": "sha512-5IPEspJt38t9ROj4xLUesOVEYlTT/R9Skd9meHRxJQZX1qrzBICs5PC/WRIsnexrvTBhdxpYgCYjpvpsJBlKuQ=="
},
"@tiptap/extension-paragraph": {
"version": "2.0.0-beta.23",
"resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-2.0.0-beta.23.tgz",
"integrity": "sha512-VWAxyzecErYWk97Kv/Gkghh97zAQTcaVOisEnYYArZAlyYDaYM48qVssAC/vnRRynP2eQxb1EkppbAxE+bMHAA=="
},
"@tiptap/extension-text": {
"version": "2.0.0-beta.15",
"resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-2.0.0-beta.15.tgz",
"integrity": "sha512-S3j2+HyV2gsXZP8Wg/HA+YVXQsZ3nrXgBM9HmGAxB0ESOO50l7LWfip0f3qcw1oRlh5H3iLPkA6/f7clD2/TFA=="
},
"@tiptap/vue-2": {
"version": "2.0.0-beta.77",
"resolved": "https://registry.npmjs.org/@tiptap/vue-2/-/vue-2-2.0.0-beta.77.tgz",
"integrity": "sha512-/wMi7fkqLqfWGhOpcztiGgVyqiCmOPq7TZ2LFx+cokoMJ1HpM8T7vG12u6ezOubB5Ie7/kL6WBcLJ8hONTdX0Q==",
"requires": {
"@tiptap/extension-bubble-menu": "^2.0.0-beta.55",
"@tiptap/extension-floating-menu": "^2.0.0-beta.50",
"prosemirror-view": "^1.23.6"
}
},
"@trysound/sax": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
@ -2611,12 +2692,84 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.12.tgz",
"integrity": "sha512-4YpbAsnJXWYK/fpTVFlMIcUIho2AYCi4wg5aNPrG1ng7fn/1/RZfCIpRCiBX+12RVa34RluilnvCqD+g3KiSiA=="
},
"@types/orderedmap": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@types/orderedmap/-/orderedmap-1.0.0.tgz",
"integrity": "sha512-dxKo80TqYx3YtBipHwA/SdFmMMyLCnP+5mkEqN0eMjcTBzHkiiX0ES118DsjDBjvD+zeSsSU9jULTZ+frog+Gw=="
},
"@types/parse-json": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
"integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
"dev": true
},
"@types/prosemirror-commands": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@types/prosemirror-commands/-/prosemirror-commands-1.0.4.tgz",
"integrity": "sha512-utDNYB3EXLjAfYIcRWJe6pn3kcQ5kG4RijbT/0Y/TFOm6yhvYS/D9eJVnijdg9LDjykapcezchxGRqFD5LcyaQ==",
"requires": {
"@types/prosemirror-model": "*",
"@types/prosemirror-state": "*",
"@types/prosemirror-view": "*"
}
},
"@types/prosemirror-keymap": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@types/prosemirror-keymap/-/prosemirror-keymap-1.0.4.tgz",
"integrity": "sha512-ycevwkqUh+jEQtPwqO7sWGcm+Sybmhu8MpBsM8DlO3+YTKnXbKA6SDz/+q14q1wK3UA8lHJyfR+v+GPxfUSemg==",
"requires": {
"@types/prosemirror-commands": "*",
"@types/prosemirror-model": "*",
"@types/prosemirror-state": "*",
"@types/prosemirror-view": "*"
}
},
"@types/prosemirror-model": {
"version": "1.16.1",
"resolved": "https://registry.npmjs.org/@types/prosemirror-model/-/prosemirror-model-1.16.1.tgz",
"integrity": "sha512-SrrCe2cHlYrQ9o55e2i/c3wt1yRajTTpRLvzfmB+2DWjWEbBLTByVWyjrdpKtQTxAaTeU2aeDGo1iuwl/jF27w==",
"requires": {
"@types/orderedmap": "*"
}
},
"@types/prosemirror-schema-list": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@types/prosemirror-schema-list/-/prosemirror-schema-list-1.0.3.tgz",
"integrity": "sha512-uWybOf+M2Ea7rlbs0yLsS4YJYNGXYtn4N+w8HCw3Vvfl6wBAROzlMt0gV/D/VW/7J/LlAjwMezuGe8xi24HzXA==",
"requires": {
"@types/orderedmap": "*",
"@types/prosemirror-model": "*",
"@types/prosemirror-state": "*"
}
},
"@types/prosemirror-state": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/@types/prosemirror-state/-/prosemirror-state-1.2.8.tgz",
"integrity": "sha512-mq9uyQWcpu8jeamO6Callrdvf/e1H/aRLR2kZWSpZrPHctEsxWHBbluD/wqVjXBRIOoMHLf6ZvOkrkmGLoCHVA==",
"requires": {
"@types/prosemirror-model": "*",
"@types/prosemirror-transform": "*",
"@types/prosemirror-view": "*"
}
},
"@types/prosemirror-transform": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/@types/prosemirror-transform/-/prosemirror-transform-1.1.5.tgz",
"integrity": "sha512-Wr2HXaEF4JPklWpC17RTxE6PxyU54Taqk5FMhK1ojgcN93J+GpkYW8s0mD3rl7KfTmlhVwZPCHE9o0cYf2Go5A==",
"requires": {
"@types/prosemirror-model": "*"
}
},
"@types/prosemirror-view": {
"version": "1.23.1",
"resolved": "https://registry.npmjs.org/@types/prosemirror-view/-/prosemirror-view-1.23.1.tgz",
"integrity": "sha512-6e1B2oKUnhmZPUrsVvYjDqeVjE6jGezygjtoHsAK4ZENAxHzHqy5NT4jUvdPTWjCYeH0t2Y7pSfRPNrPIyQX4A==",
"requires": {
"@types/prosemirror-model": "*",
"@types/prosemirror-state": "*",
"@types/prosemirror-transform": "*"
}
},
"@types/qs": {
"version": "6.9.7",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
@ -14396,6 +14549,11 @@
"log-symbols": "^2.1.0"
}
},
"orderedmap": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-1.1.5.tgz",
"integrity": "sha512-/fzlCGKRmfayGoI9UUXvJfc2nMZlJHW30QqEvwPvlg8tsX7jyiUSomYie6mYqx7Z9bOMGoag0H/q1PS/0PjYkg=="
},
"original": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz",
@ -16602,6 +16760,69 @@
"react-is": "^16.13.1"
}
},
"prosemirror-commands": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.2.1.tgz",
"integrity": "sha512-S/IkpXfpuLFsRynC2HQ5iYROUPiZskKS1+ClcWycGJvj4HMb/mVfeEkQrixYxgTl96EAh+RZQNWPC06GZXk5tQ==",
"requires": {
"prosemirror-model": "^1.0.0",
"prosemirror-state": "^1.0.0",
"prosemirror-transform": "^1.0.0"
}
},
"prosemirror-keymap": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.1.5.tgz",
"integrity": "sha512-8SZgPH3K+GLsHL2wKuwBD9rxhsbnVBTwpHCO4VUO5GmqUQlxd/2GtBVWTsyLq4Dp3N9nGgPd3+lZFKUDuVp+Vw==",
"requires": {
"prosemirror-state": "^1.0.0",
"w3c-keyname": "^2.2.0"
}
},
"prosemirror-model": {
"version": "1.16.1",
"resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.16.1.tgz",
"integrity": "sha512-r1/w0HDU40TtkXp0DyKBnFPYwd8FSlUSJmGCGFv4DeynfeSlyQF2FD0RQbVEMOe6P3PpUSXM6LZBV7W/YNZ4mA==",
"requires": {
"orderedmap": "^1.1.0"
}
},
"prosemirror-schema-list": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.1.6.tgz",
"integrity": "sha512-aFGEdaCWmJzouZ8DwedmvSsL50JpRkqhQ6tcpThwJONVVmCgI36LJHtoQ4VGZbusMavaBhXXr33zyD2IVsTlkw==",
"requires": {
"prosemirror-model": "^1.0.0",
"prosemirror-transform": "^1.0.0"
}
},
"prosemirror-state": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.3.4.tgz",
"integrity": "sha512-Xkkrpd1y/TQ6HKzN3agsQIGRcLckUMA9u3j207L04mt8ToRgpGeyhbVv0HI7omDORIBHjR29b7AwlATFFf2GLA==",
"requires": {
"prosemirror-model": "^1.0.0",
"prosemirror-transform": "^1.0.0"
}
},
"prosemirror-transform": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.3.4.tgz",
"integrity": "sha512-gTsg3UIeaFuEY6+YmNPMgTpEkCKPedkFIUnsPpOMbclU701fEVI/e4VOXACXh3BO5rZJaBbEBwrnzB0mLp6eBA==",
"requires": {
"prosemirror-model": "^1.0.0"
}
},
"prosemirror-view": {
"version": "1.23.6",
"resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.23.6.tgz",
"integrity": "sha512-B4DAzriNpI/AVoW0Lu6SVfX00jZZQxOVwdBQEjWlRbCdT9V0pvk4GQJ3JTFaib+b6BcPdRZ3MjWXz2xvV1rblA==",
"requires": {
"prosemirror-model": "^1.16.0",
"prosemirror-state": "^1.0.0",
"prosemirror-transform": "^1.1.0"
}
},
"proto-list": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
@ -19030,6 +19251,14 @@
"resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz",
"integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q="
},
"tippy.js": {
"version": "6.3.7",
"resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz",
"integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==",
"requires": {
"@popperjs/core": "^2.9.0"
}
},
"tmp": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
@ -20232,6 +20461,11 @@
"browser-process-hrtime": "^1.0.0"
}
},
"w3c-keyname": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.4.tgz",
"integrity": "sha512-tOhfEwEzFLJzf6d1ZPkYfGj+FWhIpBux9ppoP3rlclw3Z0BZv3N7b7030Z1kYth+6rDuAsXUFr+d0VE6Ed1ikw=="
},
"walker": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz",

View File

@ -34,6 +34,13 @@
"@babel/preset-stage-2": "^7.0.0",
"@babel/runtime": "^7.5.4",
"@iam4x/cypress-graphql-mock": "0.0.1",
"@tiptap/core": "^2.0.0-beta.174",
"@tiptap/extension-bullet-list": "^2.0.0-beta.26",
"@tiptap/extension-document": "^2.0.0-beta.15",
"@tiptap/extension-list-item": "^2.0.0-beta.20",
"@tiptap/extension-paragraph": "^2.0.0-beta.23",
"@tiptap/extension-text": "^2.0.0-beta.15",
"@tiptap/vue-2": "^2.0.0-beta.77",
"@vue/composition-api": "^1.4.2",
"appolo": "^6.0.19",
"autoprefixer": "^7.1.2",

View File

@ -1,32 +1,15 @@
<template>
<!-- eslint-disable vue/no-v-html -->
<div class="text-form">
{{ isListLocal }}
<toggle
:checked="isListLocal"
:checked="isList"
label="Liste"
@input="isListLocal=$event"
/>
<button
class="button"
@click="makeList"
>
Test
</button>
<div
class="text-form__input skillbox-textarea"
contenteditable="true"
v-once
@input="change"
v-text="text"
@input="toggleList"
/>
<div
contenteditable="true"
class="text-form__input skillbox-textarea text-form__contenteditable"
@input="changeSomeText"
@blur="updateSomeText"
v-html="localOnlyText"
<tip-tap
:value="value.text"
@input="$emit('change-text', $event)"
/>
</div>
</template>
@ -34,6 +17,7 @@
<script lang="ts">
import Vue, {PropType} from "vue";
import Toggle from "@/components/ui/Toggle.vue";
import TipTap from "@/components/content-forms/TipTap.vue";
interface Value {
text: string;
@ -44,11 +28,20 @@
textToStoreWhileFocused: string,
textBuffer: string, // text that gets saved, but not updated, when the user is typing
htmlBuffer: string, // same as above, but this is the html that's generated
isListLocal: boolean,
isList: boolean,
// listHTML: string
}
const re = /<ul(\/)?>/;
const ul = /<\/?ul>/;
const li = /<\/?li>/;
const br = /<br(\/)?>/;
const div = /(<\/?)div(>)/g;
const anythingElse = /<(?!\/?(?:ul|li|p))\/?([^>]*)>/;
// the non-breaking space is used so the cursor is positioned inside the element by default. We remove it later
const nonBreakingSpace = '&nbsp;';
const emptyParagraph = `<p>${nonBreakingSpace}</p>`;
const emptyList = `<ul><li>${nonBreakingSpace}</li></ul>`;
export default Vue.extend({
props: {
@ -58,12 +51,8 @@
return Object.prototype.hasOwnProperty.call(value, 'text');
},
},
asList: {
type: Boolean,
default: false
}
},
components: {Toggle},
components: {TipTap, Toggle},
data(): Data {
return {
@ -73,7 +62,7 @@
textToStoreWhileFocused: '', // we need to have a text that always updates for user input
textBuffer: '',
htmlBuffer: '',
isListLocal: false,
isList: false,
// listHTML: `<ul>
// <li>Hello</li>
// <li>World</li>
@ -83,31 +72,59 @@
computed: {
text(): string {
return this.value.text ? this.value.text.replace(/<br(\/)?>/, '\n').replace(/(<([^>]+)>)/ig, '') : '';
// if has ul / li, return as is
if (this.isList) {
return this.value.text;
} else {
// need p tags
return this.value.text ? this.value.text.replace(/<br(\/)?>/, '\n').replace(/(<([^>]+)>)/ig, '') : emptyParagraph;
}
},
html(): string {
return this.value.text;
},
isList(): boolean {
return this.asList || this.value.text.indexOf('<li>') > -1;
}
},
mounted() {
console.log('i was mounted now');
// sync this only once, when the component gets mounted
this.isList = ul.test(this.value.text);
console.log(this.text);
this.localOnlyText = this.text;
this.textBuffer = this.text;
this.htmlBuffer = this.text;
// when mounted, we also check if the text already contains some li or ul elements
this.isListLocal = this.asList || re.test(this.value.text);
// after loading, we use the local data property to determine if we want a list or now
},
methods: {
updateSomeText() {
console.log('updating some text');
console.log('htmlBuffer', this.htmlBuffer);
this.localOnlyText = this.htmlBuffer;
let newText = this.htmlBuffer.replace(div, '$1p$2')
.replace(nonBreakingSpace, '')
// .replace(br, '\n')
.replace(anythingElse, '');
if (newText === '') {
// if the new text would be empty, we replace it according to our needs
if (this.isList) {
newText = emptyList;
} else {
newText = emptyParagraph;
}
}
this.localOnlyText = newText;
console.log(newText);
},
toggleList(checked: boolean) {
console.log(checked);
if (checked) {
this.makeList();
} else {
this.localOnlyText = this.textBuffer;
this.isList = false;
}
},
makeList() {
// this.localOnlyText = this.localOnlyText
let sep = /\n+/;
@ -121,20 +138,14 @@
</ul>`;
console.log(list);
this.localOnlyText = list;
this.isList = true;
},
changeSomeText(event: Event) {
console.log('changing some text');
const target = (<HTMLInputElement>event.target);
let newHtml = target.innerHTML;
let newText = target.innerText;
this.htmlBuffer = newHtml;
this.textBuffer = newText;
console.log("target.innerText");
console.log(target.innerText);
console.log(target.innerText.indexOf('\n'));
console.log(target.innerHTML);
console.log('textBuffer', this.textBuffer);
console.log('htmlBuffer', this.htmlBuffer);
this.$emit('change-text', newHtml);
},
change(event: Event) {
@ -158,13 +169,22 @@
&__contenteditable {
width: 100%;
height: 300px;
background-color: pink;
display: flex;
flex-direction: column;
}
/deep/ ul {
list-style: initial;
}
/deep/ li {
@include inputfont;
}
/deep/ div {
@include inputfont;
}
/deep/ p {
@include inputfont;
}
}
</style>

View File

@ -0,0 +1,99 @@
<template>
<div class="tip-tap">
<button @click="makeList">
List
</button>
<editor-content :editor="editor" />
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import {Editor, EditorContent} from "@tiptap/vue-2";
import Document from '@tiptap/extension-document';
import Paragraph from '@tiptap/extension-paragraph';
import Text from '@tiptap/extension-text';
import BulletList from '@tiptap/extension-bullet-list';
import ListItem from '@tiptap/extension-list-item';
interface Data {
editor: Editor | null;
}
export default Vue.extend({
props: {
value: {
type: String,
default: ''
}
},
components: {
EditorContent
},
data(): Data {
return {
editor: null,
};
},
watch: {
value(newVal) {
const editor = this.editor as Editor; // editor is always initialized on mount, cast it
const isSame = editor.getHTML() === newVal;
if (isSame) {
return;
}
editor.commands.setContent(newVal, false);
}
},
mounted() {
console.log('mounted tip tap');
this.editor = new Editor({
editorProps: {
attributes: {
class: 'tip-tap__editor'
}
},
content: this.value,
extensions: [
Document,
Paragraph,
Text,
BulletList,
ListItem
],
onUpdate: () => {
this.$emit('input', (<Editor>this.editor).getHTML());
}
});
},
beforeDestroy() {
this.editor?.destroy();
},
methods: {
makeList() {
const editor = this.editor as Editor;
editor.chain().selectAll().toggleBulletList().run();
}
}
});
</script>
<style scoped lang="scss">
@import '~styles/helpers';
.tip-tap {
/deep/ &__editor {
@include inputstyle;
flex-direction: column;
}
}
</style>

View File

@ -215,8 +215,12 @@
margin-bottom: $large-spacing;
}
@mixin inputstyle {
@mixin inputfont {
font-family: $sans-serif-font-family;
}
@mixin inputstyle {
@include inputfont;
display: flex;
padding: $medium-spacing;
border-radius: 4px;