fix(react): update typescript types to be backwards-compatible (#5479)

This commit is contained in:
Nick Perez 2024-08-13 12:47:04 +02:00 committed by GitHub
parent b30462a2c6
commit a42692e479
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 33 additions and 25 deletions

View File

@ -0,0 +1,5 @@
---
"@tiptap/react": patch
---
This resolves some typescript errors with the exported React type to remove contentComponent from being exported (it is an implementation detail)

View File

@ -1,7 +1,6 @@
import { Editor } from '@tiptap/core'
import React, { createContext, ReactNode, useContext } from 'react'
import { Editor as ReactEditor } from './Editor.js'
import { EditorContent } from './EditorContent.js'
import { useEditor, UseEditorOptions } from './useEditor.js'
@ -45,7 +44,7 @@ export function EditorProvider({
{slotBefore}
<EditorConsumer>
{({ editor: currentEditor }) => (
<EditorContent editor={currentEditor as ReactEditor} />
<EditorContent editor={currentEditor} />
)}
</EditorConsumer>
{children}

View File

@ -1,16 +1,13 @@
import { Editor as CoreEditor } from '@tiptap/core'
import React from 'react'
import { Editor } from '@tiptap/core'
import { ReactPortal } from 'react'
import { ReactRenderer } from './ReactRenderer.js'
type ContentComponent = {
export type EditorWithContentComponent = Editor & { contentComponent: ContentComponent | null }
export type ContentComponent = {
setRenderer(id: string, renderer: ReactRenderer): void;
removeRenderer(id: string): void;
subscribe: (callback: () => void) => () => void;
getSnapshot: () => Record<string, React.ReactPortal>;
getServerSnapshot: () => Record<string, React.ReactPortal>;
}
export class Editor extends CoreEditor {
public contentComponent: ContentComponent | null = null
getSnapshot: () => Record<string, ReactPortal>;
getServerSnapshot: () => Record<string, ReactPortal>;
}

View File

@ -1,10 +1,11 @@
import { Editor } from '@tiptap/core'
import React, {
ForwardedRef, forwardRef, HTMLProps, LegacyRef, MutableRefObject,
} from 'react'
import ReactDOM from 'react-dom'
import { useSyncExternalStore } from 'use-sync-external-store/shim'
import { Editor } from './Editor.js'
import { ContentComponent, EditorWithContentComponent } from './Editor.js'
import { ReactRenderer } from './ReactRenderer.js'
const mergeRefs = <T extends HTMLDivElement>(
@ -24,7 +25,7 @@ const mergeRefs = <T extends HTMLDivElement>(
/**
* This component renders all of the editor's node views.
*/
const Portals: React.FC<{ contentComponent: Exclude<Editor['contentComponent'], null> }> = ({
const Portals: React.FC<{ contentComponent: ContentComponent }> = ({
contentComponent,
}) => {
// For performance reasons, we render the node view portals on state changes only
@ -47,7 +48,7 @@ export interface EditorContentProps extends HTMLProps<HTMLDivElement> {
innerRef?: ForwardedRef<HTMLDivElement | null>;
}
function getInstance(): Exclude<Editor['contentComponent'], null> {
function getInstance(): ContentComponent {
const subscribers = new Set<() => void>()
let renderers: Record<string, React.ReactPortal> = {}
@ -107,7 +108,7 @@ export class PureEditorContent extends React.Component<
this.initialized = false
this.state = {
hasContentComponentInitialized: Boolean(props.editor?.contentComponent),
hasContentComponentInitialized: Boolean((props.editor as EditorWithContentComponent).contentComponent),
}
}
@ -120,7 +121,7 @@ export class PureEditorContent extends React.Component<
}
init() {
const { editor } = this.props
const editor = this.props.editor as EditorWithContentComponent
if (editor && !editor.isDestroyed && editor.options.element) {
if (editor.contentComponent) {
@ -164,7 +165,7 @@ export class PureEditorContent extends React.Component<
}
componentWillUnmount() {
const { editor } = this.props
const editor = this.props.editor as EditorWithContentComponent
if (!editor) {
return
@ -215,6 +216,7 @@ const EditorContentWithKey = forwardRef<HTMLDivElement, EditorContentProps>(
(props: Omit<EditorContentProps, 'innerRef'>, ref) => {
const key = React.useMemo(() => {
return Math.floor(Math.random() * 0xffffffff).toString()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [props.editor])
// Can't use JSX here because it conflicts with the type definition of Vue's JSX, so use createElement

View File

@ -12,6 +12,7 @@ export const NodeViewContent: React.FC<NodeViewContentProps> = props => {
const { nodeViewContentRef } = useReactNodeView()
return (
// @ts-ignore
<Tag
{...props}
ref={nodeViewContentRef}

View File

@ -1,5 +1,6 @@
import {
DecorationWithType,
Editor,
NodeView,
NodeViewProps,
NodeViewRenderer,
@ -10,7 +11,7 @@ import { Node as ProseMirrorNode } from '@tiptap/pm/model'
import { Decoration, NodeView as ProseMirrorNodeView } from '@tiptap/pm/view'
import React from 'react'
import { Editor } from './Editor.js'
import { EditorWithContentComponent } from './Editor.js'
import { ReactRenderer } from './ReactRenderer.js'
import { ReactNodeViewContext, ReactNodeViewContextProps } from './useReactNodeView.js'
@ -216,7 +217,7 @@ export function ReactNodeViewRenderer(
// try to get the parent component
// this is important for vue devtools to show the component hierarchy correctly
// maybe its `undefined` because <editor-content> isnt rendered yet
if (!(props.editor as Editor).contentComponent) {
if (!(props.editor as EditorWithContentComponent).contentComponent) {
return {}
}

View File

@ -2,7 +2,7 @@ import { Editor } from '@tiptap/core'
import React from 'react'
import { flushSync } from 'react-dom'
import { Editor as ExtendedEditor } from './Editor.js'
import { EditorWithContentComponent } from './Editor.js'
/**
* Check if a component is a class component.
@ -86,7 +86,7 @@ type ComponentType<R, P> =
export class ReactRenderer<R = unknown, P = unknown> {
id: string
editor: ExtendedEditor
editor: Editor
component: any
@ -107,7 +107,7 @@ export class ReactRenderer<R = unknown, P = unknown> {
}: ReactRendererOptions) {
this.id = Math.floor(Math.random() * 0xFFFFFFFF).toString()
this.component = component
this.editor = editor as ExtendedEditor
this.editor = editor as EditorWithContentComponent
this.props = props
this.element = document.createElement(as)
this.element.classList.add('react-renderer')
@ -136,6 +136,7 @@ export class ReactRenderer<R = unknown, P = unknown> {
render(): void {
const Component = this.component
const props = this.props
const editor = this.editor as EditorWithContentComponent
if (isClassComponent(Component) || isForwardRefComponent(Component)) {
props.ref = (ref: R) => {
@ -145,7 +146,7 @@ export class ReactRenderer<R = unknown, P = unknown> {
this.reactElement = React.createElement(Component, props)
this.editor?.contentComponent?.setRenderer(this.id, this)
editor?.contentComponent?.setRenderer(this.id, this)
}
updateProps(props: Record<string, any> = {}): void {
@ -158,6 +159,8 @@ export class ReactRenderer<R = unknown, P = unknown> {
}
destroy(): void {
this.editor?.contentComponent?.removeRenderer(this.id)
const editor = this.editor as EditorWithContentComponent
editor?.contentComponent?.removeRenderer(this.id)
}
}

View File

@ -1,6 +1,5 @@
export * from './BubbleMenu.js'
export * from './Context.js'
export { Editor } from './Editor.js'
export * from './EditorContent.js'
export * from './FloatingMenu.js'
export * from './NodeViewContent.js'
@ -10,4 +9,5 @@ export * from './ReactRenderer.js'
export * from './useEditor.js'
export * from './useEditorState.js'
export * from './useReactNodeView.js'
export { Editor } from '@tiptap/core'
export * from '@tiptap/core'