tiptap/examples/Components/Routes/Mentions/index.vue

162 lines
3.1 KiB
Vue
Raw Normal View History

2018-09-02 02:51:17 +08:00
<template>
<div>
2018-09-25 13:43:21 +08:00
<editor class="editor" :extensions="extensions" ref="editor">
2018-09-02 02:51:17 +08:00
<div class="editor__content" slot="content" slot-scope="props">
<h2>
Mentions
</h2>
<p>
Yeah <span data-mention-type="user" data-mention-id="1">Philipp Kühn</span> and <span data-mention-type="user" data-mention-id="2">Hans Pagel</span>.
</p>
</div>
</editor>
2018-09-25 13:43:21 +08:00
<div class="suggestions">
2018-09-25 14:37:39 +08:00
<div v-if="query && !filteredUsers.length">
No users found.
</div>
2018-09-27 19:06:24 +08:00
<div
v-else
v-for="(user, index) in filteredUsers"
:key="user.id"
@click="selectUser(user)"
class="suggestions__item"
:class="{ 'is-selected': navigatedUserIndex === index }"
>
2018-09-25 13:43:21 +08:00
{{ user.name }}
</div>
</div>
2018-09-02 02:51:17 +08:00
</div>
</template>
<script>
2018-09-25 14:37:39 +08:00
import Fuse from 'fuse.js'
2018-09-02 02:51:17 +08:00
import Icon from 'Components/Icon'
import { Editor } from 'tiptap'
import {
HardBreakNode,
HeadingNode,
MentionNode,
} from 'tiptap-extensions'
export default {
components: {
Editor,
Icon,
},
data() {
return {
extensions: [
new HardBreakNode(),
new HeadingNode({ maxLevel: 3 }),
2018-09-06 04:09:18 +08:00
new MentionNode({
2018-09-27 17:35:32 +08:00
items: [
{
name: 'Philipp Kühn',
id: 1,
},
{
name: 'Hans Pagel',
id: 2,
},
],
2018-09-28 00:53:23 +08:00
onEnter: ({ items, query }) => {
this.query = query
this.filteredUsers = items
2018-09-06 04:09:18 +08:00
},
2018-09-28 00:53:23 +08:00
onChange: ({ items, query }) => {
this.query = query
this.filteredUsers = items
2018-09-06 04:09:18 +08:00
},
2018-09-28 00:53:23 +08:00
onExit: () => {
2018-09-25 14:37:39 +08:00
this.query = null
2018-09-28 00:53:23 +08:00
this.filteredUsers = []
2018-09-27 17:35:32 +08:00
},
2018-09-27 19:06:24 +08:00
onKeyDown: ({ event }) => {
// pressing up arrow
if (event.keyCode === 38) {
this.upHandler()
2018-09-28 00:50:29 +08:00
return true
2018-09-27 19:06:24 +08:00
}
// pressing down arrow
if (event.keyCode === 40) {
this.downHandler()
2018-09-28 00:50:29 +08:00
return true
2018-09-27 19:06:24 +08:00
}
// pressing enter
if (event.keyCode === 13) {
this.enterHandler()
2018-09-28 00:50:29 +08:00
return true
2018-09-27 19:06:24 +08:00
}
2018-09-28 00:50:29 +08:00
return false
2018-09-27 19:06:24 +08:00
},
2018-09-27 17:35:32 +08:00
onFilter: (items, query) => {
if (!query) {
return items
}
const fuse = new Fuse(items, {
threshold: 0.2,
keys: [
'name',
],
})
return fuse.search(query)
2018-09-06 04:09:18 +08:00
},
}),
2018-09-02 02:51:17 +08:00
],
2018-09-25 14:37:39 +08:00
query: null,
2018-09-27 17:35:32 +08:00
filteredUsers: [],
2018-09-27 19:06:24 +08:00
navigatedUserIndex: 0,
2018-09-02 02:51:17 +08:00
}
},
2018-09-25 13:43:21 +08:00
methods: {
2018-09-27 19:06:24 +08:00
upHandler() {
this.navigatedUserIndex = ((this.navigatedUserIndex + this.filteredUsers.length) - 1) % this.filteredUsers.length
},
downHandler() {
this.navigatedUserIndex = (this.navigatedUserIndex + 1) % this.filteredUsers.length
},
enterHandler() {
const user = this.filteredUsers[this.navigatedUserIndex]
this.selectUser(user)
},
2018-09-25 13:43:21 +08:00
selectUser(user) {
this.$refs.editor.menuActions.nodes.mention.command({
type: 'user',
id: user.id,
label: user.name,
})
},
},
2018-09-02 02:51:17 +08:00
}
2018-09-06 04:09:18 +08:00
</script>
<style lang="scss">
@import "~variables";
.mention {
background: rgba($color-black, 0.1);
color: rgba($color-black, 0.6);
font-size: 0.8rem;
font-weight: bold;
border-radius: 5px;
padding: 0.2rem 0.5rem;
}
2018-09-25 13:43:21 +08:00
.suggestions {
max-width: 30rem;
margin: 0 auto 2rem auto;
2018-09-27 19:06:24 +08:00
&__item {
&.is-selected {
background-color: rgba($color-black, 0.1);
}
}
2018-09-25 13:43:21 +08:00
}
2018-09-06 04:09:18 +08:00
</style>