mirror of
https://github.com/ueberdosis/tiptap.git
synced 2025-06-13 13:13:12 +08:00
fix: avoid flushSync call during <EditorContent /> lifecycle
This commit is contained in:
parent
aff018e651
commit
1f5a830e5b
@ -3,7 +3,7 @@ import { ReactPortal } from 'react'
|
|||||||
|
|
||||||
import { ReactRenderer } from './ReactRenderer.js'
|
import { ReactRenderer } from './ReactRenderer.js'
|
||||||
|
|
||||||
export type EditorWithContentComponent = Editor & { contentComponent?: ContentComponent | null }
|
export type EditorWithContentComponent = Editor & { contentComponent?: ContentComponent | null; isEditorContentInitialized?: boolean }
|
||||||
export type ContentComponent = {
|
export type ContentComponent = {
|
||||||
setRenderer(id: string, renderer: ReactRenderer): void;
|
setRenderer(id: string, renderer: ReactRenderer): void;
|
||||||
removeRenderer(id: string): void;
|
removeRenderer(id: string): void;
|
||||||
|
@ -98,18 +98,9 @@ export class PureEditorContent extends React.Component<
|
|||||||
> {
|
> {
|
||||||
editorContentRef: React.RefObject<any>
|
editorContentRef: React.RefObject<any>
|
||||||
|
|
||||||
initialized: boolean
|
|
||||||
|
|
||||||
unsubscribeToContentComponent?: () => void
|
|
||||||
|
|
||||||
constructor(props: EditorContentProps) {
|
constructor(props: EditorContentProps) {
|
||||||
super(props)
|
super(props)
|
||||||
this.editorContentRef = React.createRef()
|
this.editorContentRef = React.createRef()
|
||||||
this.initialized = false
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
hasContentComponentInitialized: Boolean((props.editor as EditorWithContentComponent | null)?.contentComponent),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@ -138,29 +129,11 @@ export class PureEditorContent extends React.Component<
|
|||||||
|
|
||||||
editor.contentComponent = getInstance()
|
editor.contentComponent = getInstance()
|
||||||
|
|
||||||
// Has the content component been initialized?
|
|
||||||
if (!this.state.hasContentComponentInitialized) {
|
|
||||||
// Subscribe to the content component
|
|
||||||
this.unsubscribeToContentComponent = editor.contentComponent.subscribe(() => {
|
|
||||||
this.setState(prevState => {
|
|
||||||
if (!prevState.hasContentComponentInitialized) {
|
|
||||||
return {
|
|
||||||
hasContentComponentInitialized: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return prevState
|
|
||||||
})
|
|
||||||
|
|
||||||
// Unsubscribe to previous content component
|
|
||||||
if (this.unsubscribeToContentComponent) {
|
|
||||||
this.unsubscribeToContentComponent()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
editor.createNodeViews()
|
editor.createNodeViews()
|
||||||
|
|
||||||
this.initialized = true
|
editor.isEditorContentInitialized = true
|
||||||
|
|
||||||
|
this.forceUpdate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,7 +144,7 @@ export class PureEditorContent extends React.Component<
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.initialized = false
|
editor.isEditorContentInitialized = false
|
||||||
|
|
||||||
if (!editor.isDestroyed) {
|
if (!editor.isDestroyed) {
|
||||||
editor.view.setProps({
|
editor.view.setProps({
|
||||||
@ -179,10 +152,6 @@ export class PureEditorContent extends React.Component<
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.unsubscribeToContentComponent) {
|
|
||||||
this.unsubscribeToContentComponent()
|
|
||||||
}
|
|
||||||
|
|
||||||
editor.contentComponent = null
|
editor.contentComponent = null
|
||||||
|
|
||||||
if (!editor.options.element.firstChild) {
|
if (!editor.options.element.firstChild) {
|
||||||
|
@ -78,7 +78,7 @@ type ComponentType<R, P> =
|
|||||||
export class ReactRenderer<R = unknown, P extends Record<string, any> = object> {
|
export class ReactRenderer<R = unknown, P extends Record<string, any> = object> {
|
||||||
id: string
|
id: string
|
||||||
|
|
||||||
editor: Editor
|
editor: EditorWithContentComponent
|
||||||
|
|
||||||
component: any
|
component: any
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ export class ReactRenderer<R = unknown, P extends Record<string, any> = object>
|
|||||||
}: ReactRendererOptions) {
|
}: ReactRendererOptions) {
|
||||||
this.id = Math.floor(Math.random() * 0xFFFFFFFF).toString()
|
this.id = Math.floor(Math.random() * 0xFFFFFFFF).toString()
|
||||||
this.component = component
|
this.component = component
|
||||||
this.editor = editor as EditorWithContentComponent
|
this.editor = editor
|
||||||
this.props = props as P
|
this.props = props as P
|
||||||
this.element = document.createElement(as)
|
this.element = document.createElement(as)
|
||||||
this.element.classList.add('react-renderer')
|
this.element.classList.add('react-renderer')
|
||||||
@ -110,7 +110,7 @@ export class ReactRenderer<R = unknown, P extends Record<string, any> = object>
|
|||||||
this.element.classList.add(...className.split(' '))
|
this.element.classList.add(...className.split(' '))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.editor.isInitialized) {
|
if (this.editor.isEditorContentInitialized) {
|
||||||
// On first render, we need to flush the render synchronously
|
// On first render, we need to flush the render synchronously
|
||||||
// Renders afterwards can be async, but this fixes a cursor positioning issue
|
// Renders afterwards can be async, but this fixes a cursor positioning issue
|
||||||
flushSync(() => {
|
flushSync(() => {
|
||||||
|
Loading…
Reference in New Issue
Block a user