mirror of
https://github.com/ueberdosis/tiptap.git
synced 2025-06-07 09:25:29 +08:00
fix(react): update typescript types to be backwards-compatible (#5479)
This commit is contained in:
parent
b30462a2c6
commit
a42692e479
5
.changeset/spotty-lobsters-compare.md
Normal file
5
.changeset/spotty-lobsters-compare.md
Normal 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)
|
@ -1,7 +1,6 @@
|
|||||||
import { Editor } from '@tiptap/core'
|
import { Editor } from '@tiptap/core'
|
||||||
import React, { createContext, ReactNode, useContext } from 'react'
|
import React, { createContext, ReactNode, useContext } from 'react'
|
||||||
|
|
||||||
import { Editor as ReactEditor } from './Editor.js'
|
|
||||||
import { EditorContent } from './EditorContent.js'
|
import { EditorContent } from './EditorContent.js'
|
||||||
import { useEditor, UseEditorOptions } from './useEditor.js'
|
import { useEditor, UseEditorOptions } from './useEditor.js'
|
||||||
|
|
||||||
@ -45,7 +44,7 @@ export function EditorProvider({
|
|||||||
{slotBefore}
|
{slotBefore}
|
||||||
<EditorConsumer>
|
<EditorConsumer>
|
||||||
{({ editor: currentEditor }) => (
|
{({ editor: currentEditor }) => (
|
||||||
<EditorContent editor={currentEditor as ReactEditor} />
|
<EditorContent editor={currentEditor} />
|
||||||
)}
|
)}
|
||||||
</EditorConsumer>
|
</EditorConsumer>
|
||||||
{children}
|
{children}
|
||||||
|
@ -1,16 +1,13 @@
|
|||||||
import { Editor as CoreEditor } from '@tiptap/core'
|
import { Editor } from '@tiptap/core'
|
||||||
import React from 'react'
|
import { ReactPortal } from 'react'
|
||||||
|
|
||||||
import { ReactRenderer } from './ReactRenderer.js'
|
import { ReactRenderer } from './ReactRenderer.js'
|
||||||
|
|
||||||
type ContentComponent = {
|
export type EditorWithContentComponent = Editor & { contentComponent: ContentComponent | null }
|
||||||
|
export type ContentComponent = {
|
||||||
setRenderer(id: string, renderer: ReactRenderer): void;
|
setRenderer(id: string, renderer: ReactRenderer): void;
|
||||||
removeRenderer(id: string): void;
|
removeRenderer(id: string): void;
|
||||||
subscribe: (callback: () => void) => () => void;
|
subscribe: (callback: () => void) => () => void;
|
||||||
getSnapshot: () => Record<string, React.ReactPortal>;
|
getSnapshot: () => Record<string, ReactPortal>;
|
||||||
getServerSnapshot: () => Record<string, React.ReactPortal>;
|
getServerSnapshot: () => Record<string, ReactPortal>;
|
||||||
}
|
|
||||||
|
|
||||||
export class Editor extends CoreEditor {
|
|
||||||
public contentComponent: ContentComponent | null = null
|
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
|
import { Editor } from '@tiptap/core'
|
||||||
import React, {
|
import React, {
|
||||||
ForwardedRef, forwardRef, HTMLProps, LegacyRef, MutableRefObject,
|
ForwardedRef, forwardRef, HTMLProps, LegacyRef, MutableRefObject,
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
import { useSyncExternalStore } from 'use-sync-external-store/shim'
|
import { useSyncExternalStore } from 'use-sync-external-store/shim'
|
||||||
|
|
||||||
import { Editor } from './Editor.js'
|
import { ContentComponent, EditorWithContentComponent } from './Editor.js'
|
||||||
import { ReactRenderer } from './ReactRenderer.js'
|
import { ReactRenderer } from './ReactRenderer.js'
|
||||||
|
|
||||||
const mergeRefs = <T extends HTMLDivElement>(
|
const mergeRefs = <T extends HTMLDivElement>(
|
||||||
@ -24,7 +25,7 @@ const mergeRefs = <T extends HTMLDivElement>(
|
|||||||
/**
|
/**
|
||||||
* This component renders all of the editor's node views.
|
* 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,
|
contentComponent,
|
||||||
}) => {
|
}) => {
|
||||||
// For performance reasons, we render the node view portals on state changes only
|
// 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>;
|
innerRef?: ForwardedRef<HTMLDivElement | null>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getInstance(): Exclude<Editor['contentComponent'], null> {
|
function getInstance(): ContentComponent {
|
||||||
const subscribers = new Set<() => void>()
|
const subscribers = new Set<() => void>()
|
||||||
let renderers: Record<string, React.ReactPortal> = {}
|
let renderers: Record<string, React.ReactPortal> = {}
|
||||||
|
|
||||||
@ -107,7 +108,7 @@ export class PureEditorContent extends React.Component<
|
|||||||
this.initialized = false
|
this.initialized = false
|
||||||
|
|
||||||
this.state = {
|
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() {
|
init() {
|
||||||
const { editor } = this.props
|
const editor = this.props.editor as EditorWithContentComponent
|
||||||
|
|
||||||
if (editor && !editor.isDestroyed && editor.options.element) {
|
if (editor && !editor.isDestroyed && editor.options.element) {
|
||||||
if (editor.contentComponent) {
|
if (editor.contentComponent) {
|
||||||
@ -164,7 +165,7 @@ export class PureEditorContent extends React.Component<
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
const { editor } = this.props
|
const editor = this.props.editor as EditorWithContentComponent
|
||||||
|
|
||||||
if (!editor) {
|
if (!editor) {
|
||||||
return
|
return
|
||||||
@ -215,6 +216,7 @@ const EditorContentWithKey = forwardRef<HTMLDivElement, EditorContentProps>(
|
|||||||
(props: Omit<EditorContentProps, 'innerRef'>, ref) => {
|
(props: Omit<EditorContentProps, 'innerRef'>, ref) => {
|
||||||
const key = React.useMemo(() => {
|
const key = React.useMemo(() => {
|
||||||
return Math.floor(Math.random() * 0xffffffff).toString()
|
return Math.floor(Math.random() * 0xffffffff).toString()
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [props.editor])
|
}, [props.editor])
|
||||||
|
|
||||||
// Can't use JSX here because it conflicts with the type definition of Vue's JSX, so use createElement
|
// Can't use JSX here because it conflicts with the type definition of Vue's JSX, so use createElement
|
||||||
|
@ -12,6 +12,7 @@ export const NodeViewContent: React.FC<NodeViewContentProps> = props => {
|
|||||||
const { nodeViewContentRef } = useReactNodeView()
|
const { nodeViewContentRef } = useReactNodeView()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
// @ts-ignore
|
||||||
<Tag
|
<Tag
|
||||||
{...props}
|
{...props}
|
||||||
ref={nodeViewContentRef}
|
ref={nodeViewContentRef}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
DecorationWithType,
|
DecorationWithType,
|
||||||
|
Editor,
|
||||||
NodeView,
|
NodeView,
|
||||||
NodeViewProps,
|
NodeViewProps,
|
||||||
NodeViewRenderer,
|
NodeViewRenderer,
|
||||||
@ -10,7 +11,7 @@ import { Node as ProseMirrorNode } from '@tiptap/pm/model'
|
|||||||
import { Decoration, NodeView as ProseMirrorNodeView } from '@tiptap/pm/view'
|
import { Decoration, NodeView as ProseMirrorNodeView } from '@tiptap/pm/view'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
import { Editor } from './Editor.js'
|
import { EditorWithContentComponent } from './Editor.js'
|
||||||
import { ReactRenderer } from './ReactRenderer.js'
|
import { ReactRenderer } from './ReactRenderer.js'
|
||||||
import { ReactNodeViewContext, ReactNodeViewContextProps } from './useReactNodeView.js'
|
import { ReactNodeViewContext, ReactNodeViewContextProps } from './useReactNodeView.js'
|
||||||
|
|
||||||
@ -216,7 +217,7 @@ export function ReactNodeViewRenderer(
|
|||||||
// try to get the parent component
|
// try to get the parent component
|
||||||
// this is important for vue devtools to show the component hierarchy correctly
|
// this is important for vue devtools to show the component hierarchy correctly
|
||||||
// maybe it’s `undefined` because <editor-content> isn’t rendered yet
|
// maybe it’s `undefined` because <editor-content> isn’t rendered yet
|
||||||
if (!(props.editor as Editor).contentComponent) {
|
if (!(props.editor as EditorWithContentComponent).contentComponent) {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import { Editor } from '@tiptap/core'
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { flushSync } from 'react-dom'
|
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.
|
* Check if a component is a class component.
|
||||||
@ -86,7 +86,7 @@ type ComponentType<R, P> =
|
|||||||
export class ReactRenderer<R = unknown, P = unknown> {
|
export class ReactRenderer<R = unknown, P = unknown> {
|
||||||
id: string
|
id: string
|
||||||
|
|
||||||
editor: ExtendedEditor
|
editor: Editor
|
||||||
|
|
||||||
component: any
|
component: any
|
||||||
|
|
||||||
@ -107,7 +107,7 @@ export class ReactRenderer<R = unknown, P = unknown> {
|
|||||||
}: 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 ExtendedEditor
|
this.editor = editor as EditorWithContentComponent
|
||||||
this.props = props
|
this.props = props
|
||||||
this.element = document.createElement(as)
|
this.element = document.createElement(as)
|
||||||
this.element.classList.add('react-renderer')
|
this.element.classList.add('react-renderer')
|
||||||
@ -136,6 +136,7 @@ export class ReactRenderer<R = unknown, P = unknown> {
|
|||||||
render(): void {
|
render(): void {
|
||||||
const Component = this.component
|
const Component = this.component
|
||||||
const props = this.props
|
const props = this.props
|
||||||
|
const editor = this.editor as EditorWithContentComponent
|
||||||
|
|
||||||
if (isClassComponent(Component) || isForwardRefComponent(Component)) {
|
if (isClassComponent(Component) || isForwardRefComponent(Component)) {
|
||||||
props.ref = (ref: R) => {
|
props.ref = (ref: R) => {
|
||||||
@ -145,7 +146,7 @@ export class ReactRenderer<R = unknown, P = unknown> {
|
|||||||
|
|
||||||
this.reactElement = React.createElement(Component, props)
|
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 {
|
updateProps(props: Record<string, any> = {}): void {
|
||||||
@ -158,6 +159,8 @@ export class ReactRenderer<R = unknown, P = unknown> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
destroy(): void {
|
destroy(): void {
|
||||||
this.editor?.contentComponent?.removeRenderer(this.id)
|
const editor = this.editor as EditorWithContentComponent
|
||||||
|
|
||||||
|
editor?.contentComponent?.removeRenderer(this.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
export * from './BubbleMenu.js'
|
export * from './BubbleMenu.js'
|
||||||
export * from './Context.js'
|
export * from './Context.js'
|
||||||
export { Editor } from './Editor.js'
|
|
||||||
export * from './EditorContent.js'
|
export * from './EditorContent.js'
|
||||||
export * from './FloatingMenu.js'
|
export * from './FloatingMenu.js'
|
||||||
export * from './NodeViewContent.js'
|
export * from './NodeViewContent.js'
|
||||||
@ -10,4 +9,5 @@ export * from './ReactRenderer.js'
|
|||||||
export * from './useEditor.js'
|
export * from './useEditor.js'
|
||||||
export * from './useEditorState.js'
|
export * from './useEditorState.js'
|
||||||
export * from './useReactNodeView.js'
|
export * from './useReactNodeView.js'
|
||||||
|
export { Editor } from '@tiptap/core'
|
||||||
export * from '@tiptap/core'
|
export * from '@tiptap/core'
|
||||||
|
Loading…
Reference in New Issue
Block a user