@openeditor/react 0.0.4
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 +24 -0
- package/dist/index.d.ts +100 -0
- package/dist/index.js +632 -0
- package/dist/index.js.map +1 -0
- package/package.json +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# `@openeditor/react`
|
|
2
|
+
|
|
3
|
+
Headless React bindings for OpenEditor's web editor runtime.
|
|
4
|
+
|
|
5
|
+
## Public surface
|
|
6
|
+
|
|
7
|
+
- `useOpenEditorController` for editor state, commands, document exports, and selection state
|
|
8
|
+
- `OpenEditorContent` for the editable Tiptap-backed content surface
|
|
9
|
+
- `OpenEditorViewer` for read-only React rendering
|
|
10
|
+
- `getDefaultSlashMenuItems` for UI packages that want the built-in insert actions
|
|
11
|
+
|
|
12
|
+
This package intentionally does not import CSS and does not render styled menus. Use `@openeditor/ui` for the optional styled components.
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
import { OpenEditorContent, useOpenEditorController } from "@openeditor/react";
|
|
18
|
+
|
|
19
|
+
export function Example() {
|
|
20
|
+
const controller = useOpenEditorController();
|
|
21
|
+
|
|
22
|
+
return <OpenEditorContent controller={controller} />;
|
|
23
|
+
}
|
|
24
|
+
```
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { OpenEditorDocument, ProseMirrorNode } from '@openeditor/core';
|
|
4
|
+
import { toExportBundle } from '@openeditor/exporters';
|
|
5
|
+
import { OpenEditorInsertPresetKey } from '@openeditor/extensions';
|
|
6
|
+
export { seedDocument } from '@openeditor/extensions';
|
|
7
|
+
import { Editor } from '@tiptap/core';
|
|
8
|
+
|
|
9
|
+
type OpenEditorReactProps = {
|
|
10
|
+
initialDocument?: OpenEditorDocument;
|
|
11
|
+
editable?: boolean;
|
|
12
|
+
placeholder?: string;
|
|
13
|
+
onChange?: (document: OpenEditorDocument) => void;
|
|
14
|
+
onFilePasteDrop?: (file: File) => boolean;
|
|
15
|
+
slashMenuItems?: readonly OpenEditorSlashMenuItem[];
|
|
16
|
+
};
|
|
17
|
+
type OpenEditorReactConfig = OpenEditorReactProps;
|
|
18
|
+
type OpenEditorController = {
|
|
19
|
+
editor: Editor | null;
|
|
20
|
+
document: OpenEditorDocument;
|
|
21
|
+
exports: ReturnType<typeof toExportBundle>;
|
|
22
|
+
editable: boolean;
|
|
23
|
+
placeholder: string;
|
|
24
|
+
selectedBlock: OpenEditorInsertPresetKey;
|
|
25
|
+
setSelectedBlock: (blockName: OpenEditorInsertPresetKey) => void;
|
|
26
|
+
getContent: () => OpenEditorDocument;
|
|
27
|
+
setContent: (document: OpenEditorDocument) => void;
|
|
28
|
+
setParagraph: () => void;
|
|
29
|
+
toggleHeading: (level: 1 | 2 | 3 | 4 | 5 | 6) => void;
|
|
30
|
+
toggleBold: () => void;
|
|
31
|
+
toggleItalic: () => void;
|
|
32
|
+
toggleUnderline: () => void;
|
|
33
|
+
toggleStrike: () => void;
|
|
34
|
+
toggleInlineCode: () => void;
|
|
35
|
+
toggleBulletList: () => void;
|
|
36
|
+
toggleOrderedList: () => void;
|
|
37
|
+
toggleTaskList: () => void;
|
|
38
|
+
undo: () => void;
|
|
39
|
+
redo: () => void;
|
|
40
|
+
insertBlock: (blockName?: OpenEditorInsertPresetKey, range?: InsertRange) => void;
|
|
41
|
+
setLink: () => void;
|
|
42
|
+
moveSelectedBlock: (direction: -1 | 1) => void;
|
|
43
|
+
duplicateSelectedBlock: () => void;
|
|
44
|
+
deleteSelectedBlock: () => void;
|
|
45
|
+
slashMenuItems: readonly OpenEditorSlashMenuItem[];
|
|
46
|
+
slashState: SlashState | null;
|
|
47
|
+
selectionBubbleState: SelectionBubbleState | null;
|
|
48
|
+
};
|
|
49
|
+
type OpenEditorContentProps = {
|
|
50
|
+
controller: OpenEditorController;
|
|
51
|
+
className?: string;
|
|
52
|
+
};
|
|
53
|
+
type InsertRange = {
|
|
54
|
+
from: number;
|
|
55
|
+
to: number;
|
|
56
|
+
};
|
|
57
|
+
type SlashState = {
|
|
58
|
+
query: string;
|
|
59
|
+
from: number;
|
|
60
|
+
to: number;
|
|
61
|
+
left: number;
|
|
62
|
+
top: number;
|
|
63
|
+
};
|
|
64
|
+
type SelectionBubbleState = {
|
|
65
|
+
left: number;
|
|
66
|
+
top: number;
|
|
67
|
+
};
|
|
68
|
+
type OpenEditorSlashMenuItem = {
|
|
69
|
+
key: string;
|
|
70
|
+
label: string;
|
|
71
|
+
group: string;
|
|
72
|
+
keywords?: readonly string[];
|
|
73
|
+
run: (context: {
|
|
74
|
+
controller: OpenEditorController;
|
|
75
|
+
range: InsertRange;
|
|
76
|
+
}) => void;
|
|
77
|
+
};
|
|
78
|
+
type OpenEditorViewerRenderer = (context: {
|
|
79
|
+
node: ProseMirrorNode;
|
|
80
|
+
children: ReactNode;
|
|
81
|
+
}) => ReactNode;
|
|
82
|
+
type OpenEditorViewerProps = {
|
|
83
|
+
document: OpenEditorDocument;
|
|
84
|
+
className?: string;
|
|
85
|
+
renderers?: Partial<Record<string, OpenEditorViewerRenderer>>;
|
|
86
|
+
};
|
|
87
|
+
declare module "@tiptap/core" {
|
|
88
|
+
interface Commands<ReturnType> {
|
|
89
|
+
columns: {
|
|
90
|
+
insertColumns: (count?: 2 | 3 | 4) => ReturnType;
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
declare const useOpenEditorController: ({ initialDocument, editable, placeholder, onChange, onFilePasteDrop, slashMenuItems, }?: OpenEditorReactProps) => OpenEditorController;
|
|
95
|
+
declare const getDefaultSlashMenuItems: (controller: OpenEditorController) => OpenEditorSlashMenuItem[];
|
|
96
|
+
declare const OpenEditorContent: ({ controller, className, }: OpenEditorContentProps) => react.JSX.Element;
|
|
97
|
+
declare const OpenEditorViewer: ({ document, className, renderers, }: OpenEditorViewerProps) => react.JSX.Element;
|
|
98
|
+
declare const useOpenEditor: ({ initialDocument, editable, placeholder, onChange, onFilePasteDrop, slashMenuItems, }?: OpenEditorReactProps) => OpenEditorController;
|
|
99
|
+
|
|
100
|
+
export { type InsertRange, OpenEditorContent, type OpenEditorContentProps, type OpenEditorController, type OpenEditorReactConfig, type OpenEditorReactProps, type OpenEditorSlashMenuItem, OpenEditorViewer, type OpenEditorViewerProps, type OpenEditorViewerRenderer, type SelectionBubbleState, type SlashState, getDefaultSlashMenuItems, useOpenEditor, useOpenEditorController };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,632 @@
|
|
|
1
|
+
import { normalizeDocument, fromProseMirrorDocument, toProseMirrorDocument, moveTopLevelBlock, duplicateTopLevelBlock, deleteTopLevelBlock, findBlockSpecForNode } from '@openeditor/core';
|
|
2
|
+
import { toExportBundle } from '@openeditor/exporters';
|
|
3
|
+
import { seedDocument, openEditorInsertPresets, createOpenEditorInsertBlock, defaultBlockRegistry } from '@openeditor/extensions';
|
|
4
|
+
export { seedDocument } from '@openeditor/extensions';
|
|
5
|
+
import { Node, mergeAttributes, InputRule } from '@tiptap/core';
|
|
6
|
+
import HorizontalRule from '@tiptap/extension-horizontal-rule';
|
|
7
|
+
import Image from '@tiptap/extension-image';
|
|
8
|
+
import Link from '@tiptap/extension-link';
|
|
9
|
+
import Placeholder from '@tiptap/extension-placeholder';
|
|
10
|
+
import { Table } from '@tiptap/extension-table';
|
|
11
|
+
import TableCell from '@tiptap/extension-table-cell';
|
|
12
|
+
import TableHeader from '@tiptap/extension-table-header';
|
|
13
|
+
import TableRow from '@tiptap/extension-table-row';
|
|
14
|
+
import TaskItem from '@tiptap/extension-task-item';
|
|
15
|
+
import TaskList from '@tiptap/extension-task-list';
|
|
16
|
+
import TextAlign from '@tiptap/extension-text-align';
|
|
17
|
+
import Underline from '@tiptap/extension-underline';
|
|
18
|
+
import { NodeSelection, Plugin } from '@tiptap/pm/state';
|
|
19
|
+
import { ReplaceStep } from '@tiptap/pm/transform';
|
|
20
|
+
import { useEditor, EditorContent } from '@tiptap/react';
|
|
21
|
+
import StarterKit from '@tiptap/starter-kit';
|
|
22
|
+
import { useState, useMemo } from 'react';
|
|
23
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
24
|
+
|
|
25
|
+
// src/index.tsx
|
|
26
|
+
var COMMON_HTML_ATTRIBUTES = ["id", "class", "title", "lang", "dir", "data-id", "style"];
|
|
27
|
+
var LAYOUT_ATTRIBUTES = ["align", "width", "height"];
|
|
28
|
+
var URL_ATTRIBUTES = /* @__PURE__ */ new Set(["href", "src"]);
|
|
29
|
+
var FORBIDDEN_PASTE_TAGS = /* @__PURE__ */ new Set(["script", "iframe", "object", "embed", "meta", "base"]);
|
|
30
|
+
var createStandardAttributes = (attributeNames) => Object.fromEntries(
|
|
31
|
+
attributeNames.map((attribute) => [
|
|
32
|
+
attribute,
|
|
33
|
+
{
|
|
34
|
+
default: null,
|
|
35
|
+
parseHTML: (element) => element.getAttribute(attribute),
|
|
36
|
+
renderHTML: (attributes) => attributes[attribute] ? { [attribute]: attributes[attribute] } : {}
|
|
37
|
+
}
|
|
38
|
+
])
|
|
39
|
+
);
|
|
40
|
+
var isSafeUrl = (value, allowDataImage) => {
|
|
41
|
+
const normalized = value.trim().toLowerCase();
|
|
42
|
+
if (normalized.startsWith("javascript:") || normalized.startsWith("vbscript:")) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
if (normalized.startsWith("data:")) {
|
|
46
|
+
return allowDataImage && normalized.startsWith("data:image/");
|
|
47
|
+
}
|
|
48
|
+
return true;
|
|
49
|
+
};
|
|
50
|
+
var sanitizePastedHtml = (html) => {
|
|
51
|
+
const parser = new DOMParser();
|
|
52
|
+
const parsed = parser.parseFromString(html, "text/html");
|
|
53
|
+
const isFromOpenEditor = /data-openeditor-|oe-|node-/.test(html);
|
|
54
|
+
const preservedAttributes = {
|
|
55
|
+
a: ["href", "target", "rel"],
|
|
56
|
+
img: ["src", "alt", "width", "height"],
|
|
57
|
+
td: ["colspan", "rowspan"],
|
|
58
|
+
th: ["colspan", "rowspan", "scope"],
|
|
59
|
+
table: ["border", "cellpadding", "cellspacing"],
|
|
60
|
+
"*": ["id"]
|
|
61
|
+
};
|
|
62
|
+
for (const tag of FORBIDDEN_PASTE_TAGS) {
|
|
63
|
+
for (const element of Array.from(parsed.body.getElementsByTagName(tag))) {
|
|
64
|
+
element.remove();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
for (const element of Array.from(parsed.body.querySelectorAll("[href], [src]"))) {
|
|
68
|
+
const allowDataImage = element.tagName.toLowerCase() === "img";
|
|
69
|
+
for (const attribute of URL_ATTRIBUTES) {
|
|
70
|
+
const value = element.getAttribute(attribute);
|
|
71
|
+
if (value !== null && !isSafeUrl(value, allowDataImage)) {
|
|
72
|
+
element.removeAttribute(attribute);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (isFromOpenEditor) {
|
|
77
|
+
return parsed.body.innerHTML;
|
|
78
|
+
}
|
|
79
|
+
const sanitizeElement = (node) => {
|
|
80
|
+
if (node.nodeType === window.Node.ELEMENT_NODE) {
|
|
81
|
+
const element = node;
|
|
82
|
+
const tagName = element.tagName.toLowerCase();
|
|
83
|
+
const allowed = /* @__PURE__ */ new Set([...preservedAttributes[tagName] ?? [], ...preservedAttributes["*"] ?? []]);
|
|
84
|
+
for (const attribute of Array.from(element.attributes)) {
|
|
85
|
+
if (attribute.name.startsWith("data-") || !allowed.has(attribute.name)) {
|
|
86
|
+
element.removeAttribute(attribute.name);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
for (const child of Array.from(node.childNodes)) {
|
|
91
|
+
sanitizeElement(child);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
sanitizeElement(parsed.body);
|
|
95
|
+
return parsed.body.innerHTML;
|
|
96
|
+
};
|
|
97
|
+
var Columns = Node.create({
|
|
98
|
+
name: "columns",
|
|
99
|
+
group: "block",
|
|
100
|
+
content: "column+",
|
|
101
|
+
isolating: true,
|
|
102
|
+
defining: true,
|
|
103
|
+
addAttributes() {
|
|
104
|
+
return {
|
|
105
|
+
...createStandardAttributes([...COMMON_HTML_ATTRIBUTES, ...LAYOUT_ATTRIBUTES, "cellspacing"]),
|
|
106
|
+
count: {
|
|
107
|
+
default: 2,
|
|
108
|
+
parseHTML: (element) => Number(element.getAttribute("data-openeditor-columns") ?? 2),
|
|
109
|
+
renderHTML: (attributes) => ({
|
|
110
|
+
"data-openeditor-columns": attributes.count
|
|
111
|
+
})
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
},
|
|
115
|
+
parseHTML() {
|
|
116
|
+
return [{ tag: "section[data-openeditor-columns]" }];
|
|
117
|
+
},
|
|
118
|
+
renderHTML({ HTMLAttributes }) {
|
|
119
|
+
const count = Number(HTMLAttributes["data-openeditor-columns"] ?? HTMLAttributes.count ?? 2);
|
|
120
|
+
return [
|
|
121
|
+
"section",
|
|
122
|
+
mergeAttributes(
|
|
123
|
+
{
|
|
124
|
+
class: "oe-columns",
|
|
125
|
+
"data-openeditor-columns": count,
|
|
126
|
+
style: `--oe-column-count:${Math.min(Math.max(count, 2), 4)};${HTMLAttributes.style ?? ""}`
|
|
127
|
+
},
|
|
128
|
+
HTMLAttributes
|
|
129
|
+
),
|
|
130
|
+
0
|
|
131
|
+
];
|
|
132
|
+
},
|
|
133
|
+
addCommands() {
|
|
134
|
+
return {
|
|
135
|
+
insertColumns: (count = 2) => ({ commands }) => commands.insertContent({
|
|
136
|
+
type: "columns",
|
|
137
|
+
attrs: { count },
|
|
138
|
+
content: Array.from({ length: count }, (_, index) => ({
|
|
139
|
+
type: "column",
|
|
140
|
+
content: [
|
|
141
|
+
{
|
|
142
|
+
type: "paragraph",
|
|
143
|
+
content: [{ type: "text", text: `Column ${index + 1}` }]
|
|
144
|
+
}
|
|
145
|
+
]
|
|
146
|
+
}))
|
|
147
|
+
})
|
|
148
|
+
};
|
|
149
|
+
},
|
|
150
|
+
addKeyboardShortcuts() {
|
|
151
|
+
return {
|
|
152
|
+
Backspace: ({ editor }) => {
|
|
153
|
+
const { selection } = editor.state;
|
|
154
|
+
if (!(selection instanceof NodeSelection) || selection.node.type.name !== "columns") {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
const allColumnsEmpty = Array.from(
|
|
158
|
+
{ length: selection.node.childCount },
|
|
159
|
+
(_, index) => selection.node.child(index)
|
|
160
|
+
).every(
|
|
161
|
+
(column) => column.childCount === 1 && column.firstChild?.type.name === "paragraph" && column.firstChild.childCount === 0
|
|
162
|
+
);
|
|
163
|
+
if (!allColumnsEmpty) {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
editor.view.dispatch(
|
|
167
|
+
editor.state.tr.replaceWith(selection.from, selection.to, editor.state.schema.nodes.paragraph.create())
|
|
168
|
+
);
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
var Column = Node.create({
|
|
175
|
+
name: "column",
|
|
176
|
+
content: "block+",
|
|
177
|
+
isolating: true,
|
|
178
|
+
defining: true,
|
|
179
|
+
addAttributes() {
|
|
180
|
+
return createStandardAttributes([...COMMON_HTML_ATTRIBUTES, ...LAYOUT_ATTRIBUTES]);
|
|
181
|
+
},
|
|
182
|
+
parseHTML() {
|
|
183
|
+
return [{ tag: "div[data-openeditor-column]" }];
|
|
184
|
+
},
|
|
185
|
+
renderHTML({ HTMLAttributes }) {
|
|
186
|
+
return ["div", mergeAttributes({ "data-openeditor-column": "", class: "oe-column" }, HTMLAttributes), 0];
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
var Divider = HorizontalRule.extend({
|
|
190
|
+
addAttributes() {
|
|
191
|
+
return {
|
|
192
|
+
...createStandardAttributes(["class", "style"]),
|
|
193
|
+
class: {
|
|
194
|
+
default: "oe-divider"
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
},
|
|
198
|
+
addInputRules() {
|
|
199
|
+
return [
|
|
200
|
+
new InputRule({
|
|
201
|
+
find: /^(?:---|___|\*\*\*)$/,
|
|
202
|
+
handler: ({ state, range }) => {
|
|
203
|
+
const { tr } = state;
|
|
204
|
+
tr.insert(range.from - 1, this.type.create()).delete(tr.mapping.map(range.from), tr.mapping.map(range.to));
|
|
205
|
+
}
|
|
206
|
+
})
|
|
207
|
+
];
|
|
208
|
+
},
|
|
209
|
+
addProseMirrorPlugins() {
|
|
210
|
+
return [
|
|
211
|
+
new Plugin({
|
|
212
|
+
filterTransaction(transaction, state) {
|
|
213
|
+
const { selection } = state;
|
|
214
|
+
const isDividerSelection = selection instanceof NodeSelection && selection.node.type.name === "horizontalRule";
|
|
215
|
+
const isTypingOverDivider = transaction.steps.some(
|
|
216
|
+
(step) => step instanceof ReplaceStep && step.slice.content.size > 0
|
|
217
|
+
);
|
|
218
|
+
return !(isDividerSelection && transaction.docChanged && isTypingOverDivider);
|
|
219
|
+
}
|
|
220
|
+
})
|
|
221
|
+
];
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
var createEditorExtensions = (placeholder) => [
|
|
225
|
+
StarterKit.configure({ horizontalRule: false }),
|
|
226
|
+
Divider,
|
|
227
|
+
Image.configure({ allowBase64: true }),
|
|
228
|
+
Link.configure({ openOnClick: false }),
|
|
229
|
+
Underline,
|
|
230
|
+
TaskList,
|
|
231
|
+
TaskItem.configure({ nested: true }),
|
|
232
|
+
Table.configure({ resizable: true }),
|
|
233
|
+
TableRow,
|
|
234
|
+
TableHeader,
|
|
235
|
+
TableCell,
|
|
236
|
+
TextAlign.configure({ types: ["heading", "paragraph"] }),
|
|
237
|
+
Placeholder.configure({ placeholder }),
|
|
238
|
+
Columns,
|
|
239
|
+
Column
|
|
240
|
+
];
|
|
241
|
+
var getSlashState = (editor) => {
|
|
242
|
+
const { selection } = editor.state;
|
|
243
|
+
if (!selection.empty) {
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
const { $from } = selection;
|
|
247
|
+
const textBeforeCursor = $from.parent.textBetween(0, $from.parentOffset, "\n", "\n");
|
|
248
|
+
const match = /(?:^|\s)\/([\w -]*)$/.exec(textBeforeCursor);
|
|
249
|
+
if (!match) {
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
const query = match[1] ?? "";
|
|
253
|
+
const from = $from.pos - query.length - 1;
|
|
254
|
+
const to = $from.pos;
|
|
255
|
+
const coordinates = editor.view.coordsAtPos(to);
|
|
256
|
+
return {
|
|
257
|
+
query,
|
|
258
|
+
from,
|
|
259
|
+
to,
|
|
260
|
+
left: coordinates.left,
|
|
261
|
+
top: coordinates.bottom + 8
|
|
262
|
+
};
|
|
263
|
+
};
|
|
264
|
+
var getSelectionBubbleState = (editor) => {
|
|
265
|
+
const { selection } = editor.state;
|
|
266
|
+
if (selection instanceof NodeSelection && selection.node.type.name === "horizontalRule") {
|
|
267
|
+
return null;
|
|
268
|
+
}
|
|
269
|
+
if (selection.empty) {
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
const fromCoordinates = editor.view.coordsAtPos(selection.from);
|
|
273
|
+
const toCoordinates = editor.view.coordsAtPos(selection.to);
|
|
274
|
+
return {
|
|
275
|
+
left: (fromCoordinates.left + toCoordinates.right) / 2,
|
|
276
|
+
top: Math.min(fromCoordinates.top, toCoordinates.top) - 8
|
|
277
|
+
};
|
|
278
|
+
};
|
|
279
|
+
var getSelectedTopLevelIndex = (editor) => {
|
|
280
|
+
const { $from } = editor.state.selection;
|
|
281
|
+
const selectedTopLevelPosition = $from.depth > 0 ? $from.before(1) : 0;
|
|
282
|
+
let selectedIndex = 0;
|
|
283
|
+
editor.state.doc.forEach((_, offset, index) => {
|
|
284
|
+
if (offset <= selectedTopLevelPosition) {
|
|
285
|
+
selectedIndex = index;
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
return selectedIndex;
|
|
289
|
+
};
|
|
290
|
+
var useOpenEditorController = ({
|
|
291
|
+
initialDocument = seedDocument,
|
|
292
|
+
editable = true,
|
|
293
|
+
placeholder = "Start writing...",
|
|
294
|
+
onChange,
|
|
295
|
+
onFilePasteDrop,
|
|
296
|
+
slashMenuItems = []
|
|
297
|
+
} = {}) => {
|
|
298
|
+
const [document, setDocument] = useState(normalizeDocument(initialDocument));
|
|
299
|
+
const [selectedBlock, setSelectedBlock] = useState("paragraph");
|
|
300
|
+
const [slashState, setSlashState] = useState(null);
|
|
301
|
+
const [selectionBubbleState, setSelectionBubbleState] = useState(null);
|
|
302
|
+
const editor = useEditor({
|
|
303
|
+
extensions: createEditorExtensions(placeholder),
|
|
304
|
+
content: toProseMirrorDocument(normalizeDocument(initialDocument)),
|
|
305
|
+
editable,
|
|
306
|
+
editorProps: {
|
|
307
|
+
attributes: {
|
|
308
|
+
class: "oe-prosemirror",
|
|
309
|
+
"aria-label": "OpenEditor document"
|
|
310
|
+
},
|
|
311
|
+
transformPastedHTML: sanitizePastedHtml,
|
|
312
|
+
handlePaste: (_view, event) => {
|
|
313
|
+
const file = event.clipboardData?.files?.[0];
|
|
314
|
+
if (!file || !onFilePasteDrop?.(file)) {
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
317
|
+
event.preventDefault();
|
|
318
|
+
return true;
|
|
319
|
+
},
|
|
320
|
+
handleDrop: (_view, event, _slice, moved) => {
|
|
321
|
+
const file = event.dataTransfer?.files?.[0];
|
|
322
|
+
if (moved || !file || !onFilePasteDrop?.(file)) {
|
|
323
|
+
return false;
|
|
324
|
+
}
|
|
325
|
+
event.preventDefault();
|
|
326
|
+
return true;
|
|
327
|
+
}
|
|
328
|
+
},
|
|
329
|
+
onUpdate: ({ editor: currentEditor }) => {
|
|
330
|
+
const nextDocument = normalizeDocument(
|
|
331
|
+
fromProseMirrorDocument(
|
|
332
|
+
currentEditor.getJSON(),
|
|
333
|
+
initialDocument.meta
|
|
334
|
+
)
|
|
335
|
+
);
|
|
336
|
+
setDocument(nextDocument);
|
|
337
|
+
onChange?.(nextDocument);
|
|
338
|
+
setSlashState(getSlashState(currentEditor));
|
|
339
|
+
setSelectionBubbleState(getSelectionBubbleState(currentEditor));
|
|
340
|
+
},
|
|
341
|
+
onSelectionUpdate: ({ editor: currentEditor }) => {
|
|
342
|
+
setSlashState(getSlashState(currentEditor));
|
|
343
|
+
setSelectionBubbleState(getSelectionBubbleState(currentEditor));
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
const exports = useMemo(
|
|
347
|
+
() => toExportBundle(document),
|
|
348
|
+
[document]
|
|
349
|
+
);
|
|
350
|
+
const insertBlock = (blockName = selectedBlock, range) => {
|
|
351
|
+
if (!editor) {
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
const preset = openEditorInsertPresets.find((item) => item.key === blockName);
|
|
355
|
+
if (!preset) {
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
const chain = () => {
|
|
359
|
+
const commandChain = editor.chain().focus();
|
|
360
|
+
return range ? commandChain.deleteRange(range) : commandChain;
|
|
361
|
+
};
|
|
362
|
+
chain().insertContent(createOpenEditorInsertBlock(preset.key)).run();
|
|
363
|
+
setSlashState(null);
|
|
364
|
+
};
|
|
365
|
+
const setDocumentContent = (content) => {
|
|
366
|
+
if (!editor) {
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
editor.commands.setContent(toProseMirrorDocument(normalizeDocument({ ...document, content })));
|
|
370
|
+
};
|
|
371
|
+
const setContent = (nextDocument) => {
|
|
372
|
+
if (!editor) {
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
editor.commands.setContent(toProseMirrorDocument(normalizeDocument(nextDocument)));
|
|
376
|
+
};
|
|
377
|
+
const moveSelectedBlock = (direction) => {
|
|
378
|
+
if (!editor) {
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
const currentDocument = normalizeDocument(fromProseMirrorDocument(editor.getJSON(), document.meta));
|
|
382
|
+
const selectedIndex = getSelectedTopLevelIndex(editor);
|
|
383
|
+
const nextIndex = selectedIndex + direction;
|
|
384
|
+
if (nextIndex < 0 || nextIndex >= currentDocument.content.length) {
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
setDocumentContent(moveTopLevelBlock(currentDocument, selectedIndex, nextIndex).content);
|
|
388
|
+
};
|
|
389
|
+
const duplicateSelectedBlock = () => {
|
|
390
|
+
if (!editor) {
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
const currentDocument = normalizeDocument(fromProseMirrorDocument(editor.getJSON(), document.meta));
|
|
394
|
+
const selectedIndex = getSelectedTopLevelIndex(editor);
|
|
395
|
+
setDocumentContent(duplicateTopLevelBlock(currentDocument, selectedIndex).content);
|
|
396
|
+
};
|
|
397
|
+
const deleteSelectedBlock = () => {
|
|
398
|
+
if (!editor) {
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
const currentDocument = normalizeDocument(fromProseMirrorDocument(editor.getJSON(), document.meta));
|
|
402
|
+
const selectedIndex = getSelectedTopLevelIndex(editor);
|
|
403
|
+
setDocumentContent(deleteTopLevelBlock(currentDocument, selectedIndex).content);
|
|
404
|
+
};
|
|
405
|
+
const setLink = () => {
|
|
406
|
+
if (!editor) {
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
const previousUrl = editor.getAttributes("link").href;
|
|
410
|
+
const url = window.prompt("URL", previousUrl ?? "https://");
|
|
411
|
+
if (url === null) {
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
if (!url) {
|
|
415
|
+
editor.chain().focus().extendMarkRange("link").unsetLink().run();
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
editor.chain().focus().extendMarkRange("link").setLink({ href: url }).run();
|
|
419
|
+
};
|
|
420
|
+
const setParagraph = () => {
|
|
421
|
+
editor?.chain().focus().setParagraph().run();
|
|
422
|
+
};
|
|
423
|
+
const toggleHeading = (level) => {
|
|
424
|
+
editor?.chain().focus().toggleHeading({ level }).run();
|
|
425
|
+
};
|
|
426
|
+
const toggleBold = () => {
|
|
427
|
+
editor?.chain().focus().toggleBold().run();
|
|
428
|
+
};
|
|
429
|
+
const toggleItalic = () => {
|
|
430
|
+
editor?.chain().focus().toggleItalic().run();
|
|
431
|
+
};
|
|
432
|
+
const toggleUnderline = () => {
|
|
433
|
+
editor?.chain().focus().toggleUnderline().run();
|
|
434
|
+
};
|
|
435
|
+
const toggleStrike = () => {
|
|
436
|
+
editor?.chain().focus().toggleStrike().run();
|
|
437
|
+
};
|
|
438
|
+
const toggleInlineCode = () => {
|
|
439
|
+
editor?.chain().focus().toggleCode().run();
|
|
440
|
+
};
|
|
441
|
+
const toggleBulletList = () => {
|
|
442
|
+
editor?.chain().focus().toggleBulletList().run();
|
|
443
|
+
};
|
|
444
|
+
const toggleOrderedList = () => {
|
|
445
|
+
editor?.chain().focus().toggleOrderedList().run();
|
|
446
|
+
};
|
|
447
|
+
const toggleTaskList = () => {
|
|
448
|
+
editor?.chain().focus().toggleTaskList().run();
|
|
449
|
+
};
|
|
450
|
+
const undo = () => {
|
|
451
|
+
editor?.chain().focus().undo().run();
|
|
452
|
+
};
|
|
453
|
+
const redo = () => {
|
|
454
|
+
editor?.chain().focus().redo().run();
|
|
455
|
+
};
|
|
456
|
+
const controller = {
|
|
457
|
+
document,
|
|
458
|
+
editor,
|
|
459
|
+
exports,
|
|
460
|
+
editable,
|
|
461
|
+
placeholder,
|
|
462
|
+
selectedBlock,
|
|
463
|
+
setSelectedBlock,
|
|
464
|
+
getContent: () => document,
|
|
465
|
+
setContent,
|
|
466
|
+
setParagraph,
|
|
467
|
+
toggleHeading,
|
|
468
|
+
toggleBold,
|
|
469
|
+
toggleItalic,
|
|
470
|
+
toggleUnderline,
|
|
471
|
+
toggleStrike,
|
|
472
|
+
toggleInlineCode,
|
|
473
|
+
toggleBulletList,
|
|
474
|
+
toggleOrderedList,
|
|
475
|
+
toggleTaskList,
|
|
476
|
+
undo,
|
|
477
|
+
redo,
|
|
478
|
+
insertBlock,
|
|
479
|
+
setLink,
|
|
480
|
+
moveSelectedBlock,
|
|
481
|
+
duplicateSelectedBlock,
|
|
482
|
+
deleteSelectedBlock,
|
|
483
|
+
slashMenuItems,
|
|
484
|
+
slashState,
|
|
485
|
+
selectionBubbleState
|
|
486
|
+
};
|
|
487
|
+
return controller;
|
|
488
|
+
};
|
|
489
|
+
var getDefaultSlashMenuItems = (controller) => {
|
|
490
|
+
const internalController = controller;
|
|
491
|
+
return [
|
|
492
|
+
...openEditorInsertPresets.map((preset) => ({
|
|
493
|
+
key: preset.key,
|
|
494
|
+
label: preset.label,
|
|
495
|
+
group: preset.group,
|
|
496
|
+
keywords: [preset.key],
|
|
497
|
+
run: ({ controller: current, range }) => current.insertBlock(preset.key, range)
|
|
498
|
+
})),
|
|
499
|
+
{
|
|
500
|
+
key: "moveBlockUp",
|
|
501
|
+
label: "Move Block Up",
|
|
502
|
+
group: "block",
|
|
503
|
+
run: ({ range }) => {
|
|
504
|
+
internalController.editor?.chain().focus().deleteRange(range).run();
|
|
505
|
+
controller.moveSelectedBlock(-1);
|
|
506
|
+
}
|
|
507
|
+
},
|
|
508
|
+
{
|
|
509
|
+
key: "moveBlockDown",
|
|
510
|
+
label: "Move Block Down",
|
|
511
|
+
group: "block",
|
|
512
|
+
run: ({ range }) => {
|
|
513
|
+
internalController.editor?.chain().focus().deleteRange(range).run();
|
|
514
|
+
controller.moveSelectedBlock(1);
|
|
515
|
+
}
|
|
516
|
+
},
|
|
517
|
+
...controller.slashMenuItems
|
|
518
|
+
];
|
|
519
|
+
};
|
|
520
|
+
var renderTextWithMarks = (text, marks = [], key) => marks.reduceRight((children, mark, index) => {
|
|
521
|
+
const nodeKey = `${key}-${mark.type}-${index}`;
|
|
522
|
+
switch (mark.type) {
|
|
523
|
+
case "bold":
|
|
524
|
+
return /* @__PURE__ */ jsx("strong", { children }, nodeKey);
|
|
525
|
+
case "italic":
|
|
526
|
+
return /* @__PURE__ */ jsx("em", { children }, nodeKey);
|
|
527
|
+
case "underline":
|
|
528
|
+
return /* @__PURE__ */ jsx("u", { children }, nodeKey);
|
|
529
|
+
case "strike":
|
|
530
|
+
return /* @__PURE__ */ jsx("s", { children }, nodeKey);
|
|
531
|
+
case "code":
|
|
532
|
+
return /* @__PURE__ */ jsx("code", { children }, nodeKey);
|
|
533
|
+
case "link":
|
|
534
|
+
return /* @__PURE__ */ jsx("a", { href: typeof mark.attrs?.href === "string" ? mark.attrs.href : void 0, children }, nodeKey);
|
|
535
|
+
default:
|
|
536
|
+
return children;
|
|
537
|
+
}
|
|
538
|
+
}, text);
|
|
539
|
+
var renderViewerNode = (node, key, renderers) => {
|
|
540
|
+
if (node.type === "text") {
|
|
541
|
+
return renderTextWithMarks(node.text ?? "", node.marks, key);
|
|
542
|
+
}
|
|
543
|
+
const children = node.content?.map((child, index) => renderViewerNode(child, `${key}-${index}`, renderers)) ?? null;
|
|
544
|
+
const blockKey = findBlockSpecForNode(defaultBlockRegistry, node)?.name ?? node.type;
|
|
545
|
+
const customRenderer = renderers?.[blockKey];
|
|
546
|
+
if (customRenderer) {
|
|
547
|
+
return customRenderer({ node, children });
|
|
548
|
+
}
|
|
549
|
+
switch (blockKey) {
|
|
550
|
+
case "paragraph":
|
|
551
|
+
return /* @__PURE__ */ jsx("p", { children }, key);
|
|
552
|
+
case "heading": {
|
|
553
|
+
const level = typeof node.attrs?.level === "number" ? Math.min(Math.max(node.attrs.level, 1), 6) : 2;
|
|
554
|
+
switch (level) {
|
|
555
|
+
case 1:
|
|
556
|
+
return /* @__PURE__ */ jsx("h1", { children }, key);
|
|
557
|
+
case 2:
|
|
558
|
+
return /* @__PURE__ */ jsx("h2", { children }, key);
|
|
559
|
+
case 3:
|
|
560
|
+
return /* @__PURE__ */ jsx("h3", { children }, key);
|
|
561
|
+
case 4:
|
|
562
|
+
return /* @__PURE__ */ jsx("h4", { children }, key);
|
|
563
|
+
case 5:
|
|
564
|
+
return /* @__PURE__ */ jsx("h5", { children }, key);
|
|
565
|
+
default:
|
|
566
|
+
return /* @__PURE__ */ jsx("h6", { children }, key);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
case "bulletList":
|
|
570
|
+
return /* @__PURE__ */ jsx("ul", { children }, key);
|
|
571
|
+
case "orderedList":
|
|
572
|
+
return /* @__PURE__ */ jsx("ol", { children }, key);
|
|
573
|
+
case "taskList":
|
|
574
|
+
return /* @__PURE__ */ jsx("ul", { "data-type": "taskList", children }, key);
|
|
575
|
+
case "blockquote":
|
|
576
|
+
return /* @__PURE__ */ jsx("blockquote", { children }, key);
|
|
577
|
+
case "codeBlock":
|
|
578
|
+
return /* @__PURE__ */ jsx("pre", { children: /* @__PURE__ */ jsx("code", { children: node.content?.map((child) => child.text ?? "").join("") }) }, key);
|
|
579
|
+
case "divider":
|
|
580
|
+
return /* @__PURE__ */ jsx("hr", {}, key);
|
|
581
|
+
case "image":
|
|
582
|
+
return /* @__PURE__ */ jsx("img", { src: typeof node.attrs?.src === "string" ? node.attrs.src : "", alt: typeof node.attrs?.alt === "string" ? node.attrs.alt : "" }, key);
|
|
583
|
+
case "columns":
|
|
584
|
+
return /* @__PURE__ */ jsx("section", { children }, key);
|
|
585
|
+
case "table":
|
|
586
|
+
return /* @__PURE__ */ jsx("table", { children: /* @__PURE__ */ jsx("tbody", { children }) }, key);
|
|
587
|
+
default:
|
|
588
|
+
if (node.type === "column") {
|
|
589
|
+
return /* @__PURE__ */ jsx("div", { children }, key);
|
|
590
|
+
}
|
|
591
|
+
if (node.type === "tableRow") {
|
|
592
|
+
return /* @__PURE__ */ jsx("tr", { children }, key);
|
|
593
|
+
}
|
|
594
|
+
if (node.type === "tableHeader") {
|
|
595
|
+
return /* @__PURE__ */ jsx("th", { children }, key);
|
|
596
|
+
}
|
|
597
|
+
if (node.type === "tableCell") {
|
|
598
|
+
return /* @__PURE__ */ jsx("td", { children }, key);
|
|
599
|
+
}
|
|
600
|
+
if (node.type === "listItem") {
|
|
601
|
+
return /* @__PURE__ */ jsx("li", { children }, key);
|
|
602
|
+
}
|
|
603
|
+
if (node.type === "taskItem") {
|
|
604
|
+
const checked = Boolean(node.attrs?.checked);
|
|
605
|
+
return /* @__PURE__ */ jsxs("li", { "data-checked": checked ? "true" : "false", children: [
|
|
606
|
+
/* @__PURE__ */ jsx("label", { className: "oe-task-item-checkbox", "aria-hidden": "true", children: /* @__PURE__ */ jsx("input", { type: "checkbox", checked, readOnly: true, tabIndex: -1 }) }),
|
|
607
|
+
/* @__PURE__ */ jsx("div", { children })
|
|
608
|
+
] }, key);
|
|
609
|
+
}
|
|
610
|
+
if (node.type === "hardBreak") {
|
|
611
|
+
return /* @__PURE__ */ jsx("br", {}, key);
|
|
612
|
+
}
|
|
613
|
+
return /* @__PURE__ */ jsx("div", { children }, key);
|
|
614
|
+
}
|
|
615
|
+
};
|
|
616
|
+
var OpenEditorContent = ({
|
|
617
|
+
controller,
|
|
618
|
+
className = "oe-canvas"
|
|
619
|
+
}) => {
|
|
620
|
+
const internalController = controller;
|
|
621
|
+
return /* @__PURE__ */ jsx(EditorContent, { editor: internalController.editor, className });
|
|
622
|
+
};
|
|
623
|
+
var OpenEditorViewer = ({
|
|
624
|
+
document,
|
|
625
|
+
className = "oe-viewer",
|
|
626
|
+
renderers
|
|
627
|
+
}) => /* @__PURE__ */ jsx("div", { className, children: normalizeDocument(document).content.map((node, index) => renderViewerNode(node, `viewer-${index}`, renderers)) });
|
|
628
|
+
var useOpenEditor = useOpenEditorController;
|
|
629
|
+
|
|
630
|
+
export { OpenEditorContent, OpenEditorViewer, getDefaultSlashMenuItems, useOpenEditor, useOpenEditorController };
|
|
631
|
+
//# sourceMappingURL=index.js.map
|
|
632
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.tsx"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import {\n deleteTopLevelBlock,\n duplicateTopLevelBlock,\n findBlockSpecForNode,\n fromProseMirrorDocument,\n moveTopLevelBlock,\n normalizeDocument,\n toProseMirrorDocument,\n type ProseMirrorMark,\n type ProseMirrorNode,\n type OpenEditorDocument,\n} from \"@openeditor/core\";\nimport { toExportBundle } from \"@openeditor/exporters\";\nimport {\n defaultBlockRegistry,\n createOpenEditorInsertBlock,\n openEditorInsertPresets,\n seedDocument,\n type OpenEditorInsertPresetKey,\n} from \"@openeditor/extensions\";\nimport { InputRule, mergeAttributes, Node, type Editor } from \"@tiptap/core\";\nimport HorizontalRule from \"@tiptap/extension-horizontal-rule\";\nimport Image from \"@tiptap/extension-image\";\nimport Link from \"@tiptap/extension-link\";\nimport Placeholder from \"@tiptap/extension-placeholder\";\nimport { Table } from \"@tiptap/extension-table\";\nimport TableCell from \"@tiptap/extension-table-cell\";\nimport TableHeader from \"@tiptap/extension-table-header\";\nimport TableRow from \"@tiptap/extension-table-row\";\nimport TaskItem from \"@tiptap/extension-task-item\";\nimport TaskList from \"@tiptap/extension-task-list\";\nimport TextAlign from \"@tiptap/extension-text-align\";\nimport Underline from \"@tiptap/extension-underline\";\nimport { NodeSelection, Plugin } from \"@tiptap/pm/state\";\nimport { ReplaceStep } from \"@tiptap/pm/transform\";\nimport { EditorContent, useEditor } from \"@tiptap/react\";\nimport StarterKit from \"@tiptap/starter-kit\";\nimport { useMemo, useState, type ReactNode } from \"react\";\n\nexport type OpenEditorReactProps = {\n initialDocument?: OpenEditorDocument;\n editable?: boolean;\n placeholder?: string;\n onChange?: (document: OpenEditorDocument) => void;\n onFilePasteDrop?: (file: File) => boolean;\n slashMenuItems?: readonly OpenEditorSlashMenuItem[];\n};\n\nexport type OpenEditorReactConfig = OpenEditorReactProps;\n\nexport type OpenEditorController = {\n editor: Editor | null;\n document: OpenEditorDocument;\n exports: ReturnType<typeof toExportBundle>;\n editable: boolean;\n placeholder: string;\n selectedBlock: OpenEditorInsertPresetKey;\n setSelectedBlock: (blockName: OpenEditorInsertPresetKey) => void;\n getContent: () => OpenEditorDocument;\n setContent: (document: OpenEditorDocument) => void;\n setParagraph: () => void;\n toggleHeading: (level: 1 | 2 | 3 | 4 | 5 | 6) => void;\n toggleBold: () => void;\n toggleItalic: () => void;\n toggleUnderline: () => void;\n toggleStrike: () => void;\n toggleInlineCode: () => void;\n toggleBulletList: () => void;\n toggleOrderedList: () => void;\n toggleTaskList: () => void;\n undo: () => void;\n redo: () => void;\n insertBlock: (blockName?: OpenEditorInsertPresetKey, range?: InsertRange) => void;\n setLink: () => void;\n moveSelectedBlock: (direction: -1 | 1) => void;\n duplicateSelectedBlock: () => void;\n deleteSelectedBlock: () => void;\n slashMenuItems: readonly OpenEditorSlashMenuItem[];\n slashState: SlashState | null;\n selectionBubbleState: SelectionBubbleState | null;\n};\n\nexport type OpenEditorContentProps = {\n controller: OpenEditorController;\n className?: string;\n};\n\ntype InternalOpenEditorController = OpenEditorController & {\n editor: Editor | null;\n};\n\ntype RenderAttributes = Record<string, string | number | boolean | null | undefined>;\nexport type InsertRange = { from: number; to: number };\nexport type SlashState = {\n query: string;\n from: number;\n to: number;\n left: number;\n top: number;\n};\nexport type SelectionBubbleState = {\n left: number;\n top: number;\n};\nexport type OpenEditorSlashMenuItem = {\n key: string;\n label: string;\n group: string;\n keywords?: readonly string[];\n run: (context: { controller: OpenEditorController; range: InsertRange }) => void;\n};\n\nexport type OpenEditorViewerRenderer = (context: {\n node: ProseMirrorNode;\n children: ReactNode;\n}) => ReactNode;\n\nexport type OpenEditorViewerProps = {\n document: OpenEditorDocument;\n className?: string;\n renderers?: Partial<Record<string, OpenEditorViewerRenderer>>;\n};\n\ndeclare module \"@tiptap/core\" {\n interface Commands<ReturnType> {\n columns: {\n insertColumns: (count?: 2 | 3 | 4) => ReturnType;\n };\n }\n}\n\nconst COMMON_HTML_ATTRIBUTES = [\"id\", \"class\", \"title\", \"lang\", \"dir\", \"data-id\", \"style\"] as const;\nconst LAYOUT_ATTRIBUTES = [\"align\", \"width\", \"height\"] as const;\nconst URL_ATTRIBUTES = new Set([\"href\", \"src\"]);\nconst FORBIDDEN_PASTE_TAGS = new Set([\"script\", \"iframe\", \"object\", \"embed\", \"meta\", \"base\"]);\n\nconst createStandardAttributes = (attributeNames: readonly string[]) =>\n Object.fromEntries(\n attributeNames.map((attribute) => [\n attribute,\n {\n default: null,\n parseHTML: (element: HTMLElement) => element.getAttribute(attribute),\n renderHTML: (attributes: Record<string, unknown>) =>\n attributes[attribute] ? { [attribute]: attributes[attribute] } : {},\n },\n ]),\n );\n\nconst isSafeUrl = (value: string, allowDataImage: boolean) => {\n const normalized = value.trim().toLowerCase();\n\n if (normalized.startsWith(\"javascript:\") || normalized.startsWith(\"vbscript:\")) {\n return false;\n }\n\n if (normalized.startsWith(\"data:\")) {\n return allowDataImage && normalized.startsWith(\"data:image/\");\n }\n\n return true;\n};\n\nconst sanitizePastedHtml = (html: string) => {\n const parser = new DOMParser();\n const parsed = parser.parseFromString(html, \"text/html\");\n const isFromOpenEditor = /data-openeditor-|oe-|node-/.test(html);\n const preservedAttributes: Record<string, string[]> = {\n a: [\"href\", \"target\", \"rel\"],\n img: [\"src\", \"alt\", \"width\", \"height\"],\n td: [\"colspan\", \"rowspan\"],\n th: [\"colspan\", \"rowspan\", \"scope\"],\n table: [\"border\", \"cellpadding\", \"cellspacing\"],\n \"*\": [\"id\"],\n };\n\n for (const tag of FORBIDDEN_PASTE_TAGS) {\n for (const element of Array.from(parsed.body.getElementsByTagName(tag))) {\n element.remove();\n }\n }\n\n for (const element of Array.from(parsed.body.querySelectorAll<HTMLElement>(\"[href], [src]\"))) {\n const allowDataImage = element.tagName.toLowerCase() === \"img\";\n\n for (const attribute of URL_ATTRIBUTES) {\n const value = element.getAttribute(attribute);\n if (value !== null && !isSafeUrl(value, allowDataImage)) {\n element.removeAttribute(attribute);\n }\n }\n }\n\n if (isFromOpenEditor) {\n return parsed.body.innerHTML;\n }\n\n const sanitizeElement = (node: globalThis.Node) => {\n if (node.nodeType === window.Node.ELEMENT_NODE) {\n const element = node as HTMLElement;\n const tagName = element.tagName.toLowerCase();\n const allowed = new Set([...(preservedAttributes[tagName] ?? []), ...(preservedAttributes[\"*\"] ?? [])]);\n\n for (const attribute of Array.from(element.attributes)) {\n if (attribute.name.startsWith(\"data-\") || !allowed.has(attribute.name)) {\n element.removeAttribute(attribute.name);\n }\n }\n }\n\n for (const child of Array.from(node.childNodes)) {\n sanitizeElement(child);\n }\n };\n\n sanitizeElement(parsed.body);\n return parsed.body.innerHTML;\n};\n\nconst Columns = Node.create({\n name: \"columns\",\n group: \"block\",\n content: \"column+\",\n isolating: true,\n defining: true,\n addAttributes() {\n return {\n ...createStandardAttributes([...COMMON_HTML_ATTRIBUTES, ...LAYOUT_ATTRIBUTES, \"cellspacing\"]),\n count: {\n default: 2,\n parseHTML: (element: HTMLElement) =>\n Number(element.getAttribute(\"data-openeditor-columns\") ?? 2),\n renderHTML: (attributes: Record<string, unknown>) => ({\n \"data-openeditor-columns\": attributes.count,\n }),\n },\n };\n },\n parseHTML() {\n return [{ tag: \"section[data-openeditor-columns]\" }];\n },\n renderHTML({ HTMLAttributes }: { HTMLAttributes: RenderAttributes }) {\n const count = Number(HTMLAttributes[\"data-openeditor-columns\"] ?? HTMLAttributes.count ?? 2);\n return [\n \"section\",\n mergeAttributes(\n {\n class: \"oe-columns\",\n \"data-openeditor-columns\": count,\n style: `--oe-column-count:${Math.min(Math.max(count, 2), 4)};${HTMLAttributes.style ?? \"\"}`,\n },\n HTMLAttributes,\n ),\n 0,\n ];\n },\n addCommands() {\n return {\n insertColumns:\n (count: 2 | 3 | 4 = 2) =>\n ({ commands }) =>\n commands.insertContent({\n type: \"columns\",\n attrs: { count },\n content: Array.from({ length: count }, (_, index) => ({\n type: \"column\",\n content: [\n {\n type: \"paragraph\",\n content: [{ type: \"text\", text: `Column ${index + 1}` }],\n },\n ],\n })),\n }),\n };\n },\n addKeyboardShortcuts() {\n return {\n Backspace: ({ editor }) => {\n const { selection } = editor.state;\n\n if (!(selection instanceof NodeSelection) || selection.node.type.name !== \"columns\") {\n return false;\n }\n\n const allColumnsEmpty = Array.from({ length: selection.node.childCount }, (_, index) =>\n selection.node.child(index),\n ).every(\n (column) =>\n column.childCount === 1 &&\n column.firstChild?.type.name === \"paragraph\" &&\n column.firstChild.childCount === 0,\n );\n\n if (!allColumnsEmpty) {\n return false;\n }\n\n editor.view.dispatch(\n editor.state.tr.replaceWith(selection.from, selection.to, editor.state.schema.nodes.paragraph.create()),\n );\n return true;\n },\n };\n },\n});\n\nconst Column = Node.create({\n name: \"column\",\n content: \"block+\",\n isolating: true,\n defining: true,\n addAttributes() {\n return createStandardAttributes([...COMMON_HTML_ATTRIBUTES, ...LAYOUT_ATTRIBUTES]);\n },\n parseHTML() {\n return [{ tag: \"div[data-openeditor-column]\" }];\n },\n renderHTML({ HTMLAttributes }: { HTMLAttributes: RenderAttributes }) {\n return [\"div\", mergeAttributes({ \"data-openeditor-column\": \"\", class: \"oe-column\" }, HTMLAttributes), 0];\n },\n});\n\nconst Divider = HorizontalRule.extend({\n addAttributes() {\n return {\n ...createStandardAttributes([\"class\", \"style\"]),\n class: {\n default: \"oe-divider\",\n },\n };\n },\n addInputRules() {\n return [\n new InputRule({\n find: /^(?:---|___|\\*\\*\\*)$/,\n handler: ({ state, range }) => {\n const { tr } = state;\n tr.insert(range.from - 1, this.type.create()).delete(tr.mapping.map(range.from), tr.mapping.map(range.to));\n },\n }),\n ];\n },\n addProseMirrorPlugins() {\n return [\n new Plugin({\n filterTransaction(transaction, state) {\n const { selection } = state;\n const isDividerSelection = selection instanceof NodeSelection && selection.node.type.name === \"horizontalRule\";\n const isTypingOverDivider = transaction.steps.some(\n (step) => step instanceof ReplaceStep && step.slice.content.size > 0,\n );\n\n return !(isDividerSelection && transaction.docChanged && isTypingOverDivider);\n },\n }),\n ];\n },\n});\n\nconst createEditorExtensions = (placeholder: string) => [\n StarterKit.configure({ horizontalRule: false }),\n Divider,\n Image.configure({ allowBase64: true }),\n Link.configure({ openOnClick: false }),\n Underline,\n TaskList,\n TaskItem.configure({ nested: true }),\n Table.configure({ resizable: true }),\n TableRow,\n TableHeader,\n TableCell,\n TextAlign.configure({ types: [\"heading\", \"paragraph\"] }),\n Placeholder.configure({ placeholder }),\n Columns,\n Column,\n];\n\nconst getNodeText = (node: { text?: string; content?: unknown[] }): string =>\n node.text ?? node.content?.map((child) => getNodeText(child as { text?: string; content?: unknown[] })).join(\"\") ?? \"\";\n\nconst getSlashState = (editor: NonNullable<ReturnType<typeof useEditor>>): SlashState | null => {\n const { selection } = editor.state;\n\n if (!selection.empty) {\n return null;\n }\n\n const { $from } = selection;\n const textBeforeCursor = $from.parent.textBetween(0, $from.parentOffset, \"\\n\", \"\\n\");\n const match = /(?:^|\\s)\\/([\\w -]*)$/.exec(textBeforeCursor);\n\n if (!match) {\n return null;\n }\n\n const query = match[1] ?? \"\";\n const from = $from.pos - query.length - 1;\n const to = $from.pos;\n const coordinates = editor.view.coordsAtPos(to);\n\n return {\n query,\n from,\n to,\n left: coordinates.left,\n top: coordinates.bottom + 8,\n };\n};\n\nconst getSelectionBubbleState = (editor: NonNullable<ReturnType<typeof useEditor>>): SelectionBubbleState | null => {\n const { selection } = editor.state;\n\n if (selection instanceof NodeSelection && selection.node.type.name === \"horizontalRule\") {\n return null;\n }\n\n if (selection.empty) {\n return null;\n }\n\n const fromCoordinates = editor.view.coordsAtPos(selection.from);\n const toCoordinates = editor.view.coordsAtPos(selection.to);\n\n return {\n left: (fromCoordinates.left + toCoordinates.right) / 2,\n top: Math.min(fromCoordinates.top, toCoordinates.top) - 8,\n };\n};\n\nconst getSelectedTopLevelIndex = (editor: NonNullable<ReturnType<typeof useEditor>>) => {\n const { $from } = editor.state.selection;\n const selectedTopLevelPosition = $from.depth > 0 ? $from.before(1) : 0;\n let selectedIndex = 0;\n\n editor.state.doc.forEach((_, offset, index) => {\n if (offset <= selectedTopLevelPosition) {\n selectedIndex = index;\n }\n });\n\n return selectedIndex;\n};\n\nexport const useOpenEditorController = ({\n initialDocument = seedDocument,\n editable = true,\n placeholder = \"Start writing...\",\n onChange,\n onFilePasteDrop,\n slashMenuItems = [],\n}: OpenEditorReactProps = {}): OpenEditorController => {\n const [document, setDocument] = useState(normalizeDocument(initialDocument));\n const [selectedBlock, setSelectedBlock] = useState<OpenEditorInsertPresetKey>(\"paragraph\");\n const [slashState, setSlashState] = useState<SlashState | null>(null);\n const [selectionBubbleState, setSelectionBubbleState] = useState<SelectionBubbleState | null>(null);\n const editor = useEditor({\n extensions: createEditorExtensions(placeholder),\n content: toProseMirrorDocument(normalizeDocument(initialDocument)),\n editable,\n editorProps: {\n attributes: {\n class: \"oe-prosemirror\",\n \"aria-label\": \"OpenEditor document\",\n },\n transformPastedHTML: sanitizePastedHtml,\n handlePaste: (_view, event) => {\n const file = event.clipboardData?.files?.[0];\n\n if (!file || !onFilePasteDrop?.(file)) {\n return false;\n }\n\n event.preventDefault();\n return true;\n },\n handleDrop: (_view, event, _slice, moved) => {\n const file = event.dataTransfer?.files?.[0];\n\n if (moved || !file || !onFilePasteDrop?.(file)) {\n return false;\n }\n\n event.preventDefault();\n return true;\n },\n },\n onUpdate: ({ editor: currentEditor }) => {\n const nextDocument = normalizeDocument(\n fromProseMirrorDocument(\n currentEditor.getJSON(),\n initialDocument.meta,\n ),\n );\n setDocument(nextDocument);\n onChange?.(nextDocument);\n setSlashState(getSlashState(currentEditor));\n setSelectionBubbleState(getSelectionBubbleState(currentEditor));\n },\n onSelectionUpdate: ({ editor: currentEditor }) => {\n setSlashState(getSlashState(currentEditor));\n setSelectionBubbleState(getSelectionBubbleState(currentEditor));\n },\n });\n const exports = useMemo(\n () => toExportBundle(document),\n [document],\n );\n\n const insertBlock = (blockName = selectedBlock, range?: InsertRange) => {\n if (!editor) {\n return;\n }\n\n const preset = openEditorInsertPresets.find((item) => item.key === blockName);\n if (!preset) {\n return;\n }\n\n const chain = () => {\n const commandChain = editor.chain().focus();\n return range ? commandChain.deleteRange(range) : commandChain;\n };\n\n chain().insertContent(createOpenEditorInsertBlock(preset.key)).run();\n setSlashState(null);\n };\n\n const setDocumentContent = (content: OpenEditorDocument[\"content\"]) => {\n if (!editor) {\n return;\n }\n\n editor.commands.setContent(toProseMirrorDocument(normalizeDocument({ ...document, content })));\n };\n\n const setContent = (nextDocument: OpenEditorDocument) => {\n if (!editor) {\n return;\n }\n\n editor.commands.setContent(toProseMirrorDocument(normalizeDocument(nextDocument)));\n };\n\n const moveSelectedBlock = (direction: -1 | 1) => {\n if (!editor) {\n return;\n }\n\n const currentDocument = normalizeDocument(fromProseMirrorDocument(editor.getJSON(), document.meta));\n const selectedIndex = getSelectedTopLevelIndex(editor);\n const nextIndex = selectedIndex + direction;\n\n if (nextIndex < 0 || nextIndex >= currentDocument.content.length) {\n return;\n }\n\n setDocumentContent(moveTopLevelBlock(currentDocument, selectedIndex, nextIndex).content);\n };\n\n const duplicateSelectedBlock = () => {\n if (!editor) {\n return;\n }\n\n const currentDocument = normalizeDocument(fromProseMirrorDocument(editor.getJSON(), document.meta));\n const selectedIndex = getSelectedTopLevelIndex(editor);\n setDocumentContent(duplicateTopLevelBlock(currentDocument, selectedIndex).content);\n };\n\n const deleteSelectedBlock = () => {\n if (!editor) {\n return;\n }\n\n const currentDocument = normalizeDocument(fromProseMirrorDocument(editor.getJSON(), document.meta));\n const selectedIndex = getSelectedTopLevelIndex(editor);\n setDocumentContent(deleteTopLevelBlock(currentDocument, selectedIndex).content);\n };\n\n const setLink = () => {\n if (!editor) {\n return;\n }\n\n const previousUrl = editor.getAttributes(\"link\").href as string | undefined;\n const url = window.prompt(\"URL\", previousUrl ?? \"https://\");\n\n if (url === null) {\n return;\n }\n\n if (!url) {\n editor.chain().focus().extendMarkRange(\"link\").unsetLink().run();\n return;\n }\n\n editor.chain().focus().extendMarkRange(\"link\").setLink({ href: url }).run();\n };\n\n const setParagraph = () => {\n editor?.chain().focus().setParagraph().run();\n };\n\n const toggleHeading = (level: 1 | 2 | 3 | 4 | 5 | 6) => {\n editor?.chain().focus().toggleHeading({ level }).run();\n };\n\n const toggleBold = () => {\n editor?.chain().focus().toggleBold().run();\n };\n\n const toggleItalic = () => {\n editor?.chain().focus().toggleItalic().run();\n };\n\n const toggleUnderline = () => {\n editor?.chain().focus().toggleUnderline().run();\n };\n\n const toggleStrike = () => {\n editor?.chain().focus().toggleStrike().run();\n };\n\n const toggleInlineCode = () => {\n editor?.chain().focus().toggleCode().run();\n };\n\n const toggleBulletList = () => {\n editor?.chain().focus().toggleBulletList().run();\n };\n\n const toggleOrderedList = () => {\n editor?.chain().focus().toggleOrderedList().run();\n };\n\n const toggleTaskList = () => {\n editor?.chain().focus().toggleTaskList().run();\n };\n\n const undo = () => {\n editor?.chain().focus().undo().run();\n };\n\n const redo = () => {\n editor?.chain().focus().redo().run();\n };\n\n const controller: InternalOpenEditorController = {\n document,\n editor,\n exports,\n editable,\n placeholder,\n selectedBlock,\n setSelectedBlock,\n getContent: () => document,\n setContent,\n setParagraph,\n toggleHeading,\n toggleBold,\n toggleItalic,\n toggleUnderline,\n toggleStrike,\n toggleInlineCode,\n toggleBulletList,\n toggleOrderedList,\n toggleTaskList,\n undo,\n redo,\n insertBlock,\n setLink,\n moveSelectedBlock,\n duplicateSelectedBlock,\n deleteSelectedBlock,\n slashMenuItems,\n slashState,\n selectionBubbleState,\n };\n\n return controller;\n};\n\nexport const getDefaultSlashMenuItems = (controller: OpenEditorController): OpenEditorSlashMenuItem[] => {\n const internalController = controller as InternalOpenEditorController;\n\n return [\n ...openEditorInsertPresets.map((preset) => ({\n key: preset.key,\n label: preset.label,\n group: preset.group,\n keywords: [preset.key],\n run: ({ controller: current, range }: { controller: OpenEditorController; range: InsertRange }) =>\n current.insertBlock(preset.key, range),\n })),\n {\n key: \"moveBlockUp\",\n label: \"Move Block Up\",\n group: \"block\",\n run: ({ range }) => {\n internalController.editor?.chain().focus().deleteRange(range).run();\n controller.moveSelectedBlock(-1);\n },\n },\n {\n key: \"moveBlockDown\",\n label: \"Move Block Down\",\n group: \"block\",\n run: ({ range }) => {\n internalController.editor?.chain().focus().deleteRange(range).run();\n controller.moveSelectedBlock(1);\n },\n },\n ...controller.slashMenuItems,\n ];\n};\n\nconst renderTextWithMarks = (\n text: string,\n marks: readonly ProseMirrorMark[] = [],\n key: string,\n): ReactNode =>\n marks.reduceRight<ReactNode>((children, mark, index) => {\n const nodeKey = `${key}-${mark.type}-${index}`;\n switch (mark.type) {\n case \"bold\":\n return <strong key={nodeKey}>{children}</strong>;\n case \"italic\":\n return <em key={nodeKey}>{children}</em>;\n case \"underline\":\n return <u key={nodeKey}>{children}</u>;\n case \"strike\":\n return <s key={nodeKey}>{children}</s>;\n case \"code\":\n return <code key={nodeKey}>{children}</code>;\n case \"link\":\n return (\n <a key={nodeKey} href={typeof mark.attrs?.href === \"string\" ? mark.attrs.href : undefined}>\n {children}\n </a>\n );\n default:\n return children;\n }\n }, text);\n\nconst renderViewerNode = (\n node: ProseMirrorNode,\n key: string,\n renderers?: Partial<Record<string, OpenEditorViewerRenderer>>,\n): ReactNode => {\n if (node.type === \"text\") {\n return renderTextWithMarks(node.text ?? \"\", node.marks, key);\n }\n\n const children = node.content?.map((child, index) => renderViewerNode(child, `${key}-${index}`, renderers)) ?? null;\n const blockKey = findBlockSpecForNode(defaultBlockRegistry, node)?.name ?? node.type;\n const customRenderer = renderers?.[blockKey];\n if (customRenderer) {\n return customRenderer({ node, children });\n }\n\n switch (blockKey) {\n case \"paragraph\":\n return <p key={key}>{children}</p>;\n case \"heading\": {\n const level = typeof node.attrs?.level === \"number\" ? Math.min(Math.max(node.attrs.level, 1), 6) : 2;\n switch (level) {\n case 1:\n return <h1 key={key}>{children}</h1>;\n case 2:\n return <h2 key={key}>{children}</h2>;\n case 3:\n return <h3 key={key}>{children}</h3>;\n case 4:\n return <h4 key={key}>{children}</h4>;\n case 5:\n return <h5 key={key}>{children}</h5>;\n default:\n return <h6 key={key}>{children}</h6>;\n }\n }\n case \"bulletList\":\n return <ul key={key}>{children}</ul>;\n case \"orderedList\":\n return <ol key={key}>{children}</ol>;\n case \"taskList\":\n return <ul key={key} data-type=\"taskList\">{children}</ul>;\n case \"blockquote\":\n return <blockquote key={key}>{children}</blockquote>;\n case \"codeBlock\":\n return <pre key={key}><code>{node.content?.map((child) => child.text ?? \"\").join(\"\")}</code></pre>;\n case \"divider\":\n return <hr key={key} />;\n case \"image\":\n return <img key={key} src={typeof node.attrs?.src === \"string\" ? node.attrs.src : \"\"} alt={typeof node.attrs?.alt === \"string\" ? node.attrs.alt : \"\"} />;\n case \"columns\":\n return <section key={key}>{children}</section>;\n case \"table\":\n return <table key={key}><tbody>{children}</tbody></table>;\n default:\n if (node.type === \"column\") {\n return <div key={key}>{children}</div>;\n }\n if (node.type === \"tableRow\") {\n return <tr key={key}>{children}</tr>;\n }\n if (node.type === \"tableHeader\") {\n return <th key={key}>{children}</th>;\n }\n if (node.type === \"tableCell\") {\n return <td key={key}>{children}</td>;\n }\n if (node.type === \"listItem\") {\n return <li key={key}>{children}</li>;\n }\n if (node.type === \"taskItem\") {\n const checked = Boolean(node.attrs?.checked);\n return (\n <li key={key} data-checked={checked ? \"true\" : \"false\"}>\n <label className=\"oe-task-item-checkbox\" aria-hidden=\"true\">\n <input type=\"checkbox\" checked={checked} readOnly tabIndex={-1} />\n </label>\n <div>{children}</div>\n </li>\n );\n }\n if (node.type === \"hardBreak\") {\n return <br key={key} />;\n }\n return <div key={key}>{children}</div>;\n }\n};\n\nexport const OpenEditorContent = ({\n controller,\n className = \"oe-canvas\",\n}: OpenEditorContentProps) => {\n const internalController = controller as InternalOpenEditorController;\n return <EditorContent editor={internalController.editor} className={className} />;\n};\n\nexport const OpenEditorViewer = ({\n document,\n className = \"oe-viewer\",\n renderers,\n}: OpenEditorViewerProps) => (\n <div className={className}>\n {normalizeDocument(document).content.map((node, index) => renderViewerNode(node, `viewer-${index}`, renderers))}\n </div>\n);\n\nexport const useOpenEditor = useOpenEditorController;\nexport { seedDocument };\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@openeditor/react",
|
|
3
|
+
"version": "0.0.4",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"sideEffects": false,
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/EasyLink-HQ/openeditor.git",
|
|
9
|
+
"directory": "packages/react"
|
|
10
|
+
},
|
|
11
|
+
"main": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"publishConfig": {
|
|
14
|
+
"access": "public"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"import": "./dist/index.js"
|
|
23
|
+
},
|
|
24
|
+
"./package.json": "./package.json"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@openeditor/core": "0.0.4",
|
|
28
|
+
"@openeditor/exporters": "0.0.4",
|
|
29
|
+
"@openeditor/extensions": "0.0.4",
|
|
30
|
+
"@tiptap/core": "3.27.1",
|
|
31
|
+
"@tiptap/extension-horizontal-rule": "3.27.1",
|
|
32
|
+
"@tiptap/extension-image": "3.27.1",
|
|
33
|
+
"@tiptap/extension-link": "3.27.1",
|
|
34
|
+
"@tiptap/extension-placeholder": "3.27.1",
|
|
35
|
+
"@tiptap/extension-table": "3.27.1",
|
|
36
|
+
"@tiptap/extension-table-cell": "3.27.1",
|
|
37
|
+
"@tiptap/extension-table-header": "3.27.1",
|
|
38
|
+
"@tiptap/extension-table-row": "3.27.1",
|
|
39
|
+
"@tiptap/extension-task-item": "3.27.1",
|
|
40
|
+
"@tiptap/extension-task-list": "3.27.1",
|
|
41
|
+
"@tiptap/extension-text-align": "3.27.1",
|
|
42
|
+
"@tiptap/extension-underline": "3.27.1",
|
|
43
|
+
"@tiptap/pm": "3.27.1",
|
|
44
|
+
"@tiptap/react": "3.27.1",
|
|
45
|
+
"@tiptap/starter-kit": "3.27.1",
|
|
46
|
+
"react": "19.2.7"
|
|
47
|
+
},
|
|
48
|
+
"peerDependencies": {
|
|
49
|
+
"react": ">=19"
|
|
50
|
+
}
|
|
51
|
+
}
|