@handlewithcare/react-prosemirror 2.7.0-tiptap.9 → 2.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -71
- package/dist/cjs/StaticEditorView.js +0 -3
- package/dist/cjs/dom.js +8 -3
- package/dist/cjs/plugins/beforeInputPlugin.js +1 -1
- package/dist/cjs/viewdesc.js +6 -0
- package/dist/esm/StaticEditorView.js +0 -3
- package/dist/esm/dom.js +8 -3
- package/dist/esm/hooks/useEditorEffect.js +0 -4
- package/dist/esm/hooks/useEditorEventCallback.js +5 -3
- package/dist/esm/plugins/beforeInputPlugin.js +1 -1
- package/dist/esm/viewdesc.js +6 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/AbstractEditorView.d.ts +0 -1
- package/dist/types/StaticEditorView.d.ts +0 -1
- package/dist/types/hooks/useEditorEffect.d.ts +0 -4
- package/dist/types/hooks/useEditorEventCallback.d.ts +5 -3
- package/dist/types/viewdesc.d.ts +2 -0
- package/package.json +8 -11
- package/dist/cjs/tiptap/TiptapEditor.js +0 -34
- package/dist/cjs/tiptap/TiptapEditorContent.js +0 -136
- package/dist/cjs/tiptap/TiptapEditorView.js +0 -99
- package/dist/cjs/tiptap/extensions/ReactProseMirror.js +0 -20
- package/dist/cjs/tiptap/hooks/useTiptapEditor.js +0 -29
- package/dist/cjs/tiptap/hooks/useTiptapEditorEffect.js +0 -32
- package/dist/cjs/tiptap/hooks/useTiptapEditorEventCallback.js +0 -35
- package/dist/cjs/tiptap/index.js +0 -44
- package/dist/cjs/tiptap/tiptapNodeView.js +0 -188
- package/dist/esm/tiptap/TiptapEditor.js +0 -24
- package/dist/esm/tiptap/TiptapEditorContent.js +0 -85
- package/dist/esm/tiptap/TiptapEditorView.js +0 -50
- package/dist/esm/tiptap/extensions/ReactProseMirror.js +0 -10
- package/dist/esm/tiptap/hooks/useTiptapEditor.js +0 -19
- package/dist/esm/tiptap/hooks/useTiptapEditorEffect.js +0 -39
- package/dist/esm/tiptap/hooks/useTiptapEditorEventCallback.js +0 -35
- package/dist/esm/tiptap/index.js +0 -8
- package/dist/esm/tiptap/tiptapNodeView.js +0 -156
- package/dist/types/tiptap/TiptapEditor.d.ts +0 -6
- package/dist/types/tiptap/TiptapEditorContent.d.ts +0 -19
- package/dist/types/tiptap/TiptapEditorView.d.ts +0 -13
- package/dist/types/tiptap/extensions/ReactProseMirror.d.ts +0 -2
- package/dist/types/tiptap/hooks/useTiptapEditor.d.ts +0 -4
- package/dist/types/tiptap/hooks/useTiptapEditorEffect.d.ts +0 -21
- package/dist/types/tiptap/hooks/useTiptapEditorEventCallback.d.ts +0 -13
- package/dist/types/tiptap/index.d.ts +0 -8
- package/dist/types/tiptap/tiptapNodeView.d.ts +0 -48
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", {
|
|
3
|
-
value: true
|
|
4
|
-
});
|
|
5
|
-
Object.defineProperty(exports, "tiptapNodeView", {
|
|
6
|
-
enumerable: true,
|
|
7
|
-
get: function() {
|
|
8
|
-
return tiptapNodeView;
|
|
9
|
-
}
|
|
10
|
-
});
|
|
11
|
-
const _core = require("@tiptap/core");
|
|
12
|
-
const _react = require("@tiptap/react");
|
|
13
|
-
const _classnames = /*#__PURE__*/ _interop_require_default(require("classnames"));
|
|
14
|
-
const _react1 = /*#__PURE__*/ _interop_require_wildcard(require("react"));
|
|
15
|
-
const _useEditorEventCallback = require("../hooks/useEditorEventCallback.js");
|
|
16
|
-
const _useIgnoreMutation = require("../hooks/useIgnoreMutation.js");
|
|
17
|
-
const _useIsNodeSelected = require("../hooks/useIsNodeSelected.js");
|
|
18
|
-
const _useStopEvent = require("../hooks/useStopEvent.js");
|
|
19
|
-
const _props = require("../props.js");
|
|
20
|
-
function _interop_require_default(obj) {
|
|
21
|
-
return obj && obj.__esModule ? obj : {
|
|
22
|
-
default: obj
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
function _getRequireWildcardCache(nodeInterop) {
|
|
26
|
-
if (typeof WeakMap !== "function") return null;
|
|
27
|
-
var cacheBabelInterop = new WeakMap();
|
|
28
|
-
var cacheNodeInterop = new WeakMap();
|
|
29
|
-
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
30
|
-
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
31
|
-
})(nodeInterop);
|
|
32
|
-
}
|
|
33
|
-
function _interop_require_wildcard(obj, nodeInterop) {
|
|
34
|
-
if (!nodeInterop && obj && obj.__esModule) {
|
|
35
|
-
return obj;
|
|
36
|
-
}
|
|
37
|
-
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
38
|
-
return {
|
|
39
|
-
default: obj
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
var cache = _getRequireWildcardCache(nodeInterop);
|
|
43
|
-
if (cache && cache.has(obj)) {
|
|
44
|
-
return cache.get(obj);
|
|
45
|
-
}
|
|
46
|
-
var newObj = {
|
|
47
|
-
__proto__: null
|
|
48
|
-
};
|
|
49
|
-
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
50
|
-
for(var key in obj){
|
|
51
|
-
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
52
|
-
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
53
|
-
if (desc && (desc.get || desc.set)) {
|
|
54
|
-
Object.defineProperty(newObj, key, desc);
|
|
55
|
-
} else {
|
|
56
|
-
newObj[key] = obj[key];
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
newObj.default = obj;
|
|
61
|
-
if (cache) {
|
|
62
|
-
cache.set(obj, newObj);
|
|
63
|
-
}
|
|
64
|
-
return newObj;
|
|
65
|
-
}
|
|
66
|
-
function tiptapNodeView(param) {
|
|
67
|
-
let { component: WrappedComponent, extension, as, className = "", attrs, contentDOMElementTag: InnerTag = "div", stopEvent, ignoreMutation } = param;
|
|
68
|
-
const TiptapNodeView = /*#__PURE__*/ (0, _react1.memo)(/*#__PURE__*/ (0, _react1.forwardRef)(function TiptapNodeView(param, ref) {
|
|
69
|
-
let { children, nodeProps, ...props } = param;
|
|
70
|
-
const { node, getPos, decorations, innerDecorations } = nodeProps;
|
|
71
|
-
const OuterTag = as ?? node.type.isInline ? "span" : "div";
|
|
72
|
-
const { editor } = (0, _react.useCurrentEditor)();
|
|
73
|
-
const extensionManager = editor?.extensionManager ?? null;
|
|
74
|
-
const extensions = extensionManager?.extensions ?? null;
|
|
75
|
-
const selected = (0, _useIsNodeSelected.useIsNodeSelected)();
|
|
76
|
-
(0, _useStopEvent.useStopEvent)((_, event)=>{
|
|
77
|
-
if (stopEvent) {
|
|
78
|
-
return stopEvent.call({
|
|
79
|
-
name: extension.name,
|
|
80
|
-
editor,
|
|
81
|
-
type: node.type
|
|
82
|
-
}, {
|
|
83
|
-
event
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
return false;
|
|
87
|
-
});
|
|
88
|
-
(0, _useIgnoreMutation.useIgnoreMutation)((_, mutation)=>{
|
|
89
|
-
if (ignoreMutation) {
|
|
90
|
-
return ignoreMutation.call({
|
|
91
|
-
name: extension.name,
|
|
92
|
-
editor,
|
|
93
|
-
type: node.type
|
|
94
|
-
}, {
|
|
95
|
-
mutation
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
return false;
|
|
99
|
-
});
|
|
100
|
-
// This is just a dummy ref to satisfy Tiptap's types
|
|
101
|
-
const innerRef = (0, _react1.useRef)(null);
|
|
102
|
-
const htmlAttributes = (0, _react1.useMemo)(()=>{
|
|
103
|
-
if (!extensions) return {};
|
|
104
|
-
const attributes = (0, _core.getAttributesFromExtensions)(extensions);
|
|
105
|
-
const extensionAttributes = attributes.filter((attribute)=>attribute.type === extension.name);
|
|
106
|
-
return (0, _core.getRenderedAttributes)(node, extensionAttributes);
|
|
107
|
-
}, [
|
|
108
|
-
extensions,
|
|
109
|
-
node
|
|
110
|
-
]);
|
|
111
|
-
const { extraClassName, htmlProps } = (0, _react1.useMemo)(()=>{
|
|
112
|
-
if (!attrs) return {};
|
|
113
|
-
const resolvedAttrs = typeof attrs === "function" ? attrs({
|
|
114
|
-
node,
|
|
115
|
-
HTMLAttributes: htmlAttributes
|
|
116
|
-
}) : attrs;
|
|
117
|
-
const { className: extraClassName, ...htmlProps } = (0, _props.htmlAttrsToReactProps)(resolvedAttrs);
|
|
118
|
-
return {
|
|
119
|
-
extraClassName,
|
|
120
|
-
htmlProps
|
|
121
|
-
};
|
|
122
|
-
}, [
|
|
123
|
-
htmlAttributes,
|
|
124
|
-
node
|
|
125
|
-
]);
|
|
126
|
-
const finalClassName = (0, _classnames.default)("react-renderer", `node-${node.type.name}`, className, extraClassName, {
|
|
127
|
-
"ProseMirror-selectednode": selected
|
|
128
|
-
});
|
|
129
|
-
const updateAttributes = (0, _useEditorEventCallback.useEditorEventCallback)((_, attributes)=>{
|
|
130
|
-
if (!editor) {
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
editor.commands.command((param)=>{
|
|
134
|
-
let { tr } = param;
|
|
135
|
-
const pos = getPos();
|
|
136
|
-
tr.setNodeMarkup(pos, undefined, {
|
|
137
|
-
...node.attrs,
|
|
138
|
-
...attributes
|
|
139
|
-
});
|
|
140
|
-
return true;
|
|
141
|
-
});
|
|
142
|
-
});
|
|
143
|
-
const deleteNode = (0, _useEditorEventCallback.useEditorEventCallback)(()=>{
|
|
144
|
-
if (!editor) {
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
const from = getPos();
|
|
148
|
-
const to = from + node.nodeSize;
|
|
149
|
-
editor.commands.deleteRange({
|
|
150
|
-
from,
|
|
151
|
-
to
|
|
152
|
-
});
|
|
153
|
-
});
|
|
154
|
-
const nodeViewContent = (0, _react1.useMemo)(()=>/*#__PURE__*/ _react1.default.createElement(InnerTag, {
|
|
155
|
-
"data-node-view-content-inner": node.type.name,
|
|
156
|
-
style: {
|
|
157
|
-
whitespace: "inherit"
|
|
158
|
-
}
|
|
159
|
-
}, children), [
|
|
160
|
-
children,
|
|
161
|
-
node.type.name
|
|
162
|
-
]);
|
|
163
|
-
if (!editor) return null;
|
|
164
|
-
return /*#__PURE__*/ _react1.default.createElement(_react.ReactNodeViewContentProvider, {
|
|
165
|
-
content: nodeViewContent
|
|
166
|
-
}, /*#__PURE__*/ _react1.default.createElement(OuterTag, {
|
|
167
|
-
ref: ref,
|
|
168
|
-
className: finalClassName,
|
|
169
|
-
...props,
|
|
170
|
-
...htmlProps
|
|
171
|
-
}, /*#__PURE__*/ _react1.default.createElement(WrappedComponent, {
|
|
172
|
-
ref: innerRef,
|
|
173
|
-
node: node,
|
|
174
|
-
getPos: getPos,
|
|
175
|
-
view: editor.view,
|
|
176
|
-
editor: editor,
|
|
177
|
-
decorations: decorations,
|
|
178
|
-
innerDecorations: innerDecorations,
|
|
179
|
-
extension: extension,
|
|
180
|
-
HTMLAttributes: htmlAttributes,
|
|
181
|
-
selected: selected,
|
|
182
|
-
updateAttributes: updateAttributes,
|
|
183
|
-
deleteNode: deleteNode
|
|
184
|
-
})));
|
|
185
|
-
}));
|
|
186
|
-
TiptapNodeView.displayName = `TiptapNodeView(${WrappedComponent.displayName ?? "Anonymous"})`;
|
|
187
|
-
return TiptapNodeView;
|
|
188
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { Editor } from "@tiptap/core";
|
|
2
|
-
import { EditorState } from "prosemirror-state";
|
|
3
|
-
import { StaticEditorView } from "../StaticEditorView.js";
|
|
4
|
-
export class TiptapEditor extends Editor {
|
|
5
|
-
constructor(options = {}){
|
|
6
|
-
super({
|
|
7
|
-
...options,
|
|
8
|
-
element: null
|
|
9
|
-
});
|
|
10
|
-
}
|
|
11
|
-
get view() {
|
|
12
|
-
return(// @ts-expect-error private property
|
|
13
|
-
this.editorView ?? new StaticEditorView({
|
|
14
|
-
state: EditorState.create({
|
|
15
|
-
schema: this.extensionManager.schema
|
|
16
|
-
}),
|
|
17
|
-
...this.options.editorProps,
|
|
18
|
-
attributes: {
|
|
19
|
-
role: "textbox",
|
|
20
|
-
...this.extensionManager.attributes
|
|
21
|
-
}
|
|
22
|
-
}));
|
|
23
|
-
}
|
|
24
|
-
}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import React, { useSyncExternalStore } from "react";
|
|
2
|
-
import { createPortal } from "react-dom";
|
|
3
|
-
import { ProseMirrorDoc } from "../components/ProseMirrorDoc.js";
|
|
4
|
-
import { useEditorEffect } from "../hooks/useEditorEffect.js";
|
|
5
|
-
/**
|
|
6
|
-
* This component renders all of the editor's registered "React renderers".
|
|
7
|
-
*/ const Portals = (param)=>{
|
|
8
|
-
let { contentComponent } = param;
|
|
9
|
-
const renderers = useSyncExternalStore(contentComponent.subscribe, contentComponent.getSnapshot, contentComponent.getServerSnapshot);
|
|
10
|
-
return /*#__PURE__*/ React.createElement(React.Fragment, null, Object.values(renderers));
|
|
11
|
-
};
|
|
12
|
-
function getInstance() {
|
|
13
|
-
const subscribers = new Set();
|
|
14
|
-
let renderers = {};
|
|
15
|
-
return {
|
|
16
|
-
/**
|
|
17
|
-
* Subscribe to the editor instance's changes.
|
|
18
|
-
*/ subscribe (callback) {
|
|
19
|
-
subscribers.add(callback);
|
|
20
|
-
return ()=>{
|
|
21
|
-
subscribers.delete(callback);
|
|
22
|
-
};
|
|
23
|
-
},
|
|
24
|
-
getSnapshot () {
|
|
25
|
-
return renderers;
|
|
26
|
-
},
|
|
27
|
-
getServerSnapshot () {
|
|
28
|
-
return renderers;
|
|
29
|
-
},
|
|
30
|
-
/**
|
|
31
|
-
* Adds a new React Renderer to the editor.
|
|
32
|
-
*/ setRenderer (id, renderer) {
|
|
33
|
-
renderers = {
|
|
34
|
-
...renderers,
|
|
35
|
-
[id]: /*#__PURE__*/ createPortal(renderer.reactElement, renderer.element, id)
|
|
36
|
-
};
|
|
37
|
-
subscribers.forEach((subscriber)=>subscriber());
|
|
38
|
-
},
|
|
39
|
-
/**
|
|
40
|
-
* Removes a React Renderer from the editor.
|
|
41
|
-
*/ removeRenderer (id) {
|
|
42
|
-
const nextRenderers = {
|
|
43
|
-
...renderers
|
|
44
|
-
};
|
|
45
|
-
delete nextRenderers[id];
|
|
46
|
-
renderers = nextRenderers;
|
|
47
|
-
subscribers.forEach((subscriber)=>subscriber());
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
export function TiptapEditorContent(param) {
|
|
52
|
-
let { editor: editorProp, ...props } = param;
|
|
53
|
-
const editor = editorProp;
|
|
54
|
-
useEditorEffect((view)=>{
|
|
55
|
-
if (editor.view === view) {
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
// @ts-expect-error private property
|
|
59
|
-
editor.editorView = view;
|
|
60
|
-
editor.contentComponent = getInstance();
|
|
61
|
-
// @ts-expect-error private method
|
|
62
|
-
editor.injectCSS();
|
|
63
|
-
const dom = view.dom;
|
|
64
|
-
dom.editor = editor;
|
|
65
|
-
setTimeout(()=>{
|
|
66
|
-
if (editor.isDestroyed) {
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
editor.commands.focus(editor.options.autofocus);
|
|
70
|
-
editor.emit("create", {
|
|
71
|
-
editor
|
|
72
|
-
});
|
|
73
|
-
editor.isInitialized = true;
|
|
74
|
-
});
|
|
75
|
-
return ()=>{
|
|
76
|
-
editor.isInitialized = false;
|
|
77
|
-
editor.contentComponent = null;
|
|
78
|
-
};
|
|
79
|
-
}, [
|
|
80
|
-
editor
|
|
81
|
-
]);
|
|
82
|
-
return /*#__PURE__*/ React.createElement(React.Fragment, null, /*#__PURE__*/ React.createElement(ProseMirrorDoc, props), editor?.contentComponent && /*#__PURE__*/ React.createElement(Portals, {
|
|
83
|
-
contentComponent: editor.contentComponent
|
|
84
|
-
}));
|
|
85
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { EditorContext } from "@tiptap/react";
|
|
2
|
-
import React, { useCallback, useMemo } from "react";
|
|
3
|
-
import { ProseMirror } from "../components/ProseMirror.js";
|
|
4
|
-
import { useForceUpdate } from "../hooks/useForceUpdate.js";
|
|
5
|
-
/**
|
|
6
|
-
* Render a Tiptap-compatible React ProseMirror editor.
|
|
7
|
-
*/ export function TiptapEditorView(param) {
|
|
8
|
-
let { editor, nodeViews, children } = param;
|
|
9
|
-
const forceUpdate = useForceUpdate();
|
|
10
|
-
const dispatchTransaction = useCallback((tr)=>{
|
|
11
|
-
// @ts-expect-error calling private method
|
|
12
|
-
editor.dispatchTransaction(tr);
|
|
13
|
-
// Tiptap's dispatchTransaction doesn't trigger
|
|
14
|
-
// a re-render, so we need to manually force
|
|
15
|
-
// one to ensure that React stays in sync.
|
|
16
|
-
forceUpdate();
|
|
17
|
-
}, [
|
|
18
|
-
editor,
|
|
19
|
-
forceUpdate
|
|
20
|
-
]);
|
|
21
|
-
const initialEditorProps = {
|
|
22
|
-
...editor.options.editorProps,
|
|
23
|
-
attributes: {
|
|
24
|
-
role: "textbox",
|
|
25
|
-
...editor.options.editorProps?.attributes
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
const { nodeViews: customNodeViews, markViews } = editor.isDestroyed ? {
|
|
29
|
-
nodeViews: undefined,
|
|
30
|
-
markViews: undefined
|
|
31
|
-
} : editor.view.props;
|
|
32
|
-
const contextValue = useMemo(()=>({
|
|
33
|
-
editor
|
|
34
|
-
}), [
|
|
35
|
-
editor
|
|
36
|
-
]);
|
|
37
|
-
return /*#__PURE__*/ React.createElement(ProseMirror, {
|
|
38
|
-
className: "tiptap",
|
|
39
|
-
...initialEditorProps,
|
|
40
|
-
markViews: markViews,
|
|
41
|
-
nodeViews: nodeViews,
|
|
42
|
-
customNodeViews: customNodeViews,
|
|
43
|
-
state: editor.isDestroyed || editor.state.plugins.length ? editor.state : editor.state.reconfigure({
|
|
44
|
-
plugins: editor.extensionManager.plugins
|
|
45
|
-
}),
|
|
46
|
-
dispatchTransaction: dispatchTransaction
|
|
47
|
-
}, /*#__PURE__*/ React.createElement(EditorContext.Provider, {
|
|
48
|
-
value: contextValue
|
|
49
|
-
}, children));
|
|
50
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { Extension } from "@tiptap/core";
|
|
2
|
-
import { reactKeys } from "../../plugins/reactKeys.js";
|
|
3
|
-
export const ReactProseMirror = Extension.create({
|
|
4
|
-
name: "@handlewithcare/react-prosemirror/reactKeys",
|
|
5
|
-
addProseMirrorPlugins () {
|
|
6
|
-
return [
|
|
7
|
-
reactKeys()
|
|
8
|
-
];
|
|
9
|
-
}
|
|
10
|
-
});
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { useEditor } from "@tiptap/react";
|
|
2
|
-
import { StaticEditorView } from "../../StaticEditorView.js";
|
|
3
|
-
export function useTiptapEditor(options, deps) {
|
|
4
|
-
const editor = useEditor({
|
|
5
|
-
...options,
|
|
6
|
-
element: null
|
|
7
|
-
}, deps);
|
|
8
|
-
// @ts-expect-error private property
|
|
9
|
-
editor.editorView ??= new StaticEditorView({
|
|
10
|
-
// @ts-expect-error private property
|
|
11
|
-
state: editor.editorState,
|
|
12
|
-
...editor.options.editorProps,
|
|
13
|
-
attributes: {
|
|
14
|
-
role: "textbox",
|
|
15
|
-
...editor.extensionManager.attributes
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
return editor;
|
|
19
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { useCurrentEditor } from "@tiptap/react";
|
|
2
|
-
import { useContext } from "react";
|
|
3
|
-
import { ReactEditorView } from "../../ReactEditorView.js";
|
|
4
|
-
import { EditorContext } from "../../contexts/EditorContext.js";
|
|
5
|
-
import { useEditorEffect } from "../../hooks/useEditorEffect.js";
|
|
6
|
-
/**
|
|
7
|
-
* Registers a layout effect to run after the EditorView has
|
|
8
|
-
* been updated with the latest EditorState and Decorations.
|
|
9
|
-
*
|
|
10
|
-
* Effects can take a Tiptap Editor instance as an argument.
|
|
11
|
-
* This hook should be used to execute layout effects that
|
|
12
|
-
* depend on the Editor, such as for positioning DOM
|
|
13
|
-
* nodes based on ProseMirror positions.
|
|
14
|
-
*
|
|
15
|
-
* Layout effects registered with this hook still fire
|
|
16
|
-
* synchronously after all DOM mutations, but they do so
|
|
17
|
-
* _after_ the Editor has been updated, even when the
|
|
18
|
-
* Editor lives in an ancestor component.
|
|
19
|
-
*
|
|
20
|
-
* This hook can only be used in a component that is mounted
|
|
21
|
-
* as a child of the TiptapEditorView component, including
|
|
22
|
-
* React node view components.
|
|
23
|
-
*/ export function useTiptapEditorEffect(effect, dependencies) {
|
|
24
|
-
const { view } = useContext(EditorContext);
|
|
25
|
-
const { editor } = useCurrentEditor();
|
|
26
|
-
useEditorEffect(()=>{
|
|
27
|
-
if (editor?.view instanceof ReactEditorView && view instanceof ReactEditorView) {
|
|
28
|
-
return effect(editor);
|
|
29
|
-
}
|
|
30
|
-
// The rules of hooks want to be able to statically
|
|
31
|
-
// verify the dependencies for the effect, but this will
|
|
32
|
-
// have already happened at the call-site.
|
|
33
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
34
|
-
}, dependencies && [
|
|
35
|
-
editor,
|
|
36
|
-
view,
|
|
37
|
-
...dependencies
|
|
38
|
-
]);
|
|
39
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { useCurrentEditor } from "@tiptap/react";
|
|
2
|
-
import { useCallback, useRef } from "react";
|
|
3
|
-
import { useEditorEffect } from "../../hooks/useEditorEffect.js";
|
|
4
|
-
function assertEditor(editor) {
|
|
5
|
-
if (editor) return;
|
|
6
|
-
throw new DOMException("Tiptap Editor is not initialized", "InvalidStateError");
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Returns a stable function reference to be used as an
|
|
10
|
-
* event handler callback.
|
|
11
|
-
*
|
|
12
|
-
* The callback will be called with the Tiptap Editor instance
|
|
13
|
-
* as its first argument.
|
|
14
|
-
*
|
|
15
|
-
* This hook can only be used in a component that is mounted
|
|
16
|
-
* as a child of the TiptapEditorView component, including
|
|
17
|
-
* React node view components.
|
|
18
|
-
*/ export function useTiptapEditorEventCallback(callback) {
|
|
19
|
-
const ref = useRef(callback);
|
|
20
|
-
const { editor } = useCurrentEditor();
|
|
21
|
-
useEditorEffect(()=>{
|
|
22
|
-
ref.current = callback;
|
|
23
|
-
}, [
|
|
24
|
-
callback
|
|
25
|
-
]);
|
|
26
|
-
return useCallback(function() {
|
|
27
|
-
for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
|
|
28
|
-
args[_key] = arguments[_key];
|
|
29
|
-
}
|
|
30
|
-
assertEditor(editor);
|
|
31
|
-
return ref.current(editor, ...args);
|
|
32
|
-
}, [
|
|
33
|
-
editor
|
|
34
|
-
]);
|
|
35
|
-
}
|
package/dist/esm/tiptap/index.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export { tiptapNodeView } from "./tiptapNodeView.js";
|
|
2
|
-
export { TiptapEditorView } from "./TiptapEditorView.js";
|
|
3
|
-
export { TiptapEditorContent } from "./TiptapEditorContent.js";
|
|
4
|
-
export { useTiptapEditorEffect } from "./hooks/useTiptapEditorEffect.js";
|
|
5
|
-
export { useTiptapEditorEventCallback } from "./hooks/useTiptapEditorEventCallback.js";
|
|
6
|
-
export { TiptapEditor } from "./TiptapEditor.js";
|
|
7
|
-
export { useTiptapEditor } from "./hooks/useTiptapEditor.js";
|
|
8
|
-
export { ReactProseMirror } from "./extensions/ReactProseMirror.js";
|
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
import { getAttributesFromExtensions, getRenderedAttributes } from "@tiptap/core";
|
|
2
|
-
import { ReactNodeViewContentProvider, useCurrentEditor } from "@tiptap/react";
|
|
3
|
-
import cx from "classnames";
|
|
4
|
-
import React, { forwardRef, memo, useMemo, useRef } from "react";
|
|
5
|
-
import { useEditorEventCallback } from "../hooks/useEditorEventCallback.js";
|
|
6
|
-
import { useIgnoreMutation } from "../hooks/useIgnoreMutation.js";
|
|
7
|
-
import { useIsNodeSelected } from "../hooks/useIsNodeSelected.js";
|
|
8
|
-
import { useStopEvent } from "../hooks/useStopEvent.js";
|
|
9
|
-
import { htmlAttrsToReactProps } from "../props.js";
|
|
10
|
-
/**
|
|
11
|
-
* Convert a Tiptap node view component to a React ProseMirror node view component
|
|
12
|
-
*
|
|
13
|
-
* Given a Tiptap-compatible React component and a Tiptap extension, returns
|
|
14
|
-
* a React component that can be passed to React ProseMirror as a custom node view.
|
|
15
|
-
*
|
|
16
|
-
* Example:
|
|
17
|
-
*
|
|
18
|
-
* ```tsx
|
|
19
|
-
* const nodeViews = {
|
|
20
|
-
* codeBlock: nodeView({
|
|
21
|
-
* component: function CodeBlock(nodeViewProps) {
|
|
22
|
-
* return (
|
|
23
|
-
* <AnnotatableNodeViewWrapper {...nodeViewProps}>
|
|
24
|
-
* <pre>
|
|
25
|
-
* <NodeViewContent as="code" />
|
|
26
|
-
* </pre>
|
|
27
|
-
* </AnnotatableNodeViewWrapper>
|
|
28
|
-
* )
|
|
29
|
-
* },
|
|
30
|
-
* extension: CodeBlockExtension,
|
|
31
|
-
* }),
|
|
32
|
-
* }
|
|
33
|
-
* ```
|
|
34
|
-
*/ export function tiptapNodeView(param) {
|
|
35
|
-
let { component: WrappedComponent, extension, as, className = "", attrs, contentDOMElementTag: InnerTag = "div", stopEvent, ignoreMutation } = param;
|
|
36
|
-
const TiptapNodeView = /*#__PURE__*/ memo(/*#__PURE__*/ forwardRef(function TiptapNodeView(param, ref) {
|
|
37
|
-
let { children, nodeProps, ...props } = param;
|
|
38
|
-
const { node, getPos, decorations, innerDecorations } = nodeProps;
|
|
39
|
-
const OuterTag = as ?? node.type.isInline ? "span" : "div";
|
|
40
|
-
const { editor } = useCurrentEditor();
|
|
41
|
-
const extensionManager = editor?.extensionManager ?? null;
|
|
42
|
-
const extensions = extensionManager?.extensions ?? null;
|
|
43
|
-
const selected = useIsNodeSelected();
|
|
44
|
-
useStopEvent((_, event)=>{
|
|
45
|
-
if (stopEvent) {
|
|
46
|
-
return stopEvent.call({
|
|
47
|
-
name: extension.name,
|
|
48
|
-
editor,
|
|
49
|
-
type: node.type
|
|
50
|
-
}, {
|
|
51
|
-
event
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
return false;
|
|
55
|
-
});
|
|
56
|
-
useIgnoreMutation((_, mutation)=>{
|
|
57
|
-
if (ignoreMutation) {
|
|
58
|
-
return ignoreMutation.call({
|
|
59
|
-
name: extension.name,
|
|
60
|
-
editor,
|
|
61
|
-
type: node.type
|
|
62
|
-
}, {
|
|
63
|
-
mutation
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
return false;
|
|
67
|
-
});
|
|
68
|
-
// This is just a dummy ref to satisfy Tiptap's types
|
|
69
|
-
const innerRef = useRef(null);
|
|
70
|
-
const htmlAttributes = useMemo(()=>{
|
|
71
|
-
if (!extensions) return {};
|
|
72
|
-
const attributes = getAttributesFromExtensions(extensions);
|
|
73
|
-
const extensionAttributes = attributes.filter((attribute)=>attribute.type === extension.name);
|
|
74
|
-
return getRenderedAttributes(node, extensionAttributes);
|
|
75
|
-
}, [
|
|
76
|
-
extensions,
|
|
77
|
-
node
|
|
78
|
-
]);
|
|
79
|
-
const { extraClassName, htmlProps } = useMemo(()=>{
|
|
80
|
-
if (!attrs) return {};
|
|
81
|
-
const resolvedAttrs = typeof attrs === "function" ? attrs({
|
|
82
|
-
node,
|
|
83
|
-
HTMLAttributes: htmlAttributes
|
|
84
|
-
}) : attrs;
|
|
85
|
-
const { className: extraClassName, ...htmlProps } = htmlAttrsToReactProps(resolvedAttrs);
|
|
86
|
-
return {
|
|
87
|
-
extraClassName,
|
|
88
|
-
htmlProps
|
|
89
|
-
};
|
|
90
|
-
}, [
|
|
91
|
-
htmlAttributes,
|
|
92
|
-
node
|
|
93
|
-
]);
|
|
94
|
-
const finalClassName = cx("react-renderer", `node-${node.type.name}`, className, extraClassName, {
|
|
95
|
-
"ProseMirror-selectednode": selected
|
|
96
|
-
});
|
|
97
|
-
const updateAttributes = useEditorEventCallback((_, attributes)=>{
|
|
98
|
-
if (!editor) {
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
editor.commands.command((param)=>{
|
|
102
|
-
let { tr } = param;
|
|
103
|
-
const pos = getPos();
|
|
104
|
-
tr.setNodeMarkup(pos, undefined, {
|
|
105
|
-
...node.attrs,
|
|
106
|
-
...attributes
|
|
107
|
-
});
|
|
108
|
-
return true;
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
const deleteNode = useEditorEventCallback(()=>{
|
|
112
|
-
if (!editor) {
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
const from = getPos();
|
|
116
|
-
const to = from + node.nodeSize;
|
|
117
|
-
editor.commands.deleteRange({
|
|
118
|
-
from,
|
|
119
|
-
to
|
|
120
|
-
});
|
|
121
|
-
});
|
|
122
|
-
const nodeViewContent = useMemo(()=>/*#__PURE__*/ React.createElement(InnerTag, {
|
|
123
|
-
"data-node-view-content-inner": node.type.name,
|
|
124
|
-
style: {
|
|
125
|
-
whitespace: "inherit"
|
|
126
|
-
}
|
|
127
|
-
}, children), [
|
|
128
|
-
children,
|
|
129
|
-
node.type.name
|
|
130
|
-
]);
|
|
131
|
-
if (!editor) return null;
|
|
132
|
-
return /*#__PURE__*/ React.createElement(ReactNodeViewContentProvider, {
|
|
133
|
-
content: nodeViewContent
|
|
134
|
-
}, /*#__PURE__*/ React.createElement(OuterTag, {
|
|
135
|
-
ref: ref,
|
|
136
|
-
className: finalClassName,
|
|
137
|
-
...props,
|
|
138
|
-
...htmlProps
|
|
139
|
-
}, /*#__PURE__*/ React.createElement(WrappedComponent, {
|
|
140
|
-
ref: innerRef,
|
|
141
|
-
node: node,
|
|
142
|
-
getPos: getPos,
|
|
143
|
-
view: editor.view,
|
|
144
|
-
editor: editor,
|
|
145
|
-
decorations: decorations,
|
|
146
|
-
innerDecorations: innerDecorations,
|
|
147
|
-
extension: extension,
|
|
148
|
-
HTMLAttributes: htmlAttributes,
|
|
149
|
-
selected: selected,
|
|
150
|
-
updateAttributes: updateAttributes,
|
|
151
|
-
deleteNode: deleteNode
|
|
152
|
-
})));
|
|
153
|
-
}));
|
|
154
|
-
TiptapNodeView.displayName = `TiptapNodeView(${WrappedComponent.displayName ?? "Anonymous"})`;
|
|
155
|
-
return TiptapNodeView;
|
|
156
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { Editor } from "@tiptap/core";
|
|
2
|
-
import { ReactRenderer } from "@tiptap/react";
|
|
3
|
-
import React, { ForwardedRef, HTMLProps, ReactPortal } from "react";
|
|
4
|
-
export type ContentComponent = {
|
|
5
|
-
setRenderer(id: string, renderer: ReactRenderer): void;
|
|
6
|
-
removeRenderer(id: string): void;
|
|
7
|
-
subscribe: (callback: () => void) => () => void;
|
|
8
|
-
getSnapshot: () => Record<string, ReactPortal>;
|
|
9
|
-
getServerSnapshot: () => Record<string, ReactPortal>;
|
|
10
|
-
};
|
|
11
|
-
export interface EditorContentProps extends HTMLProps<HTMLDivElement> {
|
|
12
|
-
editor: Editor | null;
|
|
13
|
-
innerRef?: ForwardedRef<HTMLDivElement | null>;
|
|
14
|
-
}
|
|
15
|
-
interface Props extends Omit<HTMLProps<HTMLElement>, "as"> {
|
|
16
|
-
editor: Editor;
|
|
17
|
-
}
|
|
18
|
-
export declare function TiptapEditorContent({ editor: editorProp, ...props }: Props): React.JSX.Element;
|
|
19
|
-
export {};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { Editor } from "@tiptap/core";
|
|
2
|
-
import React, { ComponentType, ReactNode } from "react";
|
|
3
|
-
import { NodeViewComponentProps } from "../components/NodeViewComponentProps.js";
|
|
4
|
-
interface Props {
|
|
5
|
-
editor: Editor;
|
|
6
|
-
nodeViews?: Record<string, ComponentType<NodeViewComponentProps>>;
|
|
7
|
-
children?: ReactNode;
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* Render a Tiptap-compatible React ProseMirror editor.
|
|
11
|
-
*/
|
|
12
|
-
export declare function TiptapEditorView({ editor, nodeViews, children }: Props): React.JSX.Element;
|
|
13
|
-
export {};
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { useEditor } from "@tiptap/react";
|
|
2
|
-
import { DependencyList } from "react";
|
|
3
|
-
export type UseTiptapEditorOptions = Omit<Parameters<typeof useEditor>[0], "element">;
|
|
4
|
-
export declare function useTiptapEditor(options: UseTiptapEditorOptions, deps?: DependencyList): import("@tiptap/core").Editor;
|