add NodeViewWrapper and NodeViewContent to vue-2
This commit is contained in:
@@ -26,6 +26,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { NodeViewWrapper } from '@tiptap/vue-2'
|
||||||
import { v4 as uuid } from 'uuid'
|
import { v4 as uuid } from 'uuid'
|
||||||
import * as d3 from 'd3'
|
import * as d3 from 'd3'
|
||||||
import simplify from 'simplify-js'
|
import simplify from 'simplify-js'
|
||||||
@@ -37,6 +38,10 @@ const getRandomElement = list => {
|
|||||||
export default {
|
export default {
|
||||||
name: 'Paper',
|
name: 'Paper',
|
||||||
|
|
||||||
|
components: {
|
||||||
|
NodeViewWrapper,
|
||||||
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
updateAttributes: {
|
updateAttributes: {
|
||||||
type: Function,
|
type: Function,
|
||||||
|
|||||||
@@ -10,6 +10,17 @@
|
|||||||
</node-view-wrapper>
|
</node-view-wrapper>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { NodeViewWrapper, NodeViewContent } from '@tiptap/vue-2'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
NodeViewWrapper,
|
||||||
|
NodeViewContent,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.draggable-item {
|
.draggable-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -14,7 +14,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { NodeViewWrapper } from '@tiptap/vue-2'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
components: {
|
||||||
|
NodeViewWrapper,
|
||||||
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
editor: {
|
editor: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
|||||||
@@ -97,13 +97,17 @@ export default Node.create({
|
|||||||
|
|
||||||
```html
|
```html
|
||||||
<template>
|
<template>
|
||||||
<node-view-wrapper>
|
<node-view-wrapper />
|
||||||
<node-view-content />
|
|
||||||
</node-view-wrapper>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { NodeViewWrapper } from '@tiptap/vue-2'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
components: {
|
||||||
|
NodeViewWrapper,
|
||||||
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
editor: {
|
editor: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@@ -145,6 +149,16 @@ export default {
|
|||||||
<node-view-content class="content-dom" />
|
<node-view-content class="content-dom" />
|
||||||
</node-view-wrapper>
|
</node-view-wrapper>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { NodeViewWrapper, NodeViewContent } from '@tiptap/vue-2'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
NodeViewWrapper,
|
||||||
|
NodeViewContent,
|
||||||
|
},
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Reference
|
## Reference
|
||||||
|
|||||||
27
packages/vue-2/src/NodeViewContent.ts
Normal file
27
packages/vue-2/src/NodeViewContent.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
|
||||||
|
export const NodeViewContent = Vue.extend({
|
||||||
|
props: {
|
||||||
|
as: {
|
||||||
|
type: String,
|
||||||
|
default: 'div',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
inject: ['isEditable'],
|
||||||
|
|
||||||
|
render(createElement) {
|
||||||
|
return createElement(
|
||||||
|
this.as, {
|
||||||
|
style: {
|
||||||
|
whiteSpace: 'pre-wrap',
|
||||||
|
},
|
||||||
|
attrs: {
|
||||||
|
'data-node-view-content': '',
|
||||||
|
// @ts-ignore
|
||||||
|
contenteditable: this.isEditable.value,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
||||||
30
packages/vue-2/src/NodeViewWrapper.ts
Normal file
30
packages/vue-2/src/NodeViewWrapper.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
|
||||||
|
export const NodeViewWrapper = Vue.extend({
|
||||||
|
props: {
|
||||||
|
as: {
|
||||||
|
type: String,
|
||||||
|
default: 'div',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
inject: ['onDragStart'],
|
||||||
|
|
||||||
|
render(createElement) {
|
||||||
|
return createElement(
|
||||||
|
this.as, {
|
||||||
|
style: {
|
||||||
|
whiteSpace: 'normal',
|
||||||
|
},
|
||||||
|
attrs: {
|
||||||
|
'data-node-view-wrapper': '',
|
||||||
|
},
|
||||||
|
on: {
|
||||||
|
// @ts-ignore
|
||||||
|
dragstart: this.onDragStart,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
this.$slots.default,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -34,8 +34,6 @@ class VueNodeView implements NodeView {
|
|||||||
|
|
||||||
decorations!: Decoration[]
|
decorations!: Decoration[]
|
||||||
|
|
||||||
id!: string
|
|
||||||
|
|
||||||
getPos!: any
|
getPos!: any
|
||||||
|
|
||||||
isDragging = false
|
isDragging = false
|
||||||
@@ -51,42 +49,10 @@ class VueNodeView implements NodeView {
|
|||||||
this.extension = props.extension
|
this.extension = props.extension
|
||||||
this.node = props.node
|
this.node = props.node
|
||||||
this.getPos = props.getPos
|
this.getPos = props.getPos
|
||||||
this.createUniqueId()
|
|
||||||
this.mount(component)
|
this.mount(component)
|
||||||
}
|
}
|
||||||
|
|
||||||
createUniqueId() {
|
onDragStart(event: DragEvent) {
|
||||||
this.id = `id_${Math.floor(Math.random() * 0xFFFFFFFF)}`
|
|
||||||
}
|
|
||||||
|
|
||||||
createNodeViewWrapper() {
|
|
||||||
const { handleDragStart } = this
|
|
||||||
const dragstart = handleDragStart.bind(this)
|
|
||||||
|
|
||||||
return Vue.extend({
|
|
||||||
props: {
|
|
||||||
as: {
|
|
||||||
type: String,
|
|
||||||
default: 'div',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
render(createElement) {
|
|
||||||
return createElement(
|
|
||||||
this.as, {
|
|
||||||
style: {
|
|
||||||
whiteSpace: 'normal',
|
|
||||||
},
|
|
||||||
on: {
|
|
||||||
dragstart,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
this.$slots.default,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
handleDragStart(event: DragEvent) {
|
|
||||||
const { view } = this.editor
|
const { view } = this.editor
|
||||||
const target = (event.target as HTMLElement)
|
const target = (event.target as HTMLElement)
|
||||||
|
|
||||||
@@ -103,41 +69,8 @@ class VueNodeView implements NodeView {
|
|||||||
view.dispatch(transaction)
|
view.dispatch(transaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
createNodeViewContent() {
|
|
||||||
const { id } = this
|
|
||||||
const { isEditable } = this.editor
|
|
||||||
|
|
||||||
return Vue.extend({
|
|
||||||
inheritAttrs: false,
|
|
||||||
props: {
|
|
||||||
as: {
|
|
||||||
type: String,
|
|
||||||
default: 'div',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
render(createElement) {
|
|
||||||
return createElement(
|
|
||||||
this.as, {
|
|
||||||
style: {
|
|
||||||
whiteSpace: 'pre-wrap',
|
|
||||||
},
|
|
||||||
domProps: {
|
|
||||||
id,
|
|
||||||
contenteditable: isEditable,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
mount(component: Vue | VueConstructor) {
|
mount(component: Vue | VueConstructor) {
|
||||||
const NodeViewWrapper = this.createNodeViewWrapper()
|
|
||||||
const NodeViewContent = this.createNodeViewContent()
|
|
||||||
|
|
||||||
const props = {
|
const props = {
|
||||||
NodeViewWrapper,
|
|
||||||
NodeViewContent,
|
|
||||||
editor: this.editor,
|
editor: this.editor,
|
||||||
node: this.node,
|
node: this.node,
|
||||||
decorations: this.decorations,
|
decorations: this.decorations,
|
||||||
@@ -147,13 +80,24 @@ class VueNodeView implements NodeView {
|
|||||||
updateAttributes: (attributes = {}) => this.updateAttributes(attributes),
|
updateAttributes: (attributes = {}) => this.updateAttributes(attributes),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onDragStart = this.onDragStart.bind(this)
|
||||||
|
const isEditable = Vue.observable({
|
||||||
|
value: this.editor.isEditable,
|
||||||
|
})
|
||||||
|
|
||||||
|
this.editor.on('viewUpdate', () => {
|
||||||
|
isEditable.value = this.editor.isEditable
|
||||||
|
})
|
||||||
|
|
||||||
const Component = Vue
|
const Component = Vue
|
||||||
.extend(component)
|
.extend(component)
|
||||||
.extend({
|
.extend({
|
||||||
props: Object.keys(props),
|
props: Object.keys(props),
|
||||||
components: {
|
provide() {
|
||||||
NodeViewWrapper,
|
return {
|
||||||
NodeViewContent,
|
onDragStart,
|
||||||
|
isEditable,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -168,15 +112,23 @@ class VueNodeView implements NodeView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get dom() {
|
get dom() {
|
||||||
|
if (!this.renderer.element.hasAttribute('data-node-view-wrapper')) {
|
||||||
|
throw Error('Please use the NodeViewWrapper component for your node view.')
|
||||||
|
}
|
||||||
|
|
||||||
return this.renderer.element
|
return this.renderer.element
|
||||||
}
|
}
|
||||||
|
|
||||||
get contentDOM() {
|
get contentDOM() {
|
||||||
if (this.dom.id === this.id) {
|
const hasContent = !this.node.type.isAtom
|
||||||
return this.dom
|
|
||||||
|
if (!hasContent) {
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.dom.querySelector(`#${this.id}`)
|
const contentElement = this.dom.querySelector('[data-node-view-content]')
|
||||||
|
|
||||||
|
return contentElement || this.dom
|
||||||
}
|
}
|
||||||
|
|
||||||
stopEvent(event: Event) {
|
stopEvent(event: Event) {
|
||||||
|
|||||||
@@ -2,3 +2,5 @@ export * from '@tiptap/core'
|
|||||||
export * from './VueRenderer'
|
export * from './VueRenderer'
|
||||||
export * from './VueNodeViewRenderer'
|
export * from './VueNodeViewRenderer'
|
||||||
export * from './EditorContent'
|
export * from './EditorContent'
|
||||||
|
export * from './NodeViewWrapper'
|
||||||
|
export * from './NodeViewContent'
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export const NodeViewContent = defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
inject: ['editable'],
|
inject: ['isEditable'],
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return h(
|
return h(
|
||||||
@@ -18,7 +18,7 @@ export const NodeViewContent = defineComponent({
|
|||||||
},
|
},
|
||||||
'data-node-view-content': '',
|
'data-node-view-content': '',
|
||||||
// @ts-ignore (https://github.com/vuejs/vue-next/issues/3031)
|
// @ts-ignore (https://github.com/vuejs/vue-next/issues/3031)
|
||||||
contenteditable: this.editable.value,
|
contenteditable: this.isEditable.value,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ class VueNodeView implements NodeView {
|
|||||||
props: Object.keys(props),
|
props: Object.keys(props),
|
||||||
setup() {
|
setup() {
|
||||||
provide('onDragStart', onDragStart)
|
provide('onDragStart', onDragStart)
|
||||||
provide('editable', isEditable)
|
provide('isEditable', isEditable)
|
||||||
|
|
||||||
return (component as any).setup?.()
|
return (component as any).setup?.()
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user