add useReactNodeView hook

This commit is contained in:
Philipp Kühn
2021-03-14 20:40:40 +01:00
parent 109bff0892
commit 380d27fe86
6 changed files with 75 additions and 13 deletions

View File

@@ -135,7 +135,6 @@ export default () => {
draggable: true,
addNodeView() {
return ReactNodeViewRenderer((props) => {
// console.log({props})
return (
<NodeViewWrapper>
<div className="heading">
@@ -156,7 +155,6 @@ export default () => {
})
}
}),
],
content: `
<h1>heading</h1>
@@ -197,6 +195,10 @@ export default () => {
return (
<div>
<div>
<button onClick={() => editor.setEditable(true)}>editable</button>
<button onClick={() => editor.setEditable(false)}>readonly</button>
</div>
<MenuBar editor={editor} />
<EditorContent editor={editor} />
</div>

View File

@@ -2,6 +2,7 @@ import React from 'react'
import ReactDOM from 'react-dom'
import { Editor } from './Editor'
import { ReactRenderer } from './ReactRenderer'
import { ReactNodeViewContext } from './useReactNodeView'
type EditorContentProps = {
editor: Editor | null

View File

@@ -1,9 +1,10 @@
import React from 'react'
import { useReactNodeView } from './useReactNodeView'
export const NodeViewContent: React.FC = props => {
// TODO
const isEditable = true
// @ts-ignore
const { isEditable } = useReactNodeView()
return (
<div

View File

@@ -1,16 +1,14 @@
import React from 'react'
import { useReactNodeView } from './useReactNodeView'
export const NodeViewWrapper: React.FC = props => {
// TODO
const onDragStart = () => {
console.log('drag start')
}
// @ts-ignore
const { onDragStart } = useReactNodeView()
return (
<div
data-node-view-wrapper=""
// contentEditable={false}
style={{
whiteSpace: 'normal'
}}

View File

@@ -1,9 +1,11 @@
import React, { useState, useEffect } from 'react'
import { Node, NodeViewRenderer, NodeViewRendererProps } from '@tiptap/core'
import { Decoration, NodeView } from 'prosemirror-view'
import { NodeSelection } from 'prosemirror-state'
import { Node as ProseMirrorNode } from 'prosemirror-model'
import { Editor } from './Editor'
import { ReactRenderer } from './ReactRenderer'
import { ReactNodeViewContext } from './useReactNodeView'
interface ReactNodeViewRendererOptions {
stopEvent: ((event: Event) => boolean) | null,
@@ -40,7 +42,24 @@ class ReactNodeView implements NodeView {
this.mount(component)
}
mount(component: any) {
onDragStart(event: DragEvent) {
const { view } = this.editor
const target = (event.target as HTMLElement)
if (this.contentDOM?.contains(target)) {
return
}
// sometimes `event.target` is not the `dom` element
event.dataTransfer?.setDragImage(this.dom, 0, 0)
const selection = NodeSelection.create(view.state.doc, this.getPos())
const transaction = view.state.tr.setSelection(selection)
view.dispatch(transaction)
}
mount(Component: any) {
const props = {
editor: this.editor,
node: this.node,
@@ -51,11 +70,44 @@ class ReactNodeView implements NodeView {
updateAttributes: (attributes = {}) => this.updateAttributes(attributes),
}
if (!component.displayName) {
component.displayName = this.extension.config.name
if (!Component.displayName) {
const capitalizeFirstChar = (string: string): string => {
return string.charAt(0).toUpperCase() + string.substring(1)
}
Component.displayName = capitalizeFirstChar(this.extension.config.name)
}
this.renderer = new ReactRenderer(component, {
const ReactNodeView: React.FC = (props) => {
const [isEditable, setIsEditable] = useState(this.editor.isEditable)
const handleEditableChange = () => {
setIsEditable(this.editor.isEditable)
}
const onDragStart = this.onDragStart.bind(this)
useEffect(() => {
this.editor.on('viewUpdate', handleEditableChange)
return () => {
this.editor.off('viewUpdate', handleEditableChange)
}
}, [])
return (
<ReactNodeViewContext.Provider
value={{
onDragStart,
isEditable,
}}
>
<Component {...props} />
</ReactNodeViewContext.Provider>
)
}
this.renderer = new ReactRenderer(ReactNodeView, {
editor: this.editor,
props,
})

View File

@@ -0,0 +1,8 @@
import React, { useContext } from 'react'
export const ReactNodeViewContext = React.createContext<any>({
isEditable: undefined,
onDragStart: undefined,
})
export const useReactNodeView = () => useContext(ReactNodeViewContext)