add nested editor experiment
This commit is contained in:
80
docs/src/demos/Experiments/Nested/CustomNode.js
Normal file
80
docs/src/demos/Experiments/Nested/CustomNode.js
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import { Node, mergeAttributes } from '@tiptap/core'
|
||||||
|
import { VueNodeViewRenderer } from '@tiptap/vue-2'
|
||||||
|
import { Plugin } from 'prosemirror-state'
|
||||||
|
|
||||||
|
import CustomNodeView from './CustomNode.vue'
|
||||||
|
|
||||||
|
export default Node.create({
|
||||||
|
name: 'customNode',
|
||||||
|
isBlock: true,
|
||||||
|
inline: false,
|
||||||
|
group: 'block',
|
||||||
|
draggable: true,
|
||||||
|
isolating: true,
|
||||||
|
defining: true,
|
||||||
|
selectable: true,
|
||||||
|
|
||||||
|
addAttributes() {
|
||||||
|
return {
|
||||||
|
nest: { default: false },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
parseHTML() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
tag: 'custom-node',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
renderHTML({ HTMLAttributes }) {
|
||||||
|
return ['custom-node', mergeAttributes(HTMLAttributes)]
|
||||||
|
},
|
||||||
|
|
||||||
|
addNodeView() {
|
||||||
|
return VueNodeViewRenderer(CustomNodeView)
|
||||||
|
},
|
||||||
|
|
||||||
|
addProseMirrorPlugins() {
|
||||||
|
return [
|
||||||
|
new Plugin({
|
||||||
|
props: {
|
||||||
|
handleKeyDown: (view, event) => {
|
||||||
|
// Prevent _any_ key from clearing block. As soon as you start typing,
|
||||||
|
// and a block is focused, it'll blast the block away.
|
||||||
|
view.state.typing = true
|
||||||
|
},
|
||||||
|
|
||||||
|
handlePaste: (view, event, slice) => {
|
||||||
|
// Prevent pasting overwriting block
|
||||||
|
view.state.pasting = true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
filterTransaction: (transaction, state) => {
|
||||||
|
let result = true
|
||||||
|
|
||||||
|
// Check if our flags are set, and if the selected node is a custom node
|
||||||
|
if (state.typing || state.pasting) {
|
||||||
|
transaction.mapping.maps.forEach(map => {
|
||||||
|
map.forEach((oldStart, oldEnd, newStart, newEnd) => {
|
||||||
|
state.doc.nodesBetween(
|
||||||
|
oldStart,
|
||||||
|
oldEnd,
|
||||||
|
(node, number, pos, parent, index) => {
|
||||||
|
if (node.type.name === 'customNode') {
|
||||||
|
result = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
})
|
||||||
106
docs/src/demos/Experiments/Nested/CustomNode.vue
Normal file
106
docs/src/demos/Experiments/Nested/CustomNode.vue
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
<template>
|
||||||
|
<node-view-wrapper class="draggable-item" :class="{ active: selected }">
|
||||||
|
<div
|
||||||
|
class="drag-handle"
|
||||||
|
contenteditable="false"
|
||||||
|
draggable="true"
|
||||||
|
data-drag-handle
|
||||||
|
/>
|
||||||
|
<div class="draggable-nested">
|
||||||
|
<tiptap-nested />
|
||||||
|
</div>
|
||||||
|
</node-view-wrapper>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { NodeViewWrapper } from '@tiptap/vue-2'
|
||||||
|
import TiptapNested from './Nested.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'CustomNode',
|
||||||
|
|
||||||
|
components: {
|
||||||
|
NodeViewWrapper,
|
||||||
|
TiptapNested,
|
||||||
|
},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
editor: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
|
||||||
|
node: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
|
||||||
|
decorations: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
|
||||||
|
selected: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
extension: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
|
||||||
|
getPos: {
|
||||||
|
type: Function,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
|
||||||
|
updateAttributes: {
|
||||||
|
type: Function,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.draggable-item {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
padding: 0.5rem;
|
||||||
|
margin: 0.5rem 0;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
background: white;
|
||||||
|
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1), 0px 10px 20px rgba(0, 0, 0, 0.1);
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
border: 1px red solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
margin: 0 0 0.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-handle {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
position: relative;
|
||||||
|
width: 1rem;
|
||||||
|
height: 1rem;
|
||||||
|
top: 0.3rem;
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
cursor: grab;
|
||||||
|
background-image: url('data:image/svg+xml;charset=UTF-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 16"><path fill-opacity="0.2" d="M4 14c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zM2 6C.9 6 0 6.9 0 8s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6C.9 0 0 .9 0 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z" /></svg>');
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: contain;
|
||||||
|
background-position: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.draggable-nested {
|
||||||
|
flex: 1
|
||||||
|
}
|
||||||
|
</style>
|
||||||
45
docs/src/demos/Experiments/Nested/Nested.vue
Normal file
45
docs/src/demos/Experiments/Nested/Nested.vue
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<template>
|
||||||
|
<div class="editor-nested" v-if="editor">
|
||||||
|
<editor-content :editor="editor" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { Editor, EditorContent } from '@tiptap/vue-2'
|
||||||
|
import StarterKit from '@tiptap/starter-kit'
|
||||||
|
import CustomNode from './CustomNode.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
EditorContent,
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
editor: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.editor = new Editor({
|
||||||
|
content: `
|
||||||
|
Nested intro text`,
|
||||||
|
extensions: [StarterKit, CustomNode],
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
beforeDestroy() {
|
||||||
|
this.editor.destroy()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.editor-nested {
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px gray solid;
|
||||||
|
}
|
||||||
|
.ProseMirror {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
49
docs/src/demos/Experiments/Nested/index.vue
Normal file
49
docs/src/demos/Experiments/Nested/index.vue
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<template>
|
||||||
|
<div class="editor" v-if="editor">
|
||||||
|
<editor-content :editor="editor" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { Editor, EditorContent } from '@tiptap/vue-2'
|
||||||
|
import StarterKit from '@tiptap/starter-kit'
|
||||||
|
import CustomNode from './CustomNode.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
EditorContent,
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
editor: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.editor = new Editor({
|
||||||
|
content: 'Testing<custom-node></custom-node>Text',
|
||||||
|
extensions: [StarterKit, CustomNode],
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
beforeDestroy() {
|
||||||
|
this.editor.destroy()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor {
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px gray solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ProseMirror {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user